Skip to content

investigate: fleet-wide format auto-fix workflow — push token, loop guard, concurrency #2014

Closed

Description

@dezren39

LIST 1. Design the mechanics for a GitHub Actions workflow, present in every fleet repo, that runs ALL formatters on main and auto-commits the resulting diff to main.

Questions to answer: (a) token strategy — the default GITHUB_TOKEN may not trigger downstream checks on its pushes; what per-repo secret/App token works fleet-wide and how is it provisioned per repo? (b) infinite-loop guard — a GitHub variable vs checking the previous commit's message/title; which is robust when the format commit itself produces a further diff? (c) concurrency — cancel-in-progress so a newer push supersedes a running format job instead of racing merges. (d) failure behaviour — what happens when the formatter diff conflicts or CI on the format commit goes red?

Program: Drew's 2026-10-28 directive (full text: hatch-personal memory/topics/id-program-2026-10-28.md).
Working pattern: parallel investigations, then the named synthesis issue merges them into a full design. Route guidance: Workhorse by default; Specialist/Summit for synthesis and ramification-heavy work. A result that says "done" is not the endpoint — the orchestrator reviews it and may commission another round. Deliverables: a markdown design/investigation doc (mermaid/SVG diagrams welcome) linked from this issue, plus follow-up issues for anything buildable. Build a proof of concept where the design calls for one, but do NOT build the permanent feature on top of an unreviewed PoC.

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Parent epic: #2055 — fleet expansion & placement program (2026-10-28 directive).

  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Triage input from #1997 (mcpx testing: format.yaml auto-format), triaged 2026-10-29 (queue task 2906) — the mcpx-side facts you need, so the PoC does not re-derive them:

    • A blocking format check already exists in this repo: .github/workflows/nix-ci.yml:4-12,29-60 — job treefmt ("treefmt check"), runs on both pull_request and push: [main], and checks only the changed files of the diff (git diff --name-only "$base...$GITHUB_SHA" → nix run .#format-check). base_sha comes from github.event.pull_request.base.sha || github.event.before, with an all-zeros fallback to HEAD^.
    • No autofix workflow exists anywhere in .github/workflows/ (no format*/*fix*), so a formatting diff that reaches main turns the check red and nothing repairs it.
    • No branch protection and no rulesets (/branches/main/protection unset, /rulesets → []), so a GITHUB_TOKEN push to main would succeed today and break the day protection is enabled. Nothing currently pushes formatting.
    • Ordering conflict to decide first: if the auto-fix commits to main, the main-side treefmt check must not be able to block the repair it needs — otherwise "fix only when CI is green" can never fire, because whenever CI is green the tree is already formatted (analysis in mcpx testing: format.yaml -- auto-format after a green run; PR head vs main #1997, "The conflict to resolve first", option 1). Note the same reasoning applies whether the gate reads the check job or the whole run.
    • What the autofix actually earns in this repo is drift that bypasses a PR: a formatter version bump in flake.lock, a direct push, or a merge that skipped the hook — PRs already get a blocking gate, so a per-PR autofix push is optional rather than the main value.

    Full analysis: #1997 (comment) (this is the mcpx-side input to #2014/#2015; #1997 stays open pending their decision rather than growing a second workflow).

  4. added
    priority/highImportant and time-sensitive
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 29, 2026
  5. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Top priority — ID program wave-1. Drew directed this be picked up in the next runs (2026-10-29): enqueued directly as triage task 3335 in repo-health-code-pilot at queue priority 20 (only breakage-class work at priority 10 outranks it). Wave-1 is the ungated investigations and designs; syntheses and PoCs stay gated on their named inputs. Investigation route: Workhorse.

  6. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

    • Agent: queue worker (repo-worker-code), lane D
    • Session / ID: queue task 3335 (triage/investigation)
    • Found via: queue claim
    • Task: Investigate investigate: fleet-wide format auto-fix workflow — push token, loop guard, concurrency #2014 (ID program wave-1, LIST 1): design the mechanics for a fleet-wide format auto-fix workflow (all formatters on main, auto-commit the diff to main) answering (a) token strategy, (b) infinite-loop guard, (c) concurrency, (d) failure behaviour — grounded in the fleet's actual current workflows, with a design doc linked from this issue and follow-on work routed.
    • Expectation: investigation verdict + design doc + follow-up routing posted this shift; no permanent feature built on an unreviewed PoC.
  7. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 29, 2026
  8. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · investigation complete — all four questions decided, design doc linked, PoC routed

    Premise verified

    No fleet-wide format auto-fix exists. code has only the treefmt check (nix-ci.yml, changed files, contents: read); opencode and dezren39/nix have no auto-fix workflow (nix does carry a root treefmt.toml). The building blocks all exist in-fleet: code's mod-tidy.yml already auto-commits to main, and openchamber's nix-hashes.yml already runs an App-token bake bot.

    The four answers (full reasoning in the design doc)

    • (a) Token — GitHub App token, fleet standard. Minted per run (actions/create-github-app-token), scoped to contents: write. Decisive reason: pushes made with the default GITHUB_TOKEN trigger no downstream workflows, so a format commit would land on main unverified (and is rejected outright where required checks gate main). The App's pushes get full CI; the token is short-lived, single-permission, per-repo revocable. This is openchamber's proven pattern (incl. its persist-credentials: false lesson — a persisted GITHUB_TOKEN shadows the App token and 403s). PATs rejected (standing, broad, person-tied). GITHUB_TOKEN stays acceptable only for trivially-safe mechanical commits — mod-tidy's exact case. Provisioning: install one fleet App per repo + org/repo secrets + ruleset bypass actor, else the bake-bot auto-PR fallback.
    • (b) Loop guard — layered; the either/or is a false choice. L1 actor/subject skip (head commit is the bot's [format] commit → exit; a variable cannot express "the previous commit was mine"). L2 idempotence — the load-bearing backstop: a converged tree yields no diff, no commit, no push (what mod-tidy already survives on). L3 consecutive-commit cap: if the format commit itself produces a further diff (non-idempotent/fighting formatters — a bug, not a loop to feed), refuse a third consecutive bot commit, fail, and summon a human via the standing issue. A repo variable FORMAT_AUTOFIX_ENABLED is included as a kill switch — that's what variables are for; they are not the guard.
    • (c) Concurrency — per-ref group, cancel-in-progress: true, deliberately opposite CI: push-to-main verification runs share one cancellable group — 11 of the last 18 id-check main runs were cancelled by the next merge #392. Verification runs are run_id-keyed so no merge's verification is ever cancelled; a fixer's input is a tree state, and a run formatting a stale SHA is worse than wasted (its push races). Push protocol completes the safety: non-force push; on rejection, fetch + rebase + re-run formatters + retry ≤2, then fail.
    • (d) Failure behaviour — all-or-nothing, visible, never silently reverted. Any formatter error → no commit (never a half-formatted tree). Rebase conflict → abort push, update one standing "format auto-fix: debt and failures" issue (also the target for L3 trips and repeat crashes). CI red on the format commit is a normal main breakage — the repos' main-broken watchers surface it; remedy is revert or fix-forward by a human/agent, never auto-revert (red may be a real defect the formatter exposed).

    Routing

    PoC implementation in developing-today/code only enqueued as queue task 3374 (workflow landed with the kill switch off; verification sequence on main once App provisioning exists, else the exact blocked remainder is recorded). Fleet rollout (opencode, openchamber, nix) is a separate follow-up after PoC review — no permanent feature on an unreviewed PoC. Open items for the reviewer are named in the doc: reuse-vs-dedicated App is Drew's call; per-repo ruleset state decides direct-push vs auto-PR fallback at rollout.

  9. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    on Oct 29, 2026
  10. 8 remaining items

  11. added
    queue/blockedQueue or user escalation state
    status/blockedQueue or user escalation state
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Oct 29, 2026
  12. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    Fresh check this shift: issue #2014 is OPEN, labelled status/blocked + queue/blocked + priority/high — no hard-stop labels, and no in-flight session in its recent notes. Latest notes are from 2026-10-29: the investigation was completed under task 3335 (all four questions decided, design doc linked, PoC routed), and the PoC task 3374 was then blocked as a packet defect — "premise superseded by auto-format.yml already on main" (note 6496196151). The claimant should re-verify that supersession at current main and drive issue #2014 to its terminal decision from there.

  13. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triaged → closing COMPLETED: the investigation is delivered and its output is consumed (also resolving the 2026-10-29 "needs a decision" block)

    What this issue asked for, and where it landed

    The deliverable was an investigation answering four mechanics questions for a fleet-wide "format on main, auto-commit the diff" workflow. That was delivered on 2026-10-29 (task 3335):

    • Design doc: files/designs/code-format-auto-fix-workflow.md (goal workspace), linked from this issue.
    • (a) token: GitHub App token, because GITHUB_TOKEN pushes trigger no downstream checks.
    • (b) loop guard: layered — actor/subject skip + idempotence as the load-bearing backstop + consecutive-commit cap + a kill-switch variable.
    • (c) concurrency: per-ref group, cancel-in-progress: true.
    • (d) failure: all-or-nothing, never silently reverted, one standing debt/failure issue.
    • PoC was routed as task 3374, which blocked as packet_defect because .github/workflows/auto-format.yml had already landed via PR ci: name the PR tier basic, state the merge requirement, replace Auto Assign with the repo sweeper (#1781) #2148 and the block asked for a decision: accept the landed workflow as the PoC, or amend it toward the design.

    The decision this block was waiting for (settled here, fresh state 2026-11-03, main d3476bce7)

    Accept the landed auto-format.yml as the PoC's de-facto implementation, and reconcile the design to it. This is no longer a near-miss frozen at merge time — it has been iterated three times since, each iteration reasoned in the workflow header:

    Deliberate divergences from the design doc, recorded here so nobody re-litigates them as defects:

    Design doc As-built Why settled
    Fleet GitHub App token repo-scoped fine-grained PAT (REPO_AUTOMATION_TOKEN) Single repo, single purpose; the App's decisive advantage (downstream CI on the push) is met by the PAT, and the fleet-App provisioning question stays with rollout (#2230), not the PoC
    per-ref concurrency, cancel true one group, cancel false + AUTO_FORMAT_LAST_SUCCESS_SHA A fixer's input is a tree state, not a run; cancelling a pass mid-diff was the bug, and the variable makes a stale queued pass a no-op
    full-tree pass changed files since last success, 25 h fallback Cheaper per run; correctness rests on the schedule cadence, not the range
    kill switch, L3 cap, standing failure issue none of the three Now optional hardening, not blockers: the trigger is scheduled (not push-chained), and idempotence is the loop guard. Revisit only if #4787 shows a real loop

    Where the remaining work actually lives (do not duplicate it here)

    Why close rather than keep open

    An investigation whose questions are answered, whose design has been reconciled to a landed and maintained implementation, and whose residuals are each owned by a live issue has no remaining work in this issue. Leaving it OPEN under status/blocked is the exact label/queue desync the coverage pass is trying to clean up.
    Reopen if #2015 or #4787 concludes the mechanics must be revisited.

  14. removed
    status/blockedQueue or user escalation state
    queue/queuedHas a queued task in the Supabase agent queue
    queue/blockedQueue or user escalation state
    on Nov 3, 2026
  15. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: reviewed (coverage loop-back)
    Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 8465 (small_fix, queued, priority 40) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
    Found via: coverage loop-back 2026-11-03

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

priority/highImportant and time-sensitivesource/creatorFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions