Skip to content

refactor(metadata-protocol): move the metadata-service code-layer read out of protocol.ts into protocol-metadata-service-read.ts (#25467 cut 20) - #26366

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-ybjm3h
Oct 27, 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 20 of the protocol.ts split (#24586 ruling A, recorded in 6270097840). Cuts 1–19 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014, #26104, #26168, #26264, #26317 and #26350. The claim is 6429678924. The scope is the cut 20 proposal of the cut 19 report (6428860550), which the server seat approved in its dispatch order. The member passed the AST screen and moved unedited.

One ObjectStackProtocolImplementation member moves unedited into a new module, packages/metadata-protocol/src/protocol-metadata-service-read.ts (#23050 shape B):

protocol.ts loses 30 net lines (29,240 to 29,210). 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 e2129cbf06 after cut 19 merged. It names no issue, so the claim comment is the identity record. It holds the move commit 1cb285a797 and the merge of main c19ad22f62 (54aaeba31e). That merge touches no file of packages/metadata-protocol/: the package's src/ tree is 953bab7a at both ends.

Serial with the file's in-flight PRs

Measured just before this PR was opened: of the 19 open PRs, three touch packages/metadata-protocol/src/. None names readItemFromMetadataService. Each was checked with git merge-tree against this branch's head (54aaeba31e) and against origin/main alone.

No open PR edits the new module.

The order's screen (private statics, new Error()

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( and no other error constructor, so no PRODUCERS row is owed. It has no try, no catch and no log line.

What moves

Member Base line Visibility Body lines AST tokens (params + return + body)
readItemFromMetadataService :9328 private async 40 383

The proposal said 40.

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

  • The class keeps the member. It keeps its name, docblock, signature and position. Its body now delegates, marked [#25467 cut 20].
  • Typing. MetadataServiceReadHost types its one member as the class member itself (ObjectStackProtocolImplementation['getServicesRegistry']). The function types its this as Pick<MetadataServiceReadHost, 'getServicesRegistry'>. The stub annotates its literal as ThisParameterType<typeof readItemFromMetadataService>. No member changes visibility.
  • Members read, measured by AST walk. The walk covers property and element accesses on this, with as casts, parentheses and ! stripped, and bare this checked too. The body reads getServicesRegistry only, as this.getServicesRegistry?.().
    • getServicesRegistry is an optional private FIELD holding the constructor-supplied callback, not a method. So it is handed over as a getter (get getServicesRegistry() { return readGetServicesRegistry(); }), and the body reads the protocol's field at call time.
    • An absent callback stays undefined, so the body's ?.() short-circuits exactly as before.
    • This is the same hand-over protocol-package-install.ts, protocol-record-reads.ts and protocol-save-door-refusals.ts already use for this field.
  • Every caller still calls the class method, as the order asks for the :9262 caller. There are four this.readItemFromMetadataService( sites in protocol.ts (:9262, :11091, :11422, :18960 at base), and none changes.

Module-level declarations, by reader

Measured by an AST walk over the body's identifiers, against protocol.ts's top-level declarations and import bindings (property names excluded):

Name Where protocol.ts has it Other readers in protocol.ts What this cut does
canonicalMetaType exported function, :484 yes (23) already exported; the new module imports it from ./protocol.js at runtime, as protocol-lock-state.ts and protocol-registry-materialize.ts do
isTenantAuthored the @objectstack/metadata-core import yes stays; the new module imports it from there too
PLURAL_TO_SINGULAR, SINGULAR_TO_PLURAL the @objectstack/spec/shared import yes stay; imported from there too

Nothing gains export, and no import of protocol.ts changes. The one new statement in protocol.ts is the import of the new module.

The durability --list

check-durability-degradation-log-level exits 0 at both ends with identical output. Its --list is identical once [@:][0-9]+ is stripped (158 lines, and no entry changes file). The body has no catch and makes no engine call. Its reads go through the metadata service.

The published .d.ts

The series bar is ruling 6348891160: sorted-union identity, measured first, with raw identity reported when it holds. This cut holds the bar, and raw identity does NOT hold, for the reason below.

Base e2129cbf06 and head 1cb285a797 were built with pnpm --filter @objectstack/metadata-protocol build against one dependency tree. The closure was built at head by a full pnpm build (119/119). For the base build, the package's src/ was swapped tree-only to base and restored from HEAD under a trap. Afterwards git diff HEAD was empty, git status was clean, and both touched blobs equalled HEAD's. The readings were taken on the pre-merge tree, and the head readings again after merging main (head 54aaeba31e, closure rebuilt by a full pnpm build, 119/119).

  • Normalised sha256 (the ruling's bar): f7f9306ed46a5605c5e4c59bbc212a7d5288061760ec85d473d2f3047a836ba5 at both ends, on dist/index.d.ts and dist/index.d.cts. The normaliser sorted 80 string-literal union runs (the cut 12 normaliser). Sorted-union identity holds.
  • Raw sha256: base a8f6adb6f9c56b8f441b7224ca8c4d43b84891bce0373446e1577a7884079dd8, head 1b134685a474f83cfa85a743e49a811d607fcaeed53ae8856dd62db65ad132f5. Both files are 776,660 bytes at each end.
    • The full raw diff is ONE line, dist/index.d.ts:2448, inside getDiscovery()'s inferred return type:
      <             status: "registered" | "available" | "degraded" | "unavailable" | "stub";
      >             status: "registered" | "degraded" | "available" | "unavailable" | "stub";
      
    • The same five members appear in a different order. This is the case the ruling's sorted-union bar exists for. tsc prints an inferred union in the order its literal types were first created in the program. Moving a body changes which file the checker visits first, which changes that order, and changes nothing else.
    • No signature, no member and no name moves. readItemFromMetadataService stays a private NAME; line.
  • The two builds differ where they should.
    • index.js hashes 9495894cdf5ce39b… at base and 7be270d93afd5f1e… at head.
    • The .call(host site of readItemFromMetadataService occurs 0 times in the base bundles and once in the head bundles (ESM and CJS alike).
    • function readItemFromMetadataService( appears 0 times at base and once at head.
  • Positive control on the head tree. private was dropped from readItemFromMetadataService on disk (restored from HEAD under a trap) and the package rebuilt. Both .d.ts files move to c9acdc769a2b94ed… (normalised c1ebd3ff0d127a7e…, which differs from the bar's f7f9306e…) and print readItemFromMetadataService(type: string, name: string, packageId?: string): Promise<{ data: unknown; degraded: boolean; errors: string[]; }>;. 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 four. Neither the moved function nor MetadataServiceReadHost appears.

No changeset: skip-changeset, per ruling 6348891160.

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 e2129cbf06 against the head module:

readItemFromMetadataService: base tokens 383, head tokens 383, differ 0, text-equal(ws-collapsed, comments incl.) true
TOTAL tokens=383 differ=0 members=1
CLASS members base=301 head=301 order-same=true byte-identical=300 stubs-with-identical-docblock+signature=1 other=[]
TOP base=248 head=249 byte-identical=248

Negative control. One token was changed in an in-memory copy of the head module: ?? SINGULAR_TO_PLURAL became || SINGULAR_TO_PLURAL, one occurrence.

MUTATED packages/metadata-protocol/src/protocol-metadata-service-read.ts "?? SINGULAR_TO_PLURAL" -> "|| SINGULAR_TO_PLURAL"
readItemFromMetadataService: base tokens 383, head tokens 383, differ 1, text-equal(ws-collapsed, comments incl.) false
TOTAL tokens=383 differ=1 members=1
  • Class side. There are 301 members at base and at head, in the same order. The 300 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 (everything before the body's opening brace).
  • Top level of protocol.ts. All 248 base statements are byte-identical, leading comments included. Head adds one statement, the new module's import.
  • Size. +101 / −37 over 2 files, 138 changed lines (the proposal's estimate was 180–230). protocol-metadata-service-read.ts has 94 lines.

Readers of the moved lines

Every test and script that reads protocol.ts by path (70 files) was grepped for the member name and for its body's text: getDiagnosed, metadataService, isTenantAuthored, get('metadata') and the plural/singular fallback. So were the test files in packages/ and ui/, and docs/qa/.

  • By path: none reads the moved body. protocol.metadata-store-outage.test.ts matches getDiagnosed in comments. It does not read protocol.ts by path: it names the file in prose and drives the read through the protocol. It passes at both ends, in the package suite.

  • Behaviour through the class method, no edit owed. packages/objectql/src/protocol-delete-boot-hydrated-object-heal.test.ts names readItemFromMetadataService in its header and drives it through the delete door. Run at head after the full build: 1 file, 5 tests passed.

  • The @objectstack/spec liveness ledgers. No row points at readItemFromMetadataService. Carried forward from cut 19, two rows still hold protocol.ts#member evidence pointers whose quoted line has moved to a seam module:

    • manifest.json's dependencies row → protocol.ts#resolveWritePackageScope (cut 19);
    • seed.json → protocol.ts#applySeedBodies (cut 14).

    check:liveness checks only that the #symbol is named in the file, and both stubs keep it, so it passes. Re-pointing them is a packages/spec/** edit, outside this card.

  • No hit in docs/qa/.

  • ADR anchors. check-adr-anchors exits 0 at both ends. The decision-letter count is unchanged at 1,879. The citation count goes 59,279 → 59,280 and the file count 8,356 → 8,357. The ADR-0048 comment in the body moves with it, and the new module's header names ADR-0048 once more. The protocol.ts anchor's governing ADRs are all still referenced.

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

    • The updateData/deleteData seams keep their entries at new line numbers (13926 → 13896, 13951 → 13921).
    • productionFiles is 3,748 at base and 3,750 at head. One of the +2 is the new file. The other is the gitignored packages/spec/src/migrations/registry.ts that the spec build writes in the head tree.
  • Identical output at both ends: 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 e2129cbf06.

  • Governed surface. check-governed-merges --branch claude/project-thread-ybjm3h finds 0 of 2 paths in the register, so the PR is NOT governed. It has 138 changed lines, under the 3,000-line human-merge bar.

Verification

  • tsc --noEmit in packages/metadata-protocol exits 0 before and after the merge.
  • pnpm exec eslint --no-inline-config packages/metadata-protocol exits 0 with no output. It covers the whole touched package, which has no lint script; these are the root lint script's flags.
  • packages/metadata-protocol suite, base and head, compared per test name and status. Each leg ran vitest --maxWorkers=2 with the JSON reporter under the shared verify lock, and both gave VERDICT command-exit 0. The runs are on the pre-merge tree; the merge changed no file of the package.
    • Base e2129cbf06: 21,568 tests (21,549 passed, 0 failed, 19 skipped), 270 files.
    • Head 1cb285a797: 21,568 tests (21,549 passed, 0 failed, 19 skipped), 270 files.
    • None lost, none added, none changed status. The base leg is the package src/ swapped tree-only from e2129cbf06 (the new module removed) and restored from HEAD under a trap.
  • check-platform-checklist --changed-from origin/main (merged tree): OK. 1 anchored file is in the change set, 29 anchors were judged, and 0 were lost.
  • Derived gates. dispatch-gates --commands --repo objectstack-ai/objectstack derives 51 gates on 2 changed paths from the merged tree 54aaeba31e, with no stale-tree warning; all 51 exit 0 after the full pnpm build (119/119). dispatch-gates --ran: 51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN, exit 0.

Carry-forward

Unchanged from cut 19. These stay in protocol.ts:

  • Public members whose return type is inferred.
  • The bodies kept by a reader: probeRecord, getMetaItemCached, findReferencesToMeta, packagelessAddress, refuseUnmintableMetaType, metaTypeNamespaceExists, viewContainerNameCollisionRefusal with overlaidShippedContainerViewNames, reportPageRequiresAbsentAtLoad, the 7 applyRegistryWriteThrough callers, readCodeLayerForCarryForward and ensureObjectStorage.
  • The private-static readers: refusePackagedBaseRemoval, packagedBaseRefusal, runPublishSideEffects, promoteDraftForPublish, publishPackageDrafts and discardPackageDrafts.
  • The field writers: warnClosureReadUnavailable.

🤖 Generated with Claude Code

https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6

…d out of protocol.ts (#25467 cut 20)

Move the body of readItemFromMetadataService unedited into
protocol-metadata-service-read.ts, behind a MetadataServiceReadHost that
hands over the getServicesRegistry field as a getter. The class keeps the
method, its docblock and declared signature; its body becomes a host
literal plus a .call. Its callers keep calling the class method.

Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

4 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
  • the SDK route bridge reached 54 of 206 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 — 11 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 e843b5b32071ec4ae4d30d3cfc618ae0203f3f95 → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json e843b5b32071ec4ae4d30d3cfc618ae0203f3f95

⚠️ 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-27T00:32Z

Head 54aaeba31e, report 6430425388 (on #25467), claim 6429678924. No contract review is owed, because there is no packages/spec/** diff and no narrowing.

item reading
Shape Draft, base main, Part of #25467 (cut 20), skip-changeset (no published behaviour moves), mergeable clean.
Files 2 files, +101/−37. readItemFromMetadataService moves into protocol-metadata-service-read.ts (#23050 shape B), with getServicesRegistry handed over as a getter. The class member stays as a delegating stub, so all 4 callers still call the class method. Not governed.
Fix A pure move. Seat probe: all 36 removed protocol.ts lines reappear in the new module, identical once the class indent is stripped, 0 missing. The module-level reads keep their other readers. canonicalMetaType is imported from ./protocol.js as an existing export, so nothing gains export and no import is dropped. Dev: AST compare 383 tokens, 0 differ (the negative control gives 1). Export tables are equal at 78 names.
.d.ts bar Ruling 6348891160 is sorted-union identity, and it holds (normalised f7f9306e… at both ends). Raw identity does not hold this time. The one raw difference is the order of the same five status literals inside getDiscovery()'s inferred return type, which is exactly the reordering the sorted-union bar exists to absorb. The positive control moves it. Accepted under the series bar.
Order questions No body constructs an error, so no PRODUCERS row is owed. The durability --list is identical once line numbers are stripped. check-adr-anchors gains one citation (ADR-0048 in the new module's header), and the gate exits 0.
Evidence 36 check runs succeeded and 16 were expected skips on this head, 0 failed. The suite ran 21,568 tests at both ends, with 0 lost, 0 added and 0 changed. Derived gates: 51 of 51 exit 0, no STALE, and --ran reconciles. Overlap: #26244's and #26138's merge-tree conflicts are the ones they already have with main, and #26337 is clean.
Carried The liveness pointer disclosure (manifest.json's dependencies row, seed.json's applySeedBodies) is unchanged from cut 19 and stays for the series' close-out. Cut 21 goes to the same thread once this lands: findServedOverlayRow paired with reportSealedOverlayRows, with findServedOverlayRow alone as the fallback.
Landing 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, now that 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 27, 2026 00:33
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 00:33
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit d677879 Oct 27, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-ybjm3h branch October 27, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m 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