v0.50.0
v0.50.0
Background task wakes over the daemon transport are fixed
Sessions using the subc daemon transport silently stopped receiving background-task completion wakes: a finished background command would sit undelivered until the next tool call instead of waking the idle agent. Four independent defects sat in series, each masking the next; all four are fixed, and every hop of the delivery path now logs its outcome:
- The background-event subscription treated a clean stream end (which routine route replacements emit) as terminal and never resubscribed.
- The module's per-session subscription index kept only one entry per session, losing sessions with more than one active record (the normal shape when a session spans a project directory and a worktree).
- Received nudges were dropped before the handler when generation provenance was unavailable — which was always, on default configurations. Delivery now falls back to the root/session handler directly.
- Every remaining early-return on the delivery path emits a rate-limited log line naming the drop cause, and the module reports arm/miss/nudge counters in health output.
Verified end-to-end: a completed background task wakes an idle session in ~2.5 seconds, with the full chain visible in the plugin log.
Hashline edit mode (opt-in beta)
A new line-addressed edit surface, ported from oh-my-pi's hashline format and implemented natively in Rust. Reads mint per-line content tags ([path#TAG]); edits address lines through those tags (PUT/CUT/REM), so edits against a stale view of the file are rejected loudly with remap recovery instead of landing on drifted lines. Includes two-phase transactions with rollback (backups are a precondition — no destructive operation runs without a restore record), exact-verbatim landing recovery, and per-session snapshot stores with bounded residency.
Off by default. Enable per project or user with:
With the gate off, the agent-facing surface is unchanged from v0.49 — tool schemas and prompts are byte-identical (the committed schema artifact has a zero diff against v0.49.4), and behavior is identical. The only wire-level change in default mode is one additive internal field (edit_slot_survives, host registration state carried on configure and tool calls), which servers ignore unless hashline is configured. The engine ships fully tested (145 unit tests, a 128-fixture parity corpus against the reference implementation, and release-profile performance gates) and works across all transports: standalone, daemon, and MCP.
Beyond the engine suites, activation was hardened by driving real agent sessions end-to-end on both transports before release. That pass surfaced and fixed eight integration defects, among them: registration split-brain (the plugin could register the default edit schema while the engine enforced hashline, leaving no working edit path), a client-side normalizer rejecting the hashline schema's own patch argument, bash cat/head/tail rewrites losing their tag headers, preview injection breaking strict argument validation, and a snapshot-store liveness bug where two ranged reads of the same file version made every subsequent edit refuse as ambiguous with no recovery path (same-version snapshots now coalesce; only true tag collisions across different content refuse, with honest steering). Each fix landed with a regression test that failed before it.
Performance
- Inspect worker threads are now a single process-wide pool instead of one pool per project root. On a daemon serving many roots this removes hundreds of idle threads (measured: 932 → 240 threads across ~60 roots) and reduces allocator arena pressure (#202).
- Dead-code scans reuse a cached callgraph projection keyed to the store generation instead of re-projecting the full graph on every scan. The duplicated projection dominated Tier-2 scan time on large workspaces (#209).
- Automatic Tier-2 refreshes skip the dead-code scanner entirely when no callgraph store can exist for the root; previously the full scan ran and its results were discarded. Manual
aft_inspectdead-code queries are unaffected. - Language servers are deduplicated by workspace: several crates of one Cargo workspace now share a single analyzer instead of each spawning their own, and analyzers rooted in reclaimed worktrees are terminated immediately.
- Allocator pressure relief now also runs on Linux (glibc
malloc_trim, resolved at runtime), and the allocator slack figure is reported in health output (#201). - Formatter probes no longer run during configure warm paths, keeping project binaries (e.g.
ruff) from executing before any edit-related tool is used (#191).
Fixes
aft_conflictsno longer reports "no conflicts" when a conflicted file cannot be read (e.g. index-unmerged but deleted from the working tree). Unreadable conflicts are reported per file withcomplete: falseand anunmerged_count.- Calls severed by a daemon route closure are reported as unknown-outcome instead of failed, so agents re-check state instead of blindly retrying a mutation that may have applied (contributed by @iceteaSA, #203; hardened to match both client error generations).
- The perf-tick log line labels its rolling tool-call window and reports the per-interval count separately, so one slow call is no longer readable as a sustained regression (contributed by @iceteaSA, #206/#208).
- The shared inspect pool's thread count accepts a development override (
AFT_INSPECT_POOL_THREADS) for allocator experiments (contributed by @iceteaSA, #207). - Subc tool registration is verified by a derived test against the embedded schemas, so adding a tool cannot silently miss one of the six registration sites (contributed by @iceteaSA, #195/#200).
- Windows: LSP server keys include config identity in the per-definition test path (CI-only fix).
Notes
- The wake fixes span the Rust module and the plugin packages: both the npm plugin update and a daemon module restart are needed to get the full chain.
- No agent-facing schema or prompt changes in default mode — prefix caches are unaffected unless hashline is enabled.