Skip to content

Epic Autonomous "Marathon" mode (v2.10) — opt-in#2

Merged
copeus merged 21 commits into
mainfrom
epic-autonomous-mode
Jul 13, 2026
Merged

Epic Autonomous "Marathon" mode (v2.10) — opt-in#2
copeus merged 21 commits into
mainfrom
epic-autonomous-mode

Conversation

@copeus

@copeus copeus commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Epic Autonomous "Marathon" mode (v2.10) — opt-in

Makes /v:epic optionally chew through its whole runnable feature DAG in one invocation instead of stopping at every feature — the productized version of the manual "keep-drilling" overnight pattern. Opt-in; the default epic is byte-for-byte unchanged.

What shipped (5 units, A→B→C→D)

  • A — marathon core contract (compound-v-epic-state.py): --init --stance marathon, next_feature_autonomous (DAG-transitive routing, terminal states), attempts + --can-retry + --last-error, --record-disposition, blocker-ledger lifecycle, --record-final-review gate, global breakers (--breaker-check/--trip-breaker/--record-progress-cycle), and human-resume (--clear-breaker/--clear-disposition/--start-sha). 214 selftests, checkpoint byte-identical.
  • B — cross-model Arbiter Panel (compound-v-epic-arbiter.py, new): on a failed feature, Codex + a fresh adversarial Claude decide retry / abandon / halt / suspected-external-blocker. Two-phase challenge-bound API (anti-replay), fail-closed secret redaction, O_NOFOLLOW evidence containment, family-diverse aggregation (one ballot per model family), Claude-only fallback capped to retry/abandon. 147 selftests. (agy/cursor are workers, not arbiters — no kernel confinement.)
  • C — driver + reviewer (v-epic.md, epic-mode.md, v-init.md, spec-reviewer.md): the autonomous loop (breaker gate before every model call, running→failed before arbitration, deterministic PASS sample-audit, final-review gate, halt-page runbook), /v:init stance config, and a new anti-reward-hacking reviewer pass (§2.5).
  • D — docs/CI/release: README Marathon Loop feature, CHANGELOG 2.10.0, version bump (lockstep), CI runs both new selftests under Python 3.9.

The Blocker Ledger (the "do everything you can" credo)

A fundamental external blocker — an upstream API that has no data — is a fact about the world, not a quality failure. Marathon isolates only the truly-impossible sub-tree, keeps building everything else, and reports the blockers to a human at the end (with the arbiter's evidence). In v2.10 blockers are always suspected (→ human verify); auto-confirmation needs a 2nd independent model family and is deferred.

Honest boundary (shipped verbatim in the docs — no overclaim)

"Survives a fall" = the loop continues automatically within one live session, and a human re-invokes /v:epic after a hard death (closed terminal, crashed machine, quota) to resume from committed state. There is NO automatic resurrection while you're away. That auto-watcher (execution lease + two-tier scheduler + generation-fenced execution layer) is a deliberately deferred, separate feature — the concurrency it needs is a distributed-systems problem in its own right, not an overnight add-on.

How it was built (dogfooded through Compound V itself)

Design converged over 4 Codex gpt-5.6-sol xhigh rounds (which drove the scope decision to defer the auto-watcher) + a plan-review round. Each code unit: a Sonnet-5 implementer + independent Codex security/correctness rounds (A: 11→5→8→0; B: 10→11→3→0), each fix re-verified, threat model pinned to converge. Cross-model review caught ~50 real defects a same-family pass missed (final-review bypass, runnable-vs-transitive-dependents, fail-open breakers, an escaped-quote secret-egress leak, evidence TOCTOU, canonical-audit clobber). All selftests green under LANG=C + Python 3.9; lint-frontmatter + manifest-validator clean.

Not merged — this is for your verdict.

🤖 Generated with Claude Code

copeus and others added 21 commits July 12, 2026 21:13
Marathon Loop + Heartbeat + Two-Tier Watcher + cross-model Arbiter Panel,
all opt-in (default epic unchanged). Pre-implementation design; under
cross-model + pre-flight review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rathon spec

Fundamental external blockers (upstream API has no data) are world-facts,
not quality failures: isolate ONLY the truly-impossible sub-tree, keep
building everything else, escalate with multi-model proof at epic end.
blocked_external requires >=2 external models to CONFIRM (opposite bias
from halt) so it can't become a lazy escape from hard work. Archetype:
astrology #150 horary sign-only cusps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Folds in code-archaeology + doc-validator(live) + domain-expert(research) +
Codex Sol xhigh. Major changes: execution lease w/ fencing token + atomic
writes (kills split-brain double-exec), global circuit breakers in-script
(total-attempts/resume-count/wall-clock dead-man), family-diverse arbiter
voting (dedupe correlated backends), parse-failure=drop-not-halt, terminal
running_with_failures vs blocked_needing_human, anti-reward-hacking PASS
audit, Py3.9 ISO Z-normalization, corrected honesty boundary (durable/
7-day-expiry/sleep/quota-auth/disable-cron). Includes expert audit + KB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes 3 critical concurrency defects + 6 secondary: flock-guarded lease
(os.replace != mutual exclusion), single atomic --claim-stale (kills the
acquire-then-recheck-stale self-defeat), honestly-scoped worker fencing
(reject stale completion at merge boundary, drop 'never double-executes'),
family-unknown ineligible for 2-family bar (cursor auto), done_with_blockers
terminal, arbiter classifies even at retry cap (only masks retry_fix->halt),
caller-supplied durable attempt token, disposition->status transition table,
core-contract serial unit owns all of epic-state.py + publishes before F3/F4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ferred

Codex Sol R3: every critical concurrency finding traces to the auto-
resurrection watcher, whose correct lease needs generation-fencing threaded
through the hardened dispatcher/worker/merge/commit layer. Decision: phase.
v2.10 = single-process marathon loop + Codex+Claude arbiter panel (agy/cursor
dropped from arbitration per Sol x3, kept as workers) + blocker ledger
(suspected->blocked_needing_human, confirmed needs 2 families) + global
breakers (--breaker-check read / --trip-breaker write) + driver + docs.
Resume = existing /v:resume + human /v:epic re-entry (no auto-revive). All
lease/flock/claim-stale/two-tier-watcher moved to a deferred v2.11 section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…2.10 spec

Final-review gate (done iff all-done AND final_review passed), remove
caller-controlled blocker confirmation (v2.10 always suspected, hard-reject
confirmed:true), arbiter ballot interface B emits prompt / accepts
--claude-ballot from driver C, agents/spec-reviewer.md into C's scope for the
anti-reward-hack gate. All 11 R4 findings bound as explicit plan constraints
(truth table, breaker frequency + honest wall-clock, --record-progress-cycle,
--init --stance, ledger lifecycle, feature-id audit validation, secret
redaction). Sol confirmed the v2.11 deferral killed the whole concurrency
race class — remaining findings are contract precision, resolved in the plan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4-unit plan: A core-contract (epic-state.py, serial), B arbiter panel,
C driver+reviewer prose, D docs+CI+release. Every spec Component + all 11
Sol-R4 constraints mapped to a task with exact signatures + acceptance tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…act corrections)

Partition confirmed disjoint; 13 runtime-contract findings bound as
acceptance criteria: A2 blocker-precedence (independent work before terminal
escalation), A2/A6 final-review roll-up (done only via --record-final-review
passed), A3 transition-gating to marathon stance, total_attempts invariant +
drop caller --attempt, B evidence-file containment + two-phase challenge-bound
ballot API + bounded supervisor output, C stance-binding + running->failed +
breaker cadence + crash-resume commit points.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the opt-in marathon stance to the epic-state spine: --init --stance,
next_feature_autonomous (DAG-transitive routing, terminal states), attempts
+ --can-retry + --last-error, --record-disposition, blocker-ledger lifecycle,
--record-final-review gate, global breakers (--breaker-check read /
--trip-breaker / --record-progress-cycle), Py3.9 ISO. Default checkpoint path
byte-identical; all new fields marathon-gated. 182 selftests (was 33) green
under LANG=C + Py3.9.

Dogfooded via Compound V: Sonnet-5 implementer + 3 Codex gpt-5.6-sol xhigh
review rounds (11->5->8->0 findings fixed: final-review bypass, runnable-
excludes-transitive-dependents, fail-safe breakers, stance-binding, ledger
reblock, idempotent-replay guards, malformed-state controlled-errors). Threat
model pinned (single-process script-owned state) to converge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New scripts/compound-v-epic-arbiter.py: two-phase prepare/classify API, HMAC-
keyed challenge with durable issued->in_progress->consumed record (anti-replay),
Codex read-only poll via the timeout supervisor (bounded --stdout/--stderr,
final-message-only parse, garbled=drop-not-halt), fail-closed secret redaction
(incl. escaped-quote/unclosed-block), O_NOFOLLOW dir-fd evidence containment
bound to the attempt dir, family-diverse aggregation truth table (one ballot
per family, unknown ineligible for the 2-family bar), Claude-only fallback
capped to retry_fix|halt_feature, blocked_external always SUSPECTED on the
Codex+Claude panel, byte-bounded audit (printed==persisted), agy/cursor
excluded from arbitration. 147 selftests green under LANG=C + Py3.9. v2.11
multi-process concerns (CAS/fsync) documented out-of-scope.

Dogfooded: Sonnet-5 implementer + 3 Codex gpt-5.6-sol xhigh security rounds
(10->11->3->0), threat model pinned (single-process, user-owned tree).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the sticky-breaker gap Codex flagged in the C driver review: a tripped
breaker / halt_epic latched the epic at blocked_needing_human forever with no
resume path but dropping to checkpoint. Adds --clear-breaker (clear latch +
re-arm: --reset-wall-clock / --set-max-total-attempts, warns if it would
re-trip), --clear-disposition (clear a sticky halt_epic so next_feature_
autonomous advances), and --init --start-sha (capture epic HEAD for the
halt-page accumulated-diff command). Marathon-gated; checkpoint byte-identical.
214 selftests (was 182) green under LANG=C + Py3.9.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wires the opt-in marathon path into /v:epic + epic-mode.md: stance-binding
(persisted autonomy.stance authoritative), --next --autonomous routing,
running->failed-before-arbitration, two-phase arbiter exchange (--prepare ->
fresh adversarial Claude Task -> --classify), breaker gate before every
model call (7 boundaries), deterministic PASS sample-audit (every 3rd done +
always the first), final-review gate before terminal done, halt-page runbook
(/v:resume <run-id>, autonomy.start_sha diff), human marathon-resume via
--clear-breaker/--clear-disposition. /v:init writes epic.autonomy.stance.
spec-reviewer.md gains PASS-2.5 anti-reward-hacking (ISSUE: REWARD_HACK).
Default checkpoint path behaviorally unchanged; honest v2.10 boundary
(in-session + human resume, no auto-resurrection — that's v2.11); no
fabricated metrics.

Dogfooded: Sonnet-5 implementer + Codex gpt-5.6-sol xhigh review (5 findings
fixed incl. the sticky-breaker gap -> the A follow-up above).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
README Marathon Loop feature bullet with the honest boundary (opt-in;
in-session + human /v:epic resume; NO auto-resurrection — deferred). CI
(validate.yml) now runs epic-state.py + epic-arbiter.py --selftest under
Python 3.9 (setup-python placed last so it doesn't repoint python3 away from
the 3.12+PyYAML lint/manifest steps). CHANGELOG [2.10.0]; plugin.json +
marketplace.json 2.9.0 -> 2.10.0 (lockstep). No fabricated metrics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…le sample-audit (v2.10)

Closes 2 cross-unit resume BLOCKERS from the Codex integration review:
(1) a breaker trip / hard death between arbiter-approval and the retry re-run
stranded the retry — next_feature_autonomous now routes a failed feature BY
its stored disposition (retry_fix+can_retry -> runnable, so the persisted
disposition IS the crash-safe retry intent; failed-without-disposition ->
needs_arbitration, re-run the arbiter, never silent-abandon).
(2) a done+commit before the PASS sample-audit let a crash skip the audit —
new --mark/--clear-sample-audit-due persist the obligation; done/final_review
are gated on no audit outstanding (record_final_review passed rejected while
due; _recompute_top_status factors it so status can't sit stale-done).
244 selftests (was 214); checkpoint byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Driver side of the 2 integration-review blockers: --record-disposition +
commit BEFORE the pre-retry breaker gate (persisted disposition = durable
retry intent); handle the needs_arbitration --next reason (re-run the
idempotent arbiter on a crash-mid-arbitration feature); persist
--mark-sample-audit-due together-with/before the done mark so a crash can't
skip the audit, surface sample_audit_due before final_review on resume.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…esume)

Integration review round 2 blockers (crash-window class): a disposition is
now stamped with the attempt it was made for and next_feature_autonomous
honors it ONLY on attempt match — a stale retry_fix from a prior attempt
routes to needs_arbitration instead of launching a second unapproved retry.
New --record-audit-failed does status=failed + last_error + clear
sample_audit_due + invalidate final_review in ONE atomic write, closing the
window where a crash mid audit-ISSUES left a bad done sticking. 264 selftests
(was 244); checkpoint byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (v2.10)

Closes the resume deadlock: --prepare rejects an in_progress/consumed
challenge, so a crash after --classify began had no recovery path. New
--resume-challenge returns absent/in_progress(+prompt)/consumed(+persisted
result) — a consumed challenge re-emits its verdict with ZERO model calls, so
the driver records the disposition without a second egress. Same containment
(validated epic dir, O_NOFOLLOW, size caps). 162 selftests (was 147).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ver (v2.10)

Driver side of integration round-2 blockers: needs_arbitration first calls
--resume-challenge and branches (consumed -> record-disposition from the
recovered result, no re-egress; in_progress -> re-dispatch+classify; absent ->
fresh prepare) so a crash mid-arbitration can't deadlock; sample-audit ISSUES
uses the atomic --record-audit-failed; a crash-recovered marathon success
routes through the sample-decide/mark-due-before-done handler instead of the
checkpoint done path so the first-success audit is never skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…xternal (v2.10)

Integration round-3 tail: a crash after --record-disposition blocked_external
but before --update --status blocked lost the ledger transition — resume
treated failed+blocked_external as abandoned. next_feature_autonomous now
surfaces needs_blocker_recording (symmetric to needs_arbitration) so the
driver completes the idempotent blocked/ledger transition on resume.
275 selftests (was 264); checkpoint byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rds (v2.10)

Integration round-3 tail: a crash after --classify persisted the frozen audit
but before flipping the challenge to consumed left the record in_progress, so
--resume-challenge re-dispatched Claude for an already-decided verdict.
It now probes the canonical audit first and returns consumed (zero model
calls) whenever the result exists. 168 selftests (was 162).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r_recording (v2.10)

Driver side of the round-3 tails: the halt-page recovery no longer bare-marks
a recovered feature done (routes through the §4 sample-decide/mark-due handler
so the first-success audit is never skipped); handles the new
needs_blocker_recording --next reason by idempotently completing the
interrupted --update --status blocked transition.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@copeus
copeus merged commit 54840fb into main Jul 13, 2026
1 check passed
copeus added a commit that referenced this pull request Jul 13, 2026
…; usage-object conformance; advisor_calls derived

Codex findings #1(BLOCKER),#2,#3,#4: empty/string/negative usage no longer becomes measured:true 0/0;
aggregate emits null (not real 0) when nothing measured; advisor_calls aggregates independent of
token-measured; collect-results deep-validates the usage object + derives advisor_calls from the
per-job advisor log (<run-dir>/logs/<job-id>.advisor.jsonl).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant