Skip to content

refactor(metadata-protocol): move the credential carry-forward group out of protocol.ts into protocol-credential-carry-forward.ts (#25467 cut 9) - #25731

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

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

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 9 of the protocol.ts split (#24586 ruling A, recorded in 6270097840). Cuts 1–8 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642 and #25719. The claim is 6391854672; the scope is the carry-forward credential group the cut 8 report (6391184870) proposed from Release 6385903828, as the server seat approved it.

Four ObjectStackProtocolImplementation members move unedited into a new module, packages/metadata-protocol/src/protocol-credential-carry-forward.ts (#23050 shape B; one getter, credentialChannels). protocol.ts loses 26 net lines (29,821 to 29,795). A fifth member of the group, readCodeLayerForCarryForward, stays in the class (see "Readers of the moved lines"). The cut also replaces cut 7's placeholder header line in protocol-package-install.ts with a written header (comment only). The cut is move-only, and the card stays open for later cuts.

Branch claude/project-thread-uly5ki is the harness-pinned branch for this thread. It names no issue, so the claim comment is the identity record. It holds one commit on main e5cf9f049c.

Serial with the file's in-flight PRs. Measured just before this PR was opened: none of the 19 open PRs touches packages/metadata-protocol/src/ (each PR's file list read in full; #25718's 9,209-file list was checked by git diff --name-only against its merge base, since the files API caps at 3,000). git log e5cf9f049c..origin/main -- packages/metadata-protocol/ is empty at 43edf90b5; main's two new commits touch other packages, and git merge-tree of this head with origin/main is clean.

What moves

Member Base line Visibility Tokens (params + return + body)
credentialChannelFor :6872 private 24
carryForwardRedactedCredentials :9190 private 103
storedBodyForCarryForward :9215 private 167
restoredCredentialPathsFor :9264 private 202

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

  • The class keeps every member with its name, docblock, signature and position, less async. Each body is now one host literal plus fn.call(host, …), marked [#25467 cut 9].
  • Typing. CredentialCarryForwardHost 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. Each stub annotates its literal as ThisParameterType of typeof fn. No cast, and no member changes visibility.
  • Members read: the field credentialChannels, as a getter; the methods credentialChannelFor, getOverlayRepo, readCodeLayerForCarryForward and storedBodyForCarryForward, as late-bound closures. No field is assigned.
  • credentialChannelFor moves cleanly, as the order asked to measure first. Its other readers (the cut 8 host literals in restoredBodyDerivation and refuseRestoredBodyTheSaveDoorRefuses, saveMetaItem, promoteDraftForPublish) still call the class method, which keeps its signature, so neither protocol-authoring-gate.ts nor AuthoringGateHost changes. No pin reads it by path.

Module-level declarations, by reader

  • None moves, and none gains export. No module-level declaration of protocol.ts is read by the moved bodies; everything they read comes from the module protocol.ts imports it from (metadata-redaction.ts, @objectstack/spec/shared). From protocol.ts the new module imports types only (ObjectStackProtocolImplementation, MetadataCredentialChannel), so there is no runtime module cycle.
  • Imports in protocol.ts. carryForwardRedactedValues and redactedPathsCarriedForward lose their last reader and leave the metadata-redaction.js import list (hasMetadataRedactor keeps a reader and stays). The one new statement is the import of the new module.

The published .d.ts

The series bar is ruling 6348891160, sorted-union identity, measured first. Base e5cf9f049c and head 428f9aa9 were built with pnpm --filter @objectstack/metadata-protocol build against one dependency tree (turbo run build --filter='@objectstack/metadata-protocol^...' once, then the package's src/ swapped tree-only to base for the base build and restored from HEAD under a trap, git diff HEAD empty after).

  • Raw sha256: 325970c1661efaa6a3762ce7de9e6bb205ea16099784f2b6c5950d62d175b331 at base and at head, on both dist/index.d.ts and dist/index.d.cts, 772,838 bytes each (the hash cut 8 reported). diff exits 0. Raw identity holds, so sorted-union identity holds too.
  • Normalised sha256: 9562749edf7b8bba67ed2f1779799a68b3d6934a8605074934572d9507c55ba6 at both ends, both files (109 string-literal union runs sorted). This run's normaliser is its own script, so the hash is not comparable with cut 8's normalised figure; the raw hashes are.
  • The two builds differ where they should: index.js hashes 12c3ff329045d303… at base (cut 8's head hash) and a41e81cf2349514e… at head; storedBodyForCarryForward.call and credentialChannelFor.call each occur 0 times in the base bundle and once in the head bundle.
  • Positive control on a copy of the head index.d.ts, the first private engine; changed to engine;: raw 3c2a24456c659dbf…, normalised 66c9d4dcf48487eb…. Both move.
  • 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. None of the moved functions or the host type appears.

No changeset: skip-changeset, per ruling 6348891160.

Proof of move-only

  • Bodies, by AST token (TypeScript scanner over parameters less the added this, return type and body): 496 tokens compared, 0 differ. The parameter and body text, comments included, is also equal with whitespace collapsed, for all four. Negative control: one changed token in restoredCredentialPathsFor's body (held.length > 0 to > 1, on a copy) makes the check report differ=1.
  • Class side. 299 members at base and at head. The 295 that did not move are byte-identical to base. Each of the 4 stubs sits at its base position and keeps its docblock and signature byte-identical, less async.
  • Top level of protocol.ts. 235 of the 236 base statements other than the class are byte-identical, leading comments included. The other one is the metadata-redaction.js import that loses two names. Head adds one statement, the new module's import.
  • Size. +239 / −60 over 3 files, 299 changed lines. protocol-credential-carry-forward.ts has 164 lines.

Readers of the moved lines

Every test and script that reads protocol.ts by path (86 files) was grepped for each moved member's name and for the calls their bodies make.

  • protocol.lookup-artifact-item-call-sites.test.ts records readCodeLayerForCarryForward: lookupArtifactItem(type, name, pkg) as a site it reads in protocol.ts, keyed by a four-space class-member header. Moving that body would take the site out of the file the pin reads and leave a forwarding closure (this.lookupArtifactItem(...a)) in its place. Verdict: readCodeLayerForCarryForward stays in the class, the same disposition the Release gives viewContainerNameCollisionRefusal for the same pin. storedBodyForCarryForward reaches it through the host. The pin is unchanged and green.
  • protocol.view-expansion-reconcile-call-sites.test.ts censuses this.getOverlayRepo() acquisitions in protocol.ts. restoredCredentialPathsFor's const repo = this.getOverlayRepo(); is the census's exempt spelling and leaves with the body (14 to 13 such lines), and the body makes no stored-row write. Verdict: no edit, as cuts 5 and 6 moved the same line. The census stays green and keeps its population of writes.
  • No other hit. No cross-package test or script names any moved member (the hypothesis in the order holds), and no docs/ or content/ page does.
  • Bracketed-refusal pin (PRODUCERS): the new module has no new Error( (0), so it gets no row.
  • ADR anchors and decision letters. check:adr-anchors output is identical at both ends: 85 anchored files, 1,846 → 1,846 decision-letter citations. No paragraph of the protocol.ts anchor entry describes the carry-forward, so the new module gets no entry.
  • Durability checker (check-durability-degradation-log-level --list): identical at both ends once [@:][0-9]+ is stripped (159 lines). The gate exits 0 at both ends with identical output.
  • Engine-double contract (check-engine-double-contract): exits 0 at both ends. The updateData/deleteData seams keep their entries at new line numbers (14065 → 14039, 14090 → 14064). productionFiles is 3,684 at base and 3,686 at head: +1 is the new file, +1 is the gitignored packages/spec/src/migrations/registry.ts, which the spec build writes in the head tree and the base tree had not built.
  • 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-nul-bytes differs only in the scanned file count, +1. check-platform-checklist --changed-from origin/main: OK, 29 anchors judged, 0 lost.
  • Governed surface. check-governed-merges --branch claude/project-thread-uly5ki: 0 of 3 paths hit the register, NOT governed; 299 changed lines, under the 3,000-line human-merge bar.

Verification

  • pnpm --filter @objectstack/metadata-protocol typecheck exits 0. eslint --no-inline-config packages/metadata-protocol exits 0.
  • 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):
    • Base e5cf9f049c: 21,504 tests (21,485 passed, 0 failed, 19 skipped), 266 files.
    • Head 428f9aa9: 21,504 tests (21,485 passed, 0 failed, 19 skipped), 266 files.
    • None lost, none added, none changed status. The base leg is the package src/ swapped tree-only from e5cf9f049c and restored from HEAD under a trap; git diff HEAD empty and git status clean after. The suite includes both pins named above (15 tests, all passed at head).
  • Derived gates. dispatch-gates --commands --repo objectstack-ai/objectstack derives 53 gates on 3 changed paths. 52 exit 0 at head. check-plugin-teardown-shape --self-test and check:lean-entry-closure first answered PREREQUISITE NOT MET (a pinned fixture commit outside the shallow clone; an unbuilt objectql/dist) and exit 0 once the commit was fetched and objectql built. check:dual-build-cjs-loads is NOT MEASURED locally: it needs every package's dist/ and is left to CI; this package's CJS bundle was loaded directly above. --ran reconciles 53 of 53: 52 run, 1 NOT-MEASURED, 0 UNRUN.

Acceptance notes

  • protocol-package-install.ts (cut 7) now carries a written header in the shape of the other cut modules: which members are getters (engine, getServicesRegistry), which are callbacks (packagePersistService, packageInstallUndo), the three helpers that moved with the bodies, and the two protocol.ts declarations it imports. Comment only; that file has no other change.
  • The class docblock of carryForwardRedactedCredentials keeps its {@link carryForwardRedactedValues}, which protocol.ts no longer imports. The docblock is unchanged by design (move-only); the link names the function in metadata-redaction.ts.

Carry-forward

Unchanged from cut 8, plus one: 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 now readCodeLayerForCarryForward), and the private-static readers stay in protocol.ts.


Generated by Claude Code

…out of protocol.ts into protocol-credential-carry-forward.ts (#25467 cut 9)

credentialChannelFor, carryForwardRedactedCredentials,
storedBodyForCarryForward and restoredCredentialPathsFor move unedited
(shape B: getter credentialChannels; callbacks credentialChannelFor,
getOverlayRepo, readCodeLayerForCarryForward, storedBodyForCarryForward).
readCodeLayerForCarryForward stays in the class: the lookupArtifactItem
call-site pin reads it in protocol.ts. Cut 7's module gets its written
header in place of the placeholder line (comment only).

Claude-Session: https://claude.ai/code/session_018R7PXvRqqGBhprFi6EWucU
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 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via packages.uninstall (sdk, the route ledger binds it to DELETE /packages/:id))
  • content/docs/api/environment-routing.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/api/metadata-api.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/concepts/metadata-lifecycle.mdx (via getOverlayRepo (symbol, a field of interface CredentialCarryForwardHost), getOverlayRepo (literal, a string literal in getOverlayRepo; a string literal in restoredCredentialPathsFor))
  • content/docs/data-modeling/formulas.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/deployment/publish-and-preview.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/kernel/contracts/metadata-service.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/permissions/permission-sets.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/permissions/system-context.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/protocol/kernel/error-handling.mdx (via /packages/:id (route, a path literal in a comment on a changed line))

⛔ 6 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/releases/v17/17-0.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/releases/v17/17-4.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/releases/v17/17-5.mdx (via packages.get (sdk, the route ledger binds it to GET /packages/:id))
  • content/docs/releases/v18/18-0.mdx (via /packages/:id (route, a path literal in a comment on a changed line))
  • content/docs/releases/v18/18-1.mdx (via /packages/:id (route, a path literal in a comment on a changed line))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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 f3fea0a03df3f4859dd389899df5a4ea036d1545 → packageMentionDocs.

Which tree this was computed on

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

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

⚠️ 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 f3fea0a03df3f4859dd389899df5a4ea036d1545 → 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-25T02:07Z

Head 428f9aa930, report 6392271625, claim 6391854672.

item reading
Shape draft, base main, Part of #25467 (no closing keyword), skip-changeset label, Clause-②: no and Metadata-protocol: none line-initial.
Files (3, +239/−60) protocol.ts, the new protocol-credential-carry-forward.ts, and cut 7's protocol-package-install.ts (comment only: the header placeholder becomes a real module header). Exactly the claim's surface; no packages/spec/**, no docs/adr/**. Not governed (check-governed-merges --pr 25731: 0 of 3 paths), 299 changed lines.
Move-only report's AST proof: 496 tokens, 0 differ; one-token negative control reads differ=1. Seat's read of the stubs: each host literal carries only callbacks to class members (storedBodyForCarryForward, readCodeLayerForCarryForward, credentialChannelFor, getOverlayRepo) plus credentialChannels through a live getter. Cut 8's module untouched.
Accepted deviation readCodeLayerForCarryForward stays in the class: protocol.lookup-artifact-item-call-sites.test.ts reads its lookupArtifactItem(type, name, pkg) site in protocol.ts by path, the same stay rule the Release applies to viewContainerNameCollisionRefusal. The claim allowed credentialChannelFor only if it moved cleanly; it did.
.d.ts raw identity at both ends (325970c1…, same as cut 8); export tables 78/78. Ruling 6348891160 holds.
Gates dev 53 derived, 52 exit 0, check:dual-build-cjs-loads NOT MEASURED (CI); package suite 21,504 tests at both ends, 0 failed; letters 1,846 → 1,846. CI at this act: in progress. Lint & Repo Gates and Type Check owed success before ready.
Landing ready + auto-merge through the relay once every check on this head is green or an expected skip. The cut 10 proposal in the report is the next claim on this card after this merges.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 25, 2026 02:38
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 25, 2026 02:38
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit ec4ef94 Oct 25, 2026
51 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-uly5ki branch October 25, 2026 03:06
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