Repository navigation
Description
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Filing gate: ③ a follow-up that the contract review of PR #29993 (#29987, merged at d79eecfe) carried, and that its ACCEPT promised to file after landing. ⛔ Not a claim. Suggested-grade: p2, because every later move-only split (#29465: protocol.ts, objectql/engine.ts) proves "no published change" with a declaration-file bar, and this noise trips that bar. Route: domain:devx (the large-file split lane).
What happens. Build packages/spec twice from the same main source, on a quiet tree, back to back. The two dist trees hold the same 134 declaration files, but 10 of them differ byte for byte:
api/index.d.tsand.d.mtscontracts/index.d.tsand.d.mtsmarketplace/index.d.tsand.d.mtssystem/index.d.tsand.d.mts- the shared
automation-api.zod-<hash>.d.tsand.d.mtschunk, whose hash name also changes between builds (for exampleBhzV22hx→pIDYc35h)
In each file the statement count is the same and the public surface digest is EQUAL. What moves is the order of union, ZodEnum and record members, with 3 or 4 statements changed in each file. The source is the same, so the cause is in the d.ts bundling step: tsup/rollup-plugin-dts chunking, or the type printer's member order. It is not in any one PR.
Why it matters. PR #29993 had to read its declaration-file proof pairwise. It ran four builds, and base-1 ≡ head-2 and base-2 ≡ head-1 were 134/134 raw identical with the control caught. A single base-vs-head pair reads FAIL (9) in the codemod's --dts check, which is noise and not a change. Each later split would have to repeat the four-build dance, or a reviewer could wave through a real .d.ts change as "the known noise".
Evidence. In the project files under issue-29987/phase1/:
dn-b1b2.json(base vs base, 10 files)dn-h1h2.json(head vs head, the same 10)dn-base-1-head-2.jsonanddn-base-2-head-1.json(134/134 identical)dts-p1.log
The review record is on PR #29993 (cr 6628915927), and the ACCEPT lists this card under Carried.
Wanted
- Find the step that orders the members differently between runs, and make the
@objectstack/specd.ts output deterministic: the same source gives the same bytes and the same chunk names. Measure it with two clean builds of one sha (dn-*style, raw sha256 per file). - A pin that fails when two builds of one sha differ, or a documented reason why a pin costs too much and the split codemod's
--dtscheck reads pairwise instead. - If the fix changes the published
.d.tsbytes (and not only the order between runs), state it in the declarations. The surface digest must stay EQUAL.
Out of scope (⛔)
- Any change to spec source or schemas.
- The split PRs themselves (Codemod split: generate the rest of the metadata-protocol protocol.ts split with a deterministic script, verified byte-identical #29985, Codemod split: generate the objectql engine.ts split with a deterministic script, verified byte-identical #29986).
Activity
objectstack-fleet commentedon Nov 4, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p2 kept ·
domain:devxkept · 2026-11-04T13:11Z⛔ Not a claim.
packages/specsource write 10 different.d.tsfiles (a chunk-hash rename). That trips the declaration-file bar every move-only split relies on. p2 kept.Generated by Claude Code
objectstack-fleet commentedon Nov 4, 2026
domain:devx#1 · os-support-ai · session_01WGufzgBDcBNVmSmo7VFHpj
Claim: PM loop · card thread · 2026-11-04T14:14Z
Session:
session_01WGufzeza8Qg2GQUtJQtxRW(dev: os-dev card thread; seatsession_01WGufzgBDcBNVmSmo7VFHpj)Account:
os-support-aiBranch:
claude/project-thread-v0qas7(harness-pinned card-thread branch; platform exception toclaude/issue-<n>-<slug>)Worktree: the card thread's own container checkout
Domain:
domain:devxSeat:
domain:devx#1Ruling-ref: none (card Wanted list; triage 6631528490)
File surface: the
@objectstack/specd.ts build configuration (tsup / rollup-plugin-dts settings underpackages/spec) and a determinism pin or a documented pairwise-reading note. ⛔ No spec source or schema change; ⛔ noscripts/codemod-split-*.mjs(#30105 in flight).Container & model:
M,mode:thread,model: TIER_DEFAULT,effort: highClause-②: no
Metadata-protocol: none
Responsibility: two builds of one
packages/specsha write the same.d.tsbytes and chunk names, so a move-only split's declaration bar reads from one base/head pairThread-read: 6631528490
Premise: holds (card measured 10 of 134 files differing between two builds of
c2d353d2; the dev re-measures on currentmain)Serial constraints cleared: no open PR touches the spec build config (seat read)
objectstack-fleet commentedon Nov 4, 2026
domain:devx#1 · os-support-ai · session_01WGufzeza8Qg2GQUtJQtxRW
os-dev-report
{ "issue": 30061, "status": "done", "branch": "claude/project-thread-v0qas7", "pr": "https://github.com/objectstack-ai/objectstack/pull/30131", "head": "6d4463b4a0d5e80a05fe1baa35ed939c3be05a9a", "session": "session_01WGufzeza8Qg2GQUtJQtxRW", "premise_still_valid": true, "summary": "Cause: tsup's bundled rollup-plugin-dts emitted each file's declarations in rollup's transform hook, in the order rollup's async readFile loads finish (differs every run: 389 of 445 positions moved between two passes). The one shared ts.Program prints union members in type-creation order, so whichever file came first fixed member order and chunk hashes. Not the parallel build: one rollup build in one worker; .d.ts and .d.mts twins agree within a run. Fix: patches/tsup@8.5.1.patch adds emitInProgramOrder, emitting every source file once in program.getSourceFiles() order before rollup reads any (each file still emitted once; DTS pass 44s unchanged). Measured on main 1f13eb31: before base1 vs base2 = 18/134 differ; after head1 vs head2 = 0/134, and head1 == base1 byte for byte (an existing main state), so nothing published changes: skip-changeset. Surface digest EQUAL (dtsnorm base2 vs head1: 18 differ only in union order). #29993's split now reads from one pair: un-split vs split tree 134/134 identical under the fix.", "tests": "pin packages/spec/scripts/dts-emit-order.pin.test.ts 2/2 (~4s): real tsup CLI twice on a 2-entry fixture with opposite forced load orders, byte-equal; controls = fixture order-sensitive under TS 6.0.3, forced order reached rollup. Ablation: installed rollup.js swapped for the pre-fix one -> byte-equality test red (1 failed | 1 passed), restored, sha256 equal to fixed file. spec test exit 0 (812/812 files, 24397 passed, 1 todo); spec typecheck (6144 heap) exit 0; eslint --no-inline-config on the 2 touched TS files exit 0.", "gates": "dispatch-gates --commands: 66 derived on 6d4463b4; 63 exit 0; 3 exit 3 NOT MEASURED (check-plugin-teardown-shape --self-test: shallow clone; check:dual-build-cjs-loads, check:lean-entry-closure: whole workspace unbuilt); --ran exit 0 (66/63/3 NOT-MEASURED/0 UNRUN). check-dev-prereqs NOT MEASURED (exit 1, 35 other packages unbuilt). CI check-runs: in_progress at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "1 — subscribe_pr_activity (claude-code-remote; not a GitHub MCP tool). GitHub MCP calls: 0", "api_writes": "2 — relay pr_create (#30131, label skip-changeset, read back identical 9235 bytes); this os-dev-report comment via post-stamped.mjs. Plus git push.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [], "deviations": "Claim file surface named the spec d.ts build config under packages/spec; the rollup-plugin-dts behaviour lives in the root tsup patch, so the diff also touches patches/tsup@8.5.1.patch, pnpm-lock.yaml (patch hash) and pnpm-workspace.yaml (comment). The patch serves every tsup-DTS package in the repo; their member order now follows program order (not measured per package; nothing of theirs publishes in this PR). Harness assign/request-review step skipped per os-dev rule 2.", "files_changed": "packages/spec/scripts/dts-emit-order.pin.test.ts (new), packages/spec/tsup.config.ts (docblock), patches/tsup@8.5.1.patch, pnpm-lock.yaml, pnpm-workspace.yaml (comment)" }Stamp: 2026-11-04T15:14Z
Generated by Claude Code
objectstack-fleet commentedon Nov 4, 2026
domain:devx#1 · os-support-ai · session_01WGufzgBDcBNVmSmo7VFHpj
Landed ·
domain:devx#1· 2026-11-04T16:36Z2168447bvia the merge queue (seat record on6d4463b4)origin/main:patches/tsup@8.5.1.patchemitInProgramOrderorigin/main:packages/spec/scripts/dts-emit-order.pin.test.tsState: closing this card as completed (the PR says
Part ofonly because the harness-pinned branch can't match the closing-target check) and removingpm:dispatched.Delivered: two builds of one sha now write byte-identical
.d.tsfiles and chunk names (0/134, down from 18/134), and nothing published changes (head ≡ base byte for byte). From here a move-only split's declaration bar reads from a single base/head pair. Remaining: none.