From harness-claude
Proposes a full-context revert PR when a shipped PR fails post-merge evaluation or crosses a signal threshold. Never auto-merges; a human merges the revert.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:harness-rollbackThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Post-ship circuit breaker. Proposes a full-context **revert PR** when a shipped PR fails post-merge evaluation or crosses a signal threshold. v1 is **propose-only** — it NEVER auto-merges. A human merges the revert.
Post-ship circuit breaker. Proposes a full-context revert PR when a shipped PR fails post-merge evaluation or crosses a signal threshold. v1 is propose-only — it NEVER auto-merges. A human merges the revert.
.harness/signals/ series) crosses a threshold and you want the implicated PR(s) evaluated for rollback.rollback-propose workflow drives automatically.git/gh directly).v1 never auto-merges a revert. It opens a revert PR and stops. A human decides.
Auto-merging code — even a revert — is a high-blast-radius write, and a wrong revert is itself an incident. The trust model earns auto-merge authority only after the propose loop has demonstrably proposed correct reverts over time (recorded via the rollback_event breadcrumb). Until then, the workflow carries pull-requests: write but not contents: write and no self-approving PAT. If you find yourself merging a revert automatically, STOP — that is a separate, deferred trust tier (see ADR 0063).
--pr <n>) and the trigger (signal or eval).gh. If the PR is not merged (no merge commit), stop with a structured skipped decision — there is nothing to revert.-m 1); a squash/rebase merge is single-parent and reverts against its sole parent. This repo uses both — never assume a two-parent merge.Run classifyRevert (core). A target is revert-ready only when BOTH hold:
git merge-tree --write-tree of the revert applies with no conflicts. (Never a working-tree-mutating git revert -n.)action: 'blocked' (a naive revert would orphan newer work).blastRadius and migrationWarnings are context only, never gates — they enrich the PR body so the human reviewer sees the stakes; they do not decide revert-readiness.
--dry-run, print the PR body and stop — open no PR.revert: <original> (automated rollback), marker label harness:rollback, body = the full context block (trigger, target, revert-ready verdict, classification reasons, blast-radius, migration warnings, and the --reason if given).harness:rollback already references the target (#<n>, word-boundary matched — #42 must not match #420), skip — do not open a duplicate.Append one rollback_event to .harness/signals/: { targetPr, trigger, revertReady, action, prUrl, reason, ts }. This append-only record is what later justifies (or refuses) the auto-merge trust tier — it is not backfillable, so it is written on every evaluation.
rollback-propose.yml workflow runs harness rollback sweep, which reads .harness/signals/timeline.json and, for each rollback.signals entry { threshold, direction, window }, detects an edge crossing, resolves the PR(s) merged in the window, and forwards each to evaluate --trigger signal.rollback.evalTrigger.enabled (default false). When outcome-eval is wired to run post-merge (#31), a high-confidence NOT_SATISFIED will route through the same engine with --trigger eval. Until then the path exists and is unit-tested but never fires — enabling it is a config flip, not a code change.harness rollback evaluate — the CLI core; classification + compose + breadcrumb for one target PR.harness rollback sweep — the signal arm; timeline threshold detection → evaluate.classifyRevert / RollbackDecision (@harness-engineering/core) — the pure, injected-IO classification engine..github/workflows/rollback-propose.yml — propose-only post-merge + scheduled workflow. contents: read + pull-requests: write, concurrency-serialized, no self-approving PAT.harness.config.json → rollback — signals (record of { threshold, direction, window }) and evalTrigger.enabled.skipped/blocked decision and no PR.rollback_event breadcrumb.rollback.evalTrigger.enabled is false.contents: write, no self-approving PAT).merge-tree), never with git revert -n.| Rationalization | Reality |
|---|---|
| "The eval clearly failed, so I should auto-merge the revert to stop the bleeding" | v1 has no auto-merge authority. Open the PR; a human merges. Auto-merge is a deferred trust tier (ADR 0063). |
"git revert -n in a temp index is fine for the readiness check" | -n still writes the working tree. Use git merge-tree --write-tree — pure in-memory, no side effects. |
"It's a merge commit, so -m 1 is safe" | Squash/rebase merges are single-parent; -m 1 computes a meaningless revert. Check the parent count first. |
| "The signal fired, so every PR in the window should be reverted" | Only revert-ready targets are proposed, and only the human merges. A crossing is a signal to evaluate, not to revert blindly. |
Context: harness.config.json sets rollback.signals.error-rate = { threshold: 50, direction: "above", window: "24h" }. The hourly rollback-propose workflow runs harness rollback sweep.
sweep reads .harness/signals/timeline.json → error-rate crosses 50 (edge, not plateau)
→ resolves PRs merged in the 24h window: #758
→ evaluate --pr 758 --trigger signal
RESOLVE: #758 merged, two-parent merge commit
CLASSIFY: merge-tree revert clean; no later merge touches its files → revert-ready
COMPOSE: opens "revert: Add tiered discount pricing (automated rollback)"
labeled harness:rollback, body carries trigger + blast-radius + migration warning
RECORD: appends rollback_event { targetPr: 758, trigger: signal, action: proposed, ts }
→ A human reviews and merges the revert PR. Autopilot never merges it.
Context: Manual invocation harness rollback evaluate --pr 740 --dry-run.
CLASSIFY: PR #752 merged after #740 and touches the same files (dependent merge)
→ revertReady: false, action: "blocked"
→ no PR opened; decision reports "a later merge (#752) depends on this PR's files"
-m 1). If parent resolution is ambiguous, stop with a skipped decision and surface the merge shape — do not guess.git merge-tree exits non-zero for a reason other than conflict (e.g. 128 bad object): this is an error, not a conflict. Re-throw and surface it; do not report a false skipped.rollback_event track record. Open the PR and let a human merge.rollback.evalTrigger.enabled is true but #31 has not landed: the eval arm has no post-merge invoker yet, so it still won't fire; note the dependency rather than wiring a bespoke trigger.npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeProvides a git revert workflow and Revertomatic PR template for reverting merged PRs that break CI or nightly payloads.
Shepherds PRs through CI checks and code reviews to merge readiness by iteratively assessing stack health, fixing failures, and addressing all feedback.
Safely rolls back failed features, builds, or branches with a destructive confirmation step. Activated on revert/undo/abort intent.