Capture default instructions before durable prompt admission
Problem
LocalHarness bound an empty context manifest at open, so ordinary prompts omitted AGENTS.md and CLAUDE.md. Capturing mutable files at dispatch also lets a restart change an admitted prompt.
Design
Capture AGENTS.md then CLAUDE.md before publishing each durable prompt. Native checkout configurations use bounded current-file reads and content-addressed private archives. Configured volume projects use one pinned project generation for the entire capture, including when native execution is enabled. The required ModelTaskCommand reference retains the manifest's exact path and digest.
Retries observe the published manifest before reading the project. A lost publication acknowledgement cannot replace that manifest. Subsequent prompts capture current edits/deletions; unchanged checkout instruction bodies reuse archive references.
Decisions
- Uses #715's merged current-file reads and authored hard-link precedence fix. Updated from origin/main through a signed merge, preserving the published history; the PR diff now contains only instruction capture and its tests.
- State uses existing volume files and atomic publication operations. No store, protocol, polling loop, raw-host fallback, directory scan or synchronization primitive is added. The existing admission lock remains outermost.
- Native tool availability does not determine the context source. Retain the configured checkout/volume distinction; configured volumes always capture from one pinned generation.
- Explicit LocalHarnessConfig.context_manifest(FileRef) overrides automatic discovery. Otherwise the existing positive defaults cap each instruction at 65,536 bytes, further bounded by the harness file limit. Path and UTF-8/NUL checks apply before admission.
- Private staging helpers share the same existing ContentPublisher. Regression tests wrap the real provider to interrupt immediately before publication and after its commit but before acknowledgement. Filesystem transaction atomicity owns cuts inside a publication.
- This PR wires root instruction defaults. Skills/catalog and hook lifecycle integration follow separately.
Deletions
Delete the empty open-time manifest and publication block. Share the existing bounded instruction validator. Reuse one publisher across manifest, archive, prompt and mailbox staging. Net +941 lines (+996/-55); #715 is already on main.
Tests run
- bb1 through bs.ps1; latest-head native library test build passed in 2m08s with filesystem-local,native-execution,terminal,mcp-http,test-support, defaults enabled. Built binaries run directly afterward.
- 14 focused tests passed. Capture scenarios: 6, 2.369s; shrinking properties: 3, 0.005s (256 cases each); reopen: 2, 0.780s; admission cancellation: 2, 0.508s; staged goal recovery: 1, 0.438s.
- Capture coverage includes a project update between volume instruction reads and all 16 before/after publication cuts across checkout archives, manifests, prompts and mailbox files. Each cut edits AGENTS.md, deletes CLAUDE.md, discards the harness, reopens and retries. Published manifests keep the original exact reference/content; unpublished selections refresh. Completed resumes do not resend the model request.
- The race regression goes through production
stage_context_manifest, with an inline update between real instruction reads. The same byte-level detector accepts old AGENTS.md plus old CLAUDE.md and rejects the restored faulty checkout route (old AGENTS.md plus new CLAUDE.md). There is no generation-presence assertion. Its observer exists only in test builds. - Existing cases retain precedence, next-turn freshness, source edits/deletions, archive reuse and invalid/oversized input rejection before admission/model dispatch.
- Unchanged codec/discovery coverage from the initial head: 13 context-discovery tests passed; pinned-nightly debug ASan manifest fuzz target completed 1,000 executions with checked-in instruction seeds. No parser changes in this fix.
- Windows through lb.ps1: native cargo check --lib --tests passed in 27.99s (slot wait excluded), with the same feature closure.
- rustfmt, source LF/NUL checks, git diff --check and removed-caller searches passed. All measured runtime suites remain below 2.4s.