Skip to content

refactor(metadata-protocol): move the by-name item read's disabled-package face out of protocol.ts into protocol-meta-item-face.ts (#25467 cut 31) - #27181

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-ybjm3h
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-ybjm3h

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread

Part of #25467
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840

Cut 31 of the protocol.ts split (#24586 ruling A, recorded in 6270097840). Cuts 1–30 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014, #26104, #26168, #26264, #26317, #26350, #26366, #26404, #26449, #26654, #26704, #26807, #26873, #26933, #26980, #27029 and #27129. The claim is 6464007535. It takes the cut 31 proposal of the cut 30 report (6463239559): one member on its own theme. It passed the AST screen and the read-seam census and moved unedited.

One ObjectStackProtocolImplementation member moves unedited into a new module, packages/metadata-protocol/src/protocol-meta-item-face.ts (#23050 shape B): readMetaItemFace, the one body behind getMetaItem and getMetaItemForExecution. It does three things:

  • it refuses an object of a disabled package;
  • it withholds any other item of a disabled package;
  • otherwise it answers what readMetaItem answers.

protocol.ts loses 2 net lines (29,495 to 29,493). The cut is move-only, and the card stays open for later cuts.

Branch claude/project-thread-ybjm3h is the harness-pinned branch for this thread. It was restarted from main 1900c02cbe (after cut 30's merge). It names no issue, so the claim comment is the identity record. It holds the move commit 0f3c00a4d9 and, as the claim asked, one merge of main, d12ae82d8c (11 commits). That merge touches nothing in packages/metadata-protocol/. The merged tree was still measured against main (see "The merged tree against main").

One top-level edit beyond the move: noPendingDraftError gains export

The claim says the four disabled-package helpers "stay imported in protocol.ts". They are in fact protocol.ts's own module-level functions, declared at :636–:680. The new module therefore imports them from ./protocol.js.

  • isObjectOfDisabledPackage, isItemOfDisabledPackage and objectPackageDisabledError were already exported.
  • noPendingDraftError was not. It gains the export keyword in place, with nothing else in its statement changed. This follows addressPackages (cut 16) and withDeclaredPageTypeDefault (cut 23).
  • packages/metadata-protocol/src/index.ts names its re-exports from ./protocol.js one by one and does not name it. So the package's published surface does not move: the .d.ts and export-table readings below are identical at both ends.
  • All four keep another reader in protocol.ts, and all four stay there.

Serial with the file's in-flight PRs

The claim found no open PR touching protocol.ts and asked for a re-check. At pr_create, of the 21 open PRs, two touch this package: #26937 (one test) and #26517 (CHANGELOG.md / package.json). None edits protocol.ts, none names readMetaItemFace or noPendingDraftError, and both are merge-tree clean against this head and against main.

main moved 8 commits after the merge (to b8615afaba). None touches this package, and git merge-tree with this head is clean. The derivation on d12ae82d8c found nothing stale, so main was not merged again. The PR's merge ref runs CI against current main.

The order's screen (private statics, new Error(, the read-seam census)

The member passed:

  • No private-static read. The AST walk found no access on the ObjectStackProtocolImplementation identifier and none on this.constructor.
  • No error constructed. The body has no new Error(. Its two refusals come from the module-level factories objectPackageDisabledError and noPendingDraftError, which stay in protocol.ts, so no PRODUCERS row is owed.
  • Read-seam census. check-durability-degradation-log-level --list was taken on the base and again on the cut. Both read 89 read seam(s), the claim's base, and the lists are identical once [@:][0-9]+ is stripped. The full readings are under "The durability --list".

What moves

Member Base line Visibility Body lines AST tokens (params + return + body) Reads
readMetaItemFace :10702 private async, return type inferred 11 181 engine (field); readMetaItem (method); module-level isObjectOfDisabledPackage, objectPackageDisabledError, isItemOfDisabledPackage, noPendingDraftError

protocol-meta-item-face.ts has 70 lines.

The shape (#23050 shape B, as cuts 1–30 apply it)

  • The class keeps the member. It keeps its name, docblock, signature and position. Its body now delegates, marked [#25467 cut 31].
  • MetaItemFaceHost types the two members the body reads as the class members themselves (ObjectStackProtocolImplementation['engine'] and ['readMetaItem']).
  • The engine field is handed over as a getter, so the read finds it at call time, as before.
  • The call to readMetaItem is handed over as a closure, (...a) => this.readMetaItem(...a), as the claim asked. So that call still reaches the class method.
  • The return type stays inferred. The stub returns readMetaItemFace.call(host, request, face), so the method's inferred type is the moved function's inferred type. The member is private, so the .d.ts prints its name only, and the positive control below shows the full type when it is not.
  • No member changes visibility.
  • Every caller still calls the class method. They are getMetaItem (:10653) and getMetaItemForExecution (:10688). Neither changes.

The published .d.ts

The series bar is ruling 6348891160: sorted-union identity, measured first, with raw identity reported when it holds. Both hold for this cut, including on the merged tree against main. The cut 25 / cut 30 comment-offset trap was checked first: a metadata-protocol build right after the move commit gave the base's raw hash. It did not fire.

Base 1900c02cbe and head 0f3c00a4d9 were built with pnpm --filter @objectstack/metadata-protocol build against one dependency tree. The closure was built at head by a full pnpm build (116/116). For the base build, the package's src/ was swapped tree-only to base (the new module removed) and restored from HEAD under a trap. Afterwards git diff HEAD was empty, git status was clean, and both touched blobs equalled HEAD's.

  • Normalised sha256 (the ruling's bar): fd5431a235098745024b527517710c81a74652d9f8d4b842a691e9d3009207ef at both ends, on dist/index.d.ts and dist/index.d.cts. The normaliser sorted 80 string-literal union runs. Sorted-union identity holds.
  • Raw sha256: 9f7d69b1624e93986442f4d5b558d8976671c791ec19d84dda5eb68b4249128b at both ends, 784,351 bytes. Raw identity holds, with noPendingDraftError now exported from protocol.ts.
  • The two builds differ where they should.
    • index.js hashes 18aded551747cdaa… at base and b4863907a762ba0b… at head (index.cjs d859527bb8d3b7f1… → d04d03f27652735c…).
    • readMetaItemFace.call(host goes 0 → 1 in both bundles.
    • Its function …( declaration goes 0 → 1.
  • Positive control on the head tree. private was dropped from readMetaItemFace on disk (restored from HEAD under a trap) and the package rebuilt. Both .d.ts files move to 74f2db843cbc8a66… (normalised b6f0bbbad4cbbe16…, which differs from the bar's fd5431a2…) and print readMetaItemFace(request: {… with its inferred return type. So the bar can see a change on this member.
  • Export tables. The ESM and CJS bundles, loaded at runtime from the package, each export the same 78 names at base and head. The sorted list hashes to 9f18a0177ac736ed… on all of them. None of readMetaItemFace, MetaItemFaceHost or noPendingDraftError appears.

The merged tree against main

The merged tree d12ae82d8c was measured against main 3346da26df, its second parent, in the same way. The closure was rebuilt by a full pnpm build (116/116), and main's package src/ was swapped in tree-only and restored under a trap. The merged tree differs from main only by this cut: 2 files, +80 / −12.

  • .d.ts: raw 9f7d69b1624e9398… (784,351 bytes) and normalised fd5431a235098745…, the same at main and merged. Both identities hold.
  • index.js: 18aded551747cdaa… at main, b4863907a762ba0b… merged. Export tables: 78 names, 9f18a0177ac736ed… on both.
  • AST compare, main's protocol.ts against the merged one: 181 tokens, 0 differ.
  • Suite: main and merged both give 21,775 tests (21,749 passed, 0 failed, 26 skipped, 281 files), per test identical.

No changeset: skip-changeset, per ruling 6348891160.

The durability --list

check-durability-degradation-log-level exits 0 at both ends with identical output: 89 read seam(s) at both ends. Its --list is identical once [@:][0-9]+ is stripped (165 lines, and no entry changes file).

  • The body has no try, and it calls none of the gate's read vocabulary (find/findOne/count).
  • No seam enters or leaves the census.
  • On the merged tree the list is identical too, 89 read seam(s).

Proof of move-only

Body, by AST token. The compare reads the TypeScript compiler's AST leaf tokens, with JSDoc skipped, over the parameters (less the added this), the return type and the body. It compares base protocol.ts at 1900c02cbe against the head module:

readMetaItemFace: base tokens 181, head tokens 181, differ 0, text-equal(ws-collapsed, comments incl.) true
TOTAL tokens=181 differ=0 members=1
CLASS members base=304 head=304 order-same=true byte-identical=303 stubs-with-identical-docblock+signature=1 other=[]
TOP base=264 head=265 byte-identical=263
TOP base-only: [ "function noPendingDraftError(type: string, name: string): Error & { code: 'NO_DRAFT'; status: 404 } {" ]
TOP head-only: [ "import { readMetaItemFace } from './protocol-meta-item-face.js';",
                 "export function noPendingDraftError(type: string, name: string): Error & { code: 'NO_DRAFT'; status: 404 } {" ]

Negative controls. Each changed one token in an in-memory copy of the head module, and the member moved (differ 1):

"request.type === 'package'"   -> "request.type === 'object'"   differ 1
"request.state === 'draft'"    -> "request.state === 'active'"  differ 1
  • Class side. There are 304 members at base and at head, in the same order. The 303 that did not move are byte-identical to base, leading comments included. The stub sits at its base position and keeps its docblock and signature byte-identical.
  • Top level of protocol.ts. Of the 264 base statements, 263 are byte-identical, leading comments included. The other is noPendingDraftError, whose only change is the added export (see above). Head adds one statement, the new module's import.
  • Size. +80 / −12 over 2 files, 92 changed lines (the claim's estimate was 70–100).

Readers of the moved lines

These were grepped for the member name, the four helpers and the body's distinctive text (_withheld, _servedOnly):

  • the 24 files that name protocol.ts and call readFileSync;

  • the test files in packages/, docs/qa/ and scripts/;

  • the @objectstack/spec liveness ledgers.

  • By path: none reads a moved line.

  • The one other mention. protocol.item-execution-read.test.ts names the member in a comment and drives both faces through getMetaItem / getMetaItemForExecution. It passes at both ends, in the package suite.

  • The liveness ledgers. No row points at the member. Carried forward: manifest.json's dependencies row → protocol.ts#resolveWritePackageScope (cut 19), and seed.json → protocol.ts#applySeedBodies (cut 14). These are packages/spec/**, outside this card.

  • ADR anchors. check-adr-anchors exits 0 with identical output at both ends (1,900 decision-letter citations, 60,175 citations).

  • Engine-double contract (check-engine-double-contract): exits 0 at both ends.

    • The updateData/deleteData seams keep their entries at new line numbers (13999 → 13997, 14024 → 14022).
    • productionFiles is 3,832 at base and 3,834 at head. The +2 are the new file and the gitignored packages/spec/src/migrations/registry.ts that the spec build writes in the head tree, as in cuts 20–30.
  • Identical output at both ends: check-adr-anchors, check-adr-symbol-anchors, check-system-context-census, check-tenant-audit-census, check-query-options-erasure-ratchet, check-filter-alias-parity and check-durability-degradation-log-level. check-nul-bytes differs only in the scanned file count, +1. The base-end readings were taken in a clean detached worktree at 1900c02cbe.

Verification

  • tsc --noEmit in packages/metadata-protocol exits 0 at head and on the merged tree.
  • pnpm exec eslint --no-inline-config packages/metadata-protocol exits 0 with no output (the whole touched package, with the root lint script's flags).
  • packages/metadata-protocol suite, compared per test name and status. Each leg ran vitest --maxWorkers=2 with the JSON reporter under the shared verify lock.
    • Base 1900c02cbe: 21,775 tests (21,749 passed, 0 failed, 26 skipped), 281 files.
    • Head 0f3c00a4d9: 21,775 tests (21,749 passed, 0 failed, 26 skipped), 281 files.
    • None lost, none added, none changed status. The base leg is the package src/ swapped tree-only from 1900c02cbe (the new module removed) and restored from HEAD under a trap.
    • The merged head d12ae82d8c and main 3346da26df both give 21,775 tests, per test identical (0 lost, 0 added, 0 changed).
  • check-platform-checklist --changed-from origin/main (merged tree): OK, 31 anchors judged, 0 lost.
  • Governed surface. check-governed-merges --branch claude/project-thread-ybjm3h finds 0 of 2 paths in the register (13 surfaces), so the PR is NOT governed. It has 92 changed lines, under the 3,000-line human-merge bar.
  • Derived gates. dispatch-gates --commands --repo objectstack-ai/objectstack derives 46 gates on 2 changed paths from d12ae82d8c, with no stale-tree finding. All 46 exit 0 after the full pnpm build (116/116). dispatch-gates --ran reports 46 derived, 46 run, 0 NOT-MEASURED and 0 UNRUN, and exits 0.

Carry-forward

These stay in protocol.ts:

  • The read-seam members (cut 21): findEnvironmentRows, findEnvironmentRow, packagelessAddress, findServedOverlayRow, foldStoredCollection, applyObjectRegistryMutation, unmanagedImportCollisions, rollBackUnmanagedImport, readRevertableCommit and storedFlowBindingAgrees. rethrowUnlessMetadataStoreUnprovisioned cannot move at all.
  • Public members whose return type is inferred.
  • The bodies kept by a by-path reader:
    • probeRecord, getMetaItemCached, findReferencesToMeta, refuseUnmintableMetaType and metaTypeNamespaceExists.
    • viewContainerNameCollisionRefusal with overlaidShippedContainerViewNames, and reportPageRequiresAbsentAtLoad.
    • The 7 applyRegistryWriteThrough callers, readCodeLayerForCarryForward, ensureObjectStorage, dropObjectStorage and applyRemoteMetadataMutation.
    • emitMetadataMutation, and getOverlayRepo.
    • isArtifactBacked, isNestedArtifactField and packagedArtifactBase (the lookupArtifactItem site pins).
  • The private-static readers: refusePackagedBaseRemoval, packagedBaseRefusal, runPublishSideEffects, promoteDraftForPublish, publishPackageDrafts and discardPackageDrafts.
  • The field writers: warnClosureReadUnavailable and resolveSduiManifest.

🤖 Generated with Claude Code

https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6

…ckage face out of protocol.ts into protocol-meta-item-face.ts (#25467 cut 31)

Move-only, shape B. readMetaItemFace moves, unedited, into its own module.
The engine field is handed over as a getter; the call to readMetaItem is
handed over as a closure, so it still reaches the class method.
noPendingDraftError gains `export` so the module can import it, as
addressPackages and withDeclaredPageTypeDefault did in earlier cuts; the
package index does not re-export it.

Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

6 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 56 of 208 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 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; 97 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 72629f38c2e70be3d455f2ca73d44cfb3c78a790 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 10cc58ccc6f0fafcc578d49fa1c2c06dcb21124e — the merge of head d12ae82d8cfd9d6c8dd6fe0cb13dd3d7f4e3a01d into base 72629f38c2e70be3d455f2ca73d44cfb3c78a790, 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 10cc58ccc6f0fafcc578d49fa1c2c06dcb21124e && git checkout 10cc58ccc6f0fafcc578d49fa1c2c06dcb21124e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 72629f38c2e70be3d455f2ca73d44cfb3c78a790 d12ae82d8cfd9d6c8dd6fe0cb13dd3d7f4e3a01d && git checkout -B drift-repro 72629f38c2e70be3d455f2ca73d44cfb3c78a790 && git merge --no-ff d12ae82d8cfd9d6c8dd6fe0cb13dd3d7f4e3a01d

node scripts/docs-audit/affected-docs.mjs --json 72629f38c2e70be3d455f2ca73d44cfb3c78a790

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:server seat 1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC · 2026-10-28T09:55Z

Head d12ae82d8c (move 0f3c00a4d9 plus one main merge), report 6465513012 (on #25467), claim 6464007535. No contract review is owed: there is no packages/spec/** diff, no governed path, no narrowing and no Clause-②: yes.

item reading
Shape Draft, base main, Part of #25467 (cut 31). 2 files: protocol.ts and one new module for the claimed member, protocol-meta-item-face.ts (readMetaItemFace). skip-changeset (move-only). Clause-②: no, Metadata-protocol: none.
Move check (seat) 11 of the 12 non-blank lines the PR removes from protocol.ts are found verbatim (indent-stripped) in the new module. The 12th is the noPendingDraftError declaration line, re-added in place as export function with the same signature (the disclosed deviation below). The other added lines in protocol.ts are the import with its header comment and one stub through MetaItemFaceHost: engine is handed over as a getter, and readMetaItem as a closure, so that call stays on the class method, as the claim asked. Both callers (getMetaItem, getMetaItemForExecution) still call the class member.
Evidence CI green on head d12ae82d8c (34 success, 18 skipped, 0 failed). Governed check: NOT governed, 92 changed lines. The report gives an AST compare of 181 tokens with 0 differ (both negative controls differ by 1), raw and sorted-union .d.ts identity (ruling 6348891160) at both ends and on merged vs main, an unchanged 78-name export table, identical suites (21,775), the read-seam census at 89 with an identical --list, and 46 of 46 derived gates.
Disclosed noPendingDraftError was protocol.ts's own non-exported function, not an import as the claim assumed. It gained export in place so the new module can import it, following the cut 16 and cut 23 precedent. index.ts does not re-export it, so the published surface is unchanged: the export table is identical and so is the raw .d.ts. Accepted. One main merge; no open PR edits protocol.ts at pr_create.
Landing 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, once every check on this head is green or an expected skip.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 09:56
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 28, 2026 09:56
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 9b242df Oct 28, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-ybjm3h branch October 28, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants