# Autonomous Gate Self-Repair Design

Audience: AI coding agents first.

## Goal

Runplan MUST recover from task-gate failures, stale task bases, out-of-scope base defects, and stalled checks without manual babysitting. Recovery MUST preserve task scope, gate integrity, serialized landing, journal continuity, and selected preset.

## Non-Goals

- NEVER bypass, weaken, or mark a red gate green.
- NEVER mix base-repair changes into task commits.
- NEVER push directly to `main`.
- NEVER retry an unchanged failure without a bounded fingerprint ledger.
- NEVER switch presets during recovery. This design uses `codex` for current execution.

## Failure-Domain Decision

Gate failure attribution MUST stop at first matching class:

1. `base-drift`: task base differs from current integration base, or task diff contains base-only changes.
2. `gate-stalled`: active check makes no semantic progress beyond its configured budget.
3. `base-defect`: exact failing check reproduces on a clean worktree at current integration base.
4. `task-defect`: failure does not reproduce on clean base and is attributable to task delta.
5. `flake`: one clean-base or task rerun passes with identical inputs.
6. `unclassified`: evidence cannot prove one class.

`unclassified` MUST fail closed after one diagnostic attempt. Classification MUST use execution evidence, never filename guessing alone.

## Components

### Gate progress protocol

`lib/gates.sh` MUST emit line-oriented progress records for check start, active test start, active test completion, heartbeat, failure, and completion. Each record MUST include check identity, elapsed time, and output artifact path known before execution.

Human output remains concise. Machine records MUST be parseable without reading an unbounded log.

Required event shape:

```text
gate.progress { check, phase, item?, elapsedMs, outputPath }
```

Heartbeat proves liveness only. It MUST NOT reset semantic-progress timeout.

### Gate failure attribution

`src/engine/gates.js` owns attribution. It MUST:

- retain exact failing check, active item, bounded diagnostic excerpt, output path, exit status, and task/base heads;
- reproduce exact failing check once on clean current integration base;
- compare task content against current integration base before fixer dispatch;
- journal `gate.attributed` with class, fingerprint, evidence, and next action;
- route `task-defect` to scoped task fixer;
- route `base-defect` and eligible `gate-stalled` failures to base-repair transaction;
- route `base-drift` to task synchronization without fixer dispatch.

### Base-repair transaction

Base repair MUST run in dedicated branch and worktree from fetched `origin/main`:

```text
repair/<run-id>/<failure-fingerprint>
```

Transaction:

1. Freeze task dispatch for affected run.
2. Create clean repair worktree from current remote base.
3. Reproduce exact failure.
4. Dispatch fixer using run preset and evidence-bound prompt.
5. Permit only files justified by failing check plus direct critical imports; journal resolved scope.
6. Run exact failing check, then repository landing gate.
7. Land only through `.claude/scripts/ship.sh land`.
8. Fetch and fast-forward local base.
9. Remove repair worktree through landing workflow.
10. Synchronize affected task and resume its gate.

Failure before landing MUST leave main unchanged. Repair branch and evidence MUST remain recoverable when cleanup cannot complete.

### Task synchronization

Task synchronization MUST rebase task commits onto current integration base, update durable `taskBase`, and verify content delta contains only declared task deliverables. Conflict resolution uses existing constrained merge fixer and full gate.

Base-only changes MUST disappear from task scope calculation after synchronization. Synchronization MUST NOT consume task fixer budget.

### Engine migration supervisor

When target repository is active harness engine checkout and base repair changes loaded engine files, runner MUST checkpoint and request controlled restart. Launcher MUST re-exec same slug, preset, foreground mode, and arguments with `--engine-migrate` after a reserved restart exit code.

Restart MUST remain in same foreground terminal. Journal MUST append old/new engine SHAs and recovery fingerprint. No daemon or detached monitor may replace foreground ownership.

### Retry ledger

Ledger key:

```text
{ runId, taskId, failureClass, failureFingerprint, baseHead, taskHead }
```

Limits:

- one flake rerun per fingerprint;
- one base synchronization per unchanged base/task pair;
- two base-repair attempts per fingerprint, second at high fixer tier;
- zero retries after identical post-repair failure on unchanged heads.

Exhaustion MUST quarantine with full evidence and skip dependents only when dependency policy requires it.

## Data Flow

```text
task gate
  -> progress journal
  -> terminal failure or semantic stall
  -> attribution probe on clean base
  -> task fixer | base repair | base sync | bounded flake rerun
  -> gate green
  -> task land
  -> next wave
```

## Error Handling

- Base repair cannot reproduce failure: classify `flake`; rerun task gate once.
- Repair fixer touches unjustified path: restore repair snapshot; constrained retry once.
- Landing gate fails: keep repair branch; feed exact failure to second repair attempt.
- Base moves during repair: resync repair branch through landing workflow, re-gate, retry landing.
- Engine restart fails: journal `engine.restart-failed`; quarantine run without corrupting task state.
- Semantic progress stalls: terminate complete check process group, preserve output, classify `gate-stalled`.
- User-owned unrelated working-tree changes: repair worktree isolates them; NEVER stash or overwrite them.

## Testing

Deterministic tests MUST cover:

- heartbeat without semantic progress becomes `gate-stalled`;
- active test name and predeclared output path reach journal and fixer prompt;
- clean-base reproduction separates base defect from task defect;
- base repair lands through ship wrapper, never raw push;
- task branch rebases after base landing and scope contains declared files only;
- protected base files are repaired outside task worktree;
- retry fingerprint prevents loops;
- engine repair triggers same-terminal Codex preset restart and `engine.migrated` journal;
- original incident chain completes t2, then t3–t5 without quarantine or manual intervention;
- production launcher resolves rebuilt release artifact.

## Architecture Decisions

- Keep task fixer and base repair separate: deleting boundary recreates mixed diffs and protected-path quarantine.
- Put attribution in gate engine: callers need stable failure classes, not test-runner internals.
- Use launcher restart for engine changes: module-cache mutation cannot prove coherent live migration.
- Treat heartbeat as liveness only: process existence does not prove useful progress.
- Reuse existing ship wrapper, worktree primitives, journal, and retry ledger; no parallel recovery framework.
