Resolves #15221
The unit config's chroma port now derives from the checkout root instead of a machine-global fixed default: FNV-1a over the toplevel path, range-bound in a 512-port window above the historic 18180, with a synchronous child bind-probe walking past the rare cross-checkout hash collision or a squatted port (fail-open to the candidate — the derivation is the mechanism, the probe the tiebreaker). A worktree's toplevel is its own path, so parents and worktrees isolate naturally — the semantics settled on the ticket after today's incident falsified shared-parent offsets (the operator worktree ran concurrently with a main checkout). NEO_CHROMA_PORT_TEST override wins unchanged; every run banner prints the resolved port and its provenance. This completes the isolation the config always half-had: the data dir was per-process, the port was global — and reuseExistingServer: false turned that gap into today's sticky machine-wide deadlock (four concurrent agent checkouts wedged behind one orphaned server, cross-checkout cleanup correctly permission-blocked, third-victim confirmations from two peers).
Evidence: L2 (4-spec suite green + the run itself as the live integration proof: the suite derived port 18497 for this checkout, booted its own chroma there, and ran green while the incident's orphaned server still held 18180) → L2 required (derivation/probe ACs are unit-verifiable; the cross-checkout concurrency AC is post-merge-observable by construction). Residual: the two-checkout live concurrency check (tracked below).
Deltas from ticket
- The ticket's pid-derivation sketch was superseded on-ticket by Mnemosyne's checkout-root-hash shape (stable per checkout across runs — credited there); the shared-parent-offset parenthetical was resolved to distinct-per-worktree via the incident's own concurrency evidence (ticket comment carries the tiebreak).
- The probe fallback is a short-lived
node -e child (sync from the config's perspective) rather than an in-process async probe — Playwright configs evaluate synchronously.
- Banner line added per the on-ticket refinement (resolved port + provenance in every run log).
Test Evidence
npm run test-unit -- test/playwright/unit/testinfra/deriveTestPort.spec.mjs --workers=1 (NO env override — deliberately) — 4 passed, banner: [unit-config] test chroma port 18497 (checkout-derived from /Users/Shared/claude/neomjs/neo; override: NEO_CHROMA_PORT_TEST). Spec fixtures are the four REAL incident checkout roots (distinctness pinned across parent checkouts + the worktree); determinism, range-bounds, and the probe's occupied-port walk (live net squatter in-spec) all pinned.
- Directly touched surfaces: the unit config + the new helper + its spec; sibling configs (
integration, component, visual) audited per the AC — none boots a fixed-port webServer (the e2e config's NEO_E2E_PORT is caller-supplied by design) → documented N/A.
- Source + PR-body gates:
npm run agent-preflight -- --no-fix <touched files> --pr-body <this draft> — passed before commit.
Post-Merge Validation
Evolution
The fix-shape converged across three seats on the ticket itself: my pid-sketch → Mnemosyne's checkout-hash (better: stable per checkout) → my worktree-distinctness falsifier from the incident's own process table → her range-bound + banner refinements. The PR implements the converged shape verbatim.
Authored by Grace (Claude Fable 5, Claude Code). Session 75ed6708-c66b-4989-862d-2286e87abbf1.
Resolves #15221
The unit config's chroma port now derives from the checkout root instead of a machine-global fixed default: FNV-1a over the toplevel path, range-bound in a 512-port window above the historic 18180, with a synchronous child bind-probe walking past the rare cross-checkout hash collision or a squatted port (fail-open to the candidate — the derivation is the mechanism, the probe the tiebreaker). A worktree's toplevel is its own path, so parents and worktrees isolate naturally — the semantics settled on the ticket after today's incident falsified shared-parent offsets (the operator worktree ran concurrently with a main checkout).
NEO_CHROMA_PORT_TESToverride wins unchanged; every run banner prints the resolved port and its provenance. This completes the isolation the config always half-had: the data dir was per-process, the port was global — andreuseExistingServer: falseturned that gap into today's sticky machine-wide deadlock (four concurrent agent checkouts wedged behind one orphaned server, cross-checkout cleanup correctly permission-blocked, third-victim confirmations from two peers).Evidence: L2 (4-spec suite green + the run itself as the live integration proof: the suite derived port 18497 for this checkout, booted its own chroma there, and ran green while the incident's orphaned server still held 18180) → L2 required (derivation/probe ACs are unit-verifiable; the cross-checkout concurrency AC is post-merge-observable by construction). Residual: the two-checkout live concurrency check (tracked below).
Deltas from ticket
node -echild (sync from the config's perspective) rather than an in-process async probe — Playwright configs evaluate synchronously.Test Evidence
npm run test-unit -- test/playwright/unit/testinfra/deriveTestPort.spec.mjs --workers=1(NO env override — deliberately) — 4 passed, banner:[unit-config] test chroma port 18497 (checkout-derived from /Users/Shared/claude/neomjs/neo; override: NEO_CHROMA_PORT_TEST). Spec fixtures are the four REAL incident checkout roots (distinctness pinned across parent checkouts + the worktree); determinism, range-bounds, and the probe's occupied-port walk (livenetsquatter in-spec) all pinned.integration,component,visual) audited per the AC — none boots a fixed-port webServer (the e2e config'sNEO_E2E_PORTis caller-supplied by design) → documented N/A.npm run agent-preflight -- --no-fix <touched files> --pr-body <this draft>— passed before commit.Post-Merge Validation
test-unitconcurrently with zero env vars and both complete (the incident-reproduction AC — observable once a second checkout pulls this change).Evolution
The fix-shape converged across three seats on the ticket itself: my pid-sketch → Mnemosyne's checkout-hash (better: stable per checkout) → my worktree-distinctness falsifier from the incident's own process table → her range-bound + banner refinements. The PR implements the converged shape verbatim.
Authored by Grace (Claude Fable 5, Claude Code). Session 75ed6708-c66b-4989-862d-2286e87abbf1.