Skip to content

v4.4.0

Choose a tag to compare

@github-actions github-actions released this 26 Jul 19:50

What's Changed

Features

  • Council Workspace GUI: A new third Electron mode (amicus watch <councilRunId> --ui) that visualizes council runs with live reviewer progress, anonymized peer packets, tier-colored adjudication matrix with dissent drill-in, chair verdict, and cost-by-seat gauges. Historical runs render entirely from disk; live runs poll every 1.5s when focused, 5s otherwise. Includes blind-mode toggle (labels vs. model names) and two verbs: Abort (confirm-gated, delegates to engine) and Fold (writes verdict to terminal).
  • Per-seat live status in terminal: amicus watch <councilRunId> now displays per-leg rows in the terminal with model, role, status, message count, tokens, cost, and stall state, refreshed on the same poll cadence as the stage rail.
  • Live data factory and workspace CDP suite: Added CdpClient.workspace(port) for e2e testing of the Workspace GUI with fixture-driven test coverage.

Bug Fixes

  • Zero-cost reporting now reports unknown cost: Legs where all captured token totals were zero used to report estimated $0.0000 (claiming the work was free). They now report as unknown cost instead. Four separate defects fixed: token-gated cost resolution, post-loop usage re-poll to close a 155ms window before legalization, terminal progress records carrying settled usage, and spend ledger no longer coercing null costs into measured $0.0000.
  • Legs no longer marked complete while sessions are still billing: A leg was declared complete on initial reasoning preamble before tool calls finished. Root cause was shape drift: OpenCode emits no tool_result parts (only 36 tool_use records across 35 legs, zero tool_result). Tool-call liveness now keys on SDK's real state.status vocabulary (pending/running/completed/error), with a bounded grace period (AMICUS_TOOL_SETTLE_GRACE_MS, default 300s) before forcing completion.
  • costExact predicate now accurate: Was claiming exactness when every leg reported tokens but missing unattributed child-session spend. A leg that spawns a subagent now carries subtreeUnknown; costExact requires both every leg observed and no unattributed subtree.
  • Max-cost ceiling now threaded into council pre-flight: --max-cost was never passed to the transport, so the soft ceiling was inert for council runs. Each wave is now measured against remaining allowance (ceiling minus known spend minus outstanding reservations), with atomic claims so concurrent waves cannot both spend the same dollars. If a wave is refused, the run continues with a partial bench; the refusal is announced, recorded on run.json, and degrades exit code to 2.
  • Usage-settle re-poll boundary expanded: The try/catch covered only network reads; inspection afterward could throw and destroy a finished leg. The boundary now covers the entire loop body.
  • Environment number parsing honors explicit zero: AMICUS_USAGE_SETTLE_POLLS=0 and three companion knobs were silently rewritten to defaults. All four now go through envNumber() which honors explicit numeric values including 0.
  • Subagent (child-session) spend now attributed: Child OpenCode sessions spawned by task tool calls were invisible to totals. Measured across four recorded runs: $0.492506 missing. The engine now walks each leg's child sessions at finalization (bounded, cycle-proof, directory-scoped) and rolls the measured spend into run total as cost.subtreeCost / cost.subtreeSessions.
  • Stage-1 repair re-prompt carries the review it repairs: When a review's findings JSON failed validation, a repair re-prompt was launched solo without the review text. Three paid councils burned seats on models that refused to repair empty context. The prompt now embeds the original review verbatim (or the previous repair output on second attempt), and explicitly instructs the model to emit empty findings if there genuinely is no prior text.
  • Council pointer files now fenced against directory traversal: A tampered council-<runId>.json pointer could redirect reads (or writes via crash detection and abort) outside the project. All pointer-consuming surfaces now resolve and check containment before touching the filesystem, using a shared fence implementation (path-fence.js). A fenced-out pointer returns the existing "not a council run" error.

Changed

  • Unknown cost is visible, never hidden: A leg whose cost cannot be determined no longer halts the run or trips --max-cost by itself. Instead, the uncertainty is impossible to miss: run.json gains unknownLegs + costExact, the council emits a Notice: naming the count, the human summary appends + N leg(s) unknown, amicus spend shows unpriced rows explicitly, and the workspace budget gauge switches to indeterminate (hatched) with a readout.

Security

  • Path containment fencing for council pointers: Council pointer files (council-<runId>.json) are now validated for realpath containment before any filesystem access, preventing directory traversal attacks on reads or writes.

Full Changelog: v4.3.0...v4.4.0