Skip to content

Latest commit

 

History

History
76 lines (60 loc) · 3.84 KB

File metadata and controls

76 lines (60 loc) · 3.84 KB

Using Proctor

Two roles: whoever authors the contract, and whoever (or whatever) executes it under the gates. They should not be the same model — see the last section.

Writing a contract that verifies itself

The one rule that transfers trust from the model to the harness: every ACCEPTANCE bullet carries a backticked runnable command (exit 0 = pass). The bridge turns those into machine checks that goal-verify runs against reality. A prose bullet becomes human_review and stalls the close on a human — use at most one, and only when a check truly needs judgment.

=== LOCKED CONTRACT ===
GOAL: <one sentence — an outcome, not a method>
ACCEPTANCE:
  - <observable thing>: `<command that exits 0 when true>`
  - suite green: `pnpm vitest run --reporter=dot`
  - no stubs in touched code: `! grep -rn "NotImplementedError\|TODO: implement" src/area/`
NON-GOALS:
  - do not touch `src/legacy/**` or `deploy.sh`
BUDGET: ~2h, ≤4 files.
TRIPWIRE: At the budget — or any scope/non-goal temptation — STOP and report.
DISPOSITION: Before done, emit DISPOSITION LOG closing every witnessed condition BY KEY
([FIXED] <key> — evidence). [OWNED] is not a final tag.
RULES: Restate this contract before the first action. Work only to this contract.
=== Work only to this contract. ===

Two extras that also become enforced checks:

  • NON-GOALS — backticked path/globs (e.g. `src/cache/**`) become a forbidden-list checked against the actual git diff. Prose non-goals stay advisory (guessing globs from prose would cause false blocks).
  • BUDGET≤N files becomes a changed-file-count check.

Running an agent under a contract

  1. Author the contract outside the session that will execute it — that's the load-bearing rule. Use a planner model, or write it by hand.
  2. In the executing session: /clear, then paste the === LOCKED CONTRACT === block. The gates arm automatically. /clear first matters — a fresh session means the gate only ever grades the contracted work.
  3. Let it work. Stubs and failures are witnessed whether the agent mentions them or not.
  4. When it says "done": a false claim is blocked with the open conditions listed by key; an unproven claim is blocked until goal-verify signs the proof. You do nothing — the loop is agent-versus-gates.

The operator's side

When a contract needs your eyes or hands, you don't scan the transcript — you run proctor inbox: a short, current list of every session waiting on you, each with its checklist and a one-command release. Do the checklist, then proctor signoff <sid> --all. The release is recorded (signed_off_by: operator) and refuses to sign over a failing machine check — so it can't be gamed. Full workflow + trust model: operator-workflow.md.

Escape hatch: /disarm lists armed sessions; /disarm <sid> clears the whole gate set for one. Never needed for a healthy session.

The judge dial (optional)

Prose acceptance lines land on you by default. A local LLM "judge" can sign that residue so your desk only sees genuinely uncertain cases.

  • It runs in advisory mode first: it logs a verdict but signs nothing, so you can calibrate it against your own decisions (calibrate.py scores it against labeled fixtures).
  • When you trust it, set "mode": "autonomous" in judge.config.json (or trial per-session with WARDEN_JUDGE_MODE=autonomous). operator_required checks always still reach you, and an unreachable/uncertain judge escalates rather than passing.

Planner ≠ worker

The model that writes the checks must not be the model being checked. Amplifying instructions doesn't fix false completion — verification does. Author contracts (especially the ACCEPTANCE commands) with a planner model or by hand; hand the locked contract to the executor. The planner writes the exam; the worker sits it.