pi-crew 0.11.39 → 0.11.40

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,55 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.40] — fix wave 12: fixture teardown — test-harness orphan leaks (2026-10-24)
6
+
7
+ Closes the leak class wave 11 exposed but did not own: the reaping wave made production descendants provable, and
8
+ then two fixtures of the shape `node -e "process.on('SIGTERM',()=>{}); setInterval(...)"` were found alive **> 6 h**
9
+ after their run completed, re-parented to systemd. Both were tests with `finally { child.kill() }` teardown — a
10
+ pid-only signal that cannot reach a tree, is a no-op against a SIGTERM-swallower, and never runs at all when the
11
+ spawn happens after the throw (SPEC `fixwave12-fixture-teardown-2026-10-24`).
12
+
13
+ **Added — `test/helpers/fixture-process.ts` (the fixture counterpart of `src/runtime/process/reap-group.ts`).**
14
+ - `spawnFixture` / `reapFixture` / `registerFixtureTrap`: pgid-correct fixture lifecycle. `spawnFixture` snapshots
15
+ identity (`readProcIdentity`) at spawn and normalises `pgid` to `pid` (a detached child leads its own group), so
16
+ the later group kill is pgid-reuse-proof; `reapFixture` escalates SIGTERM → SIGKILL and never throws (it runs in
17
+ `finally`, where a throw would mask the failure under test); a refusal that PROVES the pid is a stranger
18
+ (`starttime-mismatch`, `uid-mismatch`, `not-group-member`) signals nothing rather than pid-killing a recycled pid.
19
+ - `spawnFixture` **refuses non-detached children** by throwing: a non-detached fixture shares the test runner's
20
+ group, so a group kill rooted at it would signal the runner, sibling test files and the harness.
21
+ - `registerFixtureTrap` flushes registered handles **synchronously** on `exit`/`SIGINT`/`SIGTERM`, covering the abort
22
+ window where no `finally` runs.
23
+
24
+ **Fixed — HIGH orphan leak (`test/integration/background-runner-sigint-cleanup.test.ts`).** The grandchild group is
25
+ now reaped even when an assertion throws; the harness stays pid-only by design (documented in
26
+ `test/helpers/README.md`).
27
+
28
+ **Fixed — orphan risk in three more fixtures.** `test/unit/retrieval-orchestrator.test.ts` (the fake `rg` writes its
29
+ pid/pgid and the group is reaped), `test/unit/runtime/child-pi/inference-broker.test.ts` (the live `pi` is spawned
30
+ detached and its group reaped via `reapFixture`; the 90 s timer is demoted to a safety net, not the teardown), and
31
+ `test/unit/runtime/process/reap-group.test.ts` (the `spawnTree` failure path reaps its own group — GAP-4).
32
+
33
+ **Fixed — teardown race (`test/unit/extension/team-tool-steer-clamp.test.ts`).** `ENOTEMPTY` on `afterEach`: the
34
+ fire-and-forget `appendEventAsync` re-creates the run directory after a plain `rmSync`. Now uses
35
+ `removeDirWithRetry` (the existing helper) so the retry absorbs the async writer.
36
+
37
+ **Added — `getuid?: () => number | undefined` seam** on `ReapGroupOptions`/`SweepOptions`, propagated to the sweep's
38
+ `reapGroup` call site so discovery and group kill can never disagree about the uid (`process.getuid` is undefined on
39
+ win32); this also removes 3 duplicated `process.getuid` monkeypatches from tests.
40
+
41
+ **Tests.** `test/unit/runtime/process/getuid-seam.test.ts` (10 pins), `test/unit/helpers/fixture-process.test.ts`
42
+ (5 pins: h1–h5), `test/helpers/README.md` (fixture lifecycle rules: detached ⇒ group reap with the spawn-time
43
+ identity snapshot, non-detached ⇒ pid-only with the reason in a comment, never read identity in `finally`).
44
+
45
+ **Fixed — shard regression.** `helpers: 180` weight registered in `scripts/test-runner.mjs` (wave 12a created
46
+ `test/unit/helpers/`, which had no shard weight).
47
+
48
+ **Docs.** real-test skill: wave-12 decision-table row, history entry, failure symptom, coverage row, and the
49
+ wave-12d lesson (teardown of a directory with async writers must retry).
50
+
51
+ **Battery (PASS).** 30/30 targeted runs, `test:critical` 124/124, full unit 10,009 pass / 2 load-flakes (adjudicated
52
+ isolated ×3), integration 144/0, static gates 0, dist MATCH.
53
+
5
54
  ## [0.11.39] — fix wave 11: worker descendant reaping (2026-10-24)
6
55
 
7
56
  Closes the leak that motivated the wave: run `team_20261022110510_cefb9164af126460` reached `completed` on