Render filesystem goal progress through native and WASM views

Merged
VA
3d ago
+2026-91

ClientViews renders GOAL.md status, reason and retained continuation count from two existing volume-scoped filesystem follows, shared by native and WASM clients. This revision also stops unreachable active goals before a new automatic admission, and bounds goal-panel redraw work by the viewport.

Pending #503

The complete stock-tool goal loop remains gated on #503's composed mount routing. #503 is still open. The required successful scenario—active private goal, unmodified stock write marks it done through its composed-view path, no further admission—must land here after that routing merges. It is not claimed by the current tests.

The follow-up custom-writer reachability finding is also pending that shared resolver. The interim check describes the stock task-view route; it does not attempt to introspect arbitrary custom executors or introduce a separate reachability declaration/API.

Coordination with gc-tools: https://github.com/acyclic-labs/sdk/pull/503#issuecomment-6211809417. The handoff requests the shared resolver for the private volume's composed path, including .volumes/scratch/GOAL.md; admission must use that resolver without maintaining another mount table.

Review fixes

  • P1 interim safety: delete the scratch-writer fixture entirely. Every scripted LocalHarness case now uses unmodified stock executors. The regression starts with an ordinary private goal, observes the stock write place status: done in the project, and requires the actual private goal to become blocked before any continuation is admitted. Runtime returns Error::GoalBlocked(GoalBlockedReason::TaskViewUnreachable) and persists the reason in GOAL.md. Replay recovers that typed reason without further model calls; the disabled control leaves the private goal active. No cap is consumed to discover the unreachable destination.
  • P2 and follow-up: cache Markdown line offsets when GOAL.md changes, and clip each visible borrowed row during traversal. Redraw never searches hidden line tails and does not drop later rows after a long line. The cache is disposable, shared by clones, absent from serialized views, and reused for replay/checkpoints and request-head updates. Multi-MB ASCII, combining, control and wide-character lines must keep Next visible while staying viewport bounded. The 64-case Unicode redraw property and old eager-scan negative control remain. A second 64-case property requires cached rows to equal standard line splitting through edits, removal, replay and reset; replay/checkpoints must retain the cache allocation. CRLF and terminal-control checks pass.

Decisions

  • Goal and request-head follows retain separate cursors. bind_goal_sources joins their disposable folds; updates from either source re-derive goal_view. Count comes only from the production decoder for inputs/current.json, with no status-record duplication, cross-volume query, polling or goal store.
  • Until composed routing lands, check the actual stock output binding's volume identity. New automatic admissions fail closed when it cannot reach the private goal. Already-staged immutable inputs and already-published continuations still recover through the existing ordinary request path; replay must not rebuild their content or identities.
  • Persist blocked contents through the same ordinary file writer and generation precondition as the finite-cap path. Goal edits remain ordinary file writes. Read-only observation uses the shared parser without reserving space for a later rewrite; runtime acceptance retains metadata headroom and unchanged limits.
  • Export existing file-query snapshot/change operations and shared views through WasmClientViews, with thin TypeScript forwarding and BigInt cursors. Native GoalPanel borrows that same view.

Main at d069a499b9fe1b757781e9872a4d528eb6c2b120 is merged. The scenario helper retains main's new ToolCall constructor; the native/WASM shared model handling and generated declarations preserve both sides.

Verification

Signed head: 65bb1bf49fad0e41d00210b48cdbb7f91eee7c96.

  • Windows through lb.ps1: cargo check -p acyclic-harness -p acyclic-harness-fuzz --locked --features acyclic-harness/filesystem-local,acyclic-harness/native-execution,acyclic-harness/test-support,acyclic-harness/tui --lib --tests --bin goal_parser --bin records passed in 1m09s.
  • bb1 through bs.ps1, native features filesystem-local,native-execution,test-support,tui: 5 LocalHarness goal tests passed in 1.18 s, including seven data-driven frame/file and rendering cases; 3 goal-panel tests passed in 0.01 s; the new cached-line property passed in 0.02 s; all 9 goal file-query tests passed in 0.01 s; both request-head cancellation/recovery tests passed in 0.47 s; all 12 goal-files parser/policy/corpus tests passed in 0.50 s. Native test build: 3m37s.
  • bb1 WASM integration target client-goal-views, features browser: native/exported-WASM parity passed in 0.03 s, covering count updates, replay, independent resets, missing/invalid heads, rejected gaps, Unicode, BigInt cursors and an omitted-update negative control. Build: 1m07s.
  • The current file-query gate includes the 64-case shrinking property enumerating every order-preserving interleaving of bounded source updates. Unchanged TypeScript client/reducer tests passed at 1208618dc: 17 tests / 590 assertions / 0.88 s. The parser fuzz target retains its 15 checked-in seeds, exercised by the current corpus gate; it now also traverses the publication-time line cache.
  • Formatting, removed-fixture/caller search and git diff --check passed. No CI wait.

API for gc-e2e / #600

Drive LocalHarness::run, or ordinary submit followed by resume, and assert scheduler wire frames and final files. Observe Query::File(FileKey::Goal) on scratch() and Query::File(FileKey::RequestHead) on journal_volume() through FilesystemContentVerifier::file_query. Feed snapshots/changes to ClientViews::query_snapshot / query_change, bind their cursor identities, and render goal_view. Browser hosts use the same querySnapshot, queryChange, bindGoalSources, and views operations. Declarative LocalHarnessConfig.goal_continuations = None disables new automatic admission. Use the stock composed-view path once #503 lands; do not substitute the stock writer in an e2e scenario.