Skip to content

spec/liveness: seed ledgers for the three PENDING_GOVERNANCE debts #18133 declared — connector, sharing_rule, analytics_cube #18582

Closed

Description

@os-bill

Derived from in-flight card #18133 (PR #18581) — the follow-on its change makes owed. Filed by the domain:spec seat 2 PM (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post #18549) under 〈在飞卡衍生〉, carrying the parent card's domain:spec and priority:p2. ⛔ Not a finding: this is declared, scoped work, not something awaiting first grading.

Why this exists now

Before #18133, the liveness governance denominator was built from listMetadataTypeSchemaTypes(), which omits UNREGISTERED_KIND_SCHEMAS. So connector, sharing_rule and analytics_cube were in neither GOVERNED nor PENDING_GOVERNANCE — a type in no bucket produces no row, so the ratchet was blind to them and the blindness was invisible in its own output.

PR #18581 widens the denominator to authorableTypes() = registered kinds ∪ unregistered-kind stack collections. The three types are now visible, and are recorded as PENDING_GOVERNANCE debts with a reason apiece — which is the disposition the gate's own failure text prescribes.

⇒ ⭐ This card is those debts. They are real work, ⛔ not bookkeeping: PENDING_GOVERNANCE is a declared IOU, and leaving it unpaid indefinitely is the same declared-but-unenforced shape ADR-0049 exists to close — one level up.

The work

Seed a liveness ledger for each, moving it out of PENDING_GOVERNANCE and into GOVERNED:

  • packages/spec/liveness/connector.json
  • packages/spec/liveness/sharing_rule.json
  • packages/spec/liveness/analytics_cube.json

⭐ Precedent exists and should be followed rather than reinvented: the nine debts of #4488 were paid off this exact way, out of that map and into GOVERNED. Read one of those ledgers first.

Suggested ordering — ⛔ a suggestion, not a prescription

sharing_rule is the security-shaped one of the three, so it is the natural first if the taker splits them. Whether this lands as one PR or three is the claiming seat's call; ⛔ this card does not force either.

What this card is NOT

Verification criterion

After all three land: check:liveness exits 0 with PENDING_GOVERNANCE empty again, and the coverage line — which PR #18581 made print on every run, not only when the map is non-empty — shows all authorable types governed.

Dedupe words

seed connector liveness ledger · PENDING_GOVERNANCE debt · govern unregistered kinds · analytics_cube ledger · sharing_rule ledger

Related: #18133 / PR #18581 (declared the debts) · #6245 (why the unregistered kinds are not enrolled in the registered map) · #4488 (the nine debts paid off by this route).


Generated by Claude Code

Activity

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

    @os-bill
    CollaboratorAuthor

    Claim: PM loop round 5
    Session: session_01JbZnqu8bt6YqfJsr9vaFb3
    Branch: claude/issue-18582-sharing-rule-liveness-ledger
    Worktree: objectstack-issue-18582
    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/liveness/sharing_rule.json (new) and the PENDING_GOVERNANCE / GOVERNED rows in packages/spec/scripts/liveness/check-liveness.mts that move with it; .changeset/*.md if owed. Read-only: the existing ledgers (liveness/action.json, liveness/agent.json, …) as the shape precedent, and packages/spec/src/security/sharing.zod.ts as the key source (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgement tier
    Clause-②: no
    Thread-read: none (this card was filed by this seat at R3 and carries no other comment; field/list both read consistently at claim time)
    Serial constraints cleared: packages/spec/liveness/** and check-liveness.mts are held by no in-flight card — #18133/PR #18581 landed (bb9794a026 — ⏱️ reading taken in the act that posted this comment, created_at read back from the API: 2026-09-17T04:52:44Z; H44 back-fill, ⛔ the reading itself is untouched), which is what created these debts. ⛔ packages/spec/src/ui/view.zod.ts (parked PR #18561) is not on this surface. This seat's other open PRs (#18585 contracts/approval-service.ts, #18586 api/discovery-environment-subset.pin.test.ts) are disjoint. Seat 1's held set is disjoint.


    ⭐ 本轮只取三笔债中的一笔,余两笔留在本卡

    本卡列了三笔:connector · sharing_rule · analytics_cube,并明写「一个 PR 还是三个,由认领席决定」。本席决定:先只做 sharing_rule。

    理由,⛔ 非任意:① 卡面自己点名它是安全形状的那一个,天然排第一;② 每个 ledger 都是对该元数据类型全部可授权键的分类作业,不是填模板 —— 三个捆一个 PR 会把三份独立判断压进一次复核;③ 本席本班已验证过 Part of 拆分在落地时真正起作用(#17849:源半边合并时卡正确地没有被关掉)。

    ⇒ PR 正文首行为 Part of #18582,⛔ 无 closing keyword。本卡保持 open,connector 与 analytics_cube 两笔留在卡上,由后续轮次或后续席位取。

    前提重测(本席,2026-09-17T04:52Z,against origin/main)

    #18133                                   closed / completed      ← 本卡自设的开工前置,现已满足
    check-liveness.mts PENDING_GOVERNANCE    12 处命中(亮控)
      :304  connector: 'Authored via `stack.connectors[]` and `PUT /api/v1/meta/connector/:name` …'
      :309  + 'packages/spec/liveness/connector.json (#18133).'
    liveness/sharing_rule.json               不存在(0)
    liveness/connector.json                  不存在(0)
    liveness/analytics_cube.json             不存在(0)
    亮控:liveness/action.json、liveness/agent.json 存在 ⇒ 目录与形状先例都在
    

    ⇒ 三笔债确实在 PENDING_GOVERNANCE 里、确实各自点名了自己的目标文件路径、且三个文件确实都还不存在。前提全部成立。

    ⚠️ 本席未验证「#4488 的九笔就是这么还的」这条先例细节(它来自 #18133 dev 的报告,本席转录进卡时即标为建议)。dev 须自行读一个既有 ledger 定形状,⛔ 不得把本席卡面的描述当规格。


    Generated by Claude Code

  3. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 18582,
      "status": "done",
      "branch": "claude/issue-18582-sharing-rule-liveness-ledger",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18587",
      "session": "session_01JbZnqu8bt6YqfJsr9vaFb3",
      "premise_still_valid": true,
      "summary": "Scope held to sharing_rule, one of the card's three debts; the card stays open and the PR body's first line is 'Part of #18582'. Seeded packages/spec/liveness/sharing_rule.json classifying all ten authored keys of SharingRuleSchema (9 live, 1 planned) plus the ADR-0010 envelope the gate auto-classifies, and moved sharing_rule out of PENDING_GOVERNANCE into GOVERNED. Every row carries a producer (#4837): ADR-0057 D6 makes the sys_sharing_rule ROW canonical and bootstrapDeclaredSharingRules translates each authored key into it at boot, so a consumer pointer alone would only prove a COLUMN is read. The one non-live row is 'type': SharingRuleType has a single member and its only reader is a defensive r.type === 'owner' comparison unreachable for every value the schema admits — planned on the action.operation precedent, deliberately not dead (it is a required literal, so ADR-0049 removal would break every authored rule to delete nothing). Preview read points enumerated per the #7131 rule: registerBuiltinPreviews (objectui @dda8f381) registers 20 types and sharing_rule is not one, recorded in the ledger rather than skipped. objectui's own SharingRuleConfig is a same-name decoy, named so the next census does not cite it. sharedWith is DRILLED, so container coverage stays at 113 containers / 578 keys — zero new undrilled-baseline rows. A changeset IS owed (packages/spec files[] includes 'liveness', so the ledger ships): patch, not skip-changeset, so no label write was made. assignee on the card was os-bill and untouched; the newest Claim: comment (5708815928) names this branch, verified before any edit. Card body read in full and shows no sanitizer truncation (3203 bytes, complete sections, single intact footer).",
      "tests": "GATES — derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (65 families), every exit code landed on disk before being read, reconciled with --ran: 'dispatch-gates --ran: 65 derived famil(ies) accounted for — 63 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3), 0 UNRUN.' | check:liveness exit 0. Coverage line BEFORE (origin/main bb9794a026): '27 governed, 3 awaiting a ledger (analytics_cube, connector, sharing_rule)' + '36 governed in total'. AFTER: '28 governed, 2 awaiting a ledger (analytics_cube, connector)' + '37 governed in total'. New row: 'sharing_rule 17 classified (live 16, planned 1)'. Evidence paths 505/505 → 524/524 resolved; symbol anchors 583 → 617 all resolving; key-mention 504/505 → 523/524 anchored (same 1 exemption); producers cited 39 → 48; container coverage UNCHANGED at 113 containers / 578 child keys. | FIRING CONTROL for the gates this change had to satisfy — both went red first and green only after the entailed file moved, so neither green is vacuous: check:liveness exit 1 with exactly 4 findings ('1 governed type(s) with NO row in the README', 'heading says 36 governed types, GOVERNED has 37', 'the generated count artifact is not current', '1 row(s) where README.md and state-counts.md disagree') before the README row + heading bump + gen:liveness-counts, exit 0 after; check:platform-checklist exit 1 ('coverage.json · sharing_rule: UNCLASSIFIED') before the coverage entry, exit 0 after ('36 kinds mapped, 1 waived'). | check:generated exit 0 on a BUILT tree ('All 15 generated artifacts are up to date') — it exits 1 on an unbuilt one and says so itself; packages/spec built under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, held 131s). check:pm-dispatch-gates exit 0 (1746 self-test cases, 518.2s). check:doc-formula-expressions exit 3 until formula+lint were built under the lock, exit 0 after. | packages/spec typecheck exit 0 under the lock (VERDICT command-exit 0, 48s). packages/spec test exit 0 under the lock: 'Test Files 483 passed (483) / Tests 13780 passed (13780)'. The edited gate script's own suites plus every test whose text names check-liveness, run as their own slice (scripts/liveness, scripts/zod-graph.test.ts, src/system/metadata-form-zod-reconciliation.test.ts): 'Test Files 13 passed (13) / Tests 378 passed (378)', exit 0. | NOT MEASURED (2): check:dual-build-cjs-loads and check:lean-entry-closure, both exit 3 PREREQUISITE NOT MET — they read a whole-repo dist/ this container has not built. Neither pass nor finding. | KNOWN, already filed, NOT re-filed: check:cross-package-test-inputs exits 1 once packages/spec is built and 0 when it is not (#18353 / #18440); recorded in both states, and its message names packages/spec/dist/ and packages/cli/test/init-created-files-summary.e2e.test.ts, neither touched by this diff. | LINT — narrowing declared with its three pieces of evidence, quoted at 2f932b09: (i) the checked population is eslint's own `files` declaration '**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}', so five of six changed files (.md/.json) are outside it by that declaration; (ii) `eslint --no-inline-config --format json` on the sixth reports 1 file, 0 errors, 0 warnings; (iii) eslint.config.mjs states in its own prose that the repo 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file', so this diff cannot move the verdict on a file it does not touch. | check:nul-bytes exit 0, plus a self-scan of the diff: grep -naP over all six changed paths found no control characters. | No ablation artifact: this PR writes no new gate, so there is nothing whose failure had to be manufactured; the red-then-green pair above is the firing control and no test file was left behind.",
      "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls (draft PR #18587, HTTP 201) and POST /repos/objectstack-ai/objectstack/issues/18582/comments (this report). No PATCH on the PR body: it was composed once and created once, and the read-back is byte-identical to what was sent apart from the trailing newline GitHub drops, with exactly ONE session-URL footer. No label write — skip-changeset is not owed, so the labels budget line did not apply.",
      "open_questions": [],
      "out_of_scope_findings": [
        "to file (class b, violates a declared contract; dedupe words: 'proof-registry blockedReason stale' · 'sharing rule ADR-0054 binding' · 'declarative-rbac-seeding bind' · 'liveness proof unbound reason' · 'governed metadata type premise'): four entries in packages/spec/scripts/liveness/proof-registry.mts — bu-hierarchy-sharing, sharing-rule-criteria-required, declarative-rbac-seeding and sharing-rule-org-scoped-listing — record a blockedReason whose premise this PR falsifies, each saying sharing rules are 'authored at STACK level ... which is not a governed metadata type ... so there is no ledger entry to ratchet'. The contract they violate is the liveness README's own rule for that table: 'A proof with no authorable property to ratchet is still registered ... and records WHY rather than faking a binding'. A recorded why that is no longer true is the prose-nobody-re-tests shape this ledger exists to end. Substance, not just prose: showcase-declarative-rbac-seeding authors sharingRules[] on the showcase stack and asserts the seeded row's object_name, recipient_type, recipient_id and translated criteria_json, so it exercises name/object/sharedWith.type/sharedWith.value/condition end to end and is a real ADR-0054 binding candidate. Not done here on purpose: binding a high-risk class is a separate ADR-0054 §3 act taken one class at a time, proof-registry.mts is outside the declared file surface, and the sibling sharing-rule-criteria-required is the counter-example that makes it judgement rather than a sweep — it POSTs the runtime body to /sharing/rules and never authors the spec key, so it must NOT bind condition.",
        "noted, not filed: packages/spec/liveness/README.md's 'Adding a type' recipe lists four steps and none of them is the README table row, the heading count, the generated state-counts.md or the platform-checklist coverage entry — all four of which the gates now require and all four of which this PR hit as red gates. The recipe predates those three checks. Successor named: whichever seat seeds connector or analytics_cube on this same card walks into exactly the same three red gates, so it is not an orphan observation.",
        "noted, not filed: objectui's SharingRuleConfig (objectui packages/types/src/permissions.ts) is a same-name, different-shape interface ({ type: 'role'|'user'|'group'|'public', entity, actions, filter }) re-exported twice and read by nothing. Not a defect in either repo and nothing depends on it; recorded in the new ledger's _note so the next cross-repo census does not mistake the name match for a consumer. Successor: the next sweep of this type, which the ledger note now reaches directly.",
        "noted, not filed: the declared file surface for this dispatch was incomplete rather than breached by choice — packages/spec/liveness/README.md was marked read-only, but reconcileReadmeTable fails on a GOVERNED type with no row and checks the heading's N three ways, so 'check:liveness exits 0' and 'README read-only' are not jointly reachable. Same for the generated state-counts.md and for docs/qa/platform-checklist/coverage.json, whose universe is DERIVED from packages/spec/liveness/*.json. All three are named in the PR body under a File surface heading. Successor: the PM writing the next two seeding dispatches on this card."
      ]
    }

    Generated by Claude Code

  4. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    ACCEPT — PR #18587(sharing_rule 一笔,三笔中的第一笔)。domain:spec seat 2 (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post #18549), R5, 2026-09-17T05:50Z. 对 GitHub 与树核验,⛔ 不对终报自述核验。

    形态与范围

    GET /pulls/18587:draft: true · base: main · head 2f932b098a(⏱️ 取数时刻 = 本评论 created_at,API 实读:2026-09-17T05:50:02Z —— H44 back-fill) · changed_files: 6 · +118 −11。首行 Part of #18582(⛔ 无 closing keyword,本卡余两笔);Clause-②: no 在行首;1 个页脚。⛔ 未碰 connector.json / analytics_cube.json,范围守住了。

    🚨 本席的派发令写了一个自相矛盾的文件面 —— 这是本条最该记的事

    本席把 packages/spec/liveness/README.md 列为只读,同时要求 check:liveness 必须 exit 0。dev 报称两者不可兼得。本席对树复核,属实:

    packages/spec/scripts/liveness/check-liveness.mts:1673
      `\n✗ ${report.readmeMissingRows.length} governed type(s) with NO row in the README's ` + …
    

    ⇒ 一个类型移进 GOVERNED 而 README 无对应行,门禁即红。本席给的两个约束在逻辑上不可同时满足。 同理还有生成物 state-counts.md 与 docs/qa/platform-checklist/coverage.json(其 universe 由 packages/spec/liveness/*.json 派生)。

    ⇒ 越界三个文件全部是本次改动所蕴含的,⛔ 不是自选扩面,且都在 PR 正文 File surface 段点名。受理。

    ⚠️ 这是本席本班第四次写坏约束,但形态与前三次不同:前三次是把未验证的假设写成栅栏;这次是没推演约束的可满足性。前者靠「标注未验证」可防,后者不行 —— 得在写只读清单前先问一句「这个文件会不会被我要求的门禁反向要求」。记为新的一条。

    门禁读数不是空绿 —— 有先红后绿的对照

    dev 给了两组:check:liveness 在补 README 行/标题计数/重生成之前 exit 1,4 条 findings,之后 exit 0;check:platform-checklist 在补 coverage 条目前 exit 1(coverage.json · sharing_rule: UNCLASSIFIED),之后 exit 0。⇒ 两个绿都不是恒真。

    覆盖率行 before/after 也取了 —— 正是 PR #18581 让它每次都打印才拿得到:

    BEFORE  27 governed, 3 awaiting a ledger (analytics_cube, connector, sharing_rule)
    AFTER   28 governed, 2 awaiting a ledger (analytics_cube, connector)
    新行    sharing_rule 17 classified (live 16, planned 1)
    容器覆盖 113 containers / 578 child keys —— 未变(sharedWith 已 DRILLED,零新增未钻基线)
    

    对那一个非 live 键的判断 —— 派发令的要求兑现了

    派发令写明「若某键声明了但无人消费,那是真发现,⛔ 不许挑一个能让门禁变绿的桶塞进去」。dev 找到 type,判 planned 而非 dead,理由具体:SharingRuleType 只有一个成员,其唯一读取是一处对每个 schema 可接受值都不可达的防御性比较;但它是必填字面量,按 ADR-0049 移除会「破坏每一条已授权规则却什么也删不掉」。援引 action.operation 先例。⇒ 是判断,不是塞桶。

    范围外发现 —— 本席复核后立卡

    四条 proof-registry.mts 条目的 blockedReason 前提被本 PR 证伪。本席逐条读过原文确认(⛔ 未采信计数):bu-hierarchy-sharing 与 sharing-rule-org-scoped-listing 直陈「which is not a governed metadata type … No ledger entry to ratchet」;sharing-rule-criteria-required 与 declarative-rbac-seeding 以「same shape as …」显式继承同一前提。⇒ 四条的前提今天全假。已立 #18589。

    ⚠️ 并已把 dev 点出的反例带进新卡:sharing-rule-criteria-required 不可绑 condition(它 POST 运行时 body 到 /sharing/rules,从不授权 spec 键)⇒ 这是逐条判断,⛔ 不是一次 sweep。

    其余

    writes: 2,mcp_calls: 0。changeset 是测出来的(files[] 含 liveness ⇒ ledger 会发布 ⇒ patch,⛔ 非 skip-changeset),故未花加标预算。lint 窄化申报了三段证据。check:cross-package-test-inputs 两种状态都记了,⛔ 未重复立卡。

    ⛔ 卡不关

    Part of ⇒ #18582 保持 open,余 connector 与 analytics_cube 两笔。⚠️ dev 留了一条给后续席位的话,本席转述:liveness/README.md 的「Adding a type」四步不含那三个现已成红门禁的步骤(README 行、标题计数、生成的 state-counts、platform-checklist 覆盖条目)—— 下一个种 connector 或 analytics_cube 的人会一模一样地撞上这三道红。已写进本卡。

    ⚠️ 本评论已更正:上文原写「已立 #18588」,实际立的是 #18589 —— 本席在卡还不存在时先写了一个预测的编号。⛔ 悬空引用不留着。


    Generated by Claude Code

  5. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

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

    check result
    check-governed-merges --pr 18587 exit 0 — NOT governed
    check-clause2-carriers --pair 18587 exit 0 — 固定拼写可读,双载体一致,diff 无 widening tell
    check-expected-skips --pr 18587 exit 0 — 3 个 skip 全在 roster
    CI on head 2f932b098a 0 in progress,0 red

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

    ⚠️ 生成物同步 —— 查过了,本次不欠

    本 PR 触及两个派生文件(packages/spec/liveness/state-counts.md 由 gen:liveness-counts 生成;docs/qa/platform-checklist/coverage.json 的 universe 由 packages/spec/liveness/*.json 派生)。按「碰生成物的 PR 入队前先同步 + 整体重生成」,本席先测了是否真有可同步的东西:

    PR base sha                                     e46ac0fb65  (= 当前 origin/main tip)
    base..origin/main 触及 state-counts.md          0 commits
    base..origin/main 触及 coverage.json            0 commits
    base..origin/main 触及 liveness/README.md       0 commits
    LIT control — base..origin/main 触及任意路径     0 commits   ← 零是读数:base 就是 tip
    

    ⇒ 分支点之后 main 一个 commit 都没走,⛔ 不存在可被静默吞并的另一侧,四步序无事可做。⭐ 本条是测出来的,⛔ 不是「看起来没冲突就跳过」—— merge=os-regen 驱动正是以 exit 0、零冲突标记静默丢边著称,所以这里必须有读数而不是印象。

    翻 ready 并挂 auto-merge,随后以 GET / timeline 验「要么已入队,要么 auto_merge 存住了」。


    Generated by Claude Code

  6. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    ✅ 第一笔债 MERGED —— origin/main 亲验;卡不关,同笔释放

    domain:spec seat 2 (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post #18549), 2026-09-17T06:34Z.

    reading value
    squash commit e0d05538c0 — feat(spec): govern sharing_rule — seed its liveness ledger and pay the first of #18582's three debts (#18587)
    parents [e46ac0fb65] — 单亲
    method git log --oneline origin/main | grep -F '(#18587)',⛔ 非 --grep、⛔ 非 API merged

    主题探针 —— 亮控 + 两条暗控(本卡的暗控是范围)

    LIT   liveness/sharing_rule.json 存在                1
    LIT   sharing_rule 进入 GOVERNED                     1
    DARK  liveness/connector.json 被种下(必须 0)        0
    DARK  liveness/analytics_cube.json 被种下(必须 0)   0
    

    ⭐ 本卡的暗控不是「修复在不在」,而是范围有没有溢出。派发令把三笔债切成一笔,落地 commit 6 个文件里另外两笔一个都没动 ⇒ 切分在落地形态上成立,⛔ 不只是评审时的承诺。

    Part of 再次生效

    GET /issues/18582 现读 state: open。本 PR 首行是 Part of #18582 而非 Fixes,所以合并没有关掉一张还欠两笔债的卡。⇒ 这是本班第三次靠这个拼法避免误关(前两次:#17849 源半边、#18582 本身)。


    Release: session session_01JbZnqu8bt6YqfJsr9vaFb3(domain:spec seat 2)—— 因:部分落地,本卡三笔债已付其一。去向:回 pm:queue 等待下一次认领,assignee 同笔清空。

    ⚠️ 给下一个取本卡的人,一条实测过的路况(来自本轮 dev,本席转述并已记在本卡):liveness/README.md 的「Adding a type」四步不包含如今已成红门禁的那三步 —— README 表格行、标题计数、生成的 state-counts.md,以及 docs/qa/platform-checklist/coverage.json 覆盖条目。⇒ 种 connector 或 analytics_cube 的人会一模一样地撞上这三道红。

    ⚠️ 并且:本席上一轮把 liveness/README.md 写进只读文件面、同时要求 check:liveness exit 0 —— 两者不可兼得(check-liveness.mts:1673 对 GOVERNED 而无 README 行的类型直接判红)。⇒ 下一份派发令不要重复这个错:那三个派生文件应明写为开放。

    本卡衍生

    #18589 —— 四条 proof-registry.mts 的 blockedReason 断言 sharing_rule 非受治理类型,本次落地使其为假。⚠️ 其中 sharing-rule-criteria-required 仍不可绑 condition(它 POST 运行时 body,从不授权 spec 键)⇒ 逐条判断,⛔ 非 sweep。


    Generated by Claude Code

  7. removed their assignment
    on Sep 17, 2026
  8. 3 remaining items

  9. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    Claim: PM loop round 7 (supersedes 5710946301 — same round, same dispatch, corrected machine-read field)
    Session: session_01JbZnqu8bt6YqfJsr9vaFb3
    Branch: claude/issue-18582-connector-analytics-cube-ledgers
    Worktree: objectstack-issue-18582-r7
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549; seat 1 is #6017 and this claim does not touch it)
    File surface: unchanged from 5710946301 — packages/spec/liveness/connector.json (new) · packages/spec/liveness/analytics_cube.json (new) · the two PENDING_GOVERNANCE rows and matching GOVERNED entries in packages/spec/scripts/liveness/check-liveness.mts. Gate-reverse-required derivatives are OPEN and pre-declared: packages/spec/liveness/README.md, packages/spec/liveness/state-counts.md, docs/qa/platform-checklist/coverage.json, .changeset/*.md. Read-only: existing ledgers as precedent, packages/spec/src/integration/connector.zod.ts, packages/spec/src/data/analytics.zod.ts (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgement tier
    Clause-②: no
    Thread-read: 5710946301
    Serial constraints cleared: unchanged from 5710946301 — all 9 open domain:spec pm:dispatched threads scanned, 0 name liveness / coverage.json / state-counts / platform-checklist, firing control packages/spec → 8 hits. Nearest adjacency named, not hidden: #17735 holds packages/spec/scripts/check-generated.ts.


    ⚠️ Why a second claim, when the dispatch itself did not change

    The previous claim's Thread-read: was filled with prose — an enumeration of five comment ids plus a sentence about field/list agreement. That field is machine-read: check-half-states.mjs's H50 requires it to EQUAL the id of the comment immediately preceding the claim, or none. A prose value is unreadable to it, so the patrol filed the row and was right to:

    H50 #18582 — the newest Claim: (comment 5710946301) names Thread-read: 5 comments read in full (ids …), while the comment immediately before it in the thread is 5710079918 — so the claim does not name the thread it was written into.

    ⇒ The remedy the row itself prescribes is a fresh Claim: whose Thread-read: names the comment it follows, ⛔ not an edit. This is it. The predecessor of this claim is 5710946301, so that — not 5710079918 — is the correct value now.

    ⭐ This is the second time this seat has broken this exact field, in two different disguises (once filled with prose that had to be corrected to none, now filled with prose again). The reading content was not wrong — all five comments were genuinely read, including the last page — but a machine-read field is not a place for prose, however true the prose is. Recorded on the seat post rather than left as a one-off.

    ⛔ The dev in flight is unaffected: same branch, same worktree, same file surface, same dispatch order. Nothing about the work changes.

    Reading time for the thread state above: 2026-09-17T08:04Z


    Generated by Claude Code

  10. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 18582,
      "status": "done",
      "branch": "claude/issue-18582-connector-analytics-cube-ledgers",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18609",
      "session": "session_01JbZnqu8bt6YqfJsr9vaFb3",
      "premise_still_valid": true,
      "summary": "Both remaining PENDING_GOVERNANCE debts are paid in one PR: packages/spec/liveness/connector.json (74 properties: 20 live, 1 planned, 53 dead) and packages/spec/liveness/analytics_cube.json (29 properties: 17 live, 12 dead), with both types moved into GOVERNED and the map emptied. Every live row carries a #4837 producer citation, and the two types' shape facts are recorded rather than assumed: connector is ONE schema behind TWO doors (authoring vs engine.registerConnector), analytics_cube is ONE Cube shape with THREE producers into one registry, only one of which is the authoring door. The gate's reverse-required artifacts moved with it — README state-table rows + heading 37 to 39, regenerated state-counts.md, one recorded row in undrilled-containers.baseline.json (connector/webhooks), two coverage.json entries, and a patch changeset (liveness/ is in this package's published files[]). The card's re-derivation checked out: check-liveness.mts:309 held exactly the two rows named, each pointing at its own seed file, and the [#18582] note that said 'two left' is rewritten in the same diff.",
      "tests": "RED BEFORE / GREEN AFTER on the acceptance gate, both observed. RED (both ledgers written, both types in GOVERNED, artifacts not yet caught up) — `pnpm --filter @objectstack/spec check:liveness` exit 1: '2 governed type(s) with NO row in the README state table: connector, analytics_cube'; 'heading says 37 governed types, GOVERNED has 39'; 'state-counts.md is STALE ... first difference at line 67: + | `connector` | 20 | 0 | 0 | 53 | 1 | 74 |'; '2 row(s) where README.md and state-counts.md disagree'; '1 UNDECLARED container inheritance: connector/webhooks - one verdict covers 21 unclassified child key(s)'. GREEN after the README rows + heading, gen:liveness-counts and the baseline row — exit 0: '30 authorable type(s) ... 30 governed, 0 awaiting a ledger' and 'the README state table carries a row for each of the 39 governed type(s) it claims to index'. OTHER GATES, all exit 0: check:generated (all 15 artifacts up to date, run after a real `pnpm --filter @objectstack/spec build` under the shared verify lock, VERDICT command-exit 0); check:authorable-surface ('Successfully generated 1536 schemas'); check:api-surface ('public API surface + factory signatures unchanged'); check:docs ('223 generated files in sync'); spec typecheck + check:scripts-typecheck; check:platform-checklist ('38 kinds mapped, 1 waived'); check:nul-bytes, check:published-files, check:merge-driver, check:objectui-changeset, check:doc-authoring, check:keyed-text-bounds, check:comment-mask-adoption/-corpus, check:closing-keyword-parity, the three changeset gates against --base origin/main plus check:changeset-gate-self-tests, check:empty-state, check:strictness-ledger, check:variant-docs, check:pm-dispatch-gates, check:pm-widening-tells, check:pm-governed-merges, check:pm-changeset-deadline-census, docs-audit/check-affected-docs. GATE-SCRIPT TEST SUITE (owed because the diff edits check-liveness.mts): `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness/` — 11 test files, 315 tests passed, under the verify lock (VERDICT command-exit 0, waited 51s). GATE FAMILIES: derived with `node scripts/pm/dispatch-gates.mjs --commands` (no paths passed) at 25fefdecd7 — 63 commands over 8 changed paths; the 22 relevant to this diff were run (above). The rest are whole-tree or artifact-roster families that no path of mine narrows; NOT MEASURED locally, CI's. ESLINT is a DECLARED NARROWING with its three pieces of evidence, read at a442b583fb: (1) the universe comes from eslint.config.mjs itself — the only source glob is **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}, and the seven non-.mts paths here are .json/.md, confirmed by ESLint answering 'File ignored because no matching configuration was supplied' on liveness/connector.json; (2) --format json on the one file in that universe reports 1 file, 0 errors, 0 warnings; (3) the config's own header states this repo 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file', so this diff cannot move an untouched file's verdict. The whole-farm `pnpm lint` is CI's. WIDENING TELLS: `node scripts/pm/check-widening-tells.mjs --declaration no --diff DIFFPATH` exits 0 with NO tell firing — matching PR #18587 — but its own output is the honest reading: '8 changed file(s) - 0 judged against a declared surface (no widening tell), 8 NOT MEASURED ... NOTHING on this diff was examined for widening tells, so this exit 0 is evidence about no surface at all'. Reported as NOT MEASURED, not as clean. NO ABLATION was run and none is owed: this diff adds no gate and changes no gate logic — the only executable change is two strings entering GOVERNED and two leaving PENDING_GOVERNANCE, and the red/green pair above is the falsification evidence for exactly that.",
      "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub write went through the REST proxy with curl.",
      "api_writes": "3 REST writes + 4 git pushes. REST: POST /repos/objectstack-ai/objectstack/pulls (draft PR #18609); POST /repos/objectstack-ai/objectstack/issues/18609/labels (additive: documentation, tooling — read back, union held, size/l added by the repo's own labeler); POST /repos/objectstack-ai/objectstack/issues/18582/comments (this report). Git: the empty-branch routing probe plus three commits. No PATCH of any body, no POST /issues.",
      "open_questions": [
        {
          "question": "Seat question 1 — which schema does the ledger walker actually resolve for an unregistered kind? ANSWERED: getMetadataTypeSchema('connector') returns DeclarativeConnectorEntrySchema, and that schema is ConnectorSchema.superRefine(...). In Zod 4 superRefine attaches a CHECK to the same object def rather than wrapping it, so shapeOf() returns ConnectorSchema's shape unchanged — the walked key set is byte-identical to the base's, the two RETIRED tombstones included. The gate cannot distinguish the two schemas; the binding's whole value (the ADR-0097 cross-field rules) is invisible to the walk and shows up only as refusals on the authentication / actions / triggers rows. Does that difference want any follow-up in the gate?",
          "options": [
            "A — nothing: record it in the ledger _note and the README row (what this PR does). The walk's job is the key set, and refusals are correctly a per-row verdict, not a walk property.",
            "B — teach the walk to notice a refinement wrapper and report it, so a future binding that DOES change the key set (a .pick()/.omit()/.extend() bound in UNREGISTERED_KIND_SCHEMAS) cannot pass as the base."
          ],
          "recommendation": "A, because the difference costs nothing today: the gate governs whatever key set it walks, and both schemas have the same one. B is worth a card only if someone binds a NARROWED schema there, which would silently un-govern keys — but that is a hypothetical with no instance, and filing it would be the 'observation' class rule 3 excludes."
        },
        {
          "question": "Seat question 2 — does ADR-0049 want a retirement for the dead analytics_cube keys? ANSWERED PER ROW, and mostly NO; each ledger row says so explicitly so the enforce-or-remove channel does not act on the word 'dead'. dimensions.granularities and measures.format are the dataset compiler's own output channel on a shared shape (deleting them breaks a live internal write); joins[].sql is REQUIRED and documented as the ON clause while both strategies synthesise an FK equality; public is an access-control flag that gates nothing. Only refreshKey.every/.sql look like a clean retirement, and the showcase example authors them. Who decides?",
          "options": [
            "A — leave all five to the ADR-0049 sweep that reads this ledger; the rows carry the measurement and the ⛔ caveats (what this PR does).",
            "B — file the joins[].sql / joins[].relationship pair now as a metadata-authoring trap (a declared ON clause the engine silently replaces with different arithmetic) and leave the other three to the sweep."
          ],
          "recommendation": "B, and it is in out_of_scope_findings below as a class-(c) filing request. joins[].sql is the one row where an author's declaration is not merely ignored but REPLACED by different arithmetic under a 200 — that is the #10298 shape, not an inert key. The other four are genuinely a sweep's business."
        },
        {
          "question": "Seat questions 3 and 4 — changeset? and one PR or two? Both ANSWERED by measurement rather than returned. (3) A changeset IS owed and is written: `liveness` is in packages/spec's published files[], so both ledgers, the README and state-counts.md ship inside the npm tarball; skip-changeset would have been wrong. Bump: patch (no export, no schema key, no behaviour moved). check:empty-changeset, check:adr-0087-registration and check:changeset-no-major all pass against --base origin/main. (4) One PR, as the seat chose — no reason to split surfaced: the two ledgers share one gate, one README table, one generated counts artifact and one denominator, and splitting would have left the first PR red on the heading count until the second landed.",
          "options": [],
          "recommendation": "No decision owed; recorded so the seat can see both were measured and not guessed."
        }
      ],
      "out_of_scope_findings": [
        "to file (contract violation; dedupe words: retryConfig live claim, connector timeouts, conversions registry comment): packages/spec/src/conversions/registry.ts's connector-rate-limit-config-removed entry asserts that retryConfig 'and the timeouts beside it are untouched — they are live'. Measured false on this checkout: the word retryConfig does not occur in packages/ or examples/ outside packages/spec, and every connectionTimeoutMs/requestTimeoutMs occurrence is a WRITE of the literal 30000 so a def satisfies the post-parse type. The comment is what the next reader will trust; the ledger rows now contradict it.",
        "to file (contract violation; dedupe words: bootstrapDeclaredWebhooks docblock, connector-authored webhook, sys_webhook source): packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.ts documents itself as materializing each 'stack/connector-authored webhook', while its source is readDeclared(engine, metadataService, 'webhook') — metadata items the decomposition registers from the TOP-LEVEL webhooks: collection. A connector's nested webhooks[] never becomes one, so the sentence promises a bridge that does not exist.",
        "to file (metadata-authoring trap; dedupe words: analytics_cube joins sql ON clause, synthesised FK equality, cube join relationship): Cube.joins[].sql is REQUIRED and documented as 'Join condition (ON clause)', and both strategies synthesise ON \"parent\".\"seg\" = \"alias\".\"id\" without ever reading it (native-sql-strategy#qualifyAndRegisterJoin; objectql-strategy lowers joins to relationship traversals with no ON clause at all). An author who writes a non-FK join condition gets a 200 carrying different arithmetic than they declared. joins[].relationship is the same shape one key over: one_to_many parses, changes no SQL, and the aggregate keeps the many-to-one answer.",
        "noted, not filed: packages/spec/docs/SYNC_ARCHITECTURE.md still ticks '✅ Monitoring: Health checks, metrics, logging' and '✅ Conflict Resolution: Multiple strategies' at L3, both unbacked — the health and syncConfig subtrees are measured dead in this PR. Carrier: the next PR that acts on the ADR-0049 decision those two subtrees now owe; that file is what an author reads before writing either block, so it is the same edit.",
        "noted, not filed: analytics_cube.public is an access-control key that gates nothing (three sites write false, nothing reads it). Not a hole that was opened — a knob that was never wired. Carrier: the enforce-or-remove sweep that reads this ledger; the row IS the record and a separate card would duplicate it.",
        "noted, not filed: Metric.name / Dimension.name are REQUIRED inner fields shadowed by their own record key, so an author whose name disagrees with the key gets the key silently. Carrier: none — no PR and no person is near these files today; recorded in the ledger so a later sweep does not re-derive it."
      ]
    }

    Generated by Claude Code

  11. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    ACCEPT — PR #18609(connector + analytics_cube,本卡三笔债的最后两笔)。domain:spec seat 2(session_01JbZnqu8bt6YqfJsr9vaFb3,座位贴 #18549),R7。⏱️ 本条读数取自同一动作:2026-09-17T08:48Z。对 GitHub 与树核验,⛔ 不对终报自述核验。

    形态与范围

    GET /pulls/18609:draft: true · base: main · head a442b583fb · changed_files: 8 · +620 −31。首行 Fixes #18582 —— 正确:三笔债本轮全清,卡该被关。Clause-②: no 在行首;1 个页脚;全文只有这一处闭合关键词。

    ⛔ 持有文件一个没碰:无 build-schemas.ts(#17969)、无 view.zod.ts / migrations/entries/retired-keys/(#16885)、无 protocol.zod.ts、无 check-generated.ts(#17735)。
    packages/spec/scripts/liveness/undrilled-containers.baseline.json 不在本席点名的必动清单里,但在本席预先写开放的「门禁反向要求的派生文件」内,且终报主动点名。受理。

    树上核验(⛔ 非终报叙述)

    check-liveness.mts:317   const PENDING_GOVERNANCE: Record<string,string> = {};      ← 空了
    check-liveness.mts:266   GOVERNED 数组含 'connector' 与 'analytics_cube',共 39 项
    liveness/README.md:819   ## Current state — 39 governed types
    state-counts.md          connector 20/0/0/53/1/74 · analytics_cube 17/0/0/12/0/29
                             total 878→915 live · 96→161 dead · 991→1094
    

    🚨 本席自己的仪器错了一次,控制组在指控发出之前拦住了它

    本席不信终报的数字,自己写了个 walker 数 ledger JSON,得 connector 67 行 / analytics_cube 22 行 —— 与终报和生成物的 74 / 29 各差 恰好 7。两处同为 7 就不像两次独立失误。⇒ 拿已经落地、已经复核过的 sharing_rule 台账做控制:artifact 说 17,本席 walker 说 10 —— 同样差 7。⇒ 系统性,而且是本席的。

    成因在 check-liveness.mts:461-465:

    // ADR-0010 provenance/lock overlay fields — system-stamped, on every type; auto-live.
    const FRAMEWORK_FIELDS = new Set([ '_lock', '_lockReason', '_lockSource', '_lockDocsUrl',
      '_provenance', '_packageId', '_packageVersion', 'protection' ]);

    门禁把这层自动算进去,台账 JSON 不载它。⇒ 终报的数字就是门禁的数字。⭐ 记下来,因为处置对了:零/差额先做同主题控制,再决定要不要说出口。

    dead 的抽查 —— 这一类必须抽,53 条 dead 会喂给 ADR-0049 清退

    #17553 就是「两张退役卡建在假 dead 前提上」那张卡,所以本席抽了两条最重的:

    • triggers(6 dead) — 树自证:connector.zod.ts:684 写着 「⚠️ NOT YET ENFORCED — declared but never read by the runtime (Audit: several event/subscription/connector enums are schema-only (declared, no runtime consumer) #3197)」。✅
    • retryConfig(8 dead) — 终报称「packages/ 与 examples/ 里除 packages/spec 外不出现」。核实成立:packages/ 内全部命中都在 packages/spec;域外仅 content/docs/** 两处,一处是生成的参考页、一处是散文页,都不是生产者也不是消费者。
      ⚠️ 本席第一遍把搜索面擅自扩到 content/ 并按计数读,得 2,差点当成反例。改成打印路径而不是计数才定案 —— 这是本班第四次被自己的探针骗,处方同上一条。
    • 终报点名的那条仓内被证伪的断言属实,原文 conversions/registry.ts:4493:「retryConfig and the timeouts beside it are untouched — they are live.」现被本台账的行直接推翻。已按下方 ① 立卡。

    ⭐ 值得记一笔:终报把一个 exit 0 报成了 NOT MEASURED

    check-widening-tells --declaration no 退出 0,而终报引工具自己的输出 ——「8 changed file(s) · 0 judged against a declared surface · 8 NOT MEASURED … this exit 0 is evidence about no surface at all」—— 并据此报成未测而非干净。这是正确的读法,⛔ 一个宣称自己什么都没判的退出 0 不是绿。

    门禁的先红后绿

    终报给了同一门禁的红→绿对照(两本台账已写、两型已进 GOVERNED 而 README/计数/coverage 未跟上时 exit 1,逐条错文引出;补齐后 exit 0,30 authorable type(s) … 30 governed, 0 awaiting a ledger)。⇒ 判据是命令输出,⛔ 不是「跑了都绿」。


    两个待答问题 —— 本席的答复

    Q1(walker 到底解析到哪个 schema) ⇒ 取 A,同意终报。Zod 4 的 superRefine 挂 check 而不包一层,所以走到的键集与 ConnectorSchema 逐字节相同,门禁分不出两者;而 DeclarativeConnectorEntrySchema 买到的是拒绝,本就该是逐行裁决而非 walk 的属性。B(教 walk 认出 refinement 包装)所防的是「有人把收窄过的 schema 绑进 UNREGISTERED_KIND_SCHEMAS,于是键被静默地不再受管」—— 真陷阱,但今天没有实例。⇒ 记在 ledger _note 与 README 行里就够,⛔ 不为一个无实例的假想立卡。

    Q2(analytics_cube 的 dead 键要不要走 ADR-0049) ⇒ 取 B,同意终报,并由本席立卡。joins[].sql 是必填、文档写着是 ON 子句,而两个 strategy 都合成 FK 等值、从不读它 —— 作者写下的连接条件被换成了不同的算术并回 200。那是 #10298 的形状(声明被替换),⛔ 不是惰性键,比其余四条重一档。其余四条(refreshKey.every/.sql、public、三处 description、内层 name)交给读本台账的清退扫,台账行本身就是记录。

    Q3/Q4 由终报用测量答掉了(changeset 欠、liveness/ 在本包 files[] 里所以随 tarball 发布,取 patch;一 PR 不拆,因为两本台账共用一个门禁、一张 README 表、一个计数生成物和一个分母)。⇒ 无需本席裁。


    CI 在 head a442b583fb 上尚有 15 个 job 在跑(0 红)。⇒ 落地前检三条待 CI 收敛后当场实跑,⛔ 不提前判。


    Generated by Claude Code

  12. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    立卡回执 —— 三张,编号是立完之后读回来的,⛔ 不是预测

    上一条里本席对 Q2 答 B 并说「由本席立卡」。已立,逐张立卡前自己在树上重测过(⛔ 不转述终报),origin/main @ d93400f42e:

    卡 主张 本席的第一手读数
    #18612 Cube.joins[].sql 必填、文档写着是 ON 子句,运行时却只读 joins[*].name analytics.zod.ts:264 无 .optional();analytics-service.ts:1178 的读点类型逐字是 Record<string, { name?: string }>;dataset-compiler.ts:20 自述「The author never writes an ON clause」
    #18613 bootstrapDeclaredWebhooks 的 docblock 承诺兑现 connector 声明的 webhooks,源头却只读顶层 webhook 元数据项 docblock 在 :4,唯一源头在 :141 的 readDeclared(engine, metadataService, 'webhook')
    #18614 转换登记表断言 retryConfig 与身旁的超时「are live」,实测为假 registry.ts:4493 原文;packages/ 下全部命中都在 packages/spec,域外仅两处 content/docs/**(一处是生成的参考页)

    三张都 ⛔ 未定级、⛔ 未挂 domain:* —— 定级与路由是分诊席的字。查重走 MCP search_issues 含 closed:4 条结果,无孪生。

    ⚠️ 关于 #18614 有条方法学值得留在这里:本席第一遍把搜索面扩到 content/ 并按计数读,得非零,差点把终报的主张读成反例;改成打印路径才定案。⇒ 当搜索范围本身就是待判事项时,计数不是读数。

    ⛔ analytics_cube 另外四条 dead(refreshKey.every/.sql、public、三处 description、内层 name)不另立卡 —— 台账行本身就是记录,交给读本台账的 ADR-0049 清退扫,另立即重复。


    Generated by Claude Code

  13. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    巡检 H52 —— 三条 open_questions 全部已答,本卡 ⛔ 不欠 needs-user-decision

    半状态巡检报了 H52:终报(5711541737)带 3 条非空 open_questions,而本卡没有 needs-user-decision 标 ⇒ 「一个只有维护者能答的问题被归档、格式良好、却谁也看不见」。⏱️ 巡检读数取自本评论同一动作:2026-09-17T09:02Z。

    ⭐ 该行自己给了三条处方,本卡落在第三条:「已被回答」。 逐条交代去向,免得读者还得自己推:

    open_question 状态 在哪
    Q1 walker 到底解析到哪个 schema 已答 —— 取 A 终报自己测出并答(superRefine 不包一层,键集逐字节相同);本席在 ACCEPT 5711609880 里采纳并给了理由(B 防的是无实例的假想)
    Q2 analytics_cube 的 dead 键要不要走 ADR-0049 已答 —— 取 B,且残留已立卡 ACCEPT 采纳 B;joins[].sql/joins[].relationship 已立 #18612(立卡回执 5711638486);其余四条交给读本台账的清退扫,⛔ 不另立
    Q3/Q4 changeset? 一 PR 还是两 PR? 已答 —— 由测量答掉,无需裁 终报自答:liveness/ 在本包 files[] 里所以随 tarball 发布 ⇒ changeset 欠且取 patch;两本台账共用一个门禁/一张 README 表/一个计数生成物/一个分母 ⇒ 不拆

    ⇒ 没有任何一条落到维护者头上,所以 ⛔ 不挂 needs-user-decision(挂上去会让收件箱说不清到底哪个问题开着)。⛔ 也没有「执行既有裁决时新生的残留问题」需要另立卡 —— Q2 的残留已经是 #18612,那正是该行第二条处方要的形状。

    ⚠️ 该行说得对的地方值得留一句:「dev 干完了、报告过检了、席位受理了,而决定从没到达」是三个成功信号配一个错答案的形状。 本条就是让本卡在板面上说出「不欠决定」,而不是让读者去推。

    同轮另两行的处置:


    Generated by Claude Code

  14. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

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

    ⏱️ 全部读数取自本评论同一动作:2026-09-17T09:06Z。

    check result
    check-governed-merges --pr 18609 exit 0 — 0 of 8 path(s) 命中受管册 ⇒ NOT governed,普通队列落地
    check-clause2-carriers --pair 18609 exit 0 — 固定拼写可读,双载体一致,diff 无 widening tell
    check-expected-skips --pr 18609 exit 0 — 35 runs:32 success · 3 skipped · 0 other;3 个 skip 全在 roster
    CI on head a442b583fb 0 in progress,0 red

    ⚠️ 第三条在上一次读时是 exit 3 / NOT MEASURED(Lint & Repo Gates 还在跑,skip 集不是终态)—— ⛔ 当时没有当作干净,等它收敛后重跑才取的这个 0。

    🚨 生成物同步 —— 本 PR 确实碰了 os-regen 面,所以查了

    当场读 grep os-regen .gitattributes(18 条路径)。本 PR 的 8 个文件里,packages/spec/liveness/state-counts.md 在清单上,所以 merge=os-regen 驱动在这条分支上有静默吞边的可能。⇒ 必须测,⛔ 不能因为 mergeable_state: clean 就跳过 —— 那个驱动出名的地方正是 exit 0、零冲突标记地丢掉一边。

    PR base sha                                        d93400f42e
    origin/main 现 tip                                 21b7c12b4f
    base..origin/main 触及 state-counts.md(os-regen 面) 0 commits
    base..origin/main 触及本 PR 八条路径中任一             1 commit
    LIT control — base..origin/main 全部 commits         2 commits   ← 零是读数
    

    唯一那 1 条是 #18602,动的是 .changeset/ 下另外两个文件名(18535-*),与本 PR 自己的 changeset 不同名 —— .changeset/ 是目录不是共享文件,各加各的是普通并发。⇒ os-regen 面零移动,四步序无事可做。

    入队

    POST /ccr/ready_for_review → {"draft":false};先复读到 draft:false / mergeable:true / mergeable_state:clean 落定再挂 auto-merge(未落定时挂上的是经典 auto-merge、不入队),PUT /ccr/auto_merge → {"enabled":true}。

    挂载后即时读 timeline:added_to_merge_queue 仍是 0,队列里在跑的是 pr-18610。⚠️ 按平台读数,入队事件与队列 ref 迟 1–3 分钟才出现,⛔ 1 分钟缺席不作「没挂上」;而 auto_merge 字段读回 null 是成功常态,⛔ 不作反证。决断读数是 timeline 事件 + 队列 ref,看护已挂,跟到 origin/main 上的 squash + 单亲为止。


    Generated by Claude Code

  15. os-bill commented on Sep 17, 2026

    @os-bill
    CollaboratorAuthor

    ✅ MERGED —— 三笔治理债全清,PENDING_GOVERNANCE 空了

    domain:spec seat 2(session_01JbZnqu8bt6YqfJsr9vaFb3,座位贴 #18549),R7。⏱️ 本条读数取自同一动作:2026-09-17T09:29Z。

    reading value
    squash commit 559041d39d — feat(spec): govern connector + analytics_cube in the liveness ledger — PENDING_GOVERNANCE reaches empty (#18609)
    parents 单亲
    method git log --oneline origin/main | grep -F '(#18609)',⛔ 非 --grep、⛔ 非 API merged

    主题探针 —— 亮控 ×3 + 暗控 ×3

    LIT   PENDING_GOVERNANCE 在 main 上是 {}                          1
    LIT   GOVERNED 同时含 'connector' 与 'analytics_cube'              1
    LIT   两本台账文件都在                                              2
    DARK  落地 commit 里的 view.zod.ts / build-schemas.ts(必须 0)      0   ← 范围守住
    DARK  sharing_rule 行有没有被改(必须仍是 16/0/0/0/1/17)             1   ← 未被吞改
    DARK  伪造类型 zzNotAType9999(必须 0)                              0
    

    🚨 os-regen 落地后再验一次 —— 这一步不是形式

    packages/spec/liveness/state-counts.md 在 merge=os-regen 清单上,而队列的合并同样走 os-regen,所以入队前查过不等于落地后成立。落地树上重读:

    | `sharing_rule`   | 16 | 0 | 0 |  0 |  1 |   17 |
    | `connector`      | 20 | 0 | 0 | 53 |  1 |   74 |
    | `analytics_cube` | 17 | 0 | 0 | 12 |  0 |   29 |
    | **total**        | **915** | **5** | **1** | **161** | **12** | **1094** |
    

    ⇒ 与入队前逐位一致,兄弟行一条未动。队列没有静默吞边。

    收口

    PR 正文全文扫闭合关键词:只有 Fixes #18582 一处,无 Part of。本卡三笔债全清 ⇒ 该关,已 closed / completed;pm:dispatched 已摘(标签联合先读回再整组写 —— 上一轮本席在这一步凭印象拼过一次,把另一张卡的 p3 写成了 p2,记着)。

    本卡全程

    笔 PR squash
    sharing_rule #18587 e0d05538c0(Part of,卡不关)
    connector + analytics_cube #18609 559041d39d(Fixes,卡关)

    ⭐ Part of 在这张卡上救了一次:第一笔落地时卡还欠两笔,若写成 Fixes 就会被静默关掉。这是本班第四次靠这个拼法避免误关。

    衍生

    立卡三张(#18612 · #18613 · #18614),⛔ 均未定级、未挂 domain:*。check:cross-package-test-inputs 那条 ⛔ 未立孪生 —— 已有 #18353 / #18440。


    Generated by Claude Code

  16. added 4 commits that reference this issue on Sep 28, 2026
    559041d
    3d8779d
    00b38d7
    351a161
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions