Skip to content

[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

@claude

Reported by the os-dev round on #17356 and filed by the domain:spec seat (a dev reports the three classes; the seat files them).

The defect

packages/spec/scripts/liveness/check-liveness.mts builds its governance denominator from listMetadataTypeSchemaTypes(), under a comment reading "i.e. exactly the set of authorable metadata types".

⚠️ That is the same sentence #17356 measured false, one gate over. listMetadataTypeSchemaTypes() deliberately omits UNREGISTERED_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

webhook is patched in by hand — an EXTRA_SCHEMAS row plus a liveness/webhook.json. The other three (connector, sharing_rule, analytics_cube) are in neither GOVERNED nor PENDING_GOVERNANCE, so report.ungoverned structurally 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.

⚠️ NOT measured and ⛔ not claimed: whether any key on those three kinds would actually be flagged if the denominator were corrected. The defect asserted here is the structural blindness, ⛔ not a count of what it hides.

Corroboration worth keeping

packages/spec/src/ui/door-reachability.testkit.ts runs the same kind of root enumeration and is not blind — it pushes ObjectStackSchema as an extra root and reaches connector through stack.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:*, no priority:*): 「执行席永不定级或路由裸卡」.


Generated by Claude Code

Activity

  1. self-assigned this
    on Sep 17, 2026
  2. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    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.mts and its test packages/spec/scripts/liveness/check-liveness.test.ts; any liveness/*.json the denominator change makes owed. Read-only unless the repair provably belongs there: packages/spec/src/kernel/metadata-type-schemas.ts (where listMetadataTypeSchemaTypes() 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 own node 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.ts is held by seat 1 (#18301, PR #18529 awaiting landing) and is NOT on this surface. This seat's own open PR #18561 holds packages/spec/src/ui/view.zod.ts — also not on this surface. packages/spec/src/kernel/metadata-type-schemas.ts is 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:

    ⚠️ 后一条是本席须点名的升级信号:达档阻塞已经从「条款②卡积压」外溢成「阻塞其它卡」 —— #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

  3. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    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

  4. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    ACCEPT — PR #18581. domain:spec seat 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 · head 7c98551bac · changed_files: 4 · +337 −41. First line Fixes #18133; Clause-②: no line-start; exactly one attribution footer (no PATCH).

    ⭐ The card was wrong and the dev was right — verified independently

    The card states webhook is patched in via an EXTRA_SCHEMAS row. The dev reports that identifier exists nowhere and the real one is SPEC_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/flow present in the registered set, view absent 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.ts read-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 as reachabilityRootTypes() 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.ts is 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:

    1. 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;
    2. the change makes an already-published sentence there factually false (PENDING_GOVERNANCE is no longer empty).

    I verified the publication premise rather than accept it: packages/spec/package.json files[] = ['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 of skip-changeset — nothing under scripts/ 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 both ungoverned and stalePending, with the three newly visible types recorded as PENDING_GOVERNANCE debts. ⭐ And the coverage line now prints on every run — previously it printed only when PENDING_GOVERNANCE was 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 connector debt row → gate exit 1 printing 1 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 printing 3 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 empty git diff HEAD, under a trap. ⛔ Not by exit code.

    Honest self-report noted and appreciated: a trailing -- --maxWorkers=2 was 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-inputs exits 0 here (unbuilt tree) — consistent with #18353 / #18440 and correctly not re-filed.

    Follow-on

    The PENDING_GOVERNANCE debts this change declares are real work, ⛔ not bookkeeping: connector, sharing_rule, analytics_cube need 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

  5. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    落地前检 —— 本分钟实跑,⛔ 无一条凭记忆

    check result
    check-governed-merges --pr 18581 exit 0 — NOT governed
    check-clause2-carriers --pair 18581 exit 0 — 固定拼写可读,双载体一致,diff 无 widening tell
    check-expected-skips --pr 18581 exit 0 — 3 个 skip 全在 roster
    CI on head 7c98551bac 35 checks,0 in progress,0 red,按 check 名读最新一次运行

    GET /pulls/18581:mergeable: true,mergeable_state: clean。

    ⚠️ 本 PR 含一处已申报的越界(packages/spec/liveness/README.md),已在 5708235919 受理:该 README 经 package.json files[] 的 liveness 条目对外发布,而本次改动令其中一句已发布的话变假 ⇒ 「本轮改动让已发布的话变假就得修它」压过派发令的文件面清单。⛔ 越界未被静默吸收,dev 点名了冲突。

    翻 ready 并挂 auto-merge,随后以 GET / timeline 验「要么已入队,要么 auto_merge 存住了」。落地判据取 fetch 后的 origin/main 加单亲检查。


    Generated by Claude Code

  6. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    ✅ MERGED — origin/main 亲验

    domain:spec seat 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

  7. added a commit that references this issue on Sep 17, 2026
    bb9794a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions