Bind LocalHarness to authorized private task files

Merged
VA
3d ago
+9699-420

Problem

LocalHarness has no authorized file/query binding for its private TaskVolume. Callers otherwise assemble owner grants and storage paths themselves or receive the privileged append interface.

Design

LocalHarness creates a private task volume and exposes task_files(). TaskFiles::open first requires an AgentPrivate volume with VolumeOwner::Agent exactly matching scope.agent(), then verifies both existing volume grants before touching storage. Project/Session owners and unbound scopes are rejected even with valid signed grants. write accepts caller requests and editable agent files against an exact generation, and rejects execution/approval records. observe reuses TaskVolume's atomic snapshot plus push follow, durable cursor and explicit reset.

The task-volume grants enter the host's signed scope after constructing the tool scope. Tools do not gain those grants. Main's newer goal admission and MCP installation remain intact.

Deletions

No bootstrap copy is deleted in this foundation slice; #514 remains required. Current diff: +661/-1, net +660 lines, including tests and models.

Decisions

  • #495 is merged. This branch merges main instead of rebasing published commits; the diff now contains only this binding slice.
  • This is the early API slice for #495 finding 1. Request-file admission and publication of actual model/tool/status files follow immediately; this PR does not claim that writing a request runs a task yet.
  • Reuse VolumeRef, ContentGrant, TaskVolume and StreamProvider. There is no service, gateway, socket, channel, new protocol or hidden runner. The actor package uses the same binding locally and when deployed.
  • All data remains logical files over existing append-only TaskVolume segments. The authorization wrapper retains no second index or authoritative state.
  • The Loom models execute the real TaskVolume/MemoryStream synchronization shim and reject deliberately broken cursor/waker variants. Ordinary features do not enable Loom.

Tests run

Final authorization head 194cb098d:

  • Windows cargo check -p acyclic-harness --lib --tests --features filesystem-local,native-execution,test-support,terminal,tui,mcp-http,model-checking through lb.ps1: passed, 14.98 s compilation.
  • Linux through bs.ps1, default test-thread stacks and RUST_MIN_STACK unset: authorization table/properties 4 passed, 0.008 s; public file follow/reopen scenario 1 passed, 0.214 s. The matrix covers every VolumeOwner variant × absent/matching/mismatched scope agent. The grants-only negative control must admit exactly the six forbidden Project/Session combinations; the production path admits only Agent+matching and leaves denied streams absent. A shrinking property covers arbitrary agent identities.

At the main conflict merge 8066b7059, before the pure authorization fix:

  • Public LocalHarness task-file write/follow/reopen scenario: 1 passed, 0.215 s.
  • Owner/grant and exhaustive file-role/size property: 2 passed, 0.008 s.
  • Instrumented handoff/wakeup models with broken controls: 2 passed, 0.032 s, using RUSTFLAGS="--cfg acyclic_harness_loom --cfg acyclic_loom". The authorization fix changes no synchronization or model path.
  • git diff --check passes against main; signed commits; no README edits.

Live steps

Connect request-file observation to durable admission and the worker, then publish accepted execution chunks/tool/status records into the same task subtree. Preserve retry identity, fencing and accounting while removing the replaced input/output representations. Finish GraphCoder/Pi repointing and bootstrap deletions in #514.