Skip to content

refactor(metadata-protocol): move the code-datasource predicates out of protocol.ts into protocol-code-datasource-predicates.ts (#25467 cut 28) - #26980

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 28 of the protocol.ts split (#24586 ruling A, recorded in 6270097840). Cuts 1–27 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 and #26933. The claim is 6455477257. It takes the cut 28 proposal of the cut 27 report (6454673268), a themed pair. Both members passed the AST screen and the read-seam census, and both moved unedited.

Two ObjectStackProtocolImplementation members move unedited into one new module, packages/metadata-protocol/src/protocol-code-datasource-predicates.ts (#23050 shape B). They are the protocol's two answers to "is this datasource name defined in code?":

protocol.ts keeps its 29,384 lines: the 15 body lines that left are replaced by 13 stub lines and the 2-line import. 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 aa00362fe5 (after cut 27's merge). It names no issue, so the claim comment is the identity record. It holds the move commit a967328ee5 and, as the claim asked, one merge of main, 4dbdd32a06 (13 commits). That merge touches one test file of this package, protocol.runtime-authoring-gate.test.ts (#26928), and not protocol.ts. The merged tree was still measured against main (see "The merged tree against main").

Serial with the file's in-flight PRs

The claim named #26920 as the open PR that also edits protocol.ts and asked for a git merge-tree against it before this PR was opened.

All 32 open PRs were checked against this head as well. Six touch this package, and none names either member:

main has not moved since the merge (0 behind at the derivation).

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

Both members passed:

  • No private-static read. The AST walk found no access on the ObjectStackProtocolImplementation identifier and none on this.constructor.
  • No error constructed. Neither body has new Error(, 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: 88 read seam(s) and an identical list once [@:][0-9]+ is stripped. The full readings, including the merged tree's 89, are under "The durability --list".

What moves

Member Base line Visibility Body lines AST tokens (params + return + body) Reads
isDeclaredCodeDatasource :15675 private 12 157 engine (field); isHostCodeDatasource (method); module-level PLURAL_TO_SINGULAR
isHostCodeDatasource :15697 private 3 83 getServicesRegistry (field); module-level PLURAL_TO_SINGULAR

protocol-code-datasource-predicates.ts has 82 lines.

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

  • The class keeps both members. Each keeps its name, docblock, signature and position. Each body now delegates, marked [#25467 cut 28].
  • CodeDatasourcePredicatesHost types the three members the bodies read as the class members themselves (ObjectStackProtocolImplementation['engine'], ['getServicesRegistry'] and ['isHostCodeDatasource']). Each function's this is a Pick of the members it reads.
  • The engine and getServicesRegistry fields are handed over as getters (the hand-over of cuts 16, 20, 24, 26 and 27). So each read finds them at call time, as before.
  • isDeclaredCodeDatasource's call to isHostCodeDatasource is handed over as a closure, (...a) => this.isHostCodeDatasource(...a), as the claim asked. So that call still reaches the class method (now its stub), not the moved function directly.
  • No member changes visibility.
  • Every caller still calls the class method. None changes:
    • isDeclaredCodeDatasource: isArtifactBacked (:15484, base) and cut 10's declinesStoredRow stub closure (:15996). The closure is typed by protocol-lock-state.ts's LockStateHost, which indexes the class member.
    • isHostCodeDatasource: isDeclaredCodeDatasource (above) and :28556.

Module-level declarations, by reader: no import leaves protocol.ts

Measured by an AST walk over each body's identifiers, against protocol.ts's top-level declarations and import bindings (property names excluded): the one module-level name the bodies read is PLURAL_TO_SINGULAR, from @objectstack/spec/shared. It has 54 code references left in protocol.ts and stays; the new module imports it from there too. So the top level of protocol.ts changes by the new module's import alone. No import comment moves.

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 adds one import statement and its comment ahead of every class docblock, so the cut 25 comment-offset trap was watched. It did not fire: the raw hash is identical at both ends.

Base aa00362fe5 and head a967328ee5 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): a9338265ddd795ccfd7fda56ee209f3c2e162f9153766351149994f20e92715f 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: 7307bcccb6026da6c004fa2daaca634d3419d202d6b742c122a7a3c64a552712 at both ends, 781,687 bytes. Raw identity holds.
  • The two builds differ where they should.
    • index.js hashes c256da7d953a800b… at base and 2eae069e2f6b4a9f… at head (index.cjs c51a78c2b343bd49… → 181916e28805d9b5…).
    • ….call(host goes 0 → 1 for each of the two members in both bundles.
    • Each function …( declaration goes 0 → 1.
  • Positive control on the head tree. private was dropped from isHostCodeDatasource on disk (restored from HEAD under a trap) and the package rebuilt. Both .d.ts files move to 6bbad327ad411fb0… (normalised 25b39e1f5e8cc68f…, which differs from the bar's a9338265…) and print isHostCodeDatasource(type: string, name: string): boolean;. 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 of them. Neither function, and not CodeDatasourcePredicatesHost, appears.

The merged tree against main

The merged tree 4dbdd32a06 was measured against main 912076f885, 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, +97 / −15.

  • .d.ts: raw 7307bcccb6026da6… (781,687 bytes) and normalised a9338265ddd795cc…, the same at main and merged. Both identities hold.
  • index.js: c256da7d953a800b… at main, 2eae069e2f6b4a9f… merged. Export tables: 78 names, 9f18a0177ac736ed… on both.
  • AST compare, main's protocol.ts against the merged one: 240 tokens, 0 differ.
  • Suite: main and merged both give 21,742 tests (21,716 passed, 0 failed, 26 skipped, 278 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: 88 read seam(s) at both ends. Its --list is identical once [@:][0-9]+ is stripped (164 lines, and no entry changes file).

Proof of move-only

Bodies, 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 aa00362fe5 against the head module:

isDeclaredCodeDatasource: base tokens 157, head tokens 157, differ 0, text-equal(ws-collapsed, comments incl.) true
isHostCodeDatasource: base tokens 83, head tokens 83, differ 0, text-equal(ws-collapsed, comments incl.) true
TOTAL tokens=240 differ=0 members=2
CLASS members base=303 head=303 order-same=true byte-identical=301 stubs-with-identical-docblock+signature=2 other=[]
TOP base=261 head=262 byte-identical=261

Negative controls, one per member. Each changed one token in an in-memory copy of the head module, and only the mutated member moved (differ 1; the other stayed 0):

"!== 'function') return false;"     -> "!== 'object') …"           isDeclaredCodeDatasource differ 1
"get('code-datasource-names')"      -> "get('code-datasource-name')"  isHostCodeDatasource differ 1
  • Class side. There are 303 members at base and at head, in the same order. The 301 that did not move are byte-identical to base, leading comments included. Both stubs sit at their base positions and keep their docblocks and signatures byte-identical.
  • Top level of protocol.ts. All 261 base statements are byte-identical, leading comments included. Head adds one statement, the new module's import.
  • Size. +97 / −15 over 2 files, 112 changed lines (the claim's estimate was 80–130).

Readers of the moved lines

These were grepped for the two member names and for the bodies' distinctive text (code-datasource-names, getAllPackages, PLURAL_TO_SINGULAR[type], #21899, #21944):

  • 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. No by-path reader names either member or that text.

  • The other files naming them: protocol-lock-state.ts (cut 10's LockStateHost, which indexes the class member, so it is unchanged) and packages/runtime/src/code-datasource-names.ts (comments).

  • isArtifactBacked is pinned by protocol.lookup-artifact-item-call-sites.test.ts. It is not in this cut, and its this.isDeclaredCodeDatasource( call text is unchanged.

  • Behaviour, no edit owed. These drive the predicates through the protocol and pass at both ends, in the package suite: protocol.code-defined-datasource-door.test.ts, protocol.declines-stored-row-published.test.ts and protocol.reads-environment-only.test.ts.

  • The liveness ledgers. No row points at either 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,896 decision-letter citations, 60,021 citations). No moved line cites an ADR.

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

    • The updateData/deleteData seams keep their entries at new line numbers (14003 → 14005, 14028 → 14030).
    • productionFiles is 3,816 at base and 3,818 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–27.
  • 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 aa00362fe5.

Verification

  • tsc --noEmit in packages/metadata-protocol exits 0 at head, on the merged tree, and on the merge-tree with fix(metadata-protocol,runtime,app-shell)!: refuse a save or draft publish naming a package that is not installed #26920.
  • 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 aa00362fe5: 21,738 tests (21,712 passed, 0 failed, 26 skipped), 278 files.
    • Head a967328ee5: 21,738 tests (21,712 passed, 0 failed, 26 skipped), 278 files.
    • None lost, none added, none changed status. The base leg is the package src/ swapped tree-only from aa00362fe5 (the new module removed) and restored from HEAD under a trap.
    • The merged head 4dbdd32a06 and main 912076f885 both give 21,742 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 112 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 4dbdd32a06, 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, packagelessAddress, findServedOverlayRow, foldStoredCollection, applyObjectRegistryMutation, unmanagedImportCollisions, rollBackUnmanagedImport, readRevertableCommit and storedFlowBindingAgrees. rethrowUnlessMetadataStoreUnprovisioned cannot move at all. findEnvironmentRow joins them: a census trial moving it drops the count by 7.
  • 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 and ensureObjectStorage.
    • emitMetadataMutation, isArtifactBacked and isNestedArtifactField (the lookupArtifactItem site pins), and getOverlayRepo.
  • 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

…of protocol.ts into protocol-code-datasource-predicates.ts (#25467 cut 28)

Move-only, shape B. isDeclaredCodeDatasource and isHostCodeDatasource move,
unedited, into one module. The engine and getServicesRegistry fields are
handed over as getters; isDeclaredCodeDatasource's call to
isHostCodeDatasource is handed over as a closure, so it still reaches 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

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 55 of 207 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 7bb808459050389864535173e117826507a6a888 → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 7bb808459050389864535173e117826507a6a888

⚠️ 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-28T00:23Z

Head 4dbdd32a06 (move a967328ee5 plus one main merge), report 6456729821 (on #25467), claim 6455477257. 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 28). 2 files: protocol.ts and one new module for the claimed theme, protocol-code-datasource-predicates.ts (isDeclaredCodeDatasource, isHostCodeDatasource). skip-changeset (move-only). Clause-②: no, Metadata-protocol: none.
Move check (seat) All 15 non-blank lines the PR removes from protocol.ts are found verbatim (indent-stripped) in the new module. The added lines in protocol.ts are the import with its header comment and two stubs, each through CodeDatasourcePredicatesHost: engine and getServicesRegistry are handed over as getters, and isDeclaredCodeDatasource reaches isHostCodeDatasource through the class member, so callers (isArtifactBacked, the declinesStoredRow stub, protocol-lock-state.ts, the :28556 call) and overrides still go through the class.
Evidence CI green on head 4dbdd32a06 (34 success, 17 skipped, 0 failed). Governed check: NOT governed, 112 changed lines. The report gives an AST compare of 240 tokens with 0 differ (each negative control differs by 1), raw and sorted-union .d.ts identity (ruling 6348891160) at both ends and on merged vs main, identical suites, and 46 of 46 derived gates. The read-seam census stays at 88 with an identical --list from base to cut. main itself is now at 89 (an objectql engine.ts site from #26930), and the merged tree's list equals main's.
Overlap The claim named #26920. Its merge-tree with this head is clean, tsc on that merged tree exits 0, and the moved bodies still compare 240/0.
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

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