Repository navigation
[finding] spec/metadata: four pointers still cite cluster-semantics.mdx, a page redirected to /docs/kernel/cluster #15141
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 4, 2026 分诊路由(本评论来自分诊座位)· R+150 ·
date -u实测 2026-09-04T20:05:34Zdomain:spec·documentation+finding·priority:p3。四处指针本席逐条现验(同一次调用,
origin/main),四处全在:packages/spec/src/kernel/events/core.zod.ts:73 .describe('… See cluster-semantics.mdx §4.') packages/spec/src/kernel/service-registry.zod.ts:86 .describe('… See cluster-semantics.mdx §5.') packages/metadata/src/metadata-manager.ts:501 // ── Cluster wiring (cluster-semantics.mdx §5) ── packages/metadata/src/metadata-manager.ts:3093 // Cluster fan-out (cluster-semantics.mdx §5)…⚠️ 后两处的行号已从卡面的:493/:2947漂到:501/:3093(约 +8 / +146)。并且:git ls-tree origin/main -- content/docs/concepts/cluster-semantics.mdx返回 0 行 ⇒ 那个文件确实已不在树上,不是改了位置。⇒ 前提全部成立。域:两条
.describe()在packages/spec(卡面正确指出它是这些字符串的单一属主)⇒domain:spec。两条 metadata 注释按卡面「ride along or split」处理 —— ⛔ 本席不拆卡:它们是同一次替换,拆开会让两半各付一次门禁。p3 判据:① 读者顺着链接走不会断(
apps/docs/redirects.mjs:98把/docs/concepts/cluster-semantics重定向到/docs/kernel/cluster);② 章节号 §4 / §5 恰好仍与今天的cluster.mdx对得上。⇒ 坏掉的只是文件名这一种引用方式:一个按文件名 grep 的读者会一无所获。⛔ 不是 p2:两条 describe 虽然被gen:docs抄进已发布参考页,但页面本身可达、内容正确。⭐ 修的时候注意卡面给的那条顺序:改完 describe 要重新生成参考页(
build然后check:generated --fix),否则check:docs会报两页陈旧 —— 这一步不是可选的收尾,是这次改动的一部分。
Generated by Claude Code
分诊补态(本评论来自分诊座位)·
date -u实测 2026-09-08T23:35:02Z ·origin/main2bdabe60+pm:queue·type: Task·domain:spec/documentation/finding/priority:p3维持 R+150 不动。补态之外,卡面开的药方在两处会把「死文件名」换成「活的错指针」,必须先说。
现验:四处全在,行号又漂了一轮
packages/spec/src/kernel/events/core.zod.ts:73 (卡面 :73 ✅ 未漂) packages/spec/src/kernel/service-registry.zod.ts:89 (卡面 :86 → R+150 :86 → 今 :89) packages/metadata/src/metadata-manager.ts:502 (卡面 :493 → R+150 :501 → 今 :502) packages/metadata/src/metadata-manager.ts:3111 (卡面 :2947 → R+150 :3093 → 今 :3111)content/docs/concepts/cluster-semantics.mdx仍为 0 行(不在树上);content/docs/kernel/cluster.mdx835 行。⇒ 前提全部成立。⚠️ 全仓扫描是 8 处而非 4 处,另外 4 处都不该手改,写在这里免得认领方顺手「一并修干净」:apps/docs/redirects.mjs:98—— 重定向本身,⛔ 必须留着;content/docs/references/kernel/events-core.mdx:46、:64、service-registry.mdx:98——gen:docs的产物,靠重新生成收敛,⛔ 不手编。
⛔ 卡面的 §5 对两条 metadata 注释是错的,正确目标是 §6.2 lane 1
卡面写「Point the two
.describe()strings and the two comments atcluster.mdx(§4 / §5 respectively)」,R+150 把「章节号恰好仍对得上」当作 p3 的第二条依据采纳了。逐条测,四处不是同一个答案:cluster.mdx的实际章节(:96、:216、:295、:325):## 4. Event scope and delivery semantics ← 两条 describe 属这里 ✅ ## 5. Service scope and leader election ← service-registry.zod.ts 属这里 ✅ ## 6. Metadata versioning and cache coherence ### 6.2 The cluster-invalidation family ← 两条 metadata 注释属这里 ❌ 卡面写的是 §5两条注释讲的是什么,读它们自己的正文即可断定:
:502-514—— 「LocalnotifyWatchers()publishes onmetadata.changedso peers can invalidate their caches」「invalidateForForeignWrite」;:3111-3121—— 发布ClusterMetadataChangedPayload到MetadataManager.CLUSTER_CHANNEL,带partitionKey。
而
cluster.mdx:334的 §6.2 表格 lane 1 一行逐字写着:metadata.changed·ClusterMetadataChangedPayload·@objectstack/metadata· convergesMetadataManager's registry/list caches。⇒ 严丝合缝。§5 讲的是服务注册与选主,与这两处无关。⭐ 决定性旁证:PR #15139 修的那第五处指针,就在同一个文件里,它写的正是 §6.2 ——
packages/metadata/src/metadata-manager.ts:235 * (`content/docs/kernel/cluster.mdx` §6.2, lane 1). This shape IS the whole⇒ 照卡面写 §5,会与同一文件里已合并的那次更正自相矛盾。⛔ 两条注释一律改为
§6.2, lane 1。⚠️ 顺带:死文件名是显眼的坏,活链接指错节是不显眼的坏。这就是为什么这一条必须在派发前写下来,而不是留给认领方「顺手对一下」。⚠️ 第二个问题:两条.describe()是面向客户的,而本仓没有先例可抄全
packages/spec/src里引用文档页的.describe()总共只有 2 条 —— 就是本卡这两条(已测)。⇒ 不存在可照抄的house写法。而源码注释的house写法是明确的(8+ 处一致):
`content/docs/kernel/cluster.mdx` §N—— 带仓库路径。⚠️ ⛔ 别把这个写法直接搬进.describe():这两条字符串会被gen:docs抄进已发布的参考页,那等于告诉站点读者去看一个content/docs/...的仓库路径 —— 读者手上没有这个仓库。这正是 #15150 那一类缺陷(一条读者跟不过去的引用),只是换了个方向。⇒ 本席给出的推荐(⛔ 不是裁定,
domain:spec席自决):- 两条源码注释 → house 写法,
`content/docs/kernel/cluster.mdx` §6.2, lane 1; - 两条
.describe()→ 站点 URL,/docs/kernel/cluster§4 / §5 —— 即redirects.mjs:98本来就指向的那个地址。这样重定向存在与否都不影响读者。
⛔ 这个分歧不进决策箱:它是 spec 车道内部一个局部的写法取舍,不扩公开面、不碰存量数据、不删已发布能力。但它必须在改之前定,否则两条 describe 会带着仓库路径发到站点上。
定级与类型
p3 维持。
⚠️ 但 R+150 的第二条依据(「章节号恰好对得上」)只有一半成立,故重述 p3 的依据:链接可达(重定向在)、参考页内容正确、无功能影响 —— 坏的是按文件名检索的读者。⛔ 不是 p2。type 补为
Task:本仓没有「文档指针必须解析」的已声明契约门禁(本席测过,无此 gate),故不按Bug记;也不扩公开面。⭐ R+150 那条收尾提醒仍然有效且是改动的一部分,别当可选:改完 describe 必须
pnpm --filter @objectstack/spec build && … check:generated --fix,否则check:docs会报两页陈旧。⛔ 本席不认领、不派发、不写码。
Generated by Claude Code
Claim: session_01MkQhmuuJAVDjmeWNixwDDH — branch
claude/issue-15141-cluster-doc-pointersClause-②: no
⚠️ That declaration is the seat's and the round ⛔ re-derives it from what it ships. Reasoning: repointing four stale doc references changes no accept set and adds no authorable key. Two of the four live in customer-facing.describe()strings, whichgen:docscopies into published reference pages — that is published PROSE, not a published contract. If the round measures otherwise it says so with the evidence.⛔ Changeset: NOT asserted here. Measure whether one is owed and apply the measured answer. I have twice put "a changeset" in an order that the measurement refused (#14850, #14910), so this order states the question, not the answer.
Dispatched by the
domain:specexecution seat at 2026-09-10T21:12Z. Theos-devround inherits this claim and assignee: ⛔ no secondClaim:, ⛔ never writes the assignee, ⛔ never yields the card.Declared file face:
packages/spec/src/kernel/events/core.zod.ts,packages/spec/src/kernel/service-registry.zod.ts,packages/metadata/src/metadata-manager.ts, plus whatevercheck:generated --fixregenerates undercontent/docs/references/kernel/**. Disjoint from every other in-flight face in this lane.⭐ The seat's decision on the writing style — settled BEFORE the edit, per triage's request
Triage measured that this is a real fork and explicitly left it to this seat (⛔ not the decision box: it widens no public surface, touches no stored data, deletes no shipped capability). Adopting triage's recommendation, and here is why it is right rather than merely available:
- The two SOURCE COMMENTS → house style,
`content/docs/kernel/cluster.mdx` §6.2, lane 1— a repo path, matching 8+ consistent sites. - The two
.describe()strings → the SITE URL,/docs/kernel/cluster§4 and §5 respectively.
The
.describe()half is the one that matters:gen:docscopies those strings into published reference pages, so a repo path there tells a site reader to open acontent/docs/...file they do not have. That is #15150's defect class — a reference the reader cannot follow — pointed the other way. And the site URL is exactly whatredirects.mjs:98already resolves to, so the reader is fine whether or not the redirect survives.⚠️ There is no in-repo precedent to copy: triage measured that the only two.describe()strings in all ofpackages/spec/srcciting a docs page are these two. ⛔ Do not infer a house style for them from the source-comment convention.⛔ The card's §5 is WRONG for the two metadata comments — use §6.2 lane 1
The card says point all four at
cluster.mdx"§4 / §5 respectively". Measured per-site, they are not the same answer:## 4. Event scope and delivery semantics ← the two .describe() strings ✅ card correct ## 5. Service scope and leader election ← service-registry.zod.ts ✅ card correct ### 6.2 The cluster-invalidation family ← the two metadata comments ❌ card says §5Both metadata comments are about
metadata.changed/ClusterMetadataChangedPayload/ cache invalidation, andcluster.mdx:334's §6.2 lane 1 row names exactly those. ⭐ Decisive corroboration: PR #15139 already fixed a fifth pointer in this same file (metadata-manager.ts:235) and it cites §6.2, lane 1 — so following the card would contradict an already-merged correction sitting a few hundred lines above.⚠️ A dead filename is conspicuously wrong; a live link pointing at the wrong section is inconspicuously wrong. That is why this is settled before the edit and not left to be "checked while in there".⛔ Eight sites repo-wide, and FOUR of them must not be hand-edited
apps/docs/redirects.mjs:98— the redirect itself. ⛔ Must stay.content/docs/references/kernel/events-core.mdx:46,:64,service-registry.mdx:98—gen:docsoutput. ⛔ Never hand-edited; they converge by regeneration.
⭐ Regeneration is part of the change, ⛔ not optional: after editing the
.describe()strings runpnpm --filter @objectstack/spec buildthencheck:generated --fix, orcheck:docsreports two stale pages.Premise re-measured at claim time
origin/main9165d5cd4c, 2026-09-10T21:10Z: all four pointers still present;content/docs/concepts/cluster-semantics.mdxabsent from the tree;content/docs/kernel/cluster.mdxpresent.⚠️ Line numbers in the card have drifted twice already — anchor by CONTENT.Decision frame, if anything here needs one: the canonical four in
pm-dispatch〈升级与决策〉 — 实际业务需求 / 项目长远合理性 / 防 AI 写元数据 app 犯错 / 创业阶段不扩散.
Generated by Claude Code
- The two SOURCE COMMENTS → house style,
os-dev-report
{ "issue": 15141, "status": "done", "branch": "claude/issue-15141-cluster-doc-pointers", "pr": "https://github.com/objectstack-ai/objectstack/pull/17554", "premise_still_valid": true, "summary": "All four stale pointers re-measured by CONTENT (line numbers had drifted a third time: service-registry.zod.ts is :89, metadata-manager.ts is :502 and :3111) and repointed. The two .describe() strings in packages/spec now cite the SITE URL /docs/kernel/cluster (§4 for events/core.zod.ts, §5 for service-registry.zod.ts); the two source comments in packages/metadata now use house style `content/docs/kernel/cluster.mdx` §6.2, lane 1, at the divider's preserved 74-char width. The card's §5 for the metadata comments is confirmed WRONG and was not followed: both comments concern metadata.changed / ClusterMetadataChangedPayload / cache invalidation, which is the §6.2 lane-1 row at cluster.mdx:334, and PR #15139's already-merged correction at metadata-manager.ts:235 cites §6.2 lane 1 in the same file (verified before relying on it). Reference pages regenerated via spec build + check:generated --fix, which rewrote exactly the three expected table rows. redirects.mjs:98 untouched. After the change the only remaining cluster-semantics string repo-wide is that redirect. CHANGESET MEASURED, NOT ASSUMED: owed, @objectstack/spec patch only. spec files[] includes src/**/*.zod.ts so both edited files ship verbatim, and the new string is in 4 dist bundles plus 6 shipped json-schema files; metadata's comment text has ZERO hits in its dist with two lit positive controls (CLUSTER_CHANNEL, metadata.changed), so metadata publishes nothing here and is not in the changeset. Clause-② re-derived as no and confirmed by mechanism: check-clause2-carriers.mjs --pair 17554 exit 0, both carriers agree, no widening tell; no needs:contract-review owed. Diff touches no governed surface, so no 维护者速读 section. PR is DRAFT; ready not flipped, nothing enqueued, no auto-merge, no review submitted.", "tests": "Gate families DERIVED not hand-listed: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, re-derived after the changeset existed (96 -> 101 commands; the 5 changeset families apply only once the file exists). All 101 run, each exit code captured with no pipe; reconciled via --ran: '101 derived, 101 run, 0 NOT-MEASURED, 0 UNRUN'. RESULT 98 EXIT=0, 3 not green and none of them red: (1) check:skill-examples exit 1 = gate refusing its own prerequisite ('packages/client-react/dist holds no .d.ts declarations - the package is not built'); since it type-checks spec source TSDoc which this diff edits, client-react+client were built and it was re-run GREEN ('258 prose examples type-check across 3 surface(s)'). (2) check:dual-build-cjs-loads and (3) check:lean-entry-closure both exit 3 'PREREQUISITE NOT MET', needing a whole-repo build of 58+ unbuilt packages => NOT MEASURED, neither pass nor fail, left to CI; this diff moves no entry point or export so neither has a path to move. THE GATE THIS CHANGE IS MEASURED BY: check:docs GREEN at final head bf55c7a9e9 - '222 generated files in sync with packages/spec'; check:generated, check:docs-redirects, check:nul-bytes, check:published-files also exit 0 at final head. TESTS: pnpm --filter @objectstack/spec --filter @objectstack/metadata test under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, 505s) - spec 'Test Files 472 passed (472)' / 'Tests 13368 passed (13368)'; metadata 'Test Files 53 passed (53)' / 'Tests 788 passed (788)'. The metadata log's ERROR lines are a test deliberately driving a loader outage, not failures. TYPECHECK: same filter under the lock, VERDICT command-exit 0, both script names echoed ('packages/spec typecheck$ tsc --noEmit && ...', 'packages/metadata typecheck$ tsc --noEmit') so this is not a zero-script no-op. LINT: not a narrowing - the whole population ran in budget at final head, 'eslint . --no-inline-config --format json' exit 0, 6588 files / 0 errors / 0 warnings, file count read from eslint's own JSON, population from eslint's own config resolution; re-run AFTER the final commit and cited from that run's sha bf55c7a9e9. ABLATION: none owed - no pin was added or adjusted. FALSE-ZERO CAUGHT: the first grep of packages/spec/dist for the new string returned zero; the positive control was lit, so it was re-grepped and found - the build emits § as an escaped \\xA7. All absence readings in this run carried a lit control in the same command, including the cluster-semantics.mdx absence (git ls-tree with cluster.mdx and events-core.mdx as lit controls in the same call).", "mcp_calls": "3 — issue_read get, issue_read get_comments, create_pull_request. Everything else (card premise re-measurement, PR body readback, clause-② pair) went over zero-quota git or the container's REST core bucket.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: packages/services/service-cluster/src/cluster.ts:78 throws a runtime Error ending 'See content/docs/kernel/cluster.mdx §6.' — a repo path handed to an application developer consuming the published @objectstack/service-cluster package, who does not have the repo. Arguably the same unfollowable-reference class this card removes from the two .describe() strings, but it meets none of the three filing classes (not a reproducible defect, breaches no declared contract, not a trap producing metadata the runtime refuses), and it is outside both this card's scope and the claim's declared file face. Successor: none known — I can name no in-flight PR or queued card that touches this file.", "noted, not filed: the JSDoc block immediately above each edited .describe() already carried the CORRECT house-style pointer (@see content/docs/kernel/cluster.mdx §4 / §5) while the .describe() one line below was stale — the two spellings had drifted apart in the same declaration. This is now consistent by construction and corroborates the seat's split (source-facing JSDoc keeps the repo path, published .describe() takes the site URL). No action owed." ] }
Generated by Claude Code
Landing record — PR #17554 merged
2026-09-10T22:56:12Zas245f3607d3. Verified by content onorigin/main, and themerge=os-regensurvivor probe PASSES.domain:specexecution seat,session_01MkQhmuuJAVDjmeWNixwDDH, read 2026-09-11T00:20Z.pm:dispatchedstripped in the same pass — a closed card carries no pm-state.⭐ Why this card got a probe most landings do not
.gitattributes:153routescontent/docs/references/**through themerge=os-regendriver, and that driver has been measured exiting 0 while silently dropping one side of a merge. Every one of this PR's four pointer rewrites lives under that path. ⇒ A green queue merge is ⛔ not evidence the content survived; the only evidence is reading the merged tree.SURVIVOR PROBE 'See /docs/kernel/cluster' under content/docs/references/kernel/ per-file rows events-core.mdx 2 service-registry.mdx 1 ⇒ 3 rows, exactly as predicted occurrences grep -o | wc -l 3 ⇒ both instruments agree, so no multi-line anchor could have voided the count LIT CONTROL 'Cluster scope' in service-registry.mdx 2 ⇒ non-zero, so the readings are readings RETIRED PATH git grep -l 'cluster-semantics' origin/main apps/docs/redirects.mjs .changeset/15141-cluster-doc-pointer-site-urls.md⇒ Nothing was dropped. Both files carry their rewritten pointers, the counts match the prediction on the nose, and the control is lit.
⚠️ One reading came back wider than the seat's own prediction, and it is recorded rather than waved through. The plan saidcluster-semanticsshould survive inapps/docs/redirects.mjsonly; it also survives in this PR's own changeset,.changeset/15141-cluster-doc-pointer-site-urls.md. That is correct and expected — a changeset describes the change and must name the old path to do so, and it is an unreleased release-note input, ⛔ not a citation an author can follow. But the prediction said "only", so the difference is stated instead of quietly reconciled: a probe whose expectations are adjusted after the fact to match what was found is not a probe.Closure
GitHub closed the card on the PR's
Fixes #15141. The four-step is discharged: the pointers are rewritten, the merge is verified by content rather than by exit code, and theos-regenrisk that made this card worth watching did not fire.findingis still on this card.⚠️ It should have come off when the card was graded (domain:spec+priority:p3are both set) — recorded here for the triage seat, ⛔ not written by this lane: 车道席 ⛔ 不定级不改标.
Generated by Claude Code
Found while executing #14180 (retiring
MetadataChangedEventPayloadSchema, PR #15139). Observation, not a defect repro — stale documentation pointers.Measurement (origin/main 2cc4610)
content/docs/concepts/cluster-semantics.mdxno longer exists;apps/docs/redirects.mjs:98redirects/docs/concepts/cluster-semanticsto/docs/kernel/cluster. Four places still cite the old file by name, two of them customer-facing.describe()strings thatgen:docscopies into the reference pages:packages/spec/src/kernel/events/core.zod.ts:73—.describe('Per-emit cluster routing & delivery options. See cluster-semantics.mdx §4.')→ lands incontent/docs/references/kernel/events-core.mdx:46and:64packages/spec/src/kernel/service-registry.zod.ts:86—.describe('Cluster scope & leader strategy. See cluster-semantics.mdx §5.')→ lands incontent/docs/references/kernel/service-registry.mdx:98packages/metadata/src/metadata-manager.ts:493and:2947— source commentsCluster wiring (cluster-semantics.mdx §5)/Cluster fan-out (cluster-semantics.mdx §5)The section numbers happen to line up with today's
content/docs/kernel/cluster.mdx(§4 event scope and delivery, §5 service scope), but the file name is dead. PR #15139 corrects a fifth such pointer — theClusterMetadataChangedPayloaddoc-comment atmetadata-manager.ts:234— only because that comment was inside its ruled file surface; these four were not.What this card asks
Point the two
.describe()strings and the two comments atcontent/docs/kernel/cluster.mdx(§4 / §5 respectively) and regenerate the reference pages (pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generated --fix—check:docswill report the two reference pages stale).packages/specis the single owner of the describe strings; the two metadata comments ride along or split.Dedup: the REST search endpoint answers 403 in this container, so one targeted MCP
search_issueswas used — it returned only the closed #14339 (which documented the lanes oncluster.mdx, not these pointers), and the control term answered #14180.Generated by Claude Code