Skip to content

A task declares filesExpected upfront, a ledger records every edit, and a Stop hook mechanically checks disk before completion is accepted — so an agent can't claim work it didn't do.

Pattern

Hook-Enforced Contract

The shape

Declared upfront, recorded during, checked at completion.

1. Declareat plan time

task.filesExpected

[

{

path: "src/auth.py",

op: "modify",

required:

[validate_token]

},

{

path: "src/old.py",

op: "delete"

}

]

in_progress

2. Recordduring execution

task-{id}.ledger.jsonl

append on every

Write / Edit:

{ ts, tool,

path, op,

taskId, plan }

distinguishes

"touched this

session" from

"already existed"

completed

3. VerifyStop hook

stop-verify.sh

for each expected:

create → exists?

modify → exists

+ ledger hit?

delete → gone?

symbols → grep -q

exit 0 → accepted

exit 1 → block

Each stage is load-bearing. Strip one and the guarantee breaks.

Why all three

Remove any one and completion becomes self-certified again.

Declaration

filesExpected on the task — what will be touched, which op, what symbols.

Remove it →

The Stop hook has nothing to check. Completion reverts to self-report.

Recording

Ledger appended on every Write/Edit in the session.

Remove it →

Can't verify modify — file may already have existed without being touched this run.

Verification

Stop hook reads expected + ledger, checks disk, exits 0 or 1.

Remove it →

Contract is declared and recorded but never enforced. Agent walks past.

The three components are a tripod — kicking any leg collapses the whole.

What this kills

The phantom-edit failure mode, step by step.

Phantom edit — anti-patternthe pattern exists to eliminate this

1

Builder writes "STATUS: COMPLETE — deleted X, modified Y"

(no files actually touched)

2

Validator runs a narrow grep on the agent's description — sees nothing suspicious — passes

3

Phase finalizer reads the real git diff — files were never touched

4

Regression discovered in production.

Step 1 is impossible under the contract. The Stop hook sees filesExpected, checks disk, finds the missing edit, exits 1 — before the validator ever runs. The error surfaces at the builder's own retry ladder, not three steps downstream in production.

What happens when it fails

The Tier 1 / 2 / 3 retry ladder.

Tier 1

Direct fix

Error names an exact path and symbol. Fix precisely what the error says — no re-investigation.

immediate retry

Tier 2

Investigate

Error is unclear. Re-read the task description and the TDD section, apply a corrected approach.

second attempt

Tier 3

Block

After two failed retries, call task_update --status blocked with a specific reason. Orchestrator creates a correction task — no infinite loops.

hand off

Two strikes and the task escalates. The orchestrator owns the fix — the agent never loops forever on a contract it can't satisfy.

The discipline

Self-reported completion is a claim. Disk state is proof.

The hook doesn't trust the agent's summary — it opens the files. Declared upfront, recorded during, checked at exit. If the contract doesn't match the disk, the agent doesn't get to say it's done.