Skip to content

refactor(metadata-protocol): move the stored-overlay row reads out of protocol.ts into protocol-stored-overlay-reads.ts (#25467 cut 16) - #26168

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-ybjm3h
Oct 26, 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 16 of the protocol.ts split (#24586 ruling A, recorded in 6270097840). Cuts 1–15 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014 and #26104. The claim is 6417245092; the scope is the cut 16 proposal of the cut 15 report (6415780867), as the server seat approved it in its dispatch order. All four members moved unedited, so no member was left behind.

Four ObjectStackProtocolImplementation members move unedited into a new module, packages/metadata-protocol/src/protocol-stored-overlay-reads.ts (#23050 shape B). They are the stored-overlay row reads:

  • readActiveOverlayRows: a type's active sys_metadata rows, through the cross-request overlay cache.
  • storedOverlayEntries: each row parsed as the list read parses it.
  • namesWithOwnStoredRow: the names that have a stored row of their own.
  • readItemActiveRows: one item's active rows.

protocol.ts loses 113 net lines (29,440 to 29,327). 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, restarted from main 95294be389 after cut 15 merged. It names no issue, so the claim comment is the identity record. It holds the move commit 2b680ef22 and the merge of main 601c77384 (afd0fc791). That merge touches no file of packages/metadata-protocol/: the package's src/ tree is d9c112bc at both ends.

Serial with the file's in-flight PRs. Measured just before this PR was opened: of the 36 open PRs, one touches packages/metadata-protocol/src/. #26005 edits protocol.meta-types-degenerate-derivation.test.ts, which does not overlap this cut. No open PR edits protocol.ts or the new module.

The order's new Error( question

The new Error( near these members is at base line :10741, inside resolveAppPackageIdKey, which does not move. None of the four moved bodies constructs an error (0 new Error(, no other error constructor), so no PRODUCERS row is owed. The only catch in the range (:10497) is in resolveRowlessExpandedView, which also stays.

What moves

Member Base line Visibility Body lines AST tokens (params + return + body)
readActiveOverlayRows :10262 private async 77 330
storedOverlayEntries :10349 private 29 166
namesWithOwnStoredRow :10431 private 9 98
readItemActiveRows :10662 private async 24 235

139 body lines (the proposal said about 139).

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

  • The class keeps every member with its name, docblock, signature and position. Each body now delegates, marked [#25467 cut 16].
  • Typing. StoredOverlayReadHost types every member as the class member itself (an indexed access on ObjectStackProtocolImplementation). Each moved function types its this as the Pick of the host over exactly the members its body reads. Each stub annotates its literal as ThisParameterType of typeof fn. No member changes visibility.
  • Members read, measured by AST walk (property and element accesses on this, with as casts, parentheses and ! stripped; bare this checked too):
    • readActiveOverlayRows and readItemActiveRows read engine (a live getter; the overlay cache keys its bucket on the engine) and findEnvironmentRows (a closure).
    • storedOverlayEntries reads convertStoredItem (a closure).
    • namesWithOwnStoredRow reads no member. It is a plain function, and its method calls it directly, the way cut 3's orderByFieldNames and groupByFieldNames stubs do. There is no host and no .call.
  • No private-static read. The AST walk found no access on the ObjectStackProtocolImplementation identifier and none on this.constructor, in any of the four bodies.
  • Every other caller still calls the class method. That covers the list and by-name reads in protocol.ts (20 this. call sites) and protocol-save-door-refusals.ts, whose own host hands readActiveOverlayRows and storedOverlayEntries over as closures to the class methods.

Module-level declarations, by reader

  • Two gain export in place, none moves. addressPackages (read by namesWithOwnStoredRow; its other reader stays) and the StoredOverlayEntry interface (the return type of storedOverlayEntries; RowlessExpandedView still names it). Neither is re-exported from index.ts, so the package's export table and .d.ts do not change (below). The new module's import from ./protocol.js of addressPackages is a runtime import; earlier modules already use that cycle (protocol-publish-batch.ts, protocol-drafts.ts), and it reads only a function declaration, at call time.

  • Imports in protocol.ts. The overlay-cache reads lose their last readers and leave the ./meta-overlay-cache.js import, which keeps bumpWriteEpoch:

    • metaOverlayCacheTtlMs
    • readMetaOverlayCache
    • readOverlayCacheGeneration
    • writeMetaOverlayCache
    • the type MetaOverlayCacheKey

    The new module imports them from there, and PLURAL_TO_SINGULAR / SINGULAR_TO_PLURAL and the type StoredOverlayRow from where protocol.ts does; those keep other readers in protocol.ts. The one new statement in protocol.ts is the import of the new module.

The durability --list (the order's re-measure)

The order expected the members' engine.find seams to change file. Measured, they do not. Neither read calls the engine directly: both route through this.findEnvironmentRows(...), which stays in the class and holds the find. check-durability-degradation-log-level exits 0 at both ends with identical output, and its --list is identical once [@:][0-9]+ is stripped (159 lines; no entry changes file).

The published .d.ts

The series bar is ruling 6348891160, sorted-union identity, measured first. Base 95294be389 and head 2b680ef22 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; git diff HEAD was empty, git status clean, and both touched blobs equal to HEAD's after. Measured twice: on the pre-merge tree (base 95294be389, head 2b680ef22) and after merging main (head afd0fc791, closure rebuilt by a full pnpm build, 119/119). The readings below hold for both.

  • Raw sha256: 08914e65f936a2b031c3f3f215481a97f53d132eefd869e4f42d928947ebe173 at base and at head, on both dist/index.d.ts and dist/index.d.cts, 775,874 bytes each. Raw identity holds, so sorted-union identity holds too. All four members stay private NAME; lines. The newly exported addressPackages and StoredOverlayEntry do not appear.
  • Normalised sha256: 46ccd7e5c4db673652513d1801ec9c9f06bf34a0a7fb6ba97fb2531ef0cc544b at both ends (80 string-literal union runs sorted; the cut 12 normaliser).
  • The two builds differ where they should: index.js hashes 5671669a82bc3837… at base and bfb1ef96fc8499bc… at head. The .call(host sites of readActiveOverlayRows, storedOverlayEntries and readItemActiveRows occur 0 times in the base bundles and once in the head bundles (ESM and CJS alike); function namesWithOwnStoredRow( appears 0 times at base and once at head.
  • Positive control on the head tree: private was dropped from readActiveOverlayRows (on disk, restored from HEAD under a trap) and the package rebuilt. Both .d.ts files move to 626578dcab46fa8f… and print readActiveOverlayRows(request: { type: string; packageId?: string; }): Promise<any[]>;, so the bar can see a change on these members.
  • 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. No moved function, the host type, addressPackages or StoredOverlayEntry appears.

No changeset: skip-changeset, per ruling 6348891160.

Proof of move-only

Bodies, by AST token (the TypeScript compiler's AST leaf tokens, JSDoc skipped, over parameters less the added this, return type and body), base protocol.ts at 95294be389 against the head module:

readActiveOverlayRows: base tokens 330, head tokens 330, differ 0, text-equal(ws-collapsed, comments incl.) true
storedOverlayEntries: base tokens 166, head tokens 166, differ 0, text-equal(ws-collapsed, comments incl.) true
namesWithOwnStoredRow: base tokens 98, head tokens 98, differ 0, text-equal(ws-collapsed, comments incl.) true
readItemActiveRows: base tokens 235, head tokens 235, differ 0, text-equal(ws-collapsed, comments incl.) true
TOTAL tokens=829 differ=0 members=4
CLASS members base=300 head=300 order-same=true byte-identical=296 stubs-with-identical-docblock+signature=4 other=[]
TOP base=244 head=245 byte-identical=241

Negative control, one token changed in an in-memory copy of the head module (overlayCacheTtlMs > 0 ? to overlayCacheTtlMs >= 0 ?, one occurrence):

MUTATED packages/metadata-protocol/src/protocol-stored-overlay-reads.ts "overlayCacheTtlMs > 0 ? readOverlayCacheGeneration" -> "overlayCacheTtlMs >= 0 ? readOverlayCacheGeneration"
readActiveOverlayRows: base tokens 330, head tokens 330, differ 1, text-equal(ws-collapsed, comments incl.) false
storedOverlayEntries: base tokens 166, head tokens 166, differ 0, text-equal(ws-collapsed, comments incl.) true
namesWithOwnStoredRow: base tokens 98, head tokens 98, differ 0, text-equal(ws-collapsed, comments incl.) true
readItemActiveRows: base tokens 235, head tokens 235, differ 0, text-equal(ws-collapsed, comments incl.) true
TOTAL tokens=829 differ=1 members=4
  • Class side. 300 members at base and at head, in the same order. The 296 that did not move are byte-identical to base, leading comments included. Each of the 4 stubs 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. 241 of the 244 base statements are byte-identical, leading comments included. The other three:

    • the ./meta-overlay-cache.js import, losing the five names above;
    • addressPackages, gaining export;
    • StoredOverlayEntry, gaining export.

    Head adds one statement, the new module's import.

  • Size. +241 / −136 over 2 files, 377 changed lines (the proposal's estimate was 400–480). protocol-stored-overlay-reads.ts has 218 lines.

Readers of the moved lines

Every test and script that reads protocol.ts by path was grepped for the four member names and for the overlay-cache names their bodies use. So was every test file in packages/ and ui/, and docs/qa/.

  • By path: none. No by-path reader names a moved member or reads a moved body's text. scripts/docs-audit/affected-docs.mjs matched only because its self-test carries inline excerpts (a MetaOverlayCacheKey struct, an auditMetaItem signature); it does not read the moved bodies.

  • Behaviour through the class method, no edit owed:

    • protocol.platform-store-system-opt-in.test.ts calls protocol.readActiveOverlayRows(...) at line 265.
    • protocol.item-active-rows-one-read.test.ts calls p.readItemActiveRows(...) at lines 114 and 123.

    Both pass at both ends (in the package suite). storedOverlayEntries and namesWithOwnStoredRow are named by no test.

  • No hit in docs/qa/.

  • ADR anchors and decision letters. check-adr-anchors exits 0 at both ends: 88 anchored files, 59,105 citations, files 8,299 → 8,300, and 1,879 → 1,877 decision-letter citations. The two that leave the anchored file are the [ADR-0131 D6/D7] comments in readActiveOverlayRows' and storedOverlayEntries' bodies (protocol.ts ADR-0131 D6 113 → 111). The protocol.ts anchor entry does not cover ADR-0131, and no entry paragraph describes these reads, so the new module gets no entry (disclosure only, as cuts 8, 12, 13 and 14).

  • Engine-double contract (check-engine-double-contract): exits 0 at both ends. The updateData/deleteData seams keep their entries at new line numbers (14087 → 13974, 14112 → 13999). productionFiles is 3,725 at base and 3,727 at head: +1 is the new file, +1 is the gitignored packages/spec/src/migrations/registry.ts 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, 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 95294be389.

  • Governed surface. check-governed-merges --branch claude/project-thread-ybjm3h: 0 of 2 paths hit the register, NOT governed; 377 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 (the whole touched package; it has no lint script, these are the root lint script's flags) exits 0, no output.
  • packages/metadata-protocol suite, base and head, compared per test name and status (vitest --maxWorkers=2, JSON reporter, each run under the shared verify lock, VERDICT command-exit 0 both legs), on the pre-merge tree (the merge changed no file of the package):
    • Base 95294be389: 21,558 tests (21,539 passed, 0 failed, 19 skipped), 269 files.
    • Head 2b680ef22: 21,558 tests (21,539 passed, 0 failed, 19 skipped), 269 files.
    • None lost, none added, none changed status. The base leg is the package src/ swapped tree-only from 95294be389 (the new module removed) and restored from HEAD under a trap.
  • No test outside the package names a moved member, so no cross-package run is owed.
  • check-platform-checklist --changed-from origin/main (merged tree): OK, 1 anchored file in the change set, 29 anchors judged, 0 lost.
  • Derived gates. dispatch-gates --commands --repo objectstack-ai/objectstack derives 53 gates on 2 changed paths from the merged tree afd0fc791, with no stale-tree warning; all 53 exit 0 after the full pnpm build (119/119). dispatch-gates --ran: 53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN, exit 0.

Carry-forward

Unchanged from cut 15. 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, and readCodeLayerForCarryForward.
  • The private-static readers: refusePackagedBaseRemoval, packagedBaseRefusal, runPublishSideEffects, promoteDraftForPublish, publishPackageDrafts and discardPackageDrafts.
  • The field writers: warnClosureReadUnavailable.

The overlay-row family's other members stay for now:

  • overlayLockLayerAt is named by the by-path kit protocol.lock-one-resolution.kit.test.ts.
  • findServedOverlayRow, expandStoredViewContainers and resolveRowlessExpandedView were outside this order.

🤖 Generated with Claude Code

https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6

… protocol.ts (#25467 cut 16)

Move-only. The bodies of readActiveOverlayRows, storedOverlayEntries,
namesWithOwnStoredRow and readItemActiveRows move into the new
protocol-stored-overlay-reads.ts (host shape B: a live engine getter and
protocol-bound closures for findEnvironmentRows and convertStoredItem;
namesWithOwnStoredRow reads no member, so its method calls it directly, as
cut 3's orderByFieldNames does). All four members keep their name, docblock
and signature in the class as stubs that delegate. addressPackages and the
StoredOverlayEntry interface gain export in place; the overlay-cache reads
(metaOverlayCacheTtlMs, readMetaOverlayCache, readOverlayCacheGeneration,
writeMetaOverlayCache, MetaOverlayCacheKey) leave protocol.ts' import with
their last readers. Nothing re-exports the new module, so the published
surface does not move.

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 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

17 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 365fe5ecc4a1f7157186d8053cd721d2384e3f56.

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

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • 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 365fe5ecc4a1f7157186d8053cd721d2384e3f56 → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 365fe5ecc4a1f7157186d8053cd721d2384e3f56

⚠️ 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 365fe5ecc4a1f7157186d8053cd721d2384e3f56 → 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

席位核对 · ACCEPT · domain:server seat 1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC · 2026-10-26T15:50Z

Head afd0fc791, report 6418840219 (on #25467), claim 6417245092. 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 16), skip-changeset (no published behaviour moves), mergeable clean.
Files 2 files, +241/−136. readActiveOverlayRows, storedOverlayEntries, namesWithOwnStoredRow and readItemActiveRows move into protocol-stored-overlay-reads.ts. Their class members stay as delegating stubs, so the 20 this. call sites and protocol-save-door-refusals.ts are unchanged. namesWithOwnStoredRow reads no member, so it becomes a plain function, as in cut 3. Not governed.
Fix A pure move. Seat probe: all 136 removed protocol.ts lines reappear verbatim in the seam module except two, and those two are addressPackages and StoredOverlayEntry. Both stay in protocol.ts and only gain export (:2831, :6230). Dev: AST compare 829 tokens, 0 differ (the negative control gives 1). .d.ts is raw-identical at both ends, before and after the merge, and the positive control moves it. Export tables are equal at 78 names.
Order questions The new Error( at base :10741 is in resolveAppPackageIdKey, which stays. No moved body constructs an error, so no PRODUCERS row is owed. The durability --list is identical once line numbers are stripped, because both reads go through findEnvironmentRows, which stays. Two ADR-0131 D6/D7 letter citations leave the anchored file. That is disclosure only, as in cuts 8 and 12–14.
Evidence 36 check runs succeeded and 16 were expected skips on this head, 0 failed. The suite ran 21,558 tests at both ends, with 0 lost, 0 added and 0 changed. Derived gates: 53 of 53 exit 0, and --ran reconciles.
Carried The cut 17 proposal in the report (classifyObjectContribution and releaseAdoptedObjectOwner, about 55 body lines, no pin edit) goes to the same thread once this lands. ensureObjectStorage stays out because of the write-through spelling pin.
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 26, 2026 15:51
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 26, 2026 15:51
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 26, 2026
Any commits made after this event will not be merged.
Merged via the queue into main with commit ffecf03 Oct 26, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-ybjm3h branch October 26, 2026 16:23
This was referenced Oct 26, 2026
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