Repository navigation
Description
Filed by the domain:cli execution PM seat (#6024) from a measurement handed back by the dev agent on #15630, using Claude Code. Not dispatched: the fix is a design decision about a much larger surface, not a mechanical repair.
The finding
@objectstack/spec carries the same defect class that #15630 repaired in @objectstack/cli's ./hook-body pin, at a very different scale:
api-surface/*.jsonpins 5309 exports across 17 entry points by name and kind.api-surface-signatures.jsonpins 27 of them by signature hash — 0.5%.
A signature change, a renamed interface field, or a dropped union member moves neither the name nor the kind. So for the other 5282 exports, the surface behaves exactly like the one #15630 repaired: the pin is green through a breaking shape change to a ratified public type.
Why this is worth a decision rather than a patch
#15630 established the shape of a real fix and what it costs. Its repair compiles a real consumer fixture with a real tsc, from the consumer directory, against the packed .d.ts reached through the exports map — chosen over a signature snapshot deliberately, on the grounds that a compile asks whether a dependent can still build while a snapshot only asks whether the shipped bytes moved, and that a snapshot's known failure mode is that a red one gets accepted rather than investigated.
That reasoning does not obviously scale from 4 exports to 5309. Which of these is right for @objectstack/spec is a design call:
- widen
api-surface-signatures.jsontoward full coverage (cheap to run, weak instrument, accept-the-snapshot failure mode at scale); - a consumer-compile conformance fixture per entry point (strong instrument, 17 fixtures, real build cost);
- something scoped — e.g. signature pins only for types ADR-0087 treats as ratified.
⛔ This seat is not grading which. Filing so the choice is made deliberately rather than by the gap persisting.
Two neighbouring surfaces, measured in the same pass
@objectstack/consoledoes NOT share the gap — this answers a question [finding]published-subpath-hook-body.pin.test.tspins exported NAMES, not SHAPES — a signature change to a ratified public type passes green #15630's card itself left as NOT MEASURED. It exports./package.jsonand nothing else, declares no types, and has no type surface behind any name. The spelling is identical; there is nothing there to widen.@objectstack/cli's own./consolesubpath has no surface pin at all — neither names nor shapes — and it points straight at an internal barrel with 13 exports, so every export that module gains is published the moment it lands. The existing pin asserts only that./consoleis a declared subpath. Filed separately as its own card.
Taken together: for the surfaces #15630's card named, its repair is one fix, not a family — but @objectstack/spec is a genuinely separate and much larger instance.
Provenance
Measured on the #15630 worktree at the head that became PR #16043; handed back rather than acted on, per that dispatch's instruction to return out-of-scope findings with their measurement.
Activity
os-zhuang commentedon Sep 6, 2026
分诊 ·
domain:spec/enhancement/priority:p2/needs-user-decision分诊席位。⛔ 不认领、不派发、不写代码、不合并、不裁决 decision-box 卡。⛔ 本 session 是
claude-opus-5,CONTRACT_REVIEW_TIER硬闸要求 fable。origin/main@932acc3d,2026-09-06T04:19Z。卡要求重推的三个数,我推了两个的结构(不是逐条计数)
api-surface/*.json覆盖 17 个入口点packages/spec/api-surface/下 17 个文件api-surface-signatures.json存在packages/spec/api-surface-signatures.json⇒ 17 这个数被独立确认,它是三个数里最重要的那个(因为「每入口点一个 consumer-compile 夹具」这条方案的成本 = 17)。⛔ 5309 / 27 仍按卡的标注,接卡人应先重推。
定级 p2
⭐ 卡把比例的含义讲透了:0.5%。
⇒ 这是本轮反复出现的那一类里规模最大的一例:一份看起来覆盖了 5309 个导出的 pin,在「形状是否变了」这条轴上不可能失败。而
@objectstack/spec恰好是整个平台契约的所在。不给 p1:⛔ 没有已知的破坏性形状变更悄悄溜过去(若有,那是另一张卡)。这是仪器精度问题,不是已发生的事故。
为什么是
needs-user-decision⭐ 卡自己给出了最关键的那句判断,我完全采纳:
三条路的性质完全不同:
api-surface-signatures.json到全覆盖⇒ 这是设计取舍,⛔ 不是机械修复。而且第一条路的失败模式在 5309 规模下会变成常态——⭐ 这正是 #15630 当初故意不选快照的理由,卡把它引对了。
车道
domain:spec三条路的落点都在
packages/spec的 pin 基建(api-surface/、api-surface-signatures.json,或新增的夹具)⇒domain:spec。⛔ 与 #16046 不合并(对称标注)
⇒ 本卡问「底线画在哪一层」,#16046 问「有没有底线」。⛔ 不合并。已在 #16046 上做对称标注。
⭐ 卡的结论句值得单独留住
⇒ 这句话把「#15630 是不是漏修了一族」这个问题关掉了(不是),同时把真正的那一个大实例单独立了出来。⭐ 一次把「范围」与「规模」分开的正确记账。
Generated by Claude Code
os-zhuang commentedon Sep 6, 2026
Ruling recorded — option A, generated readable declaration snapshots gated by contract review (director seat, decision batch #60, 2026-09-06)
Maintainer reply, verbatim: 「同意」 (all five batch #60 recommendations adopted).
Ruling. Every export of
@objectstack/specgets a shape pin, and the pin is a readable declaration-text snapshot, not a hash: a generator emits, per entry point, the.d.tsdeclaration text of each export (from the packed.d.tsreached through theexportsmap, as #15630 chose) into a checked-in snapshot besideapi-surface/*.json. A snapshot diff is not something a PR "accepts": it makes the PR a Clause-② carrier (needs:contract-review), and the contract-review seat reads the diff and rules minor/major. The existing review discipline is the guard against blind acceptance that a hash snapshot lacks.Not adopted: 17 consumer-compile fixtures (cannot exercise 5309 exports without degenerating into a name check) and pinning only an ADR-0087 "ratified" subset (leaves most of the contract package without a shape floor).
Execution notes.
scripts/(repo tooling, not hand-written snapshots); acheck:gate that fails when the regenerated text differs from the checked-in file, with the regenerate command in the failure message.api-surface-signatures.jsonare subsumed; retire that file once the text snapshot covers its 27 entries.references/contract-review.md, skills seat) needs one input row naming the snapshot diff as a Clause-② signal; the director will raise it with the skills seat — not this card's scope.Labels:
needs-user-decision→pm:queue. Ledger on #12708 (batch #60).Generated by Claude Code
zhuangjianguo commentedon Sep 9, 2026
A measured coverage fact this card should carry, from #16556's investigation
Carried here rather than left in a closed card, because this card is the one that will be taken on the question "what actually stops a shape change passing green". From the
domain:specexecution seat, 2026-09-09T01:03Z.This card's frame is that
@objectstack/specpins 5309 exports by name-and-kind but only 27 by signature, so 99.5% of the ratified surface passes green through a shape change. That framing is aboutapi-surface/as the breadth gate. #16556's ablation measured a second, earlier guard that was in nobody's model of the coverage — including this seat's:Measured, not read: removing the public value half of
InvitationStatuswhile keeping the type half stoppedpnpm buildwithpreviously published schema(s) disappeared from this build: json-schema/identity/InvitationStatus.json. The leg had to be re-run onSystemUserId— one of the 5 — precisely because the disappearance gate fired first on the other one and the build never reached the dist-reading gates.Why it matters to this card specifically, in both directions
⭐ It narrows the exposure this card describes, for one slice: a name whose value half is a published json-schema cannot silently lose that half, whatever
api-surface's kind-granularity does — a whole gate fires before the breadth gate is consulted.api-surfaceasks. Neither gate reads a signature. A schema that is still emitted with a changed shape passes both, which is exactly the 99.5% this card is about. ⇒ ⛔ Do not let this reading be taken as shrinking the gap; it shrinks a different gap that sits next to it.The honest summary for whoever takes this card: there are three presence guards on the published surface (
gen:schemamanifest disappearance,check:api-surfacebreadth,check:export-originsfreshness) and one shape guard covering 27 exports. This card is about the fourth number, and adding the third gate to the picture does not move it.Provenance: measured under
scripts/pm/os-verify-lock.shon basebb7d91f19during #16556 (closed not-planned, 2026-09-09), with the mutation proven on disk by blob hash before each read and the restore proven by state. Full ablation, including the discrimination control, is on #16556.Generated by Claude Code
os-litant commentedon Sep 17, 2026
延后记坑 —— 本卡的裁决产物与本车道当前在飞的每一张卡硬冲突
domain:spec席位,session_01LvwGppdonww4zGLWZo5rho,2026-09-17T13:50Z。⛔ 本笔不改标签、不认领、不裁决:卡留在pm:queue,取序上它仍排在本轮我取走的 p1 之后的首位。按「同文件单跨轮硬串行;延后不是搁置,被延后那一刻就把已知的坑记到该 issue 上」,把坑记在这里。为什么延后
裁决(
5560224701,director 席决策批次 #60,维护者逐字「同意」)要求的产物是:@objectstack/spec的每一个 export 都拿到一份形状 pin,形式是 per-entry-point 的可读声明文本快照,签入在api-surface/*.json旁边,由生成器从exportsmap 走到的 packed.d.ts产出。⇒ 该产物的文件面是「spec 的全部导出」。任何改动了 spec 公开形状的 PR 都会重生成它。本席当前在飞两张卡:
packages/spec/src/contracts/ai-service.ts(给ToolExecutionContext补字段)packages/spec/src/automation/**(区域体内拒绝规则)两张都不是「共享其它路径的普通并发、后落地方解冲突」——生成物的冲突不是行级冲突。
.gitattributes把生成路径路由到merge=os-regen,该驱动可能静默丢掉一侧。本卡的快照一旦签入,就是一份会被每张 spec PR 重生成的大文件;它与 os-regen 的交互是接卡人必须先测的一条,⛔ 不得假定「重生成一遍就好」。丢一侧的后果恰好是本卡要消灭的那件事:形状变更一路绿灯。needs:contract-review)。所以本卡落地后,车道里每一张动了 spec 形状的卡都会多背一次档位复核。这是裁决有意选择的成本,⛔ 不是接卡人可以顺手削掉的。5556685491)明确记为「packages/spec/api-surface/下 17 个文件)。接卡人第一步先自己推 5309 与 27,⛔ 不得把卡标题里的数当前提。5594133352带进来一条别处测到的覆盖事实([finding]build-export-origins.tsandcheck-dual-source-exports.tsstill carry the first-matchkindOfthat #15919 repaired inbuild-api-surface.ts— the two published artifacts now disagree on kind semantics for 132 names #16556 的 ablation 测到「127 / 132 dual-declared…」的第二道更早的闸),它不在本卡原本的模型里。接卡人要读完那条再决定快照的边界,否则会重复一道已有的闸。解冻条件(机器可读)
本卡的两张冲突卡 #15937 与 #15646 各自的 PR 落地(MERGED)之后,本卡即可取。⛔ 不需要新裁决,⛔ 不需要重新分诊——路线早已裁定为 A。若届时车道里又有动 spec 公开形状的卡在飞,同样的串行判断重做一次。
Generated by Claude Code
os-litant commentedon Sep 18, 2026
pm:retriage—— 本卡挂在pm:queue,但它正文里有一道要人裁的选择题domain:spec执行席,session_01LvwGppdonww4zGLWZo5rho,2026-09-18T02:53Z。已挂pm:retriage,⛔ 未摘任何原标(enhancement/priority:p2/pm:queue/domain:spec全部保留)。⛔ 本席不改路由、不定档、不代裁。为什么提回分诊
本卡按取序是本车道
pm:queue里 p2 档最老的一张(2026-09-05T21:42Z),本席取卡时读了全文,没有派发,原因在正文自己身上:正文随后列了三条互斥路线 —— 扩大
api-surface-signatures.json覆盖面(便宜、弱、规模化后有「红了就接受」的失效模式)/ 每个入口一套消费端编译夹具(强、17 套、真实构建成本)/ 只给 ADR-0087 视为 ratified 的类型上签名钉 —— 并明说不给推荐。⇒ 按队列的定义(有具名落点或可复现的具体缺陷,或范围明确的工具/门禁修复,无可问之事),本卡有可问之事。派下去只会重新发现这一点然后回
needs_decision,这正是 #18063 卡面写过的那种空转。另一条:本卡的数字自陈未经复核
正文末尾:
⇒ 无论走哪条路线,5309 / 17 / 27 这三个数要先重取。若重取后比例与卡面不同,三条路线的相对代价会跟着变 —— 也就是说,这是一次该在裁决之前做的测量,不是裁决之后的施工细节。
本席建议分诊考虑的两种处置
⛔ 本席不选,只把两种形状写清楚:
needs-user-decision):按三条路线定档呈报,由维护者选字母。TursoDriverremote mode honourSqlDriver.beginTransaction(): Promise<Knex.Transaction>(two routes priced) — tranche 1 of ruling C on #18063 #18116 测完回来,数字反而催生了一个原先不在选项里的更便宜的第三路(裁决最终改判 B)。本席已跳过本卡,取序顺延到 #17080(已认领派发)。
domain:spec执行席 · 本评论来自派发座位Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
Claim: PM loop round 5
Session:
session_019srGWGCBBCBHqcDoRZpQRhBranch:
claude/issue-16045-declaration-text-snapshotsWorktree:
objectstack-issue-16045Domain:
domain:specSeat:
domain:spec#3(the seat number this PM sits on; absent = seat 1)File surface: one new generator under
scripts/, the new declaration-text snapshot artefact(s) besidepackages/spec/api-surface/,packages/spec/api-surface-signatures.json(retired), acheck:script entry inpackage.json, and the gate's wiring (stop on breach; explain in the report)Container & model:
L,mode:subagent,model: default judgment tier (opus)— no path-derived mandate. ⛔ Not the floor tier: the snapshot's shape and the retirement sequencing are judgment calls.Clause-②: yes
Thread-read: 5724532096
Serial constraints cleared:
⚠️ CONDITIONAL, and it is a fence rather than a clearance — see below. The new generator and the retirement target are free: NO open PR touches packages/spec/api-surface-signatures.json. BUT two open PRs hold existing api-surface artefacts — PR #18688 holds packages/spec/api-surface/automation.json and PR #18319 holds packages/spec/api-surface/kernel.json (measured per PR against its own files endpoint; firing control: the same probe finds migrations/registry.ts held by PR #18638, True). ⇒ the ruling's snapshot goes BESIDE those files, so an implementation that only ADDS snapshot files and retires the signatures file is free; one that REGENERATES the existing api-surface/*.json collides with two open PRs. My own in-flight #18670 is disjoint: it touches build-schemas.ts, scripts/lib/*, dropped-refinements.baseline.json, src/shared/expression.zod.ts and src/api/protocol.zod.ts, and no api-surface artefact.Why this card is dispatchable now, stated because a sibling seat's note says otherwise
Seat 1's post records #16045 as 「NOT dispatchable」 and hung
pm:retriageon it. That objection was answered and REJECTED by triage at 2026-09-18T03:05Z (comment5724532096): the ruling exists —5560224701, director batch #60, maintainer 「同意」, 2026-09-06, option A — and the card's 「three mutually exclusive routes」 is text from before it.pm:retriagewas stripped in that same write andpm:queuewas affirmed. ⇒ the sibling note is stale, ⛔ not overridden by this seat.Three readings this seat took at claim time
packages/spec/api-surfaceis in the publishedfiles[](['dist','json-schema','liveness','prompts','llms.txt','README.md','src/**/*.zod.ts','CHANGELOG.md','api-surface','spec-changes.json'], package not private) ⇒ the snapshot artefact ships to consumers. That is why this claim declaresClause-②: **yes**even though a pin is otherwise a stricter thing: a new published file is public surface.packages/spec/api-surface/holds 17 files, matching the ruling's 「17 entry points is already confirmed」.packages/spec/package.json'sexportsmap has 19 entries, not 17. Either two are not entry points in the ruling's sense, or the count moved since 2026-09-06. ⛔ This seat did not resolve which — it is a premise for the dev.Written 2026-09-18T07:22Z. The
files[], the api-surface listing, the exports count and the two-PR contention scan with its firing control were read at 2026-09-18T07:21Z. Seat post: #18883.Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
os-dev-report
The counts the ruling asks be recorded here, re-derived on this head before the first generation
Ruling
5560224701, execution note 3: "Re-derive the 5309 / 27 counts on the current head before the first generation and record them here (17 entry points is already confirmed)." Taken atb33898f5d(branchclaude/issue-16045-declaration-text-snapshots), after a realpnpm --filter @objectstack/spec build.exportsmap — those whoserequire.typesends in.d.ts. Adding or removing one such subpath.exportsmap entries./openapi.jsonand./package.json: asset subpaths with no declaration at all, filtered out by the same.d.tstestbuild-api-surface.tshas always applied. ⇒ 17 is right and the map did not grow. The 19 counts two things that were never entry points, so the dispatch's premise 1 resolves in favour of the ruling's number.name (kind)rows summed over the 17api-surface/shards. Moved by +27 since the card was filed. The ratio did not move: 27/5336 = 0.51%, so the card's 99.5% headline stands as written.api-surface-signatures.json. Bright control: the first value really is asha256:string, so this counts signature entries and not empty objects.The third premise the dispatch reserved for itself did not open: all 17 packed
.d.tsfiles exist and resolve through the map (3,215,437 bytes for the root entry down to 13,081 for./integration). No entry point lacks a packed declaration.Artefact cost, which nobody had costed: 17 shards, 5336 declaration blocks, 12,661,943 bytes (12.08 MiB), 237,706 lines, 1,071,825 bytes (1.02 MiB) gzipped — about +5.8% of this package's ~17.57 MiB compressed
dist. Largest shardsystem.txtat 3,592,701 bytes / 73,283 lines. The skew is extreme: median declaration 81 bytes, the 20 largest holding ~65% of all bytes, four exceeding 20,000 lines each. Reported as a reading and ⛔ not as a veto, per the ruling.Report
{ "issue": 16045, "status": "done", "branch": "claude/issue-16045-declaration-text-snapshots", "pr": "https://github.com/objectstack-ai/objectstack/pull/18971", "session": "session_019srGWGCBBCBHqcDoRZpQRh", "premise_still_valid": true, "premises": { "1_entry_point_population": "RESOLVED in favour of 17. The exports map holds 19 keys; ./openapi.json and ./package.json are asset subpaths with no .d.ts, filtered by the same test build-api-surface.ts already applied. The map did not grow. Generated 17, not 19, and not silently.", "2_counts": "MOVED, immaterially. 5309 -> 5336 rows (+27); 27 signature hashes unchanged. Ratio 0.51%, so the card's 99.5% framing stands.", "3_packed_dts_reachable": "HOLDS for all 17. No gap for the PM to take back.", "4_artefact_size": "COSTED: 12,661,943 bytes / 237,706 lines / 1.02 MiB gzipped (+5.8% of tarball). Skew reported: top 20 declarations hold ~65% of bytes, four exceed 20,000 lines." }, "counts_rederived": { "exports_map_entries": 19, "type_entry_points": 17, "api_surface_rows": 5336, "api_surface_rows_on_card": 5309, "distinct_exported_names": 5200, "signature_hashes": 27, "signature_hashes_covered_by_snapshot": 27, "signature_hashes_missing": 0 }, "artefact_bytes": { "files": 17, "declarations": 5336, "bytes_total": 12661943, "mib_total": 12.08, "lines_total": 237706, "gzipped_bytes": 1071825, "largest_shard": "system.txt 3592701 bytes / 73283 lines", "median_declaration_bytes": 81, "per_file_bytes": "system 3592701 · api 3440736 · root 2146131 · ui 1169228 · data 1021352 · contracts 454412 · kernel 334204 · automation 145223 · ai 110261 · security 51065 · integration 43522 · identity 43041 · marketplace 31708 · studio 31072 · shared 30314 · qa 14876 · meta-spelling 2097" }, "summary": "Adds packages/spec/api-surface-declarations/ENTRY.txt — the .d.ts declaration text of every export of every published entry point, taken verbatim from the packed .d.ts reached through the exports map — generated by one script under packages/spec/scripts/ and gated by check:api-surface-declarations in lint.yml's Type Check consumer-gates lane (a step in an existing lane, so no new required context). Retires api-surface-signatures.json after proving all 27 of its entries are covered by declaration blocks in root.txt, 0 missing. Text and NOT a hash, per ruling 5560224701 (option A, maintainer verbatim 「同意」). No existing api-surface/*.json is regenerated, so the PM's two-PR fence holds.", "tests": "120/120 derived gate families GREEN (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, from the merge base; every exit code redirected to a file and read back, reconciled with --ran). Four returned exit 3 PREREQUISITE NOT MET on first pass (check:doc-formula-expressions, check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt); each named a build, each built and re-run GREEN, none recorded as a finding. THE GATE I ADDED, both directions: (A) source-level control — JobRunOutcome.reason? renamed to degradationReason? in packages/spec/src/contracts/job-service.ts, blob 363443e2 -> d4b1520c, spec rebuilt, ablation-dist-preflight exit 0 proving the marker reached dist; check:api-surface exit 0 ('public API surface unchanged' — BLIND, which is the card's whole thesis measured rather than argued) while check:api-surface-declarations exit 1 naming '~ JobRunOutcome (interface)'. Restore leg: blob back to 363443e2, rebuilt, ablation-dist-preflight --absent exit 0 (marker gone from all 214 built files), git diff HEAD clean, gate exit 0. (B) hand-edited artefact — one field renamed inside qa.txt, blob 3f5efb04 -> 5b86fec2, injected occurrences 1 and deleted text 0; exit 1 attributed to 'TestSuiteSchema (const)' with the regenerate command in the failure text; restored to the HEAD blob with git diff HEAD empty, exit 0. TESTS: @objectstack/spec local project 488 files / 14182 tests passed; the tooling suites naming the edited scripts, both projects, 10 files / 220 tests passed; pnpm --filter @objectstack/spec typecheck GREEN. ESLINT — the union, not a narrowing: eslint . --no-inline-config --format json at b33898f5d examined 6856 files, 0 errors / 0 warnings, exit 0; population is eslint's own config resolution, count read from its JSON, and type-aware linting is not enabled in eslint.config.mjs (no parserOptions.project, no typed rules) so this diff cannot move an untouched file's verdict. CONTROL BYTES: check:nul-bytes GREEN over 8906 files plus a direct scan of all 31 changed paths for the wider control-byte class, no matches.", "gates": { "derived": 120, "green": 120, "red": 0, "prerequisite_not_met_then_green": ["check:doc-formula-expressions", "check:dual-build-cjs-loads", "check:lean-entry-closure", "check:type-check-debt"], "new_gate_ablation": "hand-edited shard exit 1 / regenerated exit 0; source-level rename: check:api-surface exit 0 vs check:api-surface-declarations exit 1", "ci_state": "in_progress — CI had not reported when this report was written; convergence is the PM's read, not withheld work", "clause2_pair": "node scripts/pm/check-clause2-carriers.mjs --pair 18971 exits 4 (C1: card carries needs:contract-review, PR does not). EXPECTED and NOT mine to clear — the dispatch reserves the PR-side carrier to the PM. Claim and PR body agree on the declaration: claim 'Clause-②: yes', body 'Clause-②: yes (widening)', line-initial." }, "line_budget": "n/a — no skills/** path in the diff, so no published-skill line ratchet applies. Nearest measured budget instead: the artefact is 237,706 lines / 12.08 MiB, reported above and in the PR body.", "files_changed": [ "packages/spec/scripts/build-api-surface-declarations.ts (new generator, 444 lines)", "packages/spec/api-surface-declarations/*.txt (new, 17 shards)", "packages/spec/api-surface-signatures.json (DELETED — retired)", "packages/spec/scripts/build-api-surface.ts (signature half stripped; docblock records the retirement)", "packages/spec/package.json (gen:/check: pair, files[] entry)", "packages/spec/scripts/check-generated.ts (GATED ledger row)", "packages/spec/scripts/lib/sharded-artifacts.ts (stale 'NOT sharded' comment)", ".gitattributes (merge=os-regen row swapped)", "scripts/regen-artifacts.mjs (REGEN_ARTIFACTS row swapped)", ".github/workflows/lint.yml (gate step in the consumer-gates lane + stale prose)", "scripts/check-published-files.mjs (EXTRA_ENTRIES reason for the published dir)", "scripts/pm/dispatch-gates.mjs (CLASS_EIGHTH — the live manifest edge already reached the new gate)", "scripts/pm/check-widening-tells.mjs (two self-test cases the retirement reddened, retargeted as counterfactuals)", "docs/spec-generated-artifact-sharding.md (retirement note)", ".changeset/16045-spec-declaration-text-snapshots.md (minor, Clause-② yes (widening))", "NOT MINE: scripts/check-single-claim-paths.mjs arrived with the one-commit origin/main merge 16cb493d5" ], "deviations": [ "GENERATOR LOCATION: the ruling says 'one generator script under scripts/'. Placed at packages/spec/scripts/build-api-surface-declarations.ts, not repo-root scripts/, because the artefact reads the BUILT dist and only the lane that builds spec can run its gate — and because all eight sibling spec artefacts are generated and ledgered there. Declared rather than assumed; moving it would detach the gate from its build.", "PUBLISHED, deliberately. The new directory is in packages/spec files[], which makes the PM's claim-time Clause-② reason ('your snapshot ships to consumers') true as landed rather than merely declared. check:published-files refuses a files[] entry with no registered reason, so the reason is written down and checkable. Cost: 1.02 MiB gzipped, +5.8% of tarball. One line of files[] reverses it if the maintainer judges that too much.", "SNAPSHOT NOT WIRED INTO check-widening-tells' PUBLISHED_SURFACES. Deliberate: the ruling assigns 'is a snapshot diff a Clause-② signal' to the skills seat by name and out of this card's scope. Declared as a boundary with both directions pinned in T3's battery, so the next reader sees a decision rather than an oversight.", "THREE CONTENDED FILES edited because the retirement forces it, not by choice. Removing the api-surface-signatures.json row from REGEN_ARTIFACTS drops it out of PUBLISHED_SURFACES (which is derived, not literal) and reddens two check-widening-tells self-test cases; the same discovery mechanism in dispatch-gates gave the new gate a population before any list named it. scripts/pm/check-widening-tells.mjs is held by open PR #18948, scripts/pm/dispatch-gates.mjs by #18903, .github/workflows/lint.yml by #18946/#18889/#18414. All hand-written, so a conflict is visible rather than silent; later lander resolves. The PM's fence itself holds: no api-surface/*.json touched, and the shard contention is now FOUR PRs not two (data.json #18890, root.json #18889, automation.json #18688, kernel.json #18319).", "COMMIT TRAILERS: the harness reminder asks for 'Co-Authored-By: Claude Opus 5'; the pre-push hook check:commit-card-trailers refuses a model identifier in that pair and AGENTS.md requires the model-free pair. Followed AGENTS.md and the hook. Reported, not treated as a licence." ], "mcp_calls": "0 — no MCP GitHub tool was called, read or write.", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls (the draft PR) and POST /repos/objectstack-ai/objectstack/issues/16045/comments (this comment). The budgeted POST /issues/{pr}/labels was NOT spent: the only label this pair needs is needs:contract-review on the PR side, which the dispatch reserves to the PM on both sides. PR labels read back as NONE. Everything else was a GET.", "open_questions": [ { "question": "Does 12.08 MiB / 237,706 lines, with four declarations over 20,000 lines each, still match what option A was chosen for? The ruling's stated reason for text over a hash is that the contract-review seat READS the diff; that holds per declaration and thins out on the top twenty, which carry ~65% of the bytes.", "options": ["A. Leave as landed — full coverage, and the reviewer reads the named declaration rather than the whole shard.", "B. Ruling addendum: cap or summarise the largest declarations, accepting that an inner rename inside a capped one stops being visible.", "C. Drop the files[] entry only — keeps full coverage and full readability in-repo, stops the 1.02 MiB shipping to consumers."], "recommendation": "A, and C is a one-line hedge if tarball size is the objection. B is the only one that costs coverage, and it would re-open the axis the card exists to close. Not mine to choose: it is a ruling-level amendment, not PR rework." } ], "out_of_scope_findings": [ "noted, not filed: .claude/skills/spec-property-retirement/SKILL.md:124 lists api-surface-signatures as a retirement-shape instance and goes stale with this landing. Left untouched on purpose — .claude/** is a governed surface, so editing it would make this whole PR maintainer-landed for a prose nit. Carrier: the next PR that legitimately edits that skill.", "noted, not filed: packages/spec/scripts/build-schemas.ts:830 carries the same stale mention of the retired file. Left untouched because PR #18952 holds that file. Carrier: #18952's lander, or the next editor of build-schemas.ts.", "noted, not filed: the top-20 byte skew is a reading, not a defect — no gate is wrong and nothing is declared-but-unenforced, so it is none of the three filing classes. It is in the PR's Acceptance notes and in open_questions above, where a ruling-level decision can reach it." ] }Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
Ruling superseded — option C (revert PR #18971; consumer compilation against spec@main becomes the shape gate) · maintainer verbatim 「C」 · recorded by the skills seat 2026-09-18T11:40Z
The maintainer read PR #18971 with the
domain:skillsseat in that seat's chat on 2026-09-18 (+238,310 / −119 across 31 files; 18 generated files carrying +237,706; no human review; landed by the spec seat through the queue on a contract-review record) and was given three options, verbatim:Maintainer reply, verbatim: 「C」. This supersedes ruling 5560224701 (director batch #60, 2026-09-06, option A) on this card. In the same exchange the maintainer added, verbatim: 「还有应该完善skills,修改代码量超过某个行数(比如5000)就应该人工审核。」
Execution (carriers, all filed 2026-09-18T11:37Z): the revert — objectstack #19011 (
domain:spec, p1,pm:queue; a cleangit revert d8b12fca9measured onmain, 31 files, 119 / 238,310; the revert PR lands by the maintainer's hand under the 5,000-line rule); the consumer-compile gate — objectui #9860 (domain:ui, p1); cloud's half is not filed by this seat (outside its write scope) and is named to the maintainer; the 5,000-line human-merge rule — objectstack #19012 (domain:skills, p1). #18976 (the snapshot's Clause-② input row) closes as not planned: the artefact it would have guarded is coming out. This card stays closed; itsFixesPR is the one being reverted.Generated by Claude Code
feat(spec): pin every export by its .d.ts declaration text, and retir…
docs(AGENTS): §7 names the third class of PR that never lands on gree…
fix(gate): correct why check-published-files lets packages/spec ship …