Skip to content

refactor(metadata-protocol): move the record reads out of protocol.ts into protocol-record-reads.ts (#25467 cut 4) - #25589

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-uasfag
Oct 24, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-uasfag

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

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

Cut 4 of the protocol.ts split (#24586 ruling A, recorded in 6270097840). Cut 1 landed as #25494, cut 2 as #25518 and cut 3 as #25538. The claim is 6376061670. The seat agreed scope C and its five conditions before the claim, and agreed the narrowing below after it.

Six ObjectStackProtocolImplementation methods, the record reads, move unedited into a new module, packages/metadata-protocol/src/protocol-record-reads.ts, together with the four declarations of the OCC version-token reading: 568 lines, 142 of them from the last 30 days (measured at 798d480269; the lines are unchanged on this PR's base).

It is move-only, and the card stays open for the later cuts. Branch: claude/project-thread-uasfag, the harness-pinned branch for this session, restarted from origin/main at 798d480269 after cut 3 merged, and rebuilt on ce18e73483 after #25550 and #25560 landed (the move re-run from scratch on that base, see below). The branch names no issue, so the claim comment is the identity record.

Serial with the file's in-flight PRs. Measured just before this PR was opened, on main ba9e0c3749. None of the 11 open PRs touches protocol.ts, protocol-record-reads.ts or the row-serving pin (each PR's diff read against its merge base). git merge-tree of this head with each of them, and with main, is clean. At claim, #25533 was the one open PR on protocol.ts and was disjoint; it merged as 35d942ed58. Before pr_create, #25550 (#25234) added a line directly after the @objectstack/spec/contracts import this cut narrows, and merge-tree conflicted, so this cut yielded until it landed (b531016f6d), then was rebuilt on ce18e73483 and re-measured in full. origin/main has not touched these files since ce18e73483.

What moves

Method Base line Visibility Return type
omitInternalWriteFields :14526 public annotated : void
assertRecordExists :14600 private —
assertVersionOf :14662 private —
assertVersionMatch :14713 private —
readAsCaller :14731 private —
searchAll :14849–:15322 public annotated : Promise<{…}>

None is on the series' skip list of public members with inferred return types. Four are private. The two public ones declare their return type, so the published .d.ts prints the declared type from the stub, unchanged.

Narrowed from scope C during the trial, before the claim. Both members below stay in the class exactly as they are.

  • probeRecord stays. Its system-context engine.findOne is one of protocol.ts's 6 sites in scripts/query-options-erasure-baseline.json. That baseline is keyed by file and only shrinks, so the site cannot change files unedited: query-options/no-any-erasure refuses it in the new file. The moved bodies call it through the protocol, as a host closure. Its isSystem site therefore stays put too.
  • getMetaItemCached stays. The Three read-side /meta verbs (history, audit, references) never reach canonicalizeMetaRequestType — they still derive their key from the MANIFEST map #9157 pin, protocol.read-verb-canonical-fold.test.ts, derives the /meta request-boundary verbs from the method bodies in protocol.ts itself, and requires each verb to call canonicalizeMetaRequestType. With the body moved, the stub no longer folds and the pin goes red (measured). Teaching the pin to follow a stub into another module would be a change to the pin, not a move.
    • simpleHash and metadataItemNotFoundError stay with it, because only it reads them.
    • canonicalizeMetaRequestType needs no export.

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

  • The class keeps every method with its name, docblock, signature and position, less async on the five async stubs. Each body is now one host literal plus fn.call(host, …), marked [#25467 cut 4].
  • Typing. RecordReadHost types every member as the class member itself (ObjectStackProtocolImplementation['m']). Each moved function types its this as the Pick of the host over exactly the members its body reads, measured by AST. Each stub annotates its literal as ThisParameterType<typeof fn>. There is no cast, and no member becomes public or protected.
  • Members read, measured by AST:
    • Fields, as getters so each read happens when the body makes it: engine and getServicesRegistry.
    • Methods, as late-bound closures ((...a) => this.m(...a)), so a spy or double set on the instance is still the one the body reaches: assertVersionOf, getMetaItems, probeRecord and readAsCaller.
Function this: Pick<RecordReadHost, …>
omitInternalWriteFields 'engine'
assertRecordExists 'probeRecord'
assertVersionOf 'readAsCaller'
assertVersionMatch 'assertVersionOf' | 'probeRecord'
readAsCaller 'engine'
searchAll 'engine' | 'getMetaItems' | 'getServicesRegistry'

The caller-read path (seat condition 3). readAsCaller and searchAll move token-identical: 59 and 1,976 tokens, 0 differ.

  • Neither host Pick carries an elevation member. The host has no system context, no isSystem reader and no privileged engine handle, only the protocol's own engine field (the one the method read before).
  • searchAll still asks the security service's canReadObject with request.context and the spec's canServeApiOperation, in the same order, in the moved body.

Module-level declarations, by reader

Each declaration the moved bodies read was checked by an AST walk over the whole of base protocol.ts. The walk finds every identifier reference to the declaration outside its own declaration, attributes it to the enclosing class member or top-level statement, and takes the transitive closure over the moved set.

Move with the bodies, byte-identical and unexported. Each has 0 readers outside the moved bodies and the other moved declarations. Each carries exactly its own docblock (leading-trivia blocks checked: one each).

Declaration Base line Readers
assertVersionTokenNotMalformed :3176 assertVersionOf, assertVersionMatch
NormalisedVersion :3208 normaliseVersionToken, versionTokensAgree
normaliseVersionToken :3300 assertVersionOf, versionTokensAgree
versionTokensAgree :3327 assertVersionOf

None is read while the module is first evaluated.

Stay in protocol.ts and gain export in place, the only edit to it, imported back by the module:

Declaration Read by code that stays
canonicalVersionInstant (:3246) auditInstantMs (:3350)

The exported classes ConcurrentUpdateError and MalformedVersionTokenError are imported as values. src/index.ts exports from ./protocol.js by name, so nothing new is published (measured below).

Imports. protocol.ts drops the names that lose every reader (noUnusedLocals): canServeApiOperation from @objectstack/spec/data, ISecurityService from @objectstack/spec/contracts (the RLS_MEMBERSHIP_RESOLVER_SERVICE import #25550 added on the next line is untouched), and resolveI18nLabel from @objectstack/spec/ui. The module imports them from the same specifiers. protocol.ts gains one statement, the import of the new module.

The published .d.ts

Under the series bar (ruling 6348891160), measured last, on the final layout, at base ce18e73483 and at head. Both were built with pnpm --filter @objectstack/metadata-protocol build against the same dependency tree (turbo run build --filter='@objectstack/metadata-protocol^...' at base first).

node -e 'const s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]*"(?:\s*\|\s*"[^"\n]*")+/g,r=>r.split(/\s*\|\s*/).sort().join(" | ")))' dist/index.d.ts | sha256sum
  • Positive control on a copy of the head dist/index.d.ts: making line 1361, private engine;, public (engine;) gives raw 4bea7ae0… and normalised be016197…. Both differ from the real hashes.
  • Export tables. The ESM and CJS bundles each export the same 78 names at base and head, loaded at runtime (import() and require of the built bundles). The sorted list hashes e47ac7c753bcb8bee1e79c1a5f79f7394cf030bd526de81ea8bcbfcb71fa024a on all four, as at cuts 1–3. canonicalVersionInstant does not appear.

No changeset: skip-changeset, per ruling 6348891160.

Proof of move-only

  • Bodies and declarations, by AST token (recursive getChildren leaves). For each moved function, the parameters (less the added this), return type and body have the same token sequence as the base method. Each moved declaration has the same tokens, and its own docblock is byte-identical. 2,574 tokens compared against base ce18e73483, 0 differ. The module re-generated on that base is byte-identical to the one first cut on 798d480269. Negative control: one changed token makes the check report a difference.

  • Class side. The class has 299 members at base and at head. The 293 that did not move are byte-identical to base, and each of the 6 stubs keeps its docblock and signature byte-identical, less async.

  • Top level of protocol.ts. 239 of the 247 base statements other than the class are byte-identical with their leading comments. The other 8 are:

    • the 4 moved declarations;
    • canonicalVersionInstant (export added);
    • the 3 narrowed import statements.

    The one new statement is the import of the new module.

  • Size. +796 / −603 over 3 files, 1,399 changed lines. protocol.ts goes from 31,264 to 30,718 lines, and protocol-record-reads.ts has 740.

Readers of the moved lines

  • Row-serving door exposure pin (packages/core/src/security/row-serving-door-exposure.pin.test.ts, seat condition 1). The pin classifies every caller of the read admission canReadObject and checks each door's decision site.
    • searchAll's canReadObject call and its canServeApiOperation decision both move. Without a migration the pin fails 3 of its tests: an unclassified caller, a stale key, and a decision site that no longer asks.
    • The cross-object-search row's CALLERS key and decisionSite move to protocol-record-reads.ts. Its door, operation and behaviour pin (protocol.search-api-exposure.test.ts) are unchanged.
    • No wiring line of this door stays in protocol.ts: the call matcher no longer fires there, so keeping protocol.ts as a key would make the pin's stale-entry check fail.
    • No row is added, removed or reworded. The test passes at head, as at base, together with second-object-read-exposure.pin (7/7; no path of that one is touched this cut).
  • Erasure ratchet (seat condition 2). check-query-options-erasure-ratchet gives identical output at both ends: 50 unswept non-test sites in 15 files, none new, and no baseline file key added. The engine reads that move (readAsCaller's findOne, searchAll's find) are not counted sites. The counted one stays with probeRecord.
  • System-context census (seat condition 2). Identical output at both ends: 149 elevation read sites in 22 packages across 77 files. The moved text has no isSystem read. No file-count move.
  • Tenant census. check-tenant-audit-census: identical output at both ends, no --write.
  • ADR symbol anchors and the platform checklist. docs/qa/platform-checklist/areas/*.json anchor protocol.ts#searchAll and other moved methods. The method shells stay, so the anchors still resolve; they are not edited. check-adr-symbol-anchors and check-platform-checklist: identical output at both ends. The blanking check before scope C found no anchor that resolves only inside the moved bodies (seat condition 4).
  • Spec liveness. object.json cites protocol.ts#searchAll for enable.searchable. Its key-mention check still passes, on the docblock that stays. check-liveness gives identical output at both ends. The file is not edited.
  • ADR anchors and decision letters. check:adr-anchors: 84 → 84 anchored files. Decision-letter citations on the anchored surface go 1,947 → 1,942 at ce18e73483 → head, measured exactly at both ends (1,954 → 1,949 at 798d480269 before the rebuild: the same 5).
    • The 5 that leave are letter citations in comments inside searchAll's moved body: ADR-0110 D3 ×2, ADR-0079 D3, ADR-0131 D6 and ADR-0090 D2.
    • protocol.ts's anchor entry governs ADR-0005/0029/0087/0119/0126. None of its paragraphs describes these bodies (read paragraph by paragraph), so the new module gets no entry and those citations leave the anchored surface unedited.
  • Bracketed-refusal pin (PRODUCERS). No new Error( site moves: protocol.ts is 87 → 87 and the new module has 0, so no row is added.
  • Source scans. The package's source scans that read ./protocol.ts all pass at head, including read-verb-canonical-fold (the reason getMetaItemCached stays, above).

Verification

  • tsc --noEmit (package) exit 0. eslint on protocol.ts and protocol-record-reads.ts exit 0.
  • packages/metadata-protocol suite, base and head: 21,489 tests each (21,470 passed, 0 failed, 19 skipped), 266 files. Compared per test name and status: 0 differences.
  • Tests outside the package that read protocol.ts by path, run at head, all pass:
    • core row-serving-door-exposure.pin and second-object-read-exposure.pin (7);
    • objectql core-boundary.ratchet (2);
    • spec metadata-type-registry-allow-org-override-absence and scripts/liveness/evidence (44);
    • client and rest discovery-double-retired-key (3 + 2).
  • Hand gates at base and head, all exit 0 with identical output at both ends except the letter count above: check-adr-anchors, check-adr-symbol-anchors, check-platform-checklist, check-system-context-census, check-tenant-audit-census, check-query-options-erasure-ratchet, and spec check-liveness.
  • Derived gates. dispatch-gates --commands --changed derives 61 gates on the final tree (3 changed paths). All 61 exit 0 at head, and --ran reconciles 61 of 61 with 0 NOT-MEASURED. check-adr-symbol-anchors and check-liveness are not derived and were run by hand (above). The full list and the --ran reconcile are in the report on this PR.

Carry-forward (unchanged)

A public member whose return type is inferred stays in protocol.ts in this series; annotating its type would be a signature edit and needs a ruling. Later cuts skip getDiscovery, getMetaTypes, getMetaItems, getMetaItemsForExecution, getMetaItem, getMetaItemForExecution, getUiView, findData, getData, validateData, createData, cloneData, updateData, deleteData and saveMetaItem. Also staying, from this cut, are probeRecord (per-file erasure-baseline site) and getMetaItemCached (read by the #9157 pin by path). The inferred-return .d.ts still depends on protocol.ts byte offsets (cut 3's series note), so each cut measures it last.

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8pUyVs5eas1AjMdReJM7C

… into protocol-record-reads.ts

Move-only: the existence check, the OCC version checks, the read made as
the calling principal, the cross-object search and the write-response
strip move unedited into protocol-record-reads.ts (RecordReadHost); the
class keeps each method's name, docblock and signature. probeRecord and
getMetaItemCached stay. The row-serving door pin follows searchAll's
admission call and exposure decision to the new file.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8pUyVs5eas1AjMdReJM7C
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 24, 2026
@objectstack-fleet
objectstack-fleet Bot requested a review from os-sales October 24, 2026 02:29
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

45 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 ba9e0c37492cd65abb19651829910959219d5e01.

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

What this run could not see
  • 3 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 ba9e0c37492cd65abb19651829910959219d5e01 → packageMentionDocs.

Which tree this was computed on

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

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

⚠️ 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 ba9e0c37492cd65abb19651829910959219d5e01 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added the tests label Oct 24, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

os-dev-report
{
"issue": 25467,
"status": "done",
"branch": "claude/project-thread-uasfag",
"pr": "#25589",
"session": "session_01J8pUyVs5eas1AjMdReJM7C — this run's harness-stamped id, on the Claude-Session: trailer of the commit on the branch",
"premise_still_valid": true,
"summary": "Cut 4 of the protocol.ts split (#24586 ruling A, 6270097840; d.ts bar 6348891160). Claim 6376061670, scope C agreed with the seat before it, with the seat's five conditions; the narrowing below was reported to the seat after the claim and agreed. Six record-read methods (omitInternalWriteFields public : void, assertRecordExists, assertVersionOf, assertVersionMatch, readAsCaller private, searchAll public : Promise<{...}>) moved unedited to packages/metadata-protocol/src/protocol-record-reads.ts (host RecordReadHost: engine and getServicesRegistry as getters; assertVersionOf, getMetaItems, probeRecord, readAsCaller as late-bound closures; no elevation member). The 4 OCC version-token declarations (assertVersionTokenNotMalformed, NormalisedVersion, normaliseVersionToken, versionTokensAgree) moved with them, byte-identical, 0 outside readers each by AST transitive closure; canonicalVersionInstant stays and gains export (read by auditInstantMs). Narrowed from scope C in the trial, before the claim: probeRecord stays (its system-context findOne is one of protocol.ts's 6 per-file erasure-baseline sites; the lint refuses it in a new file) and getMetaItemCached stays (the #9157 pin protocol.read-verb-canonical-fold.test.ts derives /meta verbs from method bodies in protocol.ts and reds once the body moves); simpleHash and metadataItemNotFoundError stay with it. Seat condition 1: core row-serving-door-exposure.pin CALLERS key and decisionSite repointed to protocol-record-reads.ts (canReadObject and canServeApiOperation both moved; no wiring stays). Serial rule: at claim only #25533 touched protocol.ts (disjoint; merged 35d942e). Before pr_create, #25550 (spec lane, #25234) added a line right after the contracts import this cut narrows and merge-tree conflicted, so the cut yielded until #25550 merged (b531016, 00:27Z), then was rebuilt from scratch on ce18e73 (module byte-identical to the first cut) and re-measured in full. At pr_create (02:28Z, main ba9e0c3) none of 11 open PRs touched the 3 files; merge-tree clean with each and with main. No open question.",
"tests": "pnpm --filter @objectstack/metadata-protocol vitest run (JSON reporter) under os-verify-lock. Base ce18e73: 21,489 tests (21,470 passed, 0 failed, 19 skipped), 266 files. Head 034fbb2 (tree identical to 7f3dd3bdcd, measured): the same 21,489 / 21,470 / 0 / 19, 266 files. Compared per test name and status: 0 differences. Move-only, so no ablation. Package tsc --noEmit exit 0; eslint on protocol.ts and protocol-record-reads.ts exit 0. Out-of-package tests that read protocol.ts by path, at head, all pass: core row-serving-door-exposure.pin and second-object-read-exposure.pin (7, at base and head), objectql core-boundary.ratchet (2), spec metadata-type-registry-allow-org-override-absence and scripts/liveness/evidence (44), client and rest discovery-double-retired-key (3 + 2). Move proof against base ce18e73: each moved function's parameters (less the added this), return type and body have the same AST leaf-token sequence as the base method; each moved declaration has the same tokens and its own docblock byte-identical (one leading-trivia block each); 2,574 tokens compared, 0 differ (readAsCaller 59, searchAll 1,976). Negative control: one changed token fails the check. Class: 299 members both ends, 293 byte-identical, 6 stubs keep docblock and signature byte-identical less async. Top level: 239 of 247 base statements byte-identical with leading comments; the other 8 are 4 moved, 1 export added, 3 narrowed imports. +796 / -603 over 3 files (1,399 changed lines); protocol.ts 31,264 to 30,718 lines, the module 740.",
"dts_block": {
"files": "packages/metadata-protocol dist/index.d.ts and dist/index.d.cts; base ce18e73 built with turbo run build --filter='@objectstack/metadata-protocol^...' then pnpm --filter @objectstack/metadata-protocol build; head built with the same command against the same dependency tree, as the last step on the final layout",
"raw_sha256": "base index.d.ts and index.d.cts 25da084d43455d125bfd41b85b1e70477ef7caf77f2cb7da23143b325e51a14e · head index.d.ts and index.d.cts 25da084d43455d125bfd41b85b1e70477ef7caf77f2cb7da23143b325e51a14e",
"normalised_sha256": "base ff7d6892b9f1161da356208d51301816c48dc021051544b9c28a3aa14329d57e · head ff7d6892b9f1161da356208d51301816c48dc021051544b9c28a3aa14329d57e (both files, both sides)",
"normaliser": "node -e 'const s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]"(?:\s\|\s*"[^"\n]")+/g,r=>r.split(/\s\|\s*/).sort().join(" | ")))' dist/index.d.ts | sha256sum",
"raw_diff_lines": 0,
"raw_diff": "none: raw identity, 770,690 bytes both sides. (The value differs from cut 3's a3e7fd46 because #25550 and #25560 changed the published surface on main; at the first base 798d480 this same cut also measured raw identity, a3e7fd46 both ends.)",
"positive_control": "head index.d.ts line 1361, private engine; made public (engine;): raw 4bea7ae08e75e20ca2c256fb3a3110a9dda7285cbd72bb0b12650c1395c73c2c, normalised be0161971853121da3a941ad8936c6de5bdea6ad91bf0cc6072ded0c27054a58, both different from the real hashes.",
"exports": "ESM and CJS bundles loaded at runtime: 78 names each at base and head; sorted-list sha256 e47ac7c753bcb8bee1e79c1a5f79f7394cf030bd526de81ea8bcbfcb71fa024a on all four, as at cuts 1-3; canonicalVersionInstant does not appear.",
"note": "No changeset (skip-changeset), per 6348891160."
},
"adr_anchor_block": {
"gate": "node scripts/check-adr-symbol-anchors.mjs at base ce18e73 and head, exit 0 at both with identical output. The pre-claim blanking check over the scope-C bodies found no anchor that resolves only inside them (seat condition 4).",
"adr_anchors": "pnpm check:adr-anchors exit 0 at base and head; anchored files 84 to 84; decision-letter citations on the anchored surface 1,947 to 1,942 at ce18e73 to head (1,954 to 1,949 at 798d480 before the rebuild; the same 5). The 5 that leave are comment citations inside searchAll's moved body: ADR-0110 D3 x2, ADR-0079 D3, ADR-0131 D6, ADR-0090 D2. No entry added: protocol.ts's anchor entry governs ADR-0005/0029/0087/0119/0126 and none of its paragraphs describes these bodies."
},
"gates": "Local on the final tree: dispatch-gates --commands --changed derives 61 commands (3 changed paths), each run with its exit captured; all 61 exit 0. --ran: 61 derived, 61 run, 0 NOT-MEASURED (a derived zero). Run by hand, not derived, at base ce18e73 and head, all exit 0 with identical output except the letter count above: check-adr-symbol-anchors, check:adr-anchors, check-platform-checklist (protocol.ts#searchAll and the other method anchors resolve on the shells; not edited), check-tenant-audit-census (no --write), check-system-context-census (149 elevation read sites in 77 files both ends; no isSystem read moves; seat condition 2), check-query-options-erasure-ratchet (50 unswept non-test sites in 15 files both ends, no file key added; readAsCaller's findOne and searchAll's find are not counted sites, the counted one stays with probeRecord; seat condition 2), spec check-liveness (object.json protocol.ts#searchAll key-mention passes on the stay-behind docblock). Bracketed-refusal PRODUCERS: new Error( in protocol.ts 87 to 87, none in the module, no row added. CI on head 034fbb2: 46 check runs, 34 success, 12 skipped by their own filters, 0 failed or pending; mergeable_state clean. Success: Auto Label, Build Core, Check Changeset, Check Documentation Links, Check PR Size, Dogfood Regression Gate, filter, Flag docs affected by code changes, Governed Surface Queue Guard, Lint & Repo Gates, Lint · CI, release & engine gates, Lint · ESLint, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Lint · scoped · tooling self-tests, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, Test Core, Test Core (1/6) to (6/6), The card this PR closes must claim this branch, Type Check · consumer gates, Type Check · debt ledger, Type Check · source gates, Type Check · workspace, TypeScript Type Check. Skipped: 18.x upgrade harness (opt-in) x2, Auto Label (second run), Build Docs, Check Changeset (second run), Check PR Size (second run), Console Pin Gate, the sharded Dogfood Regression Gate matrix, Dogfood Verify CLI, Packed-tarball smoke (opt-in) x2, Temporal Conformance (live PG + MySQL).",
"docs_drift": "Advisory. Re-derived with node scripts/docs-audit/affected-docs.mjs --json ce18e73 on the head: 60 docs plus 15 release-owned from 32 anchors. They are reached through literals inside the moved searchAll body and names the move relocated: sys_metadata (26), updated_at (19), sys_audit_log (16), sys_activity (9), sys_session (9), sys_account (8), full_name (5), getMetaItems (host member) and fewer. Every method keeps its name, signature, docblock and behaviour and every literal moved unedited, so no page goes stale. No page reads the moved lines by path. Bot comment 6378762037.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "No MCP write tool. GitHub reads through gh api GET and the GitHub MCP list_pull_requests read (open PRs for the serial checks), PR state, check runs. Also claude-code-remote subscribe_pr_activity on #25589 (a session subscription, not a GitHub write).",
"api_writes": "5 strokes, all through the scripts/pm relay or git: (1) post-stamped claim comment 6376061670 on #25467 (relay run 40034344525); (2) git push of claude/project-thread-uasfag at 034fbb2 (new branch on ce18e73; the merged cut 3 branch had been deleted by the queue; the pre-push trailer check refused the first attempt for a model name in the co-author trailer, reworded to the model-free pair by --amend before anything was published, tree unchanged); (3) fleet-write pr_create, PR #25589 draft with assignee os-sales and label skip-changeset (relay run 40054271224; body read back identical, 15,897 bytes); (4) fleet-write pr_request_reviewers os-sales (relay run 40054325429); (5) this report, via post-stamped.",
"open_questions": [],
"out_of_scope_findings": [
"probeRecord's system-context findOne carries one of protocol.ts's 6 query-options erasures (scripts/query-options-erasure-baseline.json). Per ruling 6351993113's generalisation it can only move after a separate sweep PR removes that cast; left for the seat if the series wants probeRecord out.",
"getMetaItemCached can only move if the #9157 pin (protocol.read-verb-canonical-fold.test.ts) learns to follow a stub into its module; that is a pin change, not a move, so it stays unless the seat wants that pin edit as its own PR."
]
}

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · 2026-10-24T03:08Z

domain:services seat 1 (seat post #6021) · os-sales · session_016g7nYP9wdNx1GDa5XDr7Uy · card #25467 cut 4 (os-dev-report 6379075487) · reviewed head 034fbb27f8 · merge base ce18e73483

  • Shape: the record reads move unedited into protocol-record-reads.ts, using the cut 1 host pattern. The PR touches 3 files, +796 / −603, for 1,399 changed lines, under the 3,000 bar. It was re-derived after spec-lane feat(lint)!: membership key declarations, and the row policies that read them, are judged when authored #25550 merged. The contracts import keeps feat(lint)!: membership key declarations, and the row policies that read them, are judged when authored #25550's line and drops only ISecurityService.
  • Reader outside the package: core/src/security/row-serving-door-exposure.pin.test.ts. The CALLERS key and decisionSite are repointed to the new module, and the pin stays at protocol.search-api-exposure.test.ts. The seat read the diff: only those two paths change.
  • Stays (disclosed, accepted): probeRecord stays as a per-file erasure-baseline site, and getMetaItemCached stays for the Three read-side /meta verbs (history, audit, references) never reach canonicalizeMetaRequestType — they still derive their key from the MANIFEST map #9157 pin. Neither is owed here.
  • .d.ts, ruling 6348891160 item 1, re-run by the seat in its own worktree (turbo run build --filter=@objectstack/metadata-protocol at both ends):
    • Raw 25da084d43455d12… at base and head, on both index.d.ts and index.d.cts. The raw diff is 0 lines.
    • Normalised ff7d6892b9f1161d… at both ends.
    • Positive control: head line 1361, private engine;, is made public. That moves the hashes to raw 4bea7ae08e75e20c… and normalised be0161971853121d….
    • CJS exports: 78 at both ends.
  • Gates re-run by the seat, all exit 0 at base and at head:
    • check-adr-symbol-anchors: 2,384 anchors at both ends.
    • check-tenant-audit-census: 238 sites.
    • check-system-context-census: 149 sites.
    • check-adr-anchors, check-dispatcher-error-vocabulary and check-platform-checklist.
  • Decision-letter count, read by the seat: 1947 at the merge base and 1942 at head. The 5 citations that leave are in searchAll: ADR-0079 D3, ADR-0090 D2, ADR-0110 D3 ×2 and ADR-0131 D6. They move into the unanchored module unchanged. main has not touched packages/metadata-protocol since the merge base, so the merged tree also loses exactly these 5.
  • PRODUCERS: new Error( counts 87 in protocol.ts at both ends and 0 in the new module, so no floor row is owed.
  • Tests and gates (report): the suite has 21,489 tests at both ends with 0 per-test differences, and 61 of 61 derived gates exit 0.
  • CI: 34 success and 12 expected skips, none failed or pending (46 runs).
  • Mergeable: git merge-tree onto today's main is clean. No open PR updated since the card's 02:28Z serial check touches the three files.
  • Body: the attribution header and the os-sales reviewer are in place, and the footers are present.
  • Landing: not governed (check-governed-merges --pr 25589: 1,399 lines). Ready and auto-merge go through the relay. The card stays open and dispatched, and the next cut is claimed afresh on the merged main.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 24, 2026 03:09
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 24, 2026
Merged via the queue into main with commit ba6912c Oct 24, 2026
47 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-uasfag branch October 24, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants