Skip to content

Windows retained lifecycle fixture records its identity before the owner exits - #459

Open
avifenesh wants to merge 2 commits into
mainfrom
tower-crane/T469-windows-retained-process-tests-pass-agai
Open

avifenesh wants to merge 2 commits into
mainfrom
tower-crane/T469-windows-retained-process-tests-pass-agai

Conversation

@avifenesh

@avifenesh avifenesh commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

What changed

  • test/fixtures/containment-lifecycle.js: the fixture's owner (agent role) now exits only after it records the dispatched process's identity in identities.json. Before, it exited at 400 ms whether or not the record was there. The ordinary stray starts at that point, so its calibrated stop margin stays the same. TC_IDENTITY_DELAY_MS delays the identity query, standing in for a slow CIM query on platforms where the identity is a fast /proc read.
  • test/containment-lifecycle.test.js: new row retained supervisor: zero exit, slow-identity owner, none late limit, which sets a 600 ms delay so the owner on Linux outlives its 400 ms exit timer, as it does on Windows.

No product code changes.

Why

Main push CI at 9a718f6 failed every recorded-owner row of the retained lifecycle group on Windows (shard 2/4). T419 replaced T437's command-line and environment markers with recorded process identities (managed(rows, identities) in lib/containment.js). On Windows, C.processIdentity() is a PowerShell CIM snapshot that takes a second or more on a hosted runner. The fixture's owner exited at 400 ms, before that query returned. So when containment's final snapshot read retained(), there was nothing on record, and the managed work was stopped like any stray. The unrecorded rows, which expect nothing to survive, passed. That is the pattern in the failed log.

The product does not have this race. The supervisor computes its own identity before it launches anything (lib/spawn-monitor.js:555) and writes it into the startup receipt (lib/spawn-monitor.js:1006, detail() spreads monitor). The dispatch CLI loops until that receipt exists (lib/spawn.js:1214) and commits it in the spawn event (lib/spawn.js:1260, ...observed), which recorded() in lib/containment.js reads. So the harness that ran tower-crane spawn cannot get control back before the identity is on record. The fixture now models the same contract. T419's Windows stop order (cycle-safe BFS, no tree kill while work is spared) is unchanged.

Same-repo PRs run only shared checks, so this group never ran on Windows before T419 merged.

Verification

  • Windows: dispatch runs 39513148646, 39513151860 and 39513154962 at bbed5d5, shard 2/4: all 12 retained lifecycle rows pass in each of the three runs.

  • Reproduction on Linux: with the old fixture and a 1000 ms delay injected before processIdentity, the same 7 rows fail as on Windows CI (caller, nonzero/agent, signal/agent, wait/agent, gate/agent, tasks late, memory late). The 4 expected-not-survive rows pass.

  • The new slow-identity row fails 3 of 3 runs against the old fixture and passes with the fix.

  • npm test -- test/containment-lifecycle.test.js: 3 consecutive runs, each 21 pass, 1 skipped (the POSIX-only TERM row), 0 fail.

  • npm test -- test/signal-waits.test.js: pass. npm run check:shared -- --base origin/main: pass.

Pending

  • Linux full suite: the tests gate runs it.

Pre-submit review

  • Head: d601e67 (bbed5d5 merged with main at 0881d0f; the merge changes none of this PR's files or lib/containment.js, lib/processes.js, lib/spawn-monitor.js, lib/spawn.js)
  • Fresh context: no
  • Acceptance: Windows 3 consecutive runs: in workflow_dispatch runs 39513148646, 39513151860 and 39513154962 at bbed5d5, windows-latest node 26 shard 2/4 succeeded each time and passes all 12 retained rows, including slow-identity (570 pass, 0 fail). Linux: test/containment-lifecycle.test.js 3/3 green locally and again at the merge head (21 pass, 1 skipped); full suite pending on the tests gate.
  • Rework coverage: none (first attempt)
  • Revuto at head: clean at bbed5d5 (no evidence-backed concerns); pending at the merge head
  • CI at head: pending. Dispatch runs at bbed5d5 also failed in test/interrupt.test.js (Windows shard 1/4, run 39513154962) and a gate scratch proof timeout (run 39513151860). Neither touches this change; the orchestrator filed them as T471 and T472
  • Left open: none
  • Result: pass

🤖 Generated with Claude Code

…ner exits

T419 moved retention from command-line and environment markers to recorded
process identities. The lifecycle fixture's owner started a CIM identity query
for its dispatched process and exited at 400 ms, before a hosted Windows
runner's query returned, so nothing was on record and the work was stopped.
A real dispatch waits for its supervisor's receipt, which carries the identity;
the fixture now does the same. A Linux row emulates the slow query.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 20, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 9f7118f5-3765-4632-a9df-670de23a2381)

@revuto-review revuto-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an auto review done by revuto.


Revuto completed the review and found no evidence-backed concerns.

@cursor

cursor Bot commented Oct 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 0634719a-24e1-4223-9c8b-db7d8d35b089)

@revuto-review revuto-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an auto review done by revuto.


Revuto completed the review and found no evidence-backed concerns.

@avifenesh

Copy link
Copy Markdown
Contributor Author

Review (Tower Crane, clean context)
SHA: d601e67

Blocking count: 0.

Acceptance

  • Windows, 3 consecutive CI runs: workflow_dispatch runs 39513148646, 39513151860 and 39513154962 at bbed5d5. test (windows-latest, node 26, shard 2/4) succeeded in each (jobs 118938838409, 118938847379, 118938858721). The job logs show all 12 retained ... rows passing in each run, including the new slow-identity row. git diff bbed5d5f d601e672 touches none of the lifecycle test, its fixture, lib/containment.js, lib/processes.js, lib/spawn-monitor.js, lib/spawn.js or test/helpers.js, so the evidence carries over to the merge head.
  • Linux full suite: the tests gate ran the full suite at d601e67 with exit 0.

Root cause and fix

  • T419 replaced env markers with recorded identities (managed(rows, identities)). On Windows, processIdentity (lib/containment.js:505) is a CIM snapshot, so the fixture's owner exited at 400 ms before identities.json had anything in it. Every recorded-owner row then lost its work, and the unrecorded rows passed. That matches the failed main log.
  • The product contract the fixture now models is real. The supervisor computes monitorIdentity at lib/spawn-monitor.js:555, before the receipt write at :1006, and lib/spawn.js:1214 blocks until the receipt exists. So a dispatch cannot return before its identity is on record.
  • Probe on Linux (scratch export of d601e67, only the slow-identity row): the base fixture with only the TC_IDENTITY_DELAY_MS delay added before processIdentity failed 3 of 3. The submitted fixture passed. The new row is a valid regression test for the ordering.
  • Scope: test/fixtures/containment-lifecycle.js is where the defect was, and changelog.d/T469.md is required by AGENTS.md. Both are justified even though the brief pointed at lib/. The changelog text matches the code.

Blocking findings

None

Follow-ups

  • test/fixtures/containment-lifecycle.js:58-62 - The managed role's late-limit probes (650scale ms) and its managed.done (1100scale ms) still time from managed's own start, but the owner now exits at identity time + 400 ms instead of a fixed 400 ms. On Windows that leaves 3250 ms - (CIM time + 400 ms) before the "late" probes. A CIM query near 2.9 s would fire the tasks/memory probes before the owner exits, and those rows would stop testing a late limit. Timing these from an owner-exited signal (for example a file the owner writes in end) would remove the dependence on CIM speed.
  • test/fixtures/containment-lifecycle.js:507-523 - If the managed launch emits error instead of spawn, recorded never settles and the owner never exits. The row then fails on the 10 s C.spawn timeout instead of a clear assertion. Rejecting on error would end the owner right away.
  • PR body, Verification: "The new slow-identity row fails 3 of 3 runs against the old fixture" holds only for the old exit order with the delay hook added. The literal base fixture ignores TC_IDENTITY_DELAY_MS and passes the row. The meaning is clear and my probe confirms the intended version, so this is a wording note.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant