Add task files, materialized heads and accepted query changefeeds
Task state becomes logical files in private volumes: requests, status, turn chunks, tool output/results, approvals, notifications, context and agent mount declarations. GOAL.md and plans/.md are ordinary editable files. Each event is one append; file payloads borrow immutable slices of platform-owned segments.
Folder queries provide bounded snapshots, pinned historical cuts, materialized text/reasoning heads and push follow from the same cursor. Reconnects check volume, epoch, schema, query, position and preceding commit identity, with explicit reset after history loss.
Decisions
- Filesystem-driven directive: requests use the ordinary file-write primitive at .tasks//requests/.json. The redundant submit method is deleted. Plans use the private volume's plans/ folder, replacing the former task-specific plan.md. No update_plan tool, plan store or UI protocol is added. Schema revision 2 makes this namespace change explicit and rejects old cursor/schema identities rather than introducing aliases.
- UI command definitions, skills, settings, keymap, theme, drafts, history, attention, layout/open views and session lists belong in ordinary agent/config-volume files and existing fs live queries. This foundation introduces no per-view registry or store. The client lane owns their file schemas and folds.
- Point 6/10 mapping: actor handlers consume file records through FileValue::from_record; clients read/write/follow through supplied platform providers. There is no harness server, gateway, daemon, socket protocol or actor channel. Protected-file ownership is derived from the schema and passed to existing volume authorization.
- The generic Streams Head condition and follow_checked capability are necessary provider primitives: separate file reads/writes cannot atomically fence a reused position or validate an anchor while registering a subscription. These close the demonstrated recovery races without adding harness command messages or a second transport.
- Every delta, tool event and status change is its own append. append_if joins actor/authority conditions and an optional lease deadline to that atomic publication. Accepted/durable watermarks remain distinct; followers see acceptance without waiting for a flush. The projection lock is released during acknowledgement.
- Tier 0 selects current status; tiers 1/2 hydrate text/reasoning heads at an exact cursor and follow subsequent events. gc-client owns interest sets/reducers, stream-push multiplexing/conflation, and gc-e2e the 10k-agent scenario. Snapshot-at-cursor and head-plus-follow properties preserve seamless transitions.
- Recovery pages capture anchor and suffix in one immutable provider read. Publication checks position plus commit identity. Delayed acknowledgements update the index only when the full generation still matches. NotFound, OutOfRange and PrefixNotRetained map to ResetRequired at one boundary. Rebuilding occurs outside the shared index lock; repeated loss returns ResetRequired without polling.
- Providers without atomic checked follow fail closed with Unsupported. MemoryStream and LocalStream implement the local path. Hosted and IndexedDB rollout stays under Live steps.
Recovery coverage
The 96 data cases inject loss before/after provider operations and during record delivery. Each requires its fault to fire, bounds completion, checks that a successful snapshot is one exact cut, and compares subsequent observation through the original object with fresh reconstruction.
| Interleaving | Regressions |
|---|---|
| Open: presence, header publication/read/delivery, reconstruction | open-, initialize-; empty forks and racing openers |
| Refresh: watermark, page capture, anchor, suffix/error/EOF, next page, final cut | snapshot-, refresh-; multi-page replacement |
| Pinned snapshot/head: validation, header/anchor, replay pages/items | pinned-, heads-; head-plus-follow property |
| Reconnect: generation, bounds, watermark, anchor, checked registration | follow-*; missing anchor at recovered tail, missing path, reused position |
| Live follow: registration, events, push wait, replacement/EOF | live-*; real MemoryStream recovery while waiting/before suffix consumption |
| Observe/reset: snapshot-to-subscription, reconstruction, index installation | observe-, reset-; with/without cursor and repeated loss |
| Append: refresh, expected generation, Head commit, acceptance, acknowledgement, index completion | append-, conditional-; reused positions and obsolete acknowledgements |
| Conflict reload: watermark, anchor/suffix, conflict generation | conflict-* |
| Request file: query cut, cursor watermark, generic file write | request-*; immutable request retries |
| History error classification | every StreamError variant checked at the shared conversion boundary |
Verification
All builds/checks/tests use Q:/lanes/bs.ps1 without parallelism limits. Built test binaries run directly.
- The production projection and provider synchronization import query_sync. Normal builds use std/Tokio. Only acyclic_loom selects Loom-owned exclusion, waiters and watches; no dependency receives cfg(loom), and there is no rustc wrapper. Lock orders are documented next to fields and shim guards. Model guards preserve ownership across awaits; internal gate/watch locks are released before parking or waking.
- LocalStream models now call its real append -> exclusive -> prepare -> persist -> Journal::append chain, writing actual framed bytes to an unnamed temporary file. No model producer edits journal counters or duplicates publication. Only the executor boundary is inlined onto the writer's Loom actor; deferring_durability is the existing production policy keeping fsync outside this bounded publication model. Ordinary runtime tests separately cover a blocked durable acknowledgement.
- The omitted-wake control changes only the wake site in production persist. Its follower is polled to Pending before the writer starts. Real append completes, then the test requires the registered waker to have fired before it repolls. Suppressing that wake triggers the required persist omitted publication wake assertion; the correct variant passes and checks the two journal frames and delivered record.
- The 18 models include four required-failure controls: split mutex increment, split read/write-lock increment, consuming an unseen watch publication, and omitted persist wake. Their correct counterparts pass. Every model uses two actors, minimum competing operations and preemption_bound=2 per the latest user directive; there is no permutation/duration truncation. These are guarantees within that stated bound.
- Model command: Q:/lanes/bs.ps1 --env 'RUSTFLAGS=--cfg acyclic_loom' --env CARGO_TARGET_DIR=/work/target/query-model cargo test --manifest-path rust/verification/task-volume/Cargo.toml --test query-model --no-run; run the emitted binary directly. Its separate target directory avoids cross-workspace cached-crate identity collisions.
- Shrinking proptests cover canonical path/JSON and event payload/channel round trips, zero-copy slices, query/index equality against a reference fold after each publication, head-plus-follow equality, monotonic cursor watermarks, and Head wire/persistence/native-hash accounting. Plans share these properties and the declarative folder/follow/reopen scenarios.
- Kani proves the exact production watermark function for all five u64 inputs: monotonicity, cursor containment and atomic rejection; 0 of 29 checks failed (solver 0.63 s, full proof 1.72 s). That function is unchanged by these fixes.
- cargo-fuzz with AddressSanitizer covers file/folder paths, header/segment parsing, cursor/query JSON and Head wire/persistence parsers. Sixteen checked-in seeds include plan files/folders/segments and rejected legacy paths/schema. The updated campaign completed 10,475 inputs in four seconds without a crash.
- Final main-integrated gate at fe64c2822: merged main f1ca12360, regenerated Stream bindings and descriptors retaining both auth annotations and Head fences, and updated the protocol contract assertions. All 18 models passed in 0.22 s; 34 task-volume tests including 13 declarative scenarios and all 96 recovery cases passed in 0.11 s. Stream protocol/digest checks, TypeScript build and three TypeScript/WASM Head tests passed (109 ms). Earlier focused validation also passed: bounded-query regression against 10k unrelated chunks (0.02 s), ten Stream tests, merged MCP fixture property, browser check, clippy and rustfmt. Existing unrelated warnings remain; no suite exceeds ten seconds.
Live steps
- Deploy generic Streams Head and atomic checked follow on hosted providers and SDK adapters. HTTP Head and missing checked-follow capability return Unsupported until deployment; no position-only or polling fallback exists.
- IndexedDB needs cross-context publication push plus atomic checked follow. Its legacy timer follow cannot be used by the harness. MemoryStream is the browser-local path. The reviewer accepted this capability boundary and withdrew that finding.
- Carry accepted/durable watermark controls through hosted Streams sessions/adapters in stream-push. Providers lacking them conservatively report unknown durability as zero.
- Bind the logical task/head files into the Actors package and filesystem surface using existing DemandSource/DemandFile contracts. OwnedSourceChunk already carries shared Stream OwnedBytes. Client/UI migration uses ordinary fs files/queries rather than new harness stores.