Files
Kun Chen 5d5b650300 fix(pipeline): safely publish CI repairs with proven continuity (#887)
* feat(ci): make post-repair revalidation opt-in

A CI repair used to restart the whole pipeline at Review, so every repaired
check cost another full Review, Test, Document, Lint, Push, and PR pass over
the change. That is the most expensive single behavior the pipeline has, and
it was unconditional.

ci.revalidate_repairs selects between the two deliveries. It defaults to
false: the repair is published immediately through publishRunHead - the same
guarded path the Push step uses, so review-approved-head continuity, the
force-with-lease anchor, remote verification, the push binding, and the
gate-mirror update all still apply - and the CI monitor keeps watching the
same run. Set true to keep the repair local, revoke the run's review
approval, and restart validation at Review so no CI repair is published
without having been reviewed.

The key lives in the existing ci block, so it inherits that block's global
config, trusted-default-branch-only sourcing, and repo-overrides-global
precedence with no new mechanism. It is a *bool so an explicit project false
overrides a global true rather than reading as unset.

Both CI fix paths take the same decision: the automatic auto-fix round and
the manual round a person authorizes at the CI gate. No-change retries, the
durable fix-attempt budget, duplicate-check suppression, transient reruns,
merge-conflict handling, force-push safety, custody, and cancellation are
untouched. The CI step logs which policy is in force before its first poll.

VISION.md gains the constraint this default follows from: cost is a
user-visible property of the gate, so a design that clearly adds significant
end-to-end latency or token consumption must be opt-in.

* no-mistakes(review): Preserve CI repair continuity across rebases

* no-mistakes(document): Correct stale CI repair documentation

* no-mistakes(ci): Fixed late gate-mirror failures misreporting published CI repairs. Published repairs now continue CI monitoring with a warning after durable remote binding, while Push-step mirror failures still propagate. Added regression coverage. Verified targeted race tests, rebase tests, make lint, and git diff --check

* no-mistakes(document): Document late gate-mirror failure handling

* fix(ci): decide repair publication by provable continuity

A CI repair was published whenever ci.revalidate_repairs was off, and a
merge-conflict repair rebases, so its head is not a descendant of the
reviewed head. The publication guard was relaxed for that case with a
base-ancestry exception, and a repair that reset to the rebase base
satisfied it: reproduced, the reviewed commits were force-pushed away while
the pipeline reported success. The actor was the CI repair agent itself, so
provenance cannot stand in for the proof either.

One rule now decides delivery on every CI-fix path, automatic and manual,
CI failure and merge conflict alike:

  a repair is published without revalidating only when its continuity with
  the reviewed, published head can be PROVEN; when it cannot, the repair
  revalidates from Review.

Continuity is proven when the repaired head is the run's durable
review-approved commit or a descendant of it, read through the same
reviewApprovedHead accessor the publication guard enforces, so the decision
to publish and the guard that permits the push cannot disagree. Every
failure to establish it - unreadable run, missing or malformed approval,
unverifiable ancestry - counts as unproven.

ci.revalidate_repairs still sets the intent identically on every path: false
publishes when it is provable, true revalidates outright. Merge-conflict
repairs are not carved out; they simply always land in the cannot-be-proven
half, because resolving a conflict changes the commit's patch-id and no
content-based guard can separate a resolved rebase from a dropped one. They
now revalidate rather than being refused, so conflict repair keeps working.

The base-ancestry exception and its rewriteBase plumbing are deleted;
assertReviewApprovedPushHead is descendant-only again with no exception.

Regressions: a genuine conflict rebase revalidates and succeeds; a
reset-to-base conflict repair revalidates, never reaches the remote, and the
reviewed work survives; an ordinary provable repair still publishes with the
flag off and still restarts with it on; a run with no review authority
revalidates rather than publishing.

* no-mistakes(review): Correct merge-conflict revalidation guidance across all surfaces

* no-mistakes(document): Correct CI repair revalidation documentation

* no-mistakes(lint): Regenerate no-mistakes skill documentation

* fix(push): record a publication only once all of it has settled

The gate-mirror update ran after the push binding and the recorded head,
which forced a choice between two wrong answers on a mirror failure.
Returning the error made the CI monitor call an already published repair
failed, and its next attempt then saw a clean, already-advanced head as
producing no changes. Swallowing the error left the gate behind the remote
for good, and `no-mistakes rerun` resolves its starting head from the gate,
so a later rerun silently omitted the published repair.

Settle the gate mirror before recording anything durable. Publication is now
all-or-nothing: remote push, gate mirror, push binding, and recorded head all
land or none of them are recorded. A partial failure is simply retryable - the
next attempt re-enters the same path, finds the remote already at this head
via an up-to-date no-op push, and completes the publication once the mirror
works. The CI-repair warning special case is gone with it.

Also correct four surfaces that still said the default publishes every repair,
when it publishes only a repair whose continuity is provable, and make the
merge-conflict regression conflict for real: the base and the feature now edit
the same line, so the resolved rebase genuinely changes the commit's patch-id
rather than replaying cleanly.

Regressions: an unsettled publication records nothing and the retry completes
it; a real conflict rebase revalidates and succeeds; a reset-to-base conflict
repair revalidates and the reviewed content survives on the remote.

* no-mistakes(review): Make CI repair publication atomic and retryable

* no-mistakes(document): Correct CI publication documentation

* fix(ci): fire the unsettled-publication retry only on real evidence

The retry added for a part-way publication triggered on any clean worktree
whose HEAD differed from the run's recorded head. That is not evidence a
publication was attempted: a fix agent that commits and then errors leaves
exactly that state, and so does a fixture whose recorded head trails the
branch. The retry then ran instead of the fix round and the repair agent was
never called, which is what broke
TestCIStep_BitbucketAutoFixUsesLivePRHeadSHAForLogs on CI.

publishRepair now records the commit whose publication it began and could not
finish, and clears it on success or when the repair revalidates instead. The
retry fires only for that exact commit, so it still settles a stalled
publication without spending another fix attempt, and never swallows a fix
round. The marker is in memory only: after a daemon restart the next fix
attempt settles it instead, at the cost of one attempt, which is the honest
accounting rather than a durable claim the process cannot make.

Regression: a differing head with no attempted publication still runs the fix
agent and never logs the retry.

* no-mistakes(review): Retry unsettled publications before evaluating CI checks

* no-mistakes(document): Document CI publication retry evidence

* fix(ci): bound the publication retry and order the revalidation write

Two defects in the repair-publication path, both reported on the PR.

The unsettled-publication retry costs no repair attempt by design, so a gate
mirror that could never be settled retried on every poll until the CI idle
timeout - seven days by default - while the repaired commit already sat on the
remote. Bound it to three attempts, then park for a person with the published
head named, because a rerun would resume from the stale gate head and omit the
repair. CI is testing the published commit, so no fix agent can help; what a
person needs is to know the local gate is behind.

recordLocalRepair advanced the in-memory head before its durable write. A
failed write left the monitor watching a head the run record did not know
about, still carrying its old review approval, with the revalidation the call
exists to trigger silently lost. Write durably first, then advance.

Regressions: the retry stops at its bound and parks naming the published head
while spending only one fix attempt; a failed revalidation write leaves both
the live head and the review approval untouched.

* no-mistakes(review): Persist and safely settle CI publication retries

* no-mistakes(document): Clarify CI publication settlement documentation

* no-mistakes(ci): Serialized the process-heavy CI repair fixture tests to prevent macOS subprocess exhaustion and indefinite fake-gh stalls. Verified with 3 repeated focused runs, 25 repetitions of the previously hanging case, and the full internal/pipeline/steps suite (passed in 113.6s)

* test(ci): stop paying for a monitor loop to assert a delivery decision

The macOS job timed out at the 600s package cap: the repair fixture tests each
drove the full CI monitor loop, so every case spent provider polls and several
subprocesses on a two-core runner to observe something commitRepair already
reports. Serializing them made the wall clock worse, not better.

Assert the delivery decision from commitRepair - Revalidate, the remote, the
review approval, the push binding - and keep exactly one monitor-loop test for
the wiring that is genuinely the monitor's: turning a held repair into a
restart at Review and stating the policy in force. Four full monitor loops go
away and the cases run in parallel again.

Coverage is unchanged: every case still asserts the same observables, and the
paths that are about the monitor - the fix round not being swallowed, the
bounded publication retry - still drive Execute.

* revert(ci): strip the unscoped publication-retry machinery

Two things were added to this branch by auto-answered review findings that
were never in its scope, and the captain has declined both.

Removed, not repaired:
- retryPendingRepair and its CI poll-loop call site, its bound, and its
  exhaustion gate. New runtime behaviour in the monitor.
- The durable pending-publication state it needed: SetCIPendingPublication,
  the ci_pending_publish_head / ci_pending_publish_attempts columns and their
  migration, the StepResult fields, and the restore-on-CI-entry path. A
  persistence and schema addition.
- publishRunHead's publicationProgress return, which existed only to tell that
  machinery whether the remote had been verified.

Three reported defects went with the code that contained them rather than
being fixed: a restored pending publication bypassed by a provider skip path,
a marker write that could be lost, and a marker never consumed after a daemon
restart. They are not reachable once the machinery is gone.

Kept unchanged: the uniform provable-continuity rule, the corrected agent
guidance and docs, the single-statement UpdateRunPublication, the reference
docs that no longer describe the removed mirror warning, and the real
merge-conflict regression.

Tests that only exercised the removed machinery go with it. What survives
still covers behaviour that survives, including that a partial publication
records nothing and the next attempt completes it - which is the atomicity
guarantee, not the retry.

* no-mistakes(document): Deduplicate CI revalidation configuration guidance
2026-08-28 22:30:37 -07:00

8.0 KiB

git push no-mistakes

Release Platform X Discord

kunchenguid%2Fno-mistakes | Trendshift

Kill all the slop. Raise clean PR.

English · 简体中文

no-mistakes demo

no-mistakes puts a local git proxy in front of your real remote. Push to no-mistakes instead of origin, and it spins up a disposable worktree, runs an AI-driven validation pipeline, forwards the branch to the configured push target only after every check passes, and opens a clean PR automatically.

  • Non-blocking - the pipeline runs in an isolated worktree without disrupting your work.
  • Agent-agnostic - claude, codex, grok, rovodev, opencode, pi, copilot, antigravity, or cursor / acp:<target> via acpx, with ordered fallbacks; every gate requires a runnable configured pipeline agent.
  • Agent-native - /no-mistakes lets your coding agent do a task and gate it, or gate existing committed work: it runs the pipeline, has the pipeline apply safe fixes, and escalates the rest to you.
  • Human stays in charge - auto-fix or review findings, your call.
  • Clean PRs by default - push, open PR, watch CI, and auto-fix failures in one shot.

Full documentation: https://kunchenguid.github.io/no-mistakes/

How it works

        your branch
            │  git push no-mistakes
            ▼
   ┌────────────────────────────────────────────────┐
   │  disposable worktree — your work stays put     │
   │  review → test → docs → lint → push → PR → CI  │
   └────────────────────────────────────────────────┘
            │  every check green
            ▼
        clean PR, opened for you

Each step either passes on its own or stops with a finding for you to act on. Safe, mechanical fixes are applied automatically; anything that touches your intent is escalated for you to approve, fix, or skip. The initial change reaches the configured push target only after every local gate is green.

When CI itself fails, the pipeline repairs it and publishes that repair through the same guarded force-push path - but only when it can prove the repair builds on the head you already reviewed. When it cannot prove that, the repair goes back through Review before it is published, so unrelated history cannot replace the reviewed commit. Merge-conflict repairs rewrite history, so they always take that safer route. Set ci.revalidate_repairs: true if every CI repair must itself be reviewed, at the cost of another full pass over your change each time CI is repaired.

Install

curl -fsSL https://raw.githubusercontent.com/kunchenguid/no-mistakes/main/docs/install.sh | sh

Windows, Go install, and build-from-source instructions are in the installation guide.

Quick Start

$ no-mistakes init
  ✓ Gate initialized

    repo  /Users/you/src/my-repo
    gate  no-mistakes → /Users/you/.no-mistakes/repos/abc123def456.git
  remote  git@github.com:you/my-repo.git
   skill  /no-mistakes installed for agents at user level

  Push through the gate with:
  git push no-mistakes <branch>

$ git checkout my-branch

# do some work in the branch...

$ git push no-mistakes
  * Pipeline started

  Run no-mistakes to review.

$ no-mistakes
# opens the TUI for the active run

For GitHub fork contributions, keep origin pointed at the parent repository and initialize with no-mistakes init --fork-url <your-fork-url>.

From the TUI you act on each finding: auto-fix ones are applied for you (or approve to let them), ask-user ones are a judgement call you approve, fix, or skip. Once every check is green, the gate forwards your branch to the configured push target and opens the PR for you, so there is no manual git push origin and no hand-written PR body. Prefer to let your coding agent drive the same flow headlessly? Use /no-mistakes (see below).

Three ways to trigger the gate

Every change runs through the same pipeline. Pick the entry point that fits how you're working when the change is ready:

  • git push no-mistakes - the explicit Git path. Push a committed branch to the gate remote instead of origin.
  • no-mistakes - the TUI. Run it after making changes (no commit needed) and a wizard walks you through creating a branch, committing, and pushing through the gate, then attaches to the run. no-mistakes -y does all of that automatically.
  • /no-mistakes - the agent skill. Tell the coding agent to do a task and gate it with /no-mistakes <task>, or use bare /no-mistakes to gate existing committed work. It runs the pipeline, has the pipeline apply safe fixes, and stops to ask you about anything that needs a human call.

no-mistakes init installs the /no-mistakes skill for Claude Code and other agents. Under the hood the skill drives no-mistakes axi, a non-interactive TOON interface to the same approval flow.

See the quick start for the full first-run walkthrough.

Development

make build   # Build bin/no-mistakes with version info
make test    # Run go test -race ./... (excludes the e2e suite)
make e2e     # Run the tagged end-to-end agent journey suite
make e2e-record # Re-record e2e fixtures when agent wire formats change
make lint    # Check generated skill drift and run go vet ./...
make skill   # Regenerate committed no-mistakes skill files
make fmt     # Run gofmt -w .
make demo    # Regenerate demo.gif and demo.mp4 (needs vhs and ffmpeg)
make docs    # Build the Astro docs site in docs/dist

See Makefile for the full target list.

make e2e-record overwrites internal/e2e/fixtures/ from the real claude, codex, opencode, and antigravity CLIs, spends real API quota, and should be reviewed before committing.

Star History

Star History Chart