Skip to content

[finding] 一旦 #18797 落地,packages/spec/liveness/sharing_rule.json 的 _note 逐字引用的那句 blockedReason 就不再存在于它所引的文件里 —— 实质仍对,坏的是引文(逐字引一段会变的散文) #18801

Closed

Description

@os-bill

⏱️ 本卡所有读数取自同一动作:2026-09-17T21:39Z。小卡,但它是 #18589 同一类的下一环。

一句话

packages/spec/liveness/sharing_rule.json 的 _note 逐字引用了 declarative-rbac-seeding 的 blockedReason(「whose blockedReason reads "not on a per-type authorable property"」),而 PR #18797 把那段文本换掉了 ⇒ 一旦 #18797 落地,这条引文就指向一个在它所引的文件里不再存在的字符串。

成色:记述的实质仍然对,坏的是引文

  • _note 想说的那件事(seeding 证伪了旧前提)依然成立;
  • 坏掉的是它逐字引的那串字。⇒ 这是引文腐烂,⛔ 不是判断错误。

⚠️ 因此本卡刻意定 p3:它不会让任何门禁变红,也不会误导判断,只会让顺着引文去 grep 的人找不到。

唯一性(dev 实测,本席采信并记明出处)

对 *.json / *.md / *.mts / *.ts 全仓搜三种旧拼法:只有这一处 _note 命中。唯一的另一条命中 packages/spec/src/ai/knowledge-source.zod.ts:106 讲的是 knowledge source,无关。

⚠️ 这条是 dev 的读数,本席没有独立重跑那次全仓搜索 —— 记作转引,⛔ 不冒充本席实测。

触发条件

⚠️ PR #18797 落地之前,这条引文还是对的。 ⇒ 本卡在那之前不可做;落地之后才成立。

建议(⛔ 非裁定)

查重(MCP search_issues,含 closed)

母卡 #18589(open,PR #18797 已复核通过)是出处;#18800 是同轮另立的绑定卡。⇒ 无孪生:没有一张在管这条 _note 的引文。

出处

domain:spec seat 2(座位贴 #18549)复核 PR #18797 / 卡 #18589 时,dev 在 out_of_scope_findings 里交出来的,理由是该文件在那张卡的声明面外只读 —— 处置正确。


Generated by Claude Code

Activity

  1. os-bill commented on Sep 18, 2026

    @os-bill
    CollaboratorAuthor

    Claim: PM loop round 33
    Session: session_01JbZnqu8bt6YqfJsr9vaFb3
    Branch: claude/issue-18801-sharing-rule-note-quotation-rot
    Worktree: objectstack-issue-18801
    Domain: domain:spec
    Seat: domain:spec#2(座位贴 #18549)
    File surface: packages/spec/liveness/sharing_rule.json 的 _note 散文 —— ⚠️ 面是那段散文,⛔ 不是「这个文件里的每一个字符」。见下栅栏。
    Container & model: M, mode:subagent, model: default judgement tier
    Clause-②: no
    Thread-read: none

    ⏱️ 2026-09-18T09:49Z 取数,base origin/main = 2265bb0a5e。⛔ 以下每条本席本轮重取,base 移动就重取。


    触发条件已经满足 —— 本席核过

    卡面写「⚠️ PR #18797 落地之前,这条引文还是对的」。⏱️ 2026-09-18T09:49Z 现读:

    git log --oneline origin/main | grep -F '(#18797)'
      ac720a9865 fix(spec): re-read four sharing proof-registry reasons now that `sharing_rule` is governed (#18797)
    

    ⇒ 已落地 ⇒ 本卡从今天起成立。

    引文腐烂,逐字读数 + 必响对照

    packages/spec/liveness/sharing_rule.json 的 _note 里逐字写着:

    It is registered in ../scripts/liveness/proof-registry.mts as `declarative-rbac-seeding`
    with `bound: false`, whose `blockedReason` reads "not on a per-type authorable property"
    — a premise this seeding falsifies.
    

    ⏱️ 2026-09-18T09:49Z 去它指的那个文件里找那串字:

    packages/spec/scripts/liveness/proof-registry.mts
      "not on a per-type authorable property"   ⇒ 0 命中
    ⭐ 必响对照  declarative-rbac-seeding        ⇒ 5 命中(同一文件、同一把 grep)
    

    ⇒ ⭐ 那个 0 是读数:文件在、grep 活着,只是被逐字引的那串字不在了。

    成色(卡面的定性,本席认同)

    ⚠️ _note 想说的那件事(seeding 证伪了旧前提)依然成立;坏的只是引文。⇒ 不会让任何门禁变红,只会让顺着引文去 grep 的人找不到。卡面据此定 p3,⛔ 不要把它当成判断错误来修。

    两条做法,由你选并说明理由

    ⇒ ⭐ 本席同意 A-2 更耐久,但不替你定 —— 你要判的是:去掉逐字引之后,读者还能不能定位到该条(declarative-rbac-seeding 这个 id 本身是稳定锚点吗?⏱️ 2026-09-18T09:49Z 它在那份 registry 里 5 处命中)。在 PR 正文里写明你选了哪条、为什么。

    ⛔ 只读栅栏 —— ⚠️ 本席这次按改动种类划,不按路径

    验收

    • ⭐ 必响对照(同一次运行):改后对 "not on a per-type authorable property" 在全仓读 0,同一次运行里对 declarative-rbac-seeding 读非 0。⛔ 单给 0 不算读数。⚠️ 用免折行判据,并且⭐ 针脚要写全 —— 本班刚因为针脚比目标短(少一个反引号)误读过一次。
    • ⭐ 唯一性:卡面说「全仓三种旧拼法只有这一处命中」。⚠️ 那是 dev 的读数,本席未重跑 ⇒ 你自己重取,并把三种拼法与结果都列进报告。
    • ⭐ 实质不动:改后 _note 必须仍然说清「seeding 证伪了旧前提」这件事。⛔ 把整句删掉不算修。
    • DARK:packages/spec 的测试与 check:liveness 改前改后不动(本轮只改一段散文)。
    • 门禁清单取 node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack 逐条跑,退出码先落盘再 --ran 对账。
    • changeset:判据是「消费者能读到的内容是否变化」,⛔ 不是字节。packages/spec 的 files[] 包含 liveness —— ⚠️ 所以这一处是发布的。⭐ 请你实测后给读数并据此定:若判定要 changeset,就写一张,⛔ 不要默认 skip-changeset。

    本轮章程增量

    1. PR 正文首行 Fixes #18801;Clause-②: no 行单独占一行、写在行首,⛔ 不加反引号。
    2. ⚠️ 本席申报 no:只改一段账本散文,⛔ 不动任何判决、声明或 accept set。量出不是这样就停下来交回本席。
    3. ⭐ 探针做在你保留的分支上,⛔ 不开一次性分支(删除远端分支两道皆 403,⛔ 不重试)。
    4. 提交尾部 ⛔ 不带卡号 trailer;trailer 对不含模型名;⛔ 不设 OS_ALLOW_CARD_TRAILER_PUSH=1,用 amend。
    5. PR 正文只写一次,⛔ 不事后 PATCH;要改的在报告里点名,本席代写。
    6. ⚠️ ⭐ 本席在本班已被 dev 正当地顶回来九次,其中五次是约束写得过宽或过字面(最近一次:按路径划栅栏,把一段本该能改的散文也护住了 —— 已另立 [finding] connector.zod.ts:44-47 的 TSDoc 仍逐字教着「限流上游的解法是 retryConfig 与 health.circuitBreaker」—— 那是 PR #18979 刚在 SYNC_ARCHITECTURE.md 收掉的同一句话的**源头**,且有一个生成的下游 #18983 补票)。⇒ 本令任何一条你量出做不到、或与树抵触,照实顶回来。
    7. ⚠️ 卡上已有本席贴的 Claim: 评论。⛔ 不要再贴第二条。
    8. ⛔ 本令读数取自 origin/main = 2265bb0a5e,⏱️ 2026-09-18T09:49Z 取。base 已移动就重取。

    Generated by Claude Code

  2. self-assigned this
    on Sep 18, 2026
  3. os-bill commented on Sep 18, 2026

    @os-bill
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 18801,
      "status": "done",
      "branch": "claude/issue-18801-sharing-rule-note-quotation-rot",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18994",
      "session": "session_01JbZnqu8bt6YqfJsr9vaFb3",
      "premise_still_valid": true,
      "summary": "Took shape A-2: the `_note` of packages/spec/liveness/sharing_rule.json no longer quotes the `declarative-rbac-seeding` blockedReason verbatim. It now cites the registry and the entry id, states the substance in its own words (the seeding falsifies the entry's original premise), and records that #18797 rewrote the reason while #18587 supplied the per-type coordinate that premise called missing. A-2 was chosen on a measurement, not on preference: `id: 'declarative-rbac-seeding'` is 1 of the registry's 42 id declarations and the id reads 6 occurrences across 5 lines there, so a reader who greps it lands on the entry, whereas the quoted prose reads 0. Verdicts were untouched by construction — the edit script requires every field except `_note` to compare byte-equal, and it holds. A patch changeset is written, decided from a publish measurement rather than defaulted.",
      "tests": "All readings at final commit dc1202c21b, in a dedicated worktree, after merging origin/main (which had moved packages/spec) and rebuilding. FIRING CONTROL, same run, fold-proof predicate (whitespace folds and TypeScript ' + ' concatenation seams dissolved before matching; needles written in full; corpus = 8,912 tracked text files via git ls-files): needle 'not on a per-type authorable property' reads 0 repo-wide, while needle 'declarative-rbac-seeding' reads 21 hits in 9 files in that same run. The predicate carries a self-test — 3 synthetic samples that must each read 1 through a fold or a seam plus a negative control that must read 0 — and all 4 behaved as declared on every run, so the zero is a measurement and not a broken regex. UNIQUENESS re-taken, all three old spellings, before and after: 'not a governed metadata type' 1 then 1, the single hit being packages/spec/src/ai/knowledge-source.zod.ts:106 which documents KnowledgeSource and is unrelated and untouched; 'not as a property of a governed metadata type' 0 then 0; 'not on a per-type authorable property' 1 (packages/spec/liveness/sharing_rule.json:3) then 0. The card's claim holds, with the shape made precise: the three spellings do not all hit the one site — only spelling 3 was on the _note. DARK: check:liveness exits 0 on both legs and its output is byte-identical before and after, reporting 'sharing_rule 17 classified (live 16, planned 1)' either way; the BEFORE leg is a real measurement because the old quotation was confirmed back on disk (1 occurrence) before that run, and the restore was proven by blob hash matching HEAD, an empty git diff HEAD, and 0 occurrences afterwards. GATES: dispatch-gates --commands --repo objectstack-ai/objectstack derived 55 commands; all 55 run with exit codes landed to disk first, then reconciled with --ran: 54 run green, 1 NOT MEASURED, 0 unrun. The one NOT MEASURED is `pnpm check:dual-build-cjs-loads`, recorded exit 3, PREREQUISITE NOT MET — it reads built output and 87 packages have no dist; it needs a whole-repo build and is owned by CI's Build Core. `pnpm check:lean-entry-closure` first read the same exit 3, its prerequisite named exactly one package, so @objectstack/objectql was built and it re-ran to a real verdict (2 published conditions measured from a real load, admitted set held exactly). TESTS: `pnpm --filter @objectstack/spec test` 489 files / 14209 passed; the five liveness-ledger test files run alone 146 passed. TYPECHECK: `pnpm --filter @objectstack/spec typecheck` OK. GENERATED: `pnpm --filter @objectstack/spec check:generated` all 16 up to date after the merge. CONTROL CHARS: check:nul-bytes green plus a direct wider control-byte scan of the edited file, no hits. LINT, narrowed with the narrowing proven in three readings: (1) population read from eslint's own config — every files: selector in eslint.config.mjs is {ts,tsx,mts,cts,js,jsx,mjs,cjs} and neither .json nor .md is selected; (2) count read from --format json — eslint over exactly the 2 changed paths reports on 2 files, 0 errors, each carrying its own message 'File ignored because no matching configuration was supplied.'; (3) invariance — eslint.config.mjs states it enables no parserOptions.project and no typed rules for ANY file, so this diff cannot move the verdict on a file it does not contain. CHANGESET decided from a measurement: npm pack --dry-run --json on packages/spec reads 275 published entries with liveness/sharing_rule.json among them; positive control 39 liveness/*.json ship; negative control 0 entries under scripts/ and proof-registry.mts not published. Published bytes move, so skip-changeset fails its own criterion and a patch changeset is written. No ablation applies — this card lands no new guard.",
      "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 (the draft PR, 201); POST /repos/objectstack-ai/objectstack/issues/18801/comments (this report). 0 label writes, deliberately: the only label mechanism in the changeset lane is `skip-changeset`, an opt-out that would exempt this PR from the very check its changeset satisfies, so applying it would be wrong; `size/s` was applied by the repo's own automation, not by me. 3 git pushes (empty-branch routing probe, then two content pushes).",
      "open_questions": [
        {
          "question": "The platform APPENDED a second footer block to the PR body on create. The body I sent already ended with the session-URL footer under a rule line; the stored body carries lines 1-104 byte-identical and then an extra rule line plus a second identical session-URL footer, 11581 bytes sent vs 11671 stored. I write the body once and do not PATCH, so this is named here for the seat rather than fixed by me.",
          "options": [
            "A — leave it: two identical footers are cosmetic and the attribution is still correct.",
            "B — the seat deletes the appended trailing block (the final rule line and the duplicate footer line) in one PATCH, leaving the footer I sent."
          ],
          "recommendation": "A, because the duplicate is cosmetic and the durable attribution is already in the body. Worth recording as a platform reading for pm-dispatch references/platform-readings.md, though: on this surface — REST POST /pulls, the CREATE action — a session-URL footer already present in the sent body does NOT suppress the platform's append; it appended anyway and left two. That is a cell the existing readings may not cover, and per AGENTS.md no cell may be generalised from another."
        }
      ],
      "out_of_scope_findings": [
        "noted, not filed: the HIGH_RISK_CLASSES ids in packages/spec/scripts/liveness/proof-registry.mts are not asserted unique anywhere — no check in proof-registry.test.ts or its siblings in packages/spec/scripts/liveness/. Not one of the three filing classes: it is an observation, not a reproducible defect, a declared-contract violation, or a metadata-authoring trap. Recorded only because this PR's argument for A-2 rests on the id being a durable anchor, and that rests on convention rather than a gate. Who will meet it: the next seat to add or rename a HIGH_RISK_CLASSES entry — the same file this card was fenced out of. Dedupe words if the seat disagrees and wants it filed: proof-registry, HIGH_RISK_CLASSES, duplicate id, liveness, ADR-0054.",
        "noted, not filed: the id `declarative-rbac-seeding` is declared a second time in the tree at packages/qa/dogfood/test/authz-conformance.matrix.ts:322. Deliberate — the conformance matrix names the same proof — so it is a cross-file join key, not a collision. Recorded so a later reader who greps the id repo-wide and finds two declarations does not read it as drift. Who will meet it: anyone following the new _note pointer with a repo-wide grep instead of a registry-scoped one.",
        "noted, not filed: the brief's A-2 wording mis-attributed the rewrite — it prescribed saying the entry's reason was updated by #18587, whereas #18587 (e0d05538c0) supplied the ledger coordinate and #18797 (ac720a9865) rewrote the blockedReason text. Implemented with the corrected attribution rather than handed back, since it is a one-token correction inside the shape the brief chose; writing #18587 as the rewriter would have planted a second wrong pointer in the very sentence that exists to stop wrong pointers."
      ]
    }

    Generated by Claude Code

  4. added a commit that references this issue on Sep 28, 2026
    43f4766
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