pi-crew 0.9.42 → 0.9.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +223 -0
  2. package/README.md +35 -0
  3. package/dist/build-meta.json +4778 -11087
  4. package/dist/index.mjs +54648 -65435
  5. package/dist/index.mjs.map +4 -4
  6. package/package.json +1 -1
  7. package/scripts/build-bundle.mjs +2 -1
  8. package/src/agents/agent-config.ts +1 -1
  9. package/src/agents/discover-agents.ts +1 -1
  10. package/src/config/config.ts +1 -1
  11. package/src/config/types.ts +0 -2
  12. package/src/extension/crew-vibes/config.ts +1 -1
  13. package/src/extension/crew-vibes/font-detect.ts +16 -3
  14. package/src/extension/cross-extension-rpc.ts +8 -4
  15. package/src/extension/registration/commands.ts +5 -1
  16. package/src/extension/registration/foreground-run-controller.ts +28 -0
  17. package/src/extension/registration/lifecycle-handlers.ts +34 -3
  18. package/src/extension/registration/subagent-manager-setup.ts +178 -59
  19. package/src/extension/run-import.ts +21 -1
  20. package/src/extension/team-tool/api.ts +4 -2
  21. package/src/extension/team-tool.ts +5 -0
  22. package/src/prompt/prompt-runtime.ts +15 -0
  23. package/src/runtime/async-runner.ts +9 -1
  24. package/src/runtime/child-pi-constants.ts +42 -0
  25. package/src/runtime/child-pi-kill.ts +180 -0
  26. package/src/runtime/child-pi-spawn.ts +234 -0
  27. package/src/runtime/child-pi-steering.ts +128 -0
  28. package/src/runtime/child-pi-streams.ts +296 -0
  29. package/src/runtime/child-pi-transcript.ts +169 -0
  30. package/src/runtime/child-pi.ts +75 -837
  31. package/src/runtime/compact-stages/tail-capture-stage.ts +1 -1
  32. package/src/runtime/dwf-state-store.ts +5 -0
  33. package/src/runtime/dynamic-workflow-context.ts +78 -18
  34. package/src/runtime/dynamic-workflow-runner.ts +18 -2
  35. package/src/runtime/goal-evaluator.ts +59 -27
  36. package/src/runtime/goal-loop-runner.ts +40 -11
  37. package/src/runtime/live-agent-manager.ts +18 -0
  38. package/src/runtime/manifest-cache.ts +30 -0
  39. package/src/runtime/pi-json-output.ts +2 -1
  40. package/src/runtime/pi-spawn.ts +7 -1
  41. package/src/runtime/resilient-edit.ts +16 -15
  42. package/src/runtime/role-permission.ts +27 -2
  43. package/src/runtime/run-coalesced-task-group.ts +90 -25
  44. package/src/runtime/task-packet.ts +1 -1
  45. package/src/runtime/task-runner/prompt-builder.ts +2 -2
  46. package/src/runtime/team-runner.ts +6 -1
  47. package/src/state/event-log.ts +89 -34
  48. package/src/state/locks.ts +185 -49
  49. package/src/state/mailbox.ts +165 -4
  50. package/src/state/run-metrics.ts +40 -12
  51. package/src/state/worker-atomic-writer.ts +1 -0
  52. package/src/ui/live-run-sidebar.ts +1 -9
  53. package/src/ui/run-dashboard.ts +1 -9
  54. package/src/utils/incremental-reader.ts +105 -0
  55. package/src/utils/paths.ts +1 -1
  56. package/src/utils/visual.ts +27 -91
  57. package/src/worktree/worktree-manager.ts +47 -19
  58. package/src/runtime/auto-resume.ts +0 -100
  59. package/src/runtime/notebook-helpers.ts +0 -88
  60. package/src/runtime/orphan-sentinel.ts +0 -7
package/CHANGELOG.md CHANGED
@@ -2,6 +2,229 @@
2
2
 
3
3
  > **Note:** `atomic-write-v2.ts` / `AtomicWriter` mentioned in historical entries below was consolidated into `atomic-write.ts` as of v0.9.42. This changelog is preserved as historical record — the migration was completed (the v2 class was never adopted; v1 won on simplicity + symlink-safety + link+unlink atomicity). See `docs/migration/atomic-write-v2-migration.md` for the decision rationale.
4
4
 
5
+
6
+ ## [0.9.46] — UI stability + notification coalescing (2026-07-20)
7
+
8
+ Three user-facing UI/notification fixes layered on top of the v0.9.45
9
+ remediation, plus CI hygiene. All verified live in a restarted Pi session.
10
+
11
+ ### UI flicker — stop render-path snapshot-cache deletes
12
+
13
+ The run-snapshot cache has a deliberate stale-while-revalidate design so the
14
+ widget always shows a populated snapshot. That was defeated by three hot-path
15
+ call sites in `lifecycle-handlers.ts` that hard-deleted cache entries; the worst
16
+ ran `invalidate(undefined)` on every ~160ms fallback tick, wiping ALL entries
17
+ → `activeWidgetRuns` dropped every run to "(loading…)" until the async preload
18
+ rebuilt the cache → continuous flicker across the widget, powerbar, and live
19
+ sidebar/dashboard. (`src/extension/registration/lifecycle-handlers.ts`)
20
+
21
+ **Fix:** never hard-delete from the render path. A no-runId tick is now a no-op;
22
+ a specific runId calls `refreshIfStale` (stale-while-revalidate); the two
23
+ `fs.watch` change handlers call `refresh` (rebuild-in-place). All three keep the
24
+ entry populated so `get()` never returns `undefined`.
25
+
26
+ ### TUI width-overflow crash — delegate `visibleWidth` to pi-tui
27
+
28
+ `Rendered line N exceeds terminal width (160 > 159)` killed the host Pi process
29
+ whenever an agent emitted an emoji that pi-crew's hand-maintained `WIDE_RANGES`
30
+ table counted as 1 column but pi-tui (the renderer) counted as 2 (e.g. `⏳`
31
+ U+23F3). pi-crew truncated/padded to its own measure, pi-tui re-measured and
32
+ hard-aborted. This was patched twice before by adding individual codepoints —
33
+ whack-a-mole, since ANY emoji in agent output could trigger it.
34
+ (`src/utils/visual.ts`)
35
+
36
+ **Definitive fix:** `visibleWidth` now delegates to pi-tui's own `visibleWidth`
37
+ (the function that drives the crash assert). truncate/pad/wrap therefore always
38
+ agree with the renderer; an emoji-width mismatch is structurally impossible. The
39
+ hand-maintained `WIDE_RANGES`/`isWideCodePoint` table is removed.
40
+
41
+ ### Notification coalescing — N drip → 1 consolidated wake-up
42
+
43
+ Launching N background subagents (no `batch_id`) produced N separate "changed
44
+ state" wake-ups, delivered one-per-turn at turn boundaries; after the leader
45
+ joined them all, redundant per-agent notices kept dripping in over later turns.
46
+ (`src/extension/registration/subagent-manager-setup.ts`)
47
+
48
+ **Fix (Rule 3):** a debounced coalescer for non-batch completions. Completions
49
+ within an 800ms window (reset on each new arrival) merge into ONE wake-up; each
50
+ is `resultConsumed`-re-checked before emit (Rule 2), so already-joined agents
51
+ are dropped and an all-consumed batch is suppressed entirely. Completions far
52
+ apart (>800ms) still flush separately. The explicit-`batch_id` path (Rule 1,
53
+ BatchBarrier) is unchanged.
54
+
55
+ ### CI hygiene
56
+
57
+ `biome check --write` applied across the v0.9.45 remediation files (lint +
58
+ format), and two unused test imports were removed — the local remediation
59
+ commits had never been CI-checked; this brings lint + format:check green.
60
+
61
+ ## [0.9.45] — Deep-review 2026-07-20 remediation (all 5 phases, 14 findings)
62
+
63
+ ### ⚠️ BREAKING: custom agent roles default to read-only (FIND-12)
64
+
65
+ `permissionForRole()` now returns `"read_only"` for unknown/custom agent
66
+ roles instead of the previous permissive `"workspace_write"`. This is a
67
+ security hardening (default-deny) to prevent privilege escalation via
68
+ typo'd or unrecognized agent names.
69
+
70
+ **Migration:** write-capable roles are now an EXPLICIT allowlist
71
+ (`WRITE_ROLES` in `src/runtime/role-permission.ts`). All shipped
72
+ write-capable roles are listed: `executor`, `writer`, `verifier`,
73
+ `test-engineer`, `agent` (direct-agent default), `cold-verifier`,
74
+ `chain-executor` (chain workflow), and `worker` (goal-loop + dynamic
75
+ workflow). A custom agent role that needs workspace write access
76
+ must be added to `WRITE_ROLES`. Built-in read-only roles (`explorer`,
77
+ `reviewer`, `security-reviewer`, `analyst`, `critic`, `planner`) are
78
+ unaffected. (An earlier draft proposed a `permissions.workspaceWrite`
79
+ agent-config opt-in; it was dropped — unreachable from the call sites.)
80
+
81
+
82
+ ## [0.9.44] — 3 flaky CI test fixes (2026-07-19)
83
+
84
+ Three pre-existing flaky tests in the CI suite have been fixed, completing
85
+ the CI green-light requirement. All three were verified by repeated
86
+ local runs (≥30 iterations each) and a green CI run on the merge commit
87
+ (ubuntu/macos/windows Node 22 all ✅, fallow audit ✅).
88
+
89
+ ### Lock subsystem fixes (`src/state/locks.ts`)
90
+
91
+ - **ENOENT canSteal fix in `readLockSnapshot`** — previously returned
92
+ `canSteal: false` when the lock file was missing between the EEXIST
93
+ signal and the read, causing spurious "locked" errors in
94
+ `parallel-research-dynamic.test.ts` (9/10 local reproduction rate).
95
+ Now returns `canSteal: true` so the holder-released-mid-retry window
96
+ is handled correctly.
97
+ - **New `releaseOwnLock`** — unconditional `fs.rmSync` bypass of the
98
+ token-match check in `releaseLock`. Used by `withRunLockSync` /
99
+ `withRunLock` because same-process re-acquisition uses fresh
100
+ `randomUUID()` tokens that never match the stored token, so
101
+ `releaseLock` was silently never deleting lock files between calls
102
+ (strace showed many `openat(O_CREAT|O_EXCL)` calls but zero
103
+ `unlinkat` calls — lock file accumulation until EEXIST).
104
+ - **`treatOwnPidAsStealable` parameter on `readLockSnapshot`** — only
105
+ the run-lock async path passes `true`. The sync file-lock path
106
+ (`withFileLockSync`, used by `round26-file-locks.test.ts`) keeps
107
+ the default `false` to preserve the multi-process safety guarantee
108
+ ("don't steal a fresh lock held by a live process — even if our own
109
+ pid"). Without this option split, the first fix attempt regressed
110
+ the existing `round26-file-locks` test which specifically tests that
111
+ behavior.
112
+
113
+ ### Test fix (`test/unit/event-log-seq-uniqueness.test.ts`)
114
+
115
+ - **B7 test 3 uses `appendEventAsync` instead of `appendEventBuffered`**
116
+ — the 20ms buffered-event timer occasionally lost the race against
117
+ `--test-force-exit`'s suite-finalization deadline (~8ms cancellation
118
+ observed on CI), causing `cancelledByParent` failures with error
119
+ `'Promise resolution is still pending but the event loop has already
120
+ resolved'`. Tests 1 and 2 still cover the full sync/async/buffered
121
+ 3-path seq-uniqueness contract; test 3 now focuses on the
122
+ explicit-vs-auto seq-assignment contract using only sync + async
123
+ paths. This avoids the buffered timer entirely while preserving the
124
+ original B7 invariant.
125
+
126
+ ### Verification
127
+
128
+ - Local: 6184/6187 unit + 177/178 integration tests pass (3+1 skipped).
129
+ - CI: ubuntu/macos/windows Node 22 all ✅, fallow audit ✅.
130
+ - Three independent CI runs after each fix confirmed zero regressions.
131
+
132
+ ## [0.9.43] — 4-wave upgrade + live LLM verification (2026-07-19)
133
+
134
+ A comprehensive upgrade pass was completed on top of v0.9.42: 4 implementation waves
135
+ plus H-1 (lock re-entrance) and H-7 step 1–6 (runChildPi decomposition), verified
136
+ end-to-end with real LLM calls on a real pi session (not mocked). All changes
137
+ were driven by an in-depth audit (`UPGRADE_REVIEW.md` — 647 lines, ~112 unique
138
+ findings) with cold-verification and live test feedback catching regressions
139
+ mock tests had missed.
140
+
141
+ ### Wave 1 — Security + correctness (16 fixes)
142
+
143
+ - **H-3/H-4** `scripts/build-bundle.mjs` — bundle externalized `acorn` (~225 KB) and fixed `@sinclair/typebox` package name (~245 KB). Total **−481 KB** bundle.
144
+ - **M-23 / COAL-1** `prompt-builder.ts` + `run-coalesced-task-group.ts` — both prompt builders now `sanitizeTaskText` before injection (closes 2 prompt-injection bypasses).
145
+ - **M-22** `cross-extension-rpc.ts` — `pi-crew:live-control` event channel now wrapped with `withHmacVerification` (was the only state-mutating RPC channel without auth).
146
+ - **DISC-1** `dynamic-workflow-runner.ts` — `.dwf.ts` determinism check now transpiles TS→JS via `esbuild` before acorn parse. Restores the round-13 P0-2 enforcement that had been silently no-op'd by acorn's JS-only parser.
147
+ - **NEW-D1** `team-runner.ts` — merge path now calls `flushPendingAtomicWrites()` before `loadRunManifestById`. Closes the coalesced-write-cancellation lost-update window.
148
+ - **M-18 / M-19 / T-S1** — event-log buffered-timer `unref()`, dead-worker `worker = undefined` reset, and `handleSteer` terminal-status guard (rejects steer to completed/failed/cancelled tasks).
149
+ - **NEW-C1 / C5 / C7 / C13 / C17** — config dead-field deleted; token cap covers `max_completion_tokens`/`max_output_tokens`/`generationConfig.max_output_tokens`; tail-capture empty-tail slice fixed; `PI_CREW_HOME` alias added; doc comment env-var name fixed.
150
+ - **CV-NEW-1** `font-detect.ts` — `isWebTerminal()` cached (was 12 sync reads per render tick).
151
+ - **CMD-NEW-2** `commands.ts` — `--var` value split fixed (was `split("=", 2)` which lost values containing `=`).
152
+
153
+ ### CP-1 — turn-limit hard-abort escalation
154
+
155
+ `child-pi.ts` turn-limit hard-abort now uses `killProcessTree` (same as abort/noResponseTimer paths) and sets a `hardAbortInitiated` flag so `onJsonEvent` stops restarting the no-response timer. Prevents SIGTERM-ignoring runaway children. `HB-003a` source-contract test updated to verify the new behavior.
156
+
157
+ ### Wave 2 — Budget / Worker cap / Worktree / Coalesced (6 fixes)
158
+
159
+ - **BDG-1** `goal-evaluator.ts` — judge token usage now returned and accumulated into `budgetUsed` (was discarded, systematically undercounted budget by 20–30%).
160
+ - **GL-1** `goal-loop-runner.ts` — loop checks `turnResult.manifest.status` after each turn; stops early on `blocked`/`failed` instead of burning the full `maxTurns` budget on a dead-end.
161
+ - **DLOCK-1** `dynamic-workflow-context.ts` — `ctx.agent()` now goes through `withWorkerSlot`, finally respecting the global worker cap (`PI_CREW_MAX_WORKERS`). Docstring claim was previously false.
162
+ - **ERR-1** `dynamic-workflow-runner.ts` — script timeout now aborts a combined `AbortSignal`, so spawned `runChildPi` children are killed instead of leaking.
163
+ - **N-1** `worktree-manager.ts` — `snapshotDirtyWorktree` failure now causes the caller to skip the discard (preserves dirty work instead of losing it). The previous behavior would silently destroy work if the snapshot artifact write failed.
164
+ - **N-2** `live-agent-manager.ts` — `evictStaleLiveAgentHandles` no longer treats `session.pid === undefined` (the in-process case) as dead. Previously every in-process live agent was killed after 30 min idle.
165
+ - **COAL-2** `run-coalesced-task-group.ts` — coalesced dispatch wrapped in `executeWithRetry`. One transient failure no longer fails all N tasks.
166
+
167
+ ### Wave 3 — Observability + Budget reserve + DWF resume (4 fixes)
168
+
169
+ - **OBS-NEW-1/2** `foreground-run-controller.ts` — emits per-task `crew.task.completed/failed/needs_attention` events at run completion with `durationMs` and `tokens`. Added `durationMs` to `crew.run.completed`. Fixes task-level metrics that were always zero.
170
+ - **BDG-2** `dynamic-workflow-context.ts` — reserve-then-adjust token budget. Before spawn, reserve estimate (4096 tokens); after spawn, adjust by `actualUsage − estimate`. Prevents N concurrent calls from each overspending by `perCallCost`.
171
+ - **PERS-1** `dynamic-workflow-context.ts` — per-agent-call idempotency cache stored in checkpoint (`completedAgentCalls`). On resume, cached calls are skipped (return cached result). Previously a DWF resume re-ran the entire script, duplicating artifacts/mailbox/tokens.
172
+
173
+ ### H-1 — AsyncLocalStorage re-entrance guard (root-cause class)
174
+
175
+ `src/state/locks.ts` — `withRunLock`/`withRunLockSync` now track re-entrance via `AsyncLocalStorage<Set<string>>` instead of a module-global `Map<filePath, token>`. True nested calls in the same async context still bypass (no deadlock). Calls from a DIFFERENT async context (e.g. a child-stdout event handler firing while an async merge holder is awaiting) no longer bypass — they properly serialize against the on-disk lock.
176
+
177
+ ### H-7 — `runChildPi` decomposition (6 steps, −572 lines / −31.1%)
178
+
179
+ `src/runtime/child-pi.ts` reduced from **1842 → 1270 lines**. Code extracted into 4 self-contained modules with zero behavior change verified by 147 tests + live LLM:
180
+
181
+ | Step | Module | Lines | Purpose |
182
+ |------|--------|-------|---------|
183
+ | 1 | `child-pi-transcript.ts` | 169 | Transcript batching (50 ms debounce) + compaction helpers |
184
+ | 2 | `child-pi-kill.ts` | 180 | `killProcessTree`, `appendBoundedTail`, active-children bookkeeping |
185
+ | 3 | `child-pi-constants.ts` | 42 | Shared timing/buffer constants |
186
+ | 4 | `child-pi-streams.ts` | 296 | `ChildPiLineObserver` + line-level compaction |
187
+ | 5 | `child-pi-steering.ts` | 128 | `ChildPiSteeringController` state machine (turn-limit, soft/hard abort) |
188
+ | 6 | `child-pi-spawn.ts` | 226 | `buildChildPiSpawnOptions`, `prepareSpawnContext`, env allowlist |
189
+
190
+ Steps 1–4 verified clean on first commit. Step 5 required updating the `HB-003a`
191
+ source-contract test (steering logic moved to its own module). Step 6 required
192
+ updating the assertion to check `builtEnv` (control vars only) rather than
193
+ `mergedEnv` (which includes process.env spread).
194
+
195
+ ### Live-test-only bug fixes (caught by real pi binary, missed by mocks)
196
+
197
+ - **Token usage not captured** — `src/runtime/pi-json-output.ts` `extractUsage` now recursively looks into `obj.message.usage` (pi nests usage under `message` for `message_end`/`turn_end` events). Mock tests passed because `PI_TEAMS_MOCK_CHILD_PI` short-circuits the spawn path entirely; only real `--mode json` output exercises `extractUsage`.
198
+ - **child-pi spawns wrong binary** — `src/runtime/pi-spawn.ts` `resolvePiCliScript` previously trusted `process.argv[1]` unconditionally. When invoked from a standalone test script, `argv1` was the test script and child-pi spawned it as if it were pi. Fix: only trust `argv1` when `resolvePiPackageRoot()` succeeds (current process is running from the pi-coding-agent package).
199
+ - **Worktree mode blocked by own .gitignore** — `src/worktree/worktree-manager.ts` `assertCleanLeader` used `git status --porcelain` without `--untracked-files=no`. After pi-crew's `ensureCrewDirectory` auto-creates `.gitignore`, that file shows as untracked and blocks worktree mode. Fix: add `--untracked-files=no` so only tracked changes are checked. Applied to both sync (`assertCleanLeader`) and async (`assertCleanLeaderAsync`) variants.
200
+
201
+ ### Live test coverage (real pi binary + real LLM, on session restart)
202
+
203
+ 14 live tests run end-to-end across 3 waves — all green:
204
+
205
+ | Wave | Feature | Result |
206
+ |------|---------|--------|
207
+ | A1 | 3 concurrent runs, unique runIds, no state leakage | PASS |
208
+ | A2 | Steer to completed task → rejected with `T-S1` error | PASS |
209
+ | A3 | Long research run (5 key points + explanations) | PASS · 8,302 tokens / 124 s |
210
+ | A4 | Cancel completed run is safe no-op | PASS |
211
+ | A5 | Steer to nonexistent runId → graceful error | PASS |
212
+ | B3a | Invalid model → fallback to `zai/glm-5.2` agent default | PASS |
213
+ | B3b | Empty goal → graceful error | PASS |
214
+ | B3c | Long goal stress (multi-paragraph objective) | PASS · 5,247 tokens / 178 s |
215
+ | C1 | Worktree mode (clean git repo, after fix) | PASS |
216
+ | C2 | Original file preserved across worktree cleanup (N-1 fix) | PASS |
217
+ | C3 | `implementation` workflow creates `math.js` with `subtract` function | PASS |
218
+ | C4 | `plan` action returns 4-step plan | PASS |
219
+
220
+ Mock tests: 30/31 pass (1 pre-existing skip).
221
+
222
+ ### Files
223
+
224
+ - `UPGRADE_REVIEW.md` — 647-line audit report (all findings + cold verification + live verification).
225
+ - `test/functional/pi-crew-live.test.ts` + `pi-crew-live-broad.test.ts` — 16 live integration tests run against the real pi binary + real LLM provider.
226
+
227
+
5
228
  ## [0.9.42] — 107-finding deep review + arch cleanup (2026-07-17)
6
229
 
7
230
  ### Deep Review Resolution
package/README.md CHANGED
@@ -279,6 +279,41 @@ The advisory is **informational only** — there is no `force:true` flag needed
279
279
  - `test/unit/topology-analyzer.test.ts` — 13 cases (each topology + edge cases)
280
280
  - `test/unit/preflight-validator.test.ts` — 11 cases (each level + advisory contract)
281
281
 
282
+
283
+ - `test/functional/pi-crew-live.test.ts` + `test/functional/pi-crew-live-broad.test.ts` — 16 live integration tests run against the **real pi binary + real LLM provider** (verified after v0.9.42 audit, ~26 commits). Use these when you want to confirm end-to-end behavior, not just unit-level invariants.
284
+
285
+ ## Recent changes
286
+
287
+ ### v0.9.45 – v0.9.46 (2026-07-20): security + perf remediation, UI stability
288
+
289
+ - **Custom agent roles default to read-only (FIND-12, breaking):**
290
+ `permissionForRole()` returns `"read_only"` for unknown roles (was
291
+ permissive `"workspace_write"`). Write-capable roles are now an explicit
292
+ allowlist (`WRITE_ROLES`). See `CHANGELOG.md` for the migration.
293
+ - **Mailbox / snapshot-cache / scan perf:** delivery cache + async append
294
+ (FIND-01/02), `listActive` TTL + mtime-sort strict limit (FIND-03/04),
295
+ byte-bounded event-log tail-read (FIND-05).
296
+ - **Heartbeat race (FIND-06):** in-flight guard + drain + terminal-safety +
297
+ late-save repair in the coalesced task group.
298
+ - **UI flicker eliminated:** the render path no longer hard-deletes snapshot
299
+ entries, so the crew widget / powerbar / live sidebar stay stable (no more
300
+ "(loading…)" flashing every ~160ms).
301
+ - **Emoji width-overflow crash fixed for good:** `visibleWidth` delegates to
302
+ pi-tui's own measure, so agent-output emoji can never exceed terminal width.
303
+ - **Background-subagent notifications coalesce:** N near-simultaneous
304
+ completions now produce ONE consolidated wake-up instead of N drips.
305
+
306
+ ### v0.9.42 – v0.9.44: 4-wave audit + flaky-CI fixes
307
+
308
+ A 4-wave audit + fix pass was completed (see `UPGRADE_REVIEW.md` for the full 647-line report and `CHANGELOG.md` for the diff):
309
+
310
+ - **−481 KB** bundle size (externalized `acorn` + fixed `@sinclair/typebox` name).
311
+ - **−31.1%** in `child-pi.ts` (1842 → 1270 lines via 6 decomposition steps).
312
+ - **~30 bug fixes** across security, correctness, budget enforcement, worker cap, observability, and worktree isolation.
313
+ - **Lock re-entrance guard** via `AsyncLocalStorage` (H-1) — fixes a root-cause mutual-exclusion violation.
314
+ - **Task-level metrics now functional** (OBS-NEW-1/2) — `crew.task.{count,duration_ms,tokens_total}` were always zero; now emit on every run completion.
315
+ - **Live-test-only bugs found** (mock tests had passed): token usage not captured (nested `obj.message.usage`), child-pi spawning wrong binary (`argv1` trust heuristic), worktree mode blocked by own `.gitignore`.
316
+
282
317
  ## Builtin Agents
283
318
 
284
319
  ```