Repository navigation
[finding] the liveness governance denominator is built from listMetadataTypeSchemaTypes(), so report.ungoverned structurally cannot name connector, sharing_rule or analytics_cube — the same sentence #17356 falsified, one gate over #18133
Description
Activity
Claim: PM loop round 3
Session:session_01JbZnqu8bt6YqfJsr9vaFb3
Branch:claude/issue-18133-liveness-governance-denominator
Worktree:objectstack-issue-18133
Domain:domain:spec
Seat:domain:spec#2(seat post #18549; seat 1 is #6017 and this claim does not touch it)
File surface:packages/spec/scripts/liveness/check-liveness.mtsand its testpackages/spec/scripts/liveness/check-liveness.test.ts; anyliveness/*.jsonthe denominator change makes owed. Read-only unless the repair provably belongs there:packages/spec/src/kernel/metadata-type-schemas.ts(wherelistMetadataTypeSchemaTypes()is defined) —⚠️ that function has a SECOND consumer (#17356's reachability gate, landed as PR #18131), so changing it moves both; if the honest repair is there, say so before doing it (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: default judgement tier— quoting this round's ownnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --tier packages/spec/scripts/liveness/check-liveness.mts: "Model tier — no path-derived mandate: the surface hits none of the 3 declared glob(s)".⚠️ This surface returns NO "Clause ② SUSPECT" line
Clause-②: no
Thread-read: 5705222969
Serial constraints cleared:packages/spec/scripts/liveness/**is held by no in-flight card.⚠️ packages/spec/scripts/build-schemas.tsis held by seat 1 (#18301, PR #18529 awaiting landing) and is NOT on this surface. This seat's own open PR #18561 holdspackages/spec/src/ui/view.zod.ts— also not on this surface.packages/spec/src/kernel/metadata-type-schemas.tsis held by nobody but is shared with a landed consumer, declared read-only-by-default above.
本轮取卡说明 —— 为什么是这张,以及两张被热文件挡住的卡
⭐ Recorded because the blockage is structural, ⛔ not a preference:
- [finding] a nested RETIRED_KEYS_BY_MAJOR row is unverifiable — check (b2) passes a fabricated one, so a typo'd nested retirement registers silently and forever #17969(nested
RETIRED_KEYS_BY_MAJORrow unverifiable)—— 其主题RETIRED_KEYS_BY_MAJOR位于packages/spec/scripts/build-schemas.ts,该文件由**席 1 的 check (c) has no proof shape for a guidance-route retirement on a reachable def — add a fourth proof soUNKNOWN_KEY_GUIDANCEretirements prove themselves (batch #135 item 3, C) #18301(PR feat(spec): check (c) proves a guidance-route retirement on a reachable def (#18301) #18529)**持有且尚未落地。⇒ 硬串行,⛔ 本轮不派。 - spec: every repeater item schema except dashboard header.actions still has no JSON Schema title, so 21 property-panel tables render machine keys in every locale #17232(21 张 property-panel 表渲染机器键)—— 其文件面覆盖 11 个
*.form.ts与对应*.zod.ts,其中含packages/spec/src/ui/view.zod.ts,由本席自己的 PR spec(ui): declaretitleFieldonKanbanConfigSchema— the optional key its five item-titled siblings already carry #18561持有(draft,停在达档复核上)。⇒ 同样硬串行。
⚠️ 后一条是本席须点名的升级信号:达档阻塞已经从「条款②卡积压」外溢成「阻塞其它卡」 —— #18561 落不了地,#17232 就取不了卡。已在轮次报告中呈报维护者。前提重测(本席,2026-09-17T02:54Z,against
origin/main)packages/spec/scripts/liveness/check-liveness.mts在树上,同目录另有check-empty-state.mts/drill.mts/elsewhere.mts及各自测试。listMetadataTypeSchemaTypes()定义在packages/spec/src/kernel/metadata-type-schemas.ts(单一定义点)。
⚠️ 卡面点名的UNREGISTERED_KIND_SCHEMAS省略行为、webhook的EXTRA_SCHEMAS手工补丁,以及connector/sharing_rule/analytics_cube三者既不在GOVERNED也不在PENDING_GOVERNANCE—— 这三条本席未逐条复测,交 dev 首手核验。⛔ 不作已验事实引用。条款② 判据
本卡收紧治理分母(让 ratchet 覆盖到三个今天看不见的可授权类型),⛔ 不放宽接受集、⛔ 不扩大公开面 ⇒
no。⚠️ 若交付的 diff 最终动了listMetadataTypeSchemaTypes()本身并因此改变任何消费者的接受面,重新申报,⛔ 不为本no辩护。
Generated by Claude Code
- [finding] a nested RETIRED_KEYS_BY_MAJOR row is unverifiable — check (b2) passes a fabricated one, so a typo'd nested retirement registers silently and forever #17969(nested
os-dev-report
{
"issue": 18133,
"status": "done",
"branch": "claude/issue-18133-liveness-governance-denominator",
"pr": "#18581",
"session": "session_01JbZnqu8bt6YqfJsr9vaFb3",
"premise_still_valid": true,
"summary": "All four unverified ZONE 2 claims measured first-hand at base 879b512 and CONFIRMED, with one card correction: webhook is patched in via SPEC_ONLY_SCHEMAS, not EXTRA_SCHEMAS — that identifier exists nowhere in the repo. listMetadataTypeSchemaTypes() returns 26 names and omits all four UNREGISTERED_KIND_SCHEMAS entries (firing control: view and flow present in the registered set, view absent from the unregistered one); connector, sharing_rule and analytics_cube sit in neither GOVERNED nor PENDING_GOVERNANCE and have no ledger file. THE FORK IS NOT A FORK, shown on the merits with the target file quoted: listUnregisteredKindSchemaTypes() already exists in metadata-type-schemas.ts (#6931) declaring it exists so a check can ENUMERATE that map and that being listed by it grants NOTHING, and the identical union already landed one gate over as reachabilityRootTypes() in build-schemas.ts (#17356 / PR #18131), computed INSIDE the consuming gate under a docblock saying listMetadataTypeSchemaTypes() answers its own question correctly and this file does not touch it. So metadata-type-schemas.ts is not in the diff and #6245 survives byte-for-byte. The repair adds authorableTypes() = registered kinds UNION unregistered-kind stack collections inside check-liveness.mts, uses it for both ungoverned and stalePending, records the three newly visible types as PENDING_GOVERNANCE debts with a reason and an issue number apiece (the disposition the gate own failure text prescribes), and prints the denominator plus its composition on EVERY run — it previously printed only when PENDING_GOVERNANCE was non-empty, so the one state worth reporting rendered as the same silence an unseen type produces. check:liveness exits 0 and no existing check turns red.",
"tests": "Final commit 7c98551; all readings from that tree. (1) pnpm --filter @objectstack/spec test — 482 files passed / 1 skipped, 13776 tests passed / 1 skipped. (2) pnpm --filter @objectstack/spec exec vitest run scripts/liveness/check-liveness.test.ts — 58 passed (was 53). (3) pnpm --filter @objectstack/spec typecheck — exit 0; both edited files proven inside a tsc program by tsc -p tsconfig.scripts.json --listFiles naming scripts/liveness/check-liveness.mts and scripts/liveness/check-liveness.test.ts. (4) check:liveness exit 0, check:empty-state exit 0. (5) ESLINT NARROWED AND THE NARROWING PROVEN: eslint --no-inline-config --format json over the two changed TS files reports 2 files linted, 0 errors, 0 warnings, the count read from the JSON rather than from prose; population read from eslint.config.mjs itself, whose global block is files: [/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}] minus NEVER_LINTED, so the two .md paths in this diff are outside the eslint population entirely; invariance declared by that config in its own words — this repo runs one eslint.config.mjs which never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file — so this diff cannot move the verdict on any untouched file. The repo-wide sweep is left to CI. (6) Control-character scan beyond check:nul-bytes: grep -naP over all four changed files, no matches. ABLATION — two legs, both fired, both restored, run against the COMMITTED implementation, each mutation proved on disk by anchor count BEFORE the gate ran, restore by git checkout HEAD -- PATH under trap EXIT INT TERM and verified by blob hash rather than by an exit code. LEG A (the widened denominator really reaches an unregistered kind): removed the connector row from PENDING_GOVERNANCE, anchor count 1 to 0, gate exit 1 printing: 1 AUTHORABLE metadata type(s) governed by nothing / connector. The old denominator could never have produced that row for connector; it would have called it stale instead. LEG C (the union line is load-bearing, not decorative): reverted authorableTypes() to the registered set alone while keeping the three rows, anchor count 1 to 0 and injected marker count 1, gate exit 1 printing: 3 stale PENDING_GOVERNANCE row(s) — analytics_cube, connector, sharing_rule. That output is exactly the old code entire vocabulary for these three: not a type I know, never a type nobody governs. Restore proof for both legs: on-disk blob b3c8aded6e38ce73bd8097dba62554da19ec97ff equals HEAD:packages/spec/scripts/liveness/check-liveness.mts, and git diff HEAD --stat for that path is empty. No permanent test file was left behind by either leg. NOTE: pnpm --filter @objectstack/spec test was invoked with a trailing bare -- --maxWorkers=2, which vitest silently discards, so the suite ran at default concurrency; the reading is the suite result, not the flag.",
"gates": "Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands off the merge base itself (never a hand-fed path list), re-derived after the changeset existed, reconciled with --ran carrying one exit code per line. RESULT: 68 derived, 63 run green, 5 NOT MEASURED, 0 UNRUN. Every exit code was landed to disk before being read; no pipe anywhere. The 5 NOT MEASURED all exit 3 = PREREQUISITE NOT MET, each refusing because no package has a dist: check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content, check:type-check-debt. They need a repo-wide build; this diff contains no built-output source and CI covers them — neither pass nor finding. check:cross-package-test-inputs exits 0 here, consistent with the known behaviour already carried by #18353 / #18440 and NOT re-filed. PR #18581 carries NO labels at all, so needs:contract-review is absent — reported, not attached, not awaited.",
"line_budget": "n/a — this diff touches no skills/ path, so no published-skill line or token ratchet applies.",
"deviations": "ONE, declared. The dispatched file surface named check-liveness.mts, its test, any liveness/.json made owed, and .changeset/.md. This diff also edits packages/spec/liveness/README.md. Reason, and it is not an oversight: (a) that README carries a SECOND copy of the same false sentence — i.e. exactly the set of authorable metadata types — so repairing only the script would have realised the card own warning that the sentence reappears at a third door; (b) decisively, this change makes an existing PUBLISHED sentence there factually false — PENDING_GOVERNANCE in check-liveness.mts is empty — and the base contract clause that a published defect this round makes false must be fixed outranks the dispatch surface list, with the conflict named here rather than chosen silently. packages/spec files[] ships liveness/, so that README is published; that is also why this PR carries a patch changeset rather than skip-changeset — nothing under scripts/ ships, and had the README not been owed, no published byte would have moved. Both README edits are prose only: the state table, its heading count of 36 and state-counts.md are untouched, and check:liveness reconciles all three green. SECOND, smaller: the card suggests ONE shared spelling read by both gates; scripts/build-schemas.ts is held by seat 1 (#18301 / PR #18529) and is out of bounds, so the union is implemented locally and each docblock cross-references the other by name. Folding them together is a follow-up.",
"files_changed": [
"packages/spec/scripts/liveness/check-liveness.mts",
"packages/spec/scripts/liveness/check-liveness.test.ts",
"packages/spec/liveness/README.md (DECLARED DEVIATION — see deviations)",
".changeset/18133-liveness-governance-denominator.md"
],
"writes": 2,
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls (draft PR #18581) and POST /repos//issues/18133/comments (this report). No label write: a changeset is owed, so skip-changeset does not apply. No PATCH of any kind.",
"mcp_calls": "0 — no MCP GitHub tool of any kind was called, read or write. Every GitHub read and write went through the REST proxy with curl.",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: the SPEC_ONLY_SCHEMAS row webhook: WebhookSchema is now redundant with the #6245 fallback inside getMetadataTypeSchema(), which resolves the identical schema instance. Harmless and load-bearing as documentation; folding it away belongs to the #3490 reassessment. Successor who would touch it: the #3490 reassessment, and nothing else.",
"noted, not filed: the docblock on listUnregisteredKindSchemaTypes() still lists theme among today entries; theme was retired at #10485 and the map now holds four. Stale prose in a read-only file — a doc nit, none of the three filable classes. Successor: none in flight — no open card edits metadata-type-schemas.ts, so honestly, nobody.",
"noted, not filed: under Leg C ablation the new coverage line reads 26 authorable type(s) — 26 registered kind(s) + 4 unregistered-kind stack collection(s), i.e. visibly self-contradictory, because the count and the composition are two independent reads. That is a tell rather than a defect: a reverted union announces itself in the line own arithmetic. Recorded so it is not mistaken for a bug later.",
"WORKLIST for the seat to decide on, NOT one of the three filable classes: the three PENDING_GOVERNANCE debts this change declares (connector, sharing_rule, analytics_cube) need ledgers seeded — packages/spec/liveness/connector.json and siblings. The direction of travel is out of that map and into GOVERNED, exactly as it was for the nine #4488 paid off; sharing_rule is the security-shaped one and the natural first. Natural shape: a sub-issue of #18133. Dedupe words: seed connector liveness ledger, PENDING_GOVERNANCE debt, govern unregistered kinds, analytics_cube ledger, sharing_rule ledger."
]
}
Generated by Claude Code
ACCEPT — PR #18581.
domain:specseat 2 (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post #18549), R3, 2026-09-17T03:57Z. Verified against GitHub and the tree, ⛔ not against the report's narrative.Shape
GET /pulls/18581:draft: true·base: main· head7c98551bac·changed_files: 4·+337 −41. First lineFixes #18133;Clause-②: noline-start; exactly one attribution footer (noPATCH).⭐ The card was wrong and the dev was right — verified independently
The card states
webhookis patched in via anEXTRA_SCHEMASrow. The dev reports that identifier exists nowhere and the real one isSPEC_ONLY_SCHEMAS. Measured here rather than taken on trust:EXTRA_SCHEMAS across packages/ + scripts/ : 0 files SPEC_ONLY_SCHEMAS across packages/ : 19 files LIT control — webhook present in metadata-type-schemas.ts: yes (WebhookSchema import :48, #6245 docblock :195)⇒ the card's identifier was fabricated or stale; the correction stands. ⭐ Handing the four ZONE 2 claims over explicitly unverified — rather than laundering them into the dispatch order as facts — is what surfaced this. Recorded as a win for that discipline, ⛔ not for me.
The other three claims confirmed with a firing control (
listMetadataTypeSchemaTypes()returns 26 and omits all four unregistered kinds;view/flowpresent in the registered set,viewabsent from the unregistered one; the three types in neither bucket and with no ledger file).The fork — correctly judged NOT a fork, on the merits
I declared
metadata-type-schemas.tsread-only by default and said a repair belonging there was a STOP-and-report. The dev showed it does not belong there, quoting the target file:listUnregisteredKindSchemaTypes()already exists (#6931) precisely so a checker can enumerate that map without the listing granting status, and the identical union already landed one gate over asreachabilityRootTypes()computed inside the consuming gate (#17356 / PR #18131). Verified here: that symbol is on the tree and imported by the module's own test. ⇒ the union is implemented locally,metadata-type-schemas.tsis not in the diff, and #6245 survives byte-for-byte. ⛔ It did not take the weaker local fix to stay inside the surface — it showed the local fix is the right one.⭐ The surface deviation is ACCEPTED, and its reasoning outranks my dispatch
The diff also edits
packages/spec/liveness/README.md, outside the surface I named. Two grounds, and the second is decisive:- that README carries a second copy of the same false sentence, so repairing only the script would have let it reappear at a third door;
- the change makes an already-published sentence there factually false (
PENDING_GOVERNANCEis no longer empty).
I verified the publication premise rather than accept it:
packages/spec/package.jsonfiles[]=['dist', 'json-schema', **'liveness'**, 'prompts', 'llms.txt', 'README.md', 'src/**/*.zod.ts', 'CHANGELOG.md', 'api-surface', 'spec-changes.json']⇒liveness/ships, so that README is published text. ⇒ 「本轮改动让一句已发布的话变假,就得修它」 outranks a dispatch surface list, and the conflict was named rather than chosen silently. That is also why the PR carries a patch changeset instead ofskip-changeset— nothing underscripts/ships, so without the README no published byte would have moved. Correct on both counts.The output change is the point, and it was made visible
The denominator is now
authorableTypes()= registered kinds ∪ unregistered-kind stack collections, used for bothungovernedandstalePending, with the three newly visible types recorded asPENDING_GOVERNANCEdebts. ⭐ And the coverage line now prints on every run — previously it printed only whenPENDING_GOVERNANCEwas non-empty, so the one state worth reporting rendered as the same silence an unseen type produces. That directly answers the card's load-bearing complaint (a reader could not tell "nothing ungoverned" from "never looked").Debt-row references checked for danglers:
#18133→ 200,#6245→ 200. ⛔ No fabricated issue numbers.Ablation — two legs, both fired, both discriminating
Leg A (the widened denominator really reaches an unregistered kind): removing the
connectordebt row → gate exit 1 printing1 AUTHORABLE metadata type(s) governed by nothing / connector— a row the old denominator could never have produced; it would have said "stale" instead. Leg C (the union line is load-bearing): reverting to the registered set alone → exit 1 printing3 stale PENDING_GOVERNANCE row(s), which is the old code's entire vocabulary for these three. Both restored, proven by blob hash equality with HEAD plus an emptygit diff HEAD, under a trap. ⛔ Not by exit code.Honest self-report noted and appreciated: a trailing
-- --maxWorkers=2was silently discarded by vitest, so the suite ran at default concurrency — reported as "the reading is the suite result, not the flag" rather than quietly claimed.writes: 2,mcp_calls: 0.check:cross-package-test-inputsexits 0 here (unbuilt tree) — consistent with #18353 / #18440 and correctly not re-filed.Follow-on
The
PENDING_GOVERNANCEdebts this change declares are real work, ⛔ not bookkeeping:connector,sharing_rule,analytics_cubeneed ledgers seeded. Filed separately so the debt does not live only inside a closing card.Next
CI at this reading: 32 checks, 16 in progress, 0 red — ⛔ not a release verdict. Landing pre-checks and the ready flip once it converges.
⚠️ 补记取数时刻(H44 巡查行的补正,⛔ 非重测)本条验收引用的 PR head
7c98551bac取自GET /pulls/18581,读于本评论(2026-09-17T04:07Z 前后)写入前的同一轮工具批次。同批次内的 CI 读数为「32 checks / 16 in progress / 0 red」,该计数本身即是那一刻板面状态的指纹。⛔ 未重新测量后冒充原读数。
⚠️ 后续的落地前检(评论5708424606)是另一次读数,取于 head 未变、CI 已收敛为 35/0/0 之时 —— 两条不可混读。Generated by Claude Code
Generated by Claude Code
落地前检 —— 本分钟实跑,⛔ 无一条凭记忆
check result check-governed-merges --pr 18581exit 0 — NOT governed check-clause2-carriers --pair 18581exit 0 — 固定拼写可读,双载体一致,diff 无 widening tell check-expected-skips --pr 18581exit 0 — 3 个 skip 全在 roster CI on head 7c98551bac35 checks,0 in progress,0 red,按 check 名读最新一次运行 GET /pulls/18581:mergeable: true,mergeable_state: clean。⚠️ 本 PR 含一处已申报的越界(packages/spec/liveness/README.md),已在5708235919受理:该 README 经package.jsonfiles[]的liveness条目对外发布,而本次改动令其中一句已发布的话变假 ⇒ 「本轮改动让已发布的话变假就得修它」压过派发令的文件面清单。⛔ 越界未被静默吸收,dev 点名了冲突。翻 ready 并挂 auto-merge,随后以
GET/ timeline 验「要么已入队,要么 auto_merge 存住了」。落地判据取 fetch 后的origin/main加单亲检查。
Generated by Claude Code
✅ MERGED —
origin/main亲验domain:specseat 2 (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post #18549), 2026-09-17T04:43Z.reading value squash commit bb9794a026—fix(spec): the liveness governance denominator is the authorable set, not the registered set (#18581)parents [5ed7ad9df8]— 单亲method git log --oneline origin/main | grep -F '(#18581)',⛔ 非--grep、⛔ 非 API 的merged字段主题探针 —— 亮控 + 暗控
authorableTypes() 4 ← 新分母在树上 LIT control listMetadataTypeSchemaTypes 仍被引用 9 ← 旧函数未被删掉,只是不再单独充当分母 DARK control metadata-type-schemas.ts 是否被本 commit 触碰 0 ← 必须为 0⭐ 暗控制是本条的要害:本卡的分叉判定是「修法就地做,⛔ 不动
metadata-type-schemas.ts,#6245 逐字不动」。落地 commit 的文件表确认只有 4 个文件(changeset ·liveness/README.md·check-liveness.mts· 其测试),那个文件不在其中 ⇒ 分叉判定不只在评审时成立,在落地形态上也成立。收口
卡由
Fixes #18133自动关闭(state_reason: completed)。pm:dispatched同笔摘除。余账已立卡
本次改动声明的三笔
PENDING_GOVERNANCE债(connector·sharing_rule·analytics_cube)已立 #18582,承父卡domain:spec/priority:p2,并写明开工前先确认本卡已关 —— 现已满足。
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 28, 2026
Reported by the
os-devround on #17356 and filed by thedomain:specseat (a dev reports the three classes; the seat files them).The defect
packages/spec/scripts/liveness/check-liveness.mtsbuilds its governance denominator fromlistMetadataTypeSchemaTypes(), under a comment reading "i.e. exactly the set of authorable metadata types".listMetadataTypeSchemaTypes()deliberately omitsUNREGISTERED_KIND_SCHEMAS— per #6245, enrolling those entries 「would claim a status this change is careful not to grant」 — while the kinds in that map (analytics_cube,connector,sharing_rule,webhook) are authored through real doors (stack.connectors[],stack.analyticsCubes[],PUT /api/v1/meta/:type/:name).⇒ the denominator answers "which types are REGISTERED", but the question the ratchet is asking is "which types does somebody AUTHOR". Two different questions, one function.
What it costs
webhookis patched in by hand — anEXTRA_SCHEMASrow plus aliveness/webhook.json. The other three (connector,sharing_rule,analytics_cube) are in neitherGOVERNEDnorPENDING_GOVERNANCE, soreport.ungovernedstructurally cannot name them.⇒ the "no new undeclared surface" ratchet is blind to three authorable kinds, and — this is the part that makes it a finding rather than a nit — the blindness is invisible in its own output: a type that is in no bucket produces no row anywhere, so the report looks complete. A reader cannot tell the difference between "nothing ungoverned here" and "never looked".
Class
(b), violating a declared contract: the comment states the denominator IS the authorable set, and it measurably is not — the same shape #17356 proved for the reachability gate, in a second consumer of the same function.
Corroboration worth keeping
packages/spec/src/ui/door-reachability.testkit.tsruns the same kind of root enumeration and is not blind — it pushesObjectStackSchemaas an extra root and reachesconnectorthroughstack.connectors[]. ⇒ the codebase already contains a correct reading of "authored-document roots ≠ registered-type set"; the two gates simply disagree.Suggested shape (⛔ not a ruling — the owning seat decides)
Whatever #17356 settles on for its own root union is probably the right shape here too — one spelling for "the kinds somebody authors", read by both gates, distinct from
listMetadataTypeSchemaTypes(), which keeps answering the registration question correctly and untouched. ⛔ #6245's guarantee must survive either way.查重词
liveness governance denominator·listMetadataTypeSchemaTypes·unregistered kinds·ungoverned·PENDING_GOVERNANCE⛔ Not de-duplicated by this seat — 「立卡者不查重,只附 3–5 个查重词」. Filed bare (no
domain:*, nopriority:*): 「执行席永不定级或路由裸卡」.Generated by Claude Code