Skip to content

refactor(metadata-protocol): move the metadata list reads, the audit read and the UI-view read through the protocol host (#25467 E2 cut 1a) - #29548

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-xniw22
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-xniw22

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread

Part of #25467

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:把 protocol.ts 里“元数据读取”一节的前半(列表读取 getMetaItems 及其两种变体、共享的 readFlattenedMetaItems,外加 auditMetaItem、getUiView)的方法体,经 E1 的宿主机制原样搬进两个新模块;6 个方法仍留在类上(签名与文档不变),方法体变成一行转发。
  • 为什么改:[maintainer] refactor(metadata-protocol): split src/protocol.ts (33,065 lines, +10,169 in 30 days) along its ObjectStackProtocolImplementation seams, one move-only slice per PR #25467 裁决 E 的 E2 第 1 节(按席位裁定拆成 1a/1b,每个 PR 1,000–3,000 行),在声明的 protocol.ts 冻结日落地;1b(单项读取、分层读取)随后另开。
  • 风险与回滚:低。只做搬移:工具逐个证明 6 个方法体与原方法体在“this. 读作 host.”之外 AST 与文本全同;对外 index.d.ts(ESM 与 CJS)与 main 构建出的逐字节相同,getMetaTypes() 的推断类型块也逐字节相同。回滚即整体 revert。
  • 先看:packages/metadata-protocol/src/protocol-meta-list-reads.ts 文件头;protocol.ts 里 6 个方法的转发体与类 static {} 块新增的宿主条目;protocol.lookup-artifact-item-call-sites.test.ts 的改动。
  • 两分钟验证:cd packages/metadata-protocol && node scripts/host-split.mjs check origin/main readFlattenedMetaItems protocol-meta-list-reads.ts,预期 "ok":true,"textIdentical":true。
  • 需要你做的:无(约 2,500 行,低于 3,000 行线,席位自审)。

What changes

Step E2, section 1 "metadata reads", part 1a of ruling E (6537939895), on the protocol.ts freeze day seat 5 declared (#28677). Seat 5 split section 1 into 1a and 1b to keep each PR within ruling E's band of 1,000 to 3,000 lines. This is a pure application of the E1 host pattern: no logic changes, and no new rewrite kind.

member moved to rewrite sites (all this.x to host.x)
getMetaItems protocol-meta-list-reads.ts 1
getMetaItemsForExecution protocol-meta-list-reads.ts 1
getMetaItemsPerPackage protocol-meta-list-reads.ts 1
readFlattenedMetaItems (809 lines) protocol-meta-list-reads.ts 44
auditMetaItem protocol-meta-audit-ui-view.ts 3
getUiView protocol-meta-audit-ui-view.ts 1

Each method keeps its docblock, modifiers and signature on the class; its body becomes return fn(protocolHost(this), …). ProtocolHost and the class's static block gain 26 entries (the members those bodies read; engine, environmentId and getServicesRegistry are read-only getters, the rest are call-time closures). node scripts/host-split.mjs check origin/main MEMBER MODULE reads ok: true, textIdentical: true for all six. Negative control, with layer === 'effective' changed to !== in readFlattenedMetaItems's moved body, then restored:

PROBLEM protocol-meta-list-reads.ts:85: ExclamationEqualsEqualsToken where the base has EqualsEqualsEqualsToken (`===`)
PROBLEM protocol-meta-list-reads.ts: readFlattenedMetaItems's body text differs from the base body rewritten and re-indented, first at body line 3

protocol.ts drops seven import names only the moved bodies used (ITEM_KEY_DISCRIMINATORS, decorateMetadataItems, soleShippingPackage, isActionWithheldByDisabledPackage, viewIdentityPatch, perPackageLayerEnvelope, storedEntryRow); each module imports what its bodies read from where protocol.ts imports it. No import comment was dropped: the one attached comment ([#7774]) also covers itemDiscriminator, which stays.

The tool (scripts/host-split.mjs). Measuring this section showed the survey misread two stub shapes, so its E1 note of "9 local named hosts" was wrong. stubKindOf now recognises:

  • the per-member series' generic spelling, a parenthesised fn with an explicit type argument, then .call(host, …);
  • a plain return fn(…) passing exactly its own parameters, which is a body that read no member and moved earlier.

move now refuses a member that is already a stub. Before this, it would have "moved" throwMetadataServiceUnavailable and namesWithOwnStoredRow, which are already plain stubs. The survey now reads 174 stubs and 4 refusals. Two of the refusals are mixed stubs (packagelessOverlayWriteRefusal, namedBaseOverlayWriteRefusal), and the other two are reconcileViewExpansions (a private static field) and publishPackageDrafts (a bare this); none of the four is in section 1. Three new tests cover this, and host-split.test.mjs reads 38 tests. Ablation, deleting the instantiation-expression unwrap, then restored: 2 failed (expected undefined to be 'call'; refuses to move stubbedGeneric again).

Forced test edits

Two by-path pins now read through the split. What each asserts is unchanged.

src/protocol.lookup-artifact-item-call-sites.test.ts:

  • The readFlattenedMetaItems site row carries file: 'protocol-meta-list-reads.ts', where its body now stands.
  • The member scanner names the class's static {} block, and a row records the host factory's lookupArtifactItem closure there. It has disposition no, because it forwards the moved bodies' calls unchanged. This is the same reasoning as cut 15's shippedArtifactsOf ...a row.
  • "Both read doors take their envelope from one rule" reads the list read's const itemPackageId = envelopePackageId(packageId, it); in protocol-meta-list-reads.ts. It also requires that module to import envelopePackageId from protocol-package-bindings.ts and to define no copy.

Ablation, with that line changed to const itemPackageId = packageId; in the module, then restored: Tests 1 failed | 5 passed (6), expected '// Copyright …' to contain 'const itemPackageId = envelopePackage…'.

src/protocol.hydrate-overlay-canonical-type.test.ts (#9111's closed caller set of hydrateOverlayIntoRegistry): the full suite found it red after the move (expected [ …(2) ] to have a length of 3 but got 2), because one of the three calls now stands in readFlattenedMetaItems's moved body as host.hydrateOverlayIntoRegistry(. The pin now counts this. calls in protocol.ts plus host. calls in every protocol-*.ts module, still exactly 3, and requires that at least one is read in a module. Ablation, planting a fourth host.hydrateOverlayIntoRegistry( call in protocol-meta-audit-ui-view.ts, then restored: Tests 1 failed | 10 passed (11), expected [ …(4) ] to have a length of 3 but got 4. A bare reference that is not a call (void host.hydrateOverlayIntoRegistry) does not count: 11 passed.

The read-verb pin (protocol.read-verb-canonical-fold.test.ts) and the read-seam census needed no edit: E1's resolution follows the new stubs. Read-verb ablation, dropping the fold from getMetaItemsForExecution's moved body, then restored: Tests 1 failed | 17 passed (18), expected [ 'getMetaItemsForExecution' ] to deeply equal []. The census reads 100 seams, the same as main 399df5b (read in a scratch worktree of main).

The published .d.ts

Built from main 399df5b (this branch's merge of main) and from this head. index.d.ts is byte-identical: raw sha256 450c9334…5d744e on both sides, ESM equal to CJS, normaliser 2 8d160c2b…78065 on both. The raw diff of getMetaTypes()'s emitted block (793 lines, its return type still inferred per the seat's E1 ruling) is empty.

The declaration-emit comment leak into that inferred type struck once after the cut: the [#23316] docblock printed inside key?. It was cleared the way E0 and E1 cleared it, by the length of the new import comment above the leaking offset. A probe of +1 to +8 characters read raw-equal at +3 to +6; the comment carries +5 (the word "also").

Serial

Re-read just before opening against main 390bd2a (6 commits past this branch's merge of main, none in packages/metadata-protocol; git merge-tree with main is clean). Open PRs whose own diff touches protocol.ts or a protocol-*.ts module:

Seat 3's #29390 work (branch claude/project-thread-gvqm55, head d776e25, no PR yet): its hunks sit at main lines 22104 and 22457 (the restore limb), outside the moved section. git merge-tree with this head is clean.

Gates

On ec53149: node scripts/pm/dispatch-gates.mjs --commands derived 62 commands, and each records exit 0. --ran reports 62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN. The package's typecheck and test, through os-verify-lock, read Test Files 307 passed, 4 skipped; Tests 22232 passed, 26 skipped. The 11 direct dependents' typecheck exits 0. Lint (eslint packages/metadata-protocol --no-inline-config) exits 0. CI is not read.


Generated by Claude Code

…generic and plain stubs as stubs, and refuses to move a stub again

Claude-Session: https://claude.ai/code/session_01ADHkmR4MjTzeUv5x6tNkbk
Co-authored-by: Claude <noreply@anthropic.com>
…read and the UI-view read through the protocol host

getMetaItems, getMetaItemsForExecution, getMetaItemsPerPackage and
readFlattenedMetaItems move to protocol-meta-list-reads.ts; auditMetaItem and
getUiView to protocol-meta-audit-ui-view.ts. Each method stays on the class
as a stub. The lookupArtifactItem call-site pin reads the list read's site
and envelope line in its new module, and the host factory's closure.

Claude-Session: https://claude.ai/code/session_01ADHkmR4MjTzeUv5x6tNkbk
Co-authored-by: Claude <noreply@anthropic.com>
…n reads moved bodies in the split's modules

Claude-Session: https://claude.ai/code/session_01ADHkmR4MjTzeUv5x6tNkbk
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling labels Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol, touching 81 documentable anchor(s).

56 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 390bd2aedca2aa46776ae52380eb11577f2bea87.

⛔ 15 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 cross-cutting symbol(s) contributed no route anchor: environmentId (40 routes)
  • 2 anchor(s) matched too much of the corpus to be a work list: created_at (literal, 43 pages), /api/v1/meta (route, 47 pages)
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 216 client-bound route-ledger rows — the other 156 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 156: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 101 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 390bd2aedca2aa46776ae52380eb11577f2bea87 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 721fad5347654765cd53c2db86f391820720b92c — the merge of head ec53149fffdddb66737ecd919a00caf4586f3c8d into base 390bd2aedca2aa46776ae52380eb11577f2bea87, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 721fad5347654765cd53c2db86f391820720b92c && git checkout 721fad5347654765cd53c2db86f391820720b92c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 390bd2aedca2aa46776ae52380eb11577f2bea87 ec53149fffdddb66737ecd919a00caf4586f3c8d && git checkout -B drift-repro 390bd2aedca2aa46776ae52380eb11577f2bea87 && git merge --no-ff ec53149fffdddb66737ecd919a00caf4586f3c8d

node scripts/docs-audit/affected-docs.mjs --json 390bd2aedca2aa46776ae52380eb11577f2bea87

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 390bd2aedca2aa46776ae52380eb11577f2bea87 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1

维护者速读

  • 改了什么:protocol.ts 拆分 E2 第 1 段前半(1a):6 个元数据列表读取成员(getMetaItems 三件、readFlattenedMetaItems、auditMetaItem、getUiView)的方法体搬到 protocol-meta-list-reads.ts 和 protocol-meta-audit-ui-view.ts。类上的声明以桩的形式保留。
  • 为什么改:[maintainer] refactor(metadata-protocol): split src/protocol.ts (33,065 lines, +10,169 in 30 days) along its ObjectStackProtocolImplementation seams, one move-only slice per PR #25467 裁决 E 的第 2 阶段,按段搬出 protocol.ts,本段在 protocol.ts 冻结窗口内。
  • 风险与回滚:无行为变化。发布的 index.d.ts 与 main 原始字节一致。回滚即 revert。
  • 先看:packages/metadata-protocol/src/protocol-meta-list-reads.ts;host-split.mjs check 的输出(6 个成员 textIdentical)。
  • 两分钟验证:pnpm --filter @objectstack/metadata-protocol test,全绿。
  • 需要你做的:无,席位落地(2,511 行,未过 3000 行线)。

席位意见:与 E2 派发相符。被迫改动的两个按路径钉断言的内容不变,只是把读取范围扩到拆出的模块,并加了非空校验。

席位核对

ACCEPT · domain:server seat 5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1 · 2026-11-02T18:30Z · head ec53149fff · Part of #25467 (E2 section 1, part 1a)

  1. Shape: draft against main, Part of #25467. A patch changeset for @objectstack/metadata-protocol. Clause-②: no, Metadata-protocol: none. Not governed. 2,511 changed lines, 9 files, face TIER_DEFAULT.
  2. Against the order: ruling E, E2. The cut was made on the declared freeze ([PM seat] domain:server · seat 5 — ⏳ vacant #28677). All 51 rewrite sites are kind 1, host-split check reads ok with textIdentical for all six members, and none was refused. index.d.ts and the getMetaTypes() block are raw byte-identical to main. The census stays at 100.
  3. Accepted deviations: two forced by-path pin edits. The lookup pin reads the new modules. The hydrateOverlayIntoRegistry caller-set pin unions the modules' host. calls, still exactly 3, with a non-vacuity check and an ablation quoted. The section is split 1a/1b to stay inside ruling E's 1,000–3,000-line band.
  4. Gates: the dev reports 62/62 derived gates exit 0 (0 NOT-MEASURED), the suite at 22,232 passed, 11/11 dependents typecheck, and lint clean. Open work on the file merges clean and sits outside the section: feat(spec): a save of a connector's served form drops a leftover undeclared auth key and names it #29456, feat(spec): a record page can name the apps whose routes open it (PageSchema.apps) #29437 and seat 3's metadata-protocol: a commit revert or package-commit rollback can restore a row bound to a read-only base package that the #28905 close now refuses to write #29390 branch. The seat readies the PR only when no check-run on this head is red or running.
  5. Out of scope: 1b (the item reads and layered reads) follows from the same branch after this merges.
  6. Landing: pr_ready + automerge_enable through the relay.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 18:52
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 2, 2026 18:52
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 41505246058 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Test Core (2/8) — 失败步骤: Run this shard's tests

    @objectstack/spec:test:repo:  FAIL   repo  scripts/strictness-ledger-doc.test.ts > the ledger and the generated counts agree > is checked in current — every shard on disk equals a fresh render, and no
      ↳ 失败原因: @objectstack/spec:test:repo: AssertionError: expected Map{ …(14) } to deeply equal Map{ …(14) }
    @objectstack/spec:test:repo:  FAIL   repo  scripts/strictness-ledger-doc.test.ts > the ledger and the generated counts agree > the read-time totals equal the sums of the shards' own rows
      ↳ 失败原因: @objectstack/spec:test:repo: AssertionError: expected 'untriaged: 1298 object site(s) across…' to be 'untriaged: 1297 object site(s) across…' // Object.is equality
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 34 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant