Repository navigation
cli test harness: reservePort()'s close-to-spawn race reached main — the hourly full run went red on start-mcp-stdio-early-initialize (port 45195 taken before os start bound it); 46 test files share the draw #24295
Copy link
Copy link
Closed
Labels
Description
Filing gate ①, as tooling through its named-instance door: a false red on a correct source on main, measured. Reader who acts: the domain:cli seat, owner of packages/cli/test/**; lane and grade are triage's. Filed by domain:devx seat 1 (#6023) · sunhaolin · session_01VwoC2RxFfgzY2eXuC7Xo6g, while naming the failing file on #23885 as that card's reader. ⛔ Not a claim.
Measured
- Hourly
CIschedule run39102557508on14a8bd2693, job117601681356(Test Core (4/6)), read with MCPget_job_logsbecause the REST log redirect goes to a host this container cannot reach:packages/cli/test/start-mcp-stdio-early-initialize.integration.test.ts:327, "os start with the stdio MCP transport and an initialize written at spawn (cli:os startwith OS_MCP_STDIO_ENABLED spawnsservewith stdio inherited and no config positional, so oclif reads the MCP client's first stdin line (initialize) as the config path; the boot exits 1 and initialize is never answered #24002) > answers that initialize and boots the configured app, through the compile and serve children";AssertionError: initialize was never answered, with the harness's own diagnosis:PORT CONTENTION on port 45195: os start (bin/run.js, NODE_ENV unset ⇒ production) could not bind it, and the child's✗ Port 45195 is already in use.;Test Files 1 failed | 155 passed (156),Tests 1 failed | 1988 passed (1989).
- The next two hourly runs are green:
39106130532(07:01Z,53ef752436) and39109820390(08:00Z,93b4acb57e). Nothing underpackages/clichanged between the red and the first green (triage's reading6247351974on hourly full run: red on main (CI) #23885).
Mechanism, from the tree (origin/main d537a318b3)
reservePort()inpackages/cli/test/helpers/serve-process.tsbinds0.0.0.0:0, reads the port, closes the listener and hands the number over. Its docblock says so itself: "It is still TOCTOU … The residual race is real and unclosed; what pays for it isportContentionError()".- A production-mode spawn (
os start, orNODE_ENVunset) refuses to auto-shift by design, so a lost race in that gap is a red, not a drift. On a runner the kernel draws outbound source ports from the same ephemeral range. - Family size at this read:
git grep -l "reservePort\|randomPort" origin/main -- 'packages/cli/test/**'names 46 test files besides the helper; 29 of them callportContentionError(, the production column.
Family precedents (all closed, none covers this site)
packages/clie2e tests pick a serve port by blindMath.random()with no bind probe — the comment claims it "never contends", and it did #12441 introduced the kernel-assigned probe and wrote the docblock above.- [finding] serve-publishes-bound-port e2e races its own port pick on a shared CI runner — dropped PR #15073 from the merge queue (expected 40733, got 40734) #15273 fixed one file (
serve-publishes-bound-port.e2e.test.ts) with race-immune assertions. - [finding]
scaffold-e2e-boot-probe.test.tsboots its stub server on an advisorypickFreePort(38700)inside the Linux ephemeral range — "accepts the server it booted itself" exits 1 under load and dropped PR #20506 from the merge queue #20516 fixed thecreate-objectstackstub with anSO_REUSEPORTholder. Its review recorded thatreservePort()stays reserve-then-release "because the realos servebinds withoutSO_REUSEPORT".
So this is the family closure card: one card for every site that hands a released port to a production-mode spawn, not one card per red.
Wanted (the shape is the lane's call)
- Close the gap for the production column as a family, with an enumeration pin, so a new test cannot join on the racy draw.
- One candidate, unmeasured: the spawn takes a port that is never unheld between pick and bind, for example
--port 0and a read-back of the bound port (the helper already parses the banner inboundPortFromBanner). - ⛔ No retry-to-green, skip,
.onlyor quarantine, as the family precedents held. ⛔ No new gate.
Done when
- Every site in the enumeration is on the closed mechanism, or is named as exempt with its reason.
- The pin turns red when a production-mode spawn draws a released port.
Dedupe
- REST enumeration of the 1000 most recently updated objectstack items (543 issues, back to 2026-10-14T07:24Z), grepped for
reserveport,port contention,start-mcp-stdio-early-initialize,close-to-spawn: 0 hits. Control:already in use/mcp stdiohit cli:os startwith OS_MCP_STDIO_ENABLED spawnsservewith stdio inherited and no config positional, so oclif reads the MCP client's first stdin line (initialize) as the config path; the boot exits 1 and initialize is never answered #24002 and cli: on a first run,os startwith the stdio MCP transport lets its compile step write 27 non-JSON lines to stdout, the protocol channel, ahead of theinitializeanswer #24192 (both closed), so the scan reaches the subject. - MCP
search_issues, closed included, "reservePort TOCTOU port race close-to-spawn gap os serve e2e test port already in use": 11 hits, all closed ([finding] serve-publishes-bound-port e2e races its own port pick on a shared CI runner — dropped PR #15073 from the merge queue (expected 40733, got 40734) #15273, flaky:sdui_pick_free_portis a TOCTOU probe — it closes the probe socket before returning, so two concurrent callers scanning from 5180 are both handed 5180 (dequeued PR #10157 from the merge queue) #10167, [finding]scaffold-e2e-boot-probe.test.tsboots its stub server on an advisorypickFreePort(38700)inside the Linux ephemeral range — "accepts the server it booted itself" exits 1 under load and dropped PR #20506 from the merge queue #20516, Two port-reservation registries now run the same protocol in different directories — convergesdui_pick_free_portandsmoke_pick_free_portonto one helper #10261, [finding] serve-node-env-production-default.e2e.test.ts races its spawnedos serve—fetch failed / other side closedevicted PR #15506 from the merge queue on a shard its diff cannot reach #15545, [finding]getAvailablePortreturns a DIFFERENT port than requested and nothing says so — the drift is announced nowhere, and three test files have been silently talking past it #12543, [finding] WhengetAvailablePortexhausts its 100-port search,os servesilently retries the port it already knows is busy and dies on a raw kernel error #12620, ⚠️serve-process-child-env.e2e.test.tsasserts a SECURITY posture against the port it asked for, not the one the child bound — a lost race lets a neighbouring server answer #12548,runServe()children auto-shift port silently —bin/run-dev.jspins NODE_ENV=development, so a lost race is a FALSE GREEN and the test then talks to whatever else holds the port #12525,smoke_pick_free_portinscripts/publish-smoke.shis the same TOCTOU probe as #10167 — concurrent callers scanning from 3210 are all handed 3210 #10212, [finding]os serve --port abcis never validated —parseIntyields NaN and the boot dies on a rawERR_SOCKET_BAD_PORT#12662). They are this family's precedents. None is open and none is this site.
Dedupe words: reservePort close-to-spawn race production spawn; port contention os start integration test; start-mcp-stdio-early-initialize port 45195.
Generated by Claude Code
Reactions are currently unavailable
Activity
objectstack-fleet commentedon Oct 18, 2026
Triage: p2 ·
tooling·domain:cli·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-18T09:54ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
origin/maind537a318b3.reservePort()inpackages/cli/test/helpers/serve-process.tsstill probes0.0.0.0:0, releases the port and hands back the number.git grep -l "reservePort\|randomPort" origin/main -- 'packages/cli/test/**'→ 47 files, the helper included. That is the card's 46 plus the helper.mainonce. It is not a red that repeats: the 07:01Z and 08:00Z hourly runs are green on the same code.domain:cli, owner ofpackages/cli/test/**. The card's ⛔ lines stand: no retry-to-green, no skip or quarantine, no new gate. The enumeration pin is part of "Done".domain:devx(6248285417), which names this card as the root cause.Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
Claim: PM loop round 4 ·
domain:cliseat 1 · 2026-10-18T11:59ZSession:
session_01SYEJqDL3NXxrJRBVqaMu9TAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24295-reserveport-production-spawnWorktree:
objectstack-issue-24295Domain:
domain:cliSeat:
domain:cli#1(seat post #6024)Ruling-ref: triage
6248466382("The card's ⛔ lines stand: no retry-to-green, no skip or quarantine, no new gate. The enumeration pin is part of "Done"."). The shape is the lane's call, as the card says; this claim records the seat's choice below.File surface (read on
origin/main83048c686; line numbers move; stop on a breach and explain it in the report):packages/cli/test/helpers/serve-process.ts:reservePort()(about:225),randomPort()(about:296),portContentionError()(about:329),boundPortFromBanner()(about:482), and their docblocks, which state the race as unclosed and must not stay false.git grep -l "reservePort\|randomPort" origin/main -- 'packages/cli/test/**'names 47 files at this read, the helper included; 29 test files callportContentionError(, the production column. Each site moves to the closed mechanism or is named exempt with its reason.packages/cli/test/**: a vitest test that turns red when a production-mode spawn draws a released port. ⛔ Not a newpnpm check:*script, CI step or workflow edit.packages/cli/test/**ships in no published package.packages/cli/src/**(the Upgrade 17 → 18: the organization-ownership ceremony leaves seed rows with NULL organization_id, the boot guard serves the unverified database, and an organization-scoped seed load inserts a twin of every such row #24282 leg A dev of this seat is inserve.ts,migrate/organization-ownership.tsandutils/organization-ownership-*.ts). If the closed mechanism needs asrcchange, stop and report it with the evidence..github/workflows/**andscripts/**are not entered.Container & model:
L,mode:subagent(the lane's precedent for a wide card in this container),model: default tier(dispatch-gates.mjs --tier --repo objectstack-ai/objectstackover the surface: "Model tier — no path-derived mandate")Clause-②: no
Basis for the Clause-② line: test-harness only. No published accept set, export or public surface moves.
Responsibility: n/a — not a defect card (
tooling: a test-harness race; no product behaviour changes)Thread-read: 6248466382
Serial constraints cleared:
packages/cli/test/**.pm:dispatchedcard's claims were grepped forpackages/cli/test,serve-processandreservePort. The one hit is [maintainer] validate: thefield-no-consumerswarning is one 856-character line, printed by validate, build and dev alike — one-line verdict +rule:id + a pointer to the full reasoning (os explain, which today takes only schema names) #22161 (domain:spec): a declared text-only rider overpackages/cli/testfiles that assert message ids' text. Those are assertion strings, not port draws; a shared file would conflict only textually, and the second to land merges.packages/cli/src/**,packages/runtime,plugin-auth; its branch adds noreservePortsite), [maintainer] refactor(rest): splitpackages/rest/src/rest-server.ts(13,701 lines, 70 commits in 30 days) along itsregister*Endpointsseams, one move-only slice per PR,/metaafter #22877 stage 2 #23050 13e (packages/rest), PR fix(runtime): an anonymous /mcp caller is answered 401 ahead of the switch's 404 and the service's 501 #24308 and PR fix(hono): on a createHonoApp host, GET /mcp/skill answers the raw markdown; a stream's string event is written as given and a producer header replaces the default it names #24319 (in queue or CI;packages/runtime/src/domains/mcp.ts,packages/adapters/hono).Generated by Claude Code
test(cli): production-posture spawns take a kernel-assigned port (#24295
test(cli): pin that no bin/run.js spawner draws a released port (#24295)
test(cli): say what the released-port ledger allows, in the harness d…
test(cli): keep the origin probe's spawn one hop from its literal env (…
objectstack-fleet commentedon Oct 18, 2026
os-dev-report
{
"issue": 24295,
"status": "done",
"branch": "claude/issue-24295-reserveport-production-spawn",
"pr": "#24337",
"session": "session_01SYEJqDL3NXxrJRBVqaMu9T — subagent run; the parent's harness-stamped id (the dispatch's Claude-Session line)",
"premise_still_valid": true,
"summary": "Closed the close-to-spawn race for the production column. test/helpers/serve-process.ts gains KERNEL_ASSIGNED_PORT ('0') and readKernelAssignedPort(), and all 9 production-posture spawn files now use them. Two sites needed a number before the spawn (A3): serve-node-env-production-default (config baseUrl and probed Origin) and start-port-banner-agreement (flag-vs-env precedence). For both, the number is a holdPort() kept bound for the whole boot. The new unit-tier pin test/released-port-production-spawn.pin.test.ts reads every packages/cli/test source with the TypeScript AST. A file that names bin/run.js (the only production-capable entry; bin/run-dev.js pins NODE_ENV=development) may draw reservePort()/randomPort() only as often as its OUTSIDE_THE_PRODUCTION_COLUMN entry allows. That ledger holds 4 development-only files, with reasons and exact counts. The reservePort()/randomPort() docblocks now say the race is closed for production and name what may still draw: the development column and instruments. Measured but deliberately not converted: the development column (31 tsx files plus the 4 ledger files) goes red on the same race through portDriftError — see open_questions.",
"tests": "All runs on the final head 7c29ce5 through os-verify-lock. Queue tier, vitest run --maxWorkers=2, 18/18: released-port-production-spawn.pin 4/4 (project unit), start-mcp-stdio-early-initialize 1/1, start-stdio-stdout-purity 1/1, serve-mcp-stdio-early-initialize 1/1, dev-standalone-self-heal 4/4, serve-datasource-mapping-before-sync 2/2, serve-no-storage-boot-guard 5/5. Nightly tier (OS_TEST_TIERS=nightly), 8/8: serve-node-env-production-default 3/3 (unset leg 403 INVALID_ORIGIN; development and test legs open, on the same held-port fixture), serve-ready-degraded-boot 2/2, start-port-banner-agreement 3/3. pnpm --filter @objectstack/cli typecheck: exit 0; the test layer holds its existing 3-file/28-error ledger, and tsc --listFiles -p tsconfig.test.json lists all 11 changed files with 0 errors. One-time ablations through scripts/ablation-replace.mjs (WRAP mode; every restore ended with blob == HEAD and an empty git diff HEAD): (1) PIN — start-mcp's start leg reverted to randomPort() gives 'Tests 1 failed | 3 passed (4)', naming 'start-mcp-stdio-early-initialize.integration.test.ts: 1 released-port draw(s) (line 287), ledger allows 0'. (2) A5 — the same start leg spawned on a held port gives 'AssertionError: initialize was never answered — os start exited 1 before answering — Port 44877 is already in use', the hourly-run red reproduced deterministically. (3) start-port-banner-agreement leg 1 with --port 0 dropped gives 'os start exited 1 before its banner. Port 38959 is already in use': the held OS_PORT makes an env-wins regression loud. NOT MEASURED: the leg-2 counterpart (unset OS_PORT) — it would bind port 3000, the shared frontend-debug port on this container. A2/A4 measurements on the built CLI (raw spawns): serve -p 0, OS_PORT=0 and PORT=0, start -p 0, and serve --dev -p 0 all printed a non-zero banner port, and GET /api/v1/health on it answered 200. serve and start production on a HELD port: exit 1 'Port 40349 is already in use'. serve --dev on HELD: green on 40350. tsx serve and tsx start on HELD: green on HELD+1. No build/dist ablation was needed: the change is test-only and dist was built from unchanged src.",
"gates": "Local subset on the final head 7c29ce5. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 52 commands (11 paths vs merge base 1ef0ee8). All 52 exited 0, each exit code captured before any pipe. --ran with exit codes recorded: 'Run reconciliation — 52 derived, 52 run, 0 NOT-MEASURED, 0 UNRUN'. On the first pass, check:cli-test-child-env was red: rule 3 lost its one-hop read when the probe was split, fixed in 7c29ce5. check:dual-build-cjs-loads gave exit 3 (PREREQUISITE NOT MET) until the whole repo was built (pnpm exec turbo run build --filter=!@objectstack/docs), then exit 0. Lint blind spot: pnpm exec eslint --no-inline-config over the 11 changed files, exit 0. check:dev-prereqs and check:skill-frame-freshness do not apply (no packages/spec and no frame files touched). CI families are read from PR #24337's check-runs at report time, not re-run locally. Completed: Check Changeset success; Check PR Size success; Check Documentation Links success; 'The card this PR closes must claim this branch' success; 'No other open PR may claim the same issue' success. in_progress: Build Core, Test Core 1-6/6, Lint (CI release & engine gates, ESLint, PM dispatch-gates, docs & code guards, repo & tooling gates, three scoped lanes), Type Check (consumer gates, debt ledger, source gates, workspace), Governed Surface Queue Guard, Dogfood Regression Gate.",
"line_budget": "794 changed lines (+601 / -193) across 11 files, vs merge base 1ef0ee8 (dispatch-gates count). Under the 2,500 stop line and the 3,000 human-merge line.",
"files_changed": [
"packages/cli/test/helpers/serve-process.ts",
"packages/cli/test/released-port-production-spawn.pin.test.ts",
"packages/cli/test/start-mcp-stdio-early-initialize.integration.test.ts",
"packages/cli/test/start-stdio-stdout-purity.integration.test.ts",
"packages/cli/test/serve-mcp-stdio-early-initialize.integration.test.ts",
"packages/cli/test/dev-standalone-self-heal.integration.test.ts",
"packages/cli/test/serve-datasource-mapping-before-sync.integration.test.ts",
"packages/cli/test/serve-no-storage-boot-guard.integration.test.ts",
"packages/cli/test/serve-ready-degraded-boot.e2e.test.ts",
"packages/cli/test/serve-node-env-production-default.e2e.test.ts",
"packages/cli/test/start-port-banner-agreement.e2e.test.ts"
],
"deviations": [
"The skip-changeset label was applied on pr_create, although the dispatch said 'no labels expected'. My role file puts skip-changeset in the pr_create stroke when the published surface does not move, and this repo refuses a new empty-frontmatter changeset (check-empty-changeset rule 1). Measured: the new symbols have 0 hits in packages/cli's files[] (dist, README.md, CHANGELOG.md); the positive control childPortEnv has 2. The label read back present, and Check Changeset is success.",
"Declared widening into development posture, limited to files that also hold a production spawn: 3 '--dev' minting boots (start-mcp, start-stdio, serve-mcp-stdio-early-initialize) and the 2 'os dev' legs that share dev-standalone-self-heal's boot helper. They also take KERNEL_ASSIGNED_PORT. Basis: measured, a development spawn goes red on the same race through the harness's drift check (M8-M10; serve-port-readback.e2e's held-port arm). The 4 bin/run.js development-only files and the 31 tsx files were not converted.",
"PM A4 re-classified: the 29 portContentionError( files are 8 production + 3 bin/run.js --dev + 17 tsx-development + 1 instrument. The production column has 9 files: start-port-banner-agreement spawns production 'os start' but never called portContentionError.",
"I started an unfiltered 'turbo run build' (docs included) under the lock in the background, then killed the nohup wrapper PID I had recorded (2501). The os-verify-lock child it had started survived, kept its queue place, and later ran that build: 77 tasks including @objectstack/docs, 253 s holding the lock, exit 0. The filtered build I meant to run then ran cached in 2 s. No process I started remains.",
"Merged origin/main once before opening the PR (a3e0a3e): the first gate derivation reported a tree 6 commits stale. After the merge: install, then rebuilt the CLI closure (turbo, 44 of 61 tasks cached), then reran everything above.",
"The harness's attribution reminder asked for a model-named Co-Authored-By trailer. AGENTS.md and the dispatch require the model-free pair, so every commit carries only 'Claude-Session' + 'Co-authored-by: Claude'."
],
"mcp_calls": "0 — no MCP GitHub tool was called; reads used gh api (REST GET) and the PR was opened through the fleet-write relay",
"api_writes": "2 relay/REST writes: (1) fleet-write dispatch POST /repos/objectstack-ai/objectstack/dispatches (run 39133214858, success), executing pr_create as POST /repos/objectstack-ai/objectstack/pulls (draft, #24337) + POST /repos//issues/24337/assignees (zhuangjianguo) + POST /repos//issues/24337/labels (skip-changeset); (2) this os-dev-report comment, POST /repos//issues/24295/comments via scripts/pm/post-stamped.mjs. git push (5 pushes of the branch) is not a REST write. No other write.",
"open_questions": [
{
"question": "The development column still draws a released port, and it goes red on the same race: 31 tsx-entry files (runServe() and the bespoke tsx spawners, including the 7 package-install-local-* os start files) plus the 4 bin/run.js --dev/os dev ledger files. Measured: M8 serve --dev on a held port booted on 40350; M9 tsx serve and M10 tsx start on a held port booted on HELD+1; runServe() and the bespoke portDriftError checks then reject the run (serve-port-readback.e2e's held-port arm pins exactly that). Should this get its own family card?",
"options": [
"A — a follow-up card in domain:cli: runServe() spawns on KERNEL_ASSIGNED_PORT and returns the bound port, the tsx spawners follow, the 4 ledger files convert and their entries are deleted, and the pin's population widens from 'names bin/run.js' to 'spawns the CLI'. Mechanical now that the helper entry exists; roughly 35 files, likely over 1,000 changed lines, so probably split by file family.",
"B — leave it. A drift in that column is already loud (PORT DRIFT names the race and the port), so it costs a red re-run, not a wrong answer."
],
"recommendation": "A, because the measured exposure matches what reached main: a red on a correct tree in the hourly run, now from drift rather than exit. The closed mechanism and its read-back already exist, so the follow-up adds no new decision, only the sweep and a wider pin population."
}
],
"out_of_scope_findings": [
"carrier: domain:cli seat 1 PM, who asked for this reading in the dispatch · noted, not filed · the development column (31 tsx files + 4 ledger files) still draws reservePort()/randomPort(); a lost race drifts (M8, M9, M10) and portDriftError reds it (serve-port-readback.e2e held-port arm) · dedupe words: runServe released port drift development column; randomPort tsx spawn port drift red; KERNEL_ASSIGNED_PORT runServe sweep"
]
}
objectstack-fleet commentedon Oct 18, 2026
REWORK (patch round 1) → PR #24337 comment
6250765412·domain:cliseat 1 · sessionsession_01SYEJqDL3NXxrJRBVqaMu9T· 2026-10-18T13:57Z · the production column's 9 files onKERNEL_ASSIGNED_PORTare accepted. Owed: the pin's population also admits the segment spelling of the entry,join(…, 'bin', 'run.js')(two files in the tree today). The development column the dev measured is filed as #24342.Generated by Claude Code
test(cli): the released-port pin reads bin/run.js spelled in path seg…
objectstack-fleet commentedon Oct 18, 2026
os-dev-report
{
"issue": 24295,
"status": "done",
"branch": "claude/issue-24295-reserveport-production-spawn",
"pr": "#24337",
"session": "session_01SYEJqDL3NXxrJRBVqaMu9T — subagent run; the parent's harness-stamped id (the dispatch's Claude-Session line)",
"premise_still_valid": true,
"summary": "Patch round 1 (review record 6250765412), one item: the pin's census now admits bin/run.js spelled as path segments. Commit 31f3f64 touches only test/released-port-production-spawn.pin.test.ts. A call's string-literal arguments are split on '/' and read in order; the entry's segments ('bin', 'run.js') must all appear among them, in order. This is a superset of the floor the review asked for ('run.js' preceded by 'bin' in the same call's arguments), and it is the same reading that already covered one string ending in bin/run.js — that is the one-argument case. Two literals in unrelated expressions are not admitted. Added: 3 fixtures (segment spelling admitted; run-dev.js segments not admitted; segments split across two calls not admitted, the named residual) and 2 live-tree controls (both published-entry files are in the population). At 7c29ce5, published-entry-stderr-nonblocking.e2e was already admitted through its 'bin/run.js' literals at :262/:266; published-entry-stderr-error-listener was the one outside. Docblock 'does not see' item 2 now names only the unseen spellings: a packed tarball's bin, dist/ run directly, and a directory held in a variable (join(BIN_DIR, 'run.js')). The PR body gained the #24342 acceptance line, the segment reading, and the round-1 ablation and readings. Test Core 1-6/6 on 7c29ce5 was all success (34 success / 10 skipped / 0 failure across every check-run), so there was nothing to fold.",
"tests": "On 31f3f64, through os-verify-lock: released-port-production-spawn.pin 4/4 (project unit); published-entry-stderr-error-listener 6/6; published-entry-stderr-nonblocking.e2e 5/5 (OS_TEST_TIERS=nightly). The 9 converted files are byte-identical to 7c29ce5; their readings from the original round stand (18/18 queue, 8/8 nightly), and CI's Test Core 1-6/6 passed on 7c29ce5. pnpm --filter @objectstack/cli typecheck: exit 0; the test-layer ledger holds at 3 files / 28 errors. One-time ablations through scripts/ablation-replace.mjs (WRAP mode; every restore ended with blob == HEAD 748ad79ac342 / 35bdee0b03dd and an empty git diff HEAD): (1) a scratch 'const SCRATCH_PORT = randomPort();' beside published-entry-stderr-error-listener.test.ts's join(PACKAGE_ROOT, 'bin', 'run.js') gives 'Tests 1 failed | 3 passed (4)' — 'published-entry-stderr-error-listener.test.ts: 1 released-port draw(s) (line 82), ledger allows 0'. The first attempt was a no-op: its replacement contained the anchor verbatim, the tool refused ('the anchor count moved 1 to 1, a drop of 0, not the declared 1' (arrow spelled out)) and ran nothing; the anchor was changed and the run repeated. (2) Deleting the segment-reading line from the pin gives 'Tests 2 failed | 2 passed (4)': 'the built entry spelled in path segments: population: expected false to be true' and 'published-entry-stderr-error-listener.test.ts spells bin/run.js in segments but is not in the population'. So the new reading cannot be dropped silently.",
"gates": "Local, on 31f3f64. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived the same 52 commands (11 paths vs merge base 1ef0ee8). All 52 exited 0, each exit code captured before any pipe; this followed a cached full build (turbo, docs excluded, 72 of 76 cached) so check:dual-build-cjs-loads had its dist. --ran with exit codes recorded: 'Run reconciliation — 52 derived, 52 run, 0 NOT-MEASURED, 0 UNRUN'. pnpm exec eslint --no-inline-config packages/cli/test/released-port-production-spawn.pin.test.ts: exit 0. CI on 7c29ce5, complete: 34 success, 10 skipped, 0 failure — including Test Core 1-6/6, Build Core, TypeScript Type Check, Lint & Repo Gates, and Governed Surface Queue Guard. CI on 31f3f64 at report time: 11 success, 10 skipped, 23 in_progress, 0 failure.",
"line_budget": "860 changed lines (+667 / -193) across 11 files, vs merge base 1ef0ee8 (dispatch-gates count). Round 1 adds +70 / -4 in one file. Under the 2,500 stop line and the 3,000 human-merge line.",
"files_changed": [
"packages/cli/test/released-port-production-spawn.pin.test.ts (round 1, the only file)",
"packages/cli/test/helpers/serve-process.ts",
"packages/cli/test/start-mcp-stdio-early-initialize.integration.test.ts",
"packages/cli/test/start-stdio-stdout-purity.integration.test.ts",
"packages/cli/test/serve-mcp-stdio-early-initialize.integration.test.ts",
"packages/cli/test/dev-standalone-self-heal.integration.test.ts",
"packages/cli/test/serve-datasource-mapping-before-sync.integration.test.ts",
"packages/cli/test/serve-no-storage-boot-guard.integration.test.ts",
"packages/cli/test/serve-ready-degraded-boot.e2e.test.ts",
"packages/cli/test/serve-node-env-production-default.e2e.test.ts",
"packages/cli/test/start-port-banner-agreement.e2e.test.ts"
],
"deviations": [
"The census reading is a superset of the review's floor, not the floor itself. The review asked for at least 'run.js' preceded by 'bin' in one call's arguments. The implementation splits each string-literal argument on '/' and asks for the entry's segments in order. It admits the floor's cases plus slash-carrying literals such as join(ROOT, 'pkg/bin', 'run.js'). It over-approximates only toward a loud red: a newly admitted file that draws needs a ledger entry.",
"Docblock item 2 names three unseen spellings, not the two the coordinator listed. The third, a directory held in a variable (join(BIN_DIR, 'run.js')), is still unseen, and a fixture pins that it is not admitted.",
"The first round-1 ablation was a no-op, refused by ablation-replace before it ran anything (the replacement contained the anchor). It was repeated with a changed anchor, and only the second run is cited as evidence.",
"No merge of origin/main this round: no conflict, and no main-caused red. The branch is at origin/main minus at least 4 commits, none touching the derived families."
],
"mcp_calls": "0 — no MCP GitHub tool was called; reads used gh api (REST GET)",
"api_writes": "Round 1: 2 relay writes. (1) fleet-write dispatch POST /repos/objectstack-ai/objectstack/dispatches (run 39136502123, success), executing issue_patch as PATCH /repos//issues/24337 (PR body; 16567 bytes sent and stored, identical). (2) This os-dev-report comment, POST /repos//issues/24295/comments via scripts/pm/post-stamped.mjs. One git push (7c29ce5..31f3f64), which is not a REST write. No other write.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: #24342 (filed by the seat) · the development column of this family, as reported in round 0 · noted here, not re-filed"
]
}
objectstack-fleet commentedon Oct 18, 2026
ACCEPT → PR #24337 comment
6251162203·domain:cliseat 1 · sessionsession_01SYEJqDL3NXxrJRBVqaMu9T· 2026-10-18T14:36Z · on head31f3f6444, after patch round 1, which made the pin admit the segment spellingjoin(…, 'bin', 'run.js'). It lands through the queue once every check on the head is green. The development column is #24342.Generated by Claude Code
objectstack-fleet commentedon Oct 18, 2026
Landed: PR #24337 →
e4bcced0b·domain:cliseat 1 ·zhuangjianguo· sessionsession_01SYEJqDL3NXxrJRBVqaMu9T· 2026-10-18T15:13Zmerged: true, merge commite4bcced0b, merged 2026-10-18T15:12Z through the merge queue (enqueued 2026-10-18T14:55Z)origin/maine4bcced0bis an ancestor oforigin/main, with a single parent (squash). The 11 files and +667 / −193 match what was reviewed at31f3f6444gh-readonly-queue/main/*pr-24337*head remains6249651480→ report6250714154→ REWORK patch round 16250765412on PR test(cli): production-posture spawns take a kernel-assigned port; a pin holds every bin/run.js spawner to it #24337, pointer6250773391→ report6251147005→ ACCEPT6251162203→ pointer6251166673.portDriftError()reds a correct tree.completedon the merge;pm:dispatchedis removed in the stroke after this comment. The lane's open set after the merge is as expected (no card closed by a stray keyword).Generated by Claude Code