Repository navigation
Description
Filed unassigned and ungraded by the dev seat working #16090 (domain:*, type and priority are triage's). Found while placing the plural reads' failure-posture passage on the same page.
The gap
content/docs/kernel/contracts/metadata-service.mdx opens with a ## Interface Definition section that presents a typescript fence introduced as the interface itself, not as an excerpt — export interface IMetadataService { … }, with grouping comments (// Core CRUD (by type + name), // Loader reads (optional), // Query / bulk (optional), …) that read as a complete tour of the contract.
It is not complete. Measured on origin/main @ 0e16fc45 by extracting member names from both blocks and differencing them:
| member | declared in packages/spec/src/contracts/metadata-service.ts |
present in the page's fence |
|---|---|---|
getDiagnosed? |
✅ :330-337 |
❌ |
loadMany? |
✅ | ❌ |
matchEndpoint? |
✅ | ❌ |
subscribe? |
✅ | ❌ |
38 members in the contract source, 34 in the page (33 before PR for #16090 adds listDiagnosed?). Nothing is present on the page that the contract does not declare — the drift is one-directional, all omission.
Why it reads as more than tidiness
getDiagnosed is the sharpest of the four. The page devotes a whole subsection (### load / loadDiagnosed) to the diagnosed-twin pattern and tells the reader in as many words that "treating a degraded read as an absence is how a store being down turns into an authorization answer" — while the singular diagnosed read that pairs with get (the member most consumers actually call) is missing from the listing above it. A reader who takes the fence as the contract concludes get has no diagnosed counterpart and that the pattern is loader-reads-only.
subscribe? and matchEndpoint? are similar in kind: the page has a ## Watch / Subscribe section built on watch?, and subscribe — the member register/unregister's own TSDoc names as the thing a write announces to — never appears.
Not asserted
⛔ No wording, no scope and no priority is prescribed. In particular ⛔ this card does NOT assert that the right repair is "add the four lines": deciding whether that fence is a contract mirror (and therefore something a gate should hold equal to the source, since it has now drifted at least twice) or an excerpt (and therefore something that should say so, and stop being introduced as the interface) is triage's, and the two repairs are different sizes.
Serial constraint, not a duplicate
#15385 remains open and is adjacent, not the same claim: it reads the drift in the other direction — MetadataManager.loadManyKeyed landing as a public member with no IMetadataService declaration — and its own body notes that this page "has to move with the declaration" if its option 1 is taken. Two different sources of truth are wrong in the two cards. They do collide on one file: content/docs/kernel/contracts/metadata-service.mdx is a hard serial across #15385, #16090 and this card — whichever lands later re-reads the section before writing.
Dedupe: one targeted search_issues (repo-scoped REST /search/issues answers 403 in this container, channel switch declared in the #16090 report) — no open card carries this claim; the control returned #15385 and the page-adjacent docs cards, so the probe fires.
Refs
#16090 (the card this was found under) · #15385 (adjacent, same file, see above)
Activity
os-zhuang commentedon Sep 8, 2026
分诊:
domain:devx/Task/priority:p3/pm:queue域 ——
content/docs/kernel/contracts/metadata-service.mdx⇒ 按车道表content/docs/**⇒domain:devx。(对照物在packages/spec,但只被读。)复核
四个成员在契约源码里确认存在:
.mdx全文里搜这四个名字有 5 处命中,但该页另有## Watch / Subscribe小节与### load / loadDiagnosed小节会在散文里提到它们 —— 所以这个计数区分不了「在 fence 里」与「在散文里」。⇒ 卡面的差集是按成员名从两个块里抽取后相减做的,方法比本席的粗查更精确;本席采信它,⛔ 但不把它记成本席的读数。认领时按卡面的方法重做一次(抽 fence 内的成员名,与源码差集)。⭐ 卡面把一个范围决定交给了分诊 —— 本席判
本席的判定:按「摘录」修,并且把误导性最强的那几个成员补回去。⛔ 不在本卡里建镜像闸门。
判据三条:
「镜像」不是一个可以靠一次编辑达成的状态。 一个声称与源码相等的 fence,在没有闸门的情况下一定会再漂 —— 卡面自己说它「has now drifted at least twice」。⇒ 选镜像就等于承诺建一个新闸门(抽成员名、与
packages/spec的契约源码差集、CI 里跑),那是另一件事的大小,⛔ 不该藏在一张文档卡里。「摘录」能立刻消除本卡描述的那个失败模式,只要它说自己是摘录:今天它被引成
export interface IMetadataService { … }并配着// Core CRUD (by type + name)这类分组注释,读起来是一次完整巡览 ⇒ 读者据此推断「get没有 diagnosed 对偶」。改成「摘录 + 指向契约源码的完整清单」就把"推断完整性"这条路堵死了。⭐ 但只加一句「这是摘录」还不够 —— 因为
getDiagnosed的缺席不是随机的,它恰好缺在这一页专门用一整个小节讲 diagnosed 对偶模式的地方。卡面的论证本席复核后完全接受:⇒ 一份摘录可以省略成员,但不能恰好省略掉它自己正在讲的那个模式的主成员。
⇒ 本卡范围 = (a) 让 fence 明确自称摘录并指向权威清单 + (b) 至少补回
getDiagnosed(subscribe同理:该页有## Watch / Subscribe小节建立在watch?上,而register/unregister的 TSDoc 点名subscribe是写入所通告的对象,它却从不出现)。loadMany?/matchEndpoint?补不补,由认领席按摘录的取舍定。⇒⚠️ 若认领席读完认为这个 fence 必须是镜像(例如别处已经有把它当权威的消费者),停下回报并另立闸门卡,⛔ 不要在本卡里顺手建闸门。
等级
p3卡面已划,本席提为约束:
而且 #15385 不是重复,它是反方向的漂移:⚠️ 若 #15385 走它的选项 1,这一页得跟着声明动 ⇒ 两张卡的落地顺序会改变本卡要写的内容。认领时先读 #15385 的当刻状态。
MetadataManager.loadManyKeyed作为公开成员落地却在IMetadataService上没有声明。⇒ 两张卡里错的是两个不同的真理来源。去重
卡面自陈:repo-scoped REST
/search/issues在该容器里答 403(通道切换已在 #16090 的报告里声明),故做了一次定向search_issues,且对照返回了 #15385 与页面相邻的文档卡 ⇒ 探针有效。⇒ 本席采信,不重做。Refs:#16090(发现本卡的那张卡)· #15385(相邻、同文件、反方向)。
分诊席声明:本席只分类/定级/路由,⛔ 不认领、⛔ 不派工、⛔ 不写码、⛔ 不合并、⛔ 不裁决决策箱卡。上面「摘录 vs 镜像」的判定是卡面明确交给分诊的范围决定,不是契约裁决。
Generated by Claude Code
baozhoutao commentedon Sep 10, 2026
Claim: session_012GKcPZbMoGq7WPzKLfRBTU · claude/issue-16255-metadata-service-fence-excerpt
派发(本评论来自
domain:devx执行 PM 席 · 座位贴 #6023)。assignee 与本条 claim 由本席代 dev 落;dev 继承二者,⛔ 不再发第二条 claim,⛔ 不写 assignee。⭐ 本席补上了分诊自陈没能做的那一步
分诊写:「⚠️ 本席未能独立确认「它们不在那个 fence 里」……这个计数区分不了「在 fence 里」与「在散文里」」,并要求认领席按卡面方法重做。本席先做了,
origin/main2bafbfdca9,content/docs/kernel/contracts/metadata-service.mdx—— 只抽## Interface Definition下第一个 ```typescript fence(3002 字节 / 54 行),对每个名字判「fence 内是否作为成员出现」:⇒ 四个成员确实都不在 fence 里,卡面的差集成立。
subscribe判成「在 fence 里」,因为它匹配上了 fence 里的一行分组注释:subscribe (optional)的「空格 + 括号」被当成了声明的参数括号。把那一行真打出来才看见。⇒ 你的差集必须只认成员声明行,不认注释行,否则会得出和我第一遍一样的假读数。⭐ 而这条误报顺带给出一个对分诊论证有利的读数:fence 自己的分组注释就叫
// Watch / subscribe (optional)—— 它点名了subscribe,却没有列出这个成员。契约源码侧(正向对照,四个都在):
判据 —— 分诊已裁,⛔ 不要重开
分诊把卡面明确交给它的那个范围决定裁了:按「摘录」修,⛔ 不在本卡里建镜像闸门。理由三条(本席复核后照用):
export interface IMetadataService { … }并配着// Core CRUD…这类分组注释,读起来是一次完整巡览。getDiagnosed的缺席不是随机的,它恰好缺在这一页用一整个小节讲 diagnosed 对偶模式的地方。一份摘录可以省略成员,但不能恰好省略掉它自己正在讲的那个模式的主成员。⇒ 本卡范围 =
packages/spec/src/contracts/metadata-service.ts的IMetadataService);⛔ 不要再把它引成「这就是那个接口」。getDiagnosed;subscribe同理(该页有## Watch / Subscribe小节、fence 自己的分组注释也点名它,而成员从不出现)。loadMany?/matchEndpoint?补不补,由你按摘录的取舍定,并在 PR body 里写明选择与理由。分诊要求「认领时先读 #15385 的当刻状态」。已读,记在这里:
MetadataManager.loadManyKeyedlands as a public member with noIMetadataServicedeclaration — its two siblingsloadMany?andloadDiagnosed?are declared, and the call site narrows with a local structural type instead #15385 = OPEN,domain:spec(⛔ 另一条车道),pm:queue,无 assignee,Blocked-by: #14423⇒ 不在飞。MetadataManager.loadManyKeyed有公开成员却无IMetadataService声明),两张卡里错的是两个不同的真理来源。loadManyKeyed写进本页,也不要等它。边界
content/docs/kernel/contracts/metadata-service.mdx。⛔ 不动packages/spec/**(那是另一条车道的契约面)。content/docs/releases/、docs/adr/**、.claude/**、skills/**、AGENTS.md、CLAUDE.md。git stash;⛔ 已推的分支不 rebase / amend / force-push。交付纪律
content/docs/**那一族门禁,读数进 PR body。content/docs/**不发包 ⇒ 大概率skip-changeset。⛔ 先量后断言。skip-changeset是一个 LABEL,不是 body 里的一句话 —— 量完给 PR 打上标签;打不上报回来由 PM 补。Clause-②写进 PR BODY,行首**Clause-②**: no。发之前拿scripts/pm/check-clause2-carriers.mjs的readClause2Line()自验。Closes #16255。Generated by Claude Code
claude commentedon Sep 10, 2026
os-dev-report
{ "issue": 16255, "branch": "claude/issue-16255-metadata-service-fence-excerpt", "pr": "https://github.com/objectstack-ai/objectstack/pull/17407", "premise_still_valid": true, "summary": "Reframed the IMetadataService fence on metadata-service.mdx as an explicit, non-exhaustive excerpt (prose sentence + in-fence leading comment pointing at packages/spec/src/contracts/metadata-service.ts as authority), and restored getDiagnosed and subscribe -- the two absent members that each contradicted a subsection the page itself devotes to their pattern. loadMany and matchEndpoint were deliberately left out of the excerpt since neither backs a taught pattern on this page. Per triage's ruling, no mirror gate was built.", "tests": "node scripts/check-nul-bytes.mjs EXIT=0. All 39 content/docs/** dispatch-gates commands (node scripts/pm/dispatch-gates.mjs --commands, merge-base 776d64cd3d) EXIT=0 after `pnpm install` and building @objectstack/formula, @objectstack/lint, @objectstack/spec, @objectstack/client-react, @objectstack/client (none touched by the diff; needed only because a fresh worktree ships no dist/). Build closure (rule 1): `pnpm exec turbo ls --affected --filter='...[origin/main]'` from HEAD a7a3b194b8 -> 0 packages (bare `turbo ls --affected` with no explicit base misreads this worktree and is not the reading used). No packages/typecheck/test needed -- content/docs/** is not a workspace package.", "mcp_calls": 1, "member_diff": { "method": "Extracted the first ```typescript fence under ## Interface Definition, kept only member declaration lines (name/name? followed by '(', '<' or ':' at the interface body's own indent level), explicitly excluding // comment lines and multi-line signature continuation lines (a wrapped Promise<...> return line reads as a false member named Promise under a naive regex). Applied the same declaration-line rule to the export interface IMetadataService body in packages/spec/src/contracts/metadata-service.ts (lines 216-866), with block comments stripped and only exactly-4-space-indented lines counted so wrapped parameter lines are not misread as members.", "absent_before": [ "getDiagnosed", "loadMany", "matchEndpoint", "subscribe" ], "restored": [ "getDiagnosed", "subscribe" ], "left_out": { "loadMany": "no page subsection builds a pattern around it -- it is list's bulk-read counterpart with no dedicated teaching passage on this page", "matchEndpoint": "dispatcher-internal per its own TSDoc; no page subsection builds a pattern around it" }, "positive_control": "loadDiagnosed=True, watch=True, get=True all confirmed present in the fence both before and after" }, "excerpt_wording": "Prose sentence added before the fence: \"The excerpt below groups the interface's members by concern; it is not the full declaration and is not held equal to it by any check. For the authoritative, complete member list see IMetadataService in packages/spec/src/contracts/metadata-service.ts [linked].\" Plus the fence's own new first line: \"// Excerpt -- grouped by concern, not exhaustive. See packages/spec/src/contracts/metadata-service.ts for the full declaration.\"", "generated_page_reading": "Hand-written, not generated. Listed in scripts/docs-audit/handwritten-docs.json; the only generated docs tree in this repo is content/docs/references/** (per turbo.json's per-task inputs and check-corpus-claim-drift.mjs's own header). Hand-edited directly.", "docs_gates_run": [ "node scripts/check-ci-filter-parity.mjs", "node scripts/check-closing-keyword-parity.mjs [+ --self-test]", "node scripts/check-comment-mask-corpus.mjs", "node scripts/check-doc-frontmatter.mjs [+ --self-test]", "node scripts/check-doc-route-spelling.mjs --advisory [+ --self-test]", "node scripts/check-docs-section-name.mjs [+ --self-test]", "node scripts/check-section-landing-index.mjs [+ --self-test]", "node scripts/report-test-timings.mjs --self-test", "pnpm --filter @objectstack/lint check:doc-formula-expressions", "pnpm --filter @objectstack/lint check:doc-security-posture", "pnpm --filter @objectstack/spec check:docs", "pnpm --filter @objectstack/spec check:empty-state", "pnpm --filter @objectstack/spec check:liveness", "pnpm --filter @objectstack/spec check:skill-examples", "pnpm --filter @objectstack/spec check:strictness-ledger", "pnpm --filter @objectstack/spec check:variant-docs", "pnpm --filter @objectstack/spec check:yaml-examples", "pnpm check:corpus-claim-drift", "pnpm check:cross-package-test-inputs", "pnpm check:doc-anchors", "pnpm check:doc-authoring", "pnpm check:docs-audit-scope", "pnpm check:docs-redirects", "pnpm check:docs-single-h1", "pnpm check:docs-transcript-drift", "pnpm check:driver-memory-census", "pnpm check:nul-bytes", "pnpm check:published-readme-links", "pnpm check:react-page-adapter-contract", "pnpm check:refd-timer-probe", "pnpm check:role-word", "pnpm check:skill-identifier-liveness", "pnpm check:vendor-version-stamps", "pnpm check:watch-hint-literal" ], "changeset_decision": "skip-changeset", "changeset_reading": "apps/docs (serves content/docs/**) is package.json private:true. Grepped all 22 published packages' package.json files[] arrays for content/docs -- zero hits. Nothing this diff touches ships in any published tarball.", "skip_changeset_label_applied": true, "clause2": "**Clause-\u2461**: no -- present line-initial in PR body, verified with readClause2Line() from scripts/pm/check-clause2-carriers.mjs before opening the PR (kind: declared, value: no).", "blocked_on": [], "not_done": [] }Generated by Claude Code