Repository navigation
Commit 9d9a06e
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4Uu2dTVig4NQQadyC11Fs5BFZ)_
Part of #25467
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Cut 6 of the `protocol.ts` split (#24586 ruling A, recorded in
`6270097840`). Cuts 1–5 landed as #25494, #25518, #25538, #25589 and
#25601. The claim is `6383176261`; the seat agreed the scope before it,
including the two narrowings below, and asked for the anchor-entry check
and the re-measure on merged main, both answered in the claim and below.
Nine PRIVATE `ObjectStackProtocolImplementation` methods, the save
door's refusals, move unedited into a new module,
`packages/metadata-protocol/src/protocol-save-door-refusals.ts`, with
the five lock-family declarations only they read. They are one
contiguous run of the class, less three members that stay.
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 `60d8fd2ea6` after cut 5
merged. 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 `7265b33e77`. None of the 11 open PRs touches
`protocol.ts`, `protocol-save-door-refusals.ts` or the bracketed-refusal
pin (each PR's diff read against its merge base), and `git merge-tree`
of this head with each of them, and with main, is clean. Since
`60d8fd2ea6`, main has touched only `build-probes.ts` and its test in
this package.
## What moves
| Method | Base line | Tokens |
|---|---|---|
| `refuseUngrammaticalMetaItemName` | `:19858` | 83 |
| `defaultRecordPageSaveRefusal` | `:20040` | 626 |
| `externalBindingSaveRefusal` | `:20155` | 347 |
| `externalBindingDatasourceDefinition` | `:20197` | 61 |
| `objectsBoundExternallyTo` | `:20213` | 296 |
| `anonymousElevatedFlowRefusal` | `:20286` | 333 |
| `authoredLockFamily` | `:20603` | 439 |
| `saveWriteBinding` | `:20666` | 204 |
| `objectNamespacePrefixViolation` | `:20710` | 54 |
All nine are `private`, so none is on the series' skip list of public
members with inferred return types.
**Stay in the class**, inside the run, narrowed out during the trial
before the claim:
- **`refuseUnmintableMetaType` and `metaTypeNamespaceExists`.**
`scripts/check-durability-degradation-log-level.mjs` follows the chain
`saveMetaItem -> refuseUnmintableMetaType -> metaTypeNamespaceExists ->
engine.findOne` (its own table, rows 3 and 5), and its `--list` carries
a `metaTypeNamespaceExists` read seam. This is the rule that kept
`packagelessAddress` in cut 5.
- **`viewContainerNameCollisionRefusal`**, with its one helper
`overlaidShippedContainerViewNames`.
`protocol.lookup-artifact-item-call-sites.test.ts` reads `protocol.ts`
and records this member's `lookupArtifactItem(` site.
## The shape (#23050 shape B, as cuts 1–5 apply it)
- **The class keeps every method** with its name, docblock, signature
and position, less `async`. Each body is now one host literal plus
`fn.call(host, …)`, marked `[#25467 cut 6]`.
- **Typing.** `SaveDoorRefusalHost` 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:
- The fields `engine` and `getServicesRegistry` (the
constructor-supplied function field, passed as cut 4 passed it), as
getters, so each read happens when the body makes it.
- These methods, as late-bound closures (`(...a) => this.m(...a)`):
`artifactLockLayerAt`, `externalBindingDatasourceDefinition`,
`getOverlayRepo`, `objectsBoundExternallyTo`, `overlayLockLayerAt`,
`readActiveOverlayRows`, `readMetaItem`,
`rethrowUnlessMetadataStoreUnprovisioned` and `storedOverlayEntries`. A
spy or double set on the instance is still the one the body reaches.
- No field is assigned, no moved body names `isSystem`, and the host
carries no elevation member.
## 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 outside the declaration itself and takes the transitive
closure over the moved set.
**Move with the bodies, byte-identical and unexported.** Each has 0
readers outside the moved code and carries exactly its own docblock.
None is a class or a type: `LOCK_FAMILY_KEYS`, `lockFamilyOf`,
`sameLockFamily`, `withLockFamily`, `authoredLockFamilyRefusal`.
`item-lock.ts` declares its own, separate `LOCK_FAMILY_KEYS`, untouched.
**Stay in `protocol.ts` and gain `export` in place**, the only edit to
each:
| Declaration | Read by code that stays |
|---|---|
| `MetadataIssueEntry` | `permissionSetOwnerBindingRefusal`,
`protectionBlockRefusal`, `publishBackfillRefusal`,
`readPublishBackfillRequest` |
| `MetadataWriteFace` | `specValidationFindings`,
`destructiveChangeRemedy`, `flowSaveReplaysRetired`, `saveMetaItem` |
| `specValidationFindings` | `saveMetaItem` |
`overlaySchemaDeclaredKey`, also read by the moved code, is already
exported. `src/index.ts` exports from `./protocol.js` by name, so none
is published (measured below).
**Imports narrowed in `protocol.ts`**, each having lost its last reader:
`METADATA_ITEM_NAME_PATTERN`, `defaultRecordPageObject`,
`MetadataProtectionFields`, `validateObjectNamespacePrefix`, and the
whole `@objectstack/spec/api` value import. That import's 3-line
`[ADR-0138 D2b]` comment moves with it onto the new module's import of
the same names. `protocol.ts` gains one statement, the import of the new
module.
## The published `.d.ts`
Under the series bar (ruling `6348891160`), measured first on merged
main as the seat asked, on the final layout, at base `60d8fd2ea6` and at
head. Both ends were built with `pnpm --filter
@objectstack/metadata-protocol build` against the same dependency tree
(`turbo run build --filter='@objectstack/metadata-protocol^...'` at base
first).
- **Raw sha256** of `dist/index.d.ts` and `dist/index.d.cts`:
`25da084d43455d125bfd41b85b1e70477ef7caf77f2cb7da23143b325e51a14e` at
base and at head, both files. That is **raw identity**: no moved
declaration prints anywhere new, and no docblock splices onto a
neighbour where a declaration gains `export`.
- **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–5. None of `MetadataIssueEntry`,
`MetadataWriteFace`, `specValidationFindings` or the moved declarations
appears.
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,966 tokens compared, 0 differ. Negative control:
one changed token makes the check report a difference.
- **Class side.** The class has 299 members at base and at head. The 290
that did not move are byte-identical to base, and each of the 9 stubs
keeps its docblock and signature byte-identical, less `async`.
- **Top level of `protocol.ts`.** 230 of the 243 base statements other
than the class are byte-identical with their leading comments. The other
13 are the 5 moved declarations, the 3 that gain `export`, and the 5
import statements narrowed or removed. The one new statement is the
import of the new module.
- **Size.** +551 / −321 over 3 files, 872 changed lines. `protocol.ts`
goes from 30,548 to 30,312 lines, and `protocol-save-door-refusals.ts`
has 464.
## Readers of the moved lines
- **Bracketed-refusal pin**
(`protocol.bracketed-refusal-opener-absence.test.ts`, `PRODUCERS`). 5
`new Error(` sites move. The new module is listed with its measured
count as its floor, `'protocol-save-door-refusals.ts': 5`, as cuts 3 and
5 listed theirs. That is the only edit outside the move. No moved site
opens with a bracketed tag.
- **Durability checker** (`check-durability-degradation-log-level
--list`): identical at both ends apart from line numbers (159 lines),
with the two members above kept.
- **ADR anchors and decision letters.** `check:adr-anchors`: 85 → 85
anchored files. Decision-letter citations on the anchored surface go
**1,871 → 1,868**, measured exactly at both ends. The three that leave:
`ADR-0138 D2b` in the moved import comment, `ADR-0138 D2b` in
`anonymousElevatedFlowRefusal`'s body, and `ADR-0131 D6` in a moved
body.
- **Anchor entry.**
`scripts/adr-anchors/packages__metadata-protocol__src__protocol.ts.json`
governs ADR-0005/0029/0087/0119/0126 and names
`applyObjectRegistryMutation`, `loadMetaFromDb`, `removeObjectOverlay`,
the `OBJECT_OVERLAY_PACKAGE_MISMATCH` producer,
`batchData`/`transaction(`,
`saveMetaItem`/`projectStorableViewBody`/`VIEW_CONSOLE_ROUND_TRIP_KEYS`,
`hydrateOverlayIntoRegistry`, `readFlattenedMetaItems` and
`isShippedFlowName`/`isStoredFlowEntryOfShippedName`. None appears in
the new module (0 hits), and both `OBJECT_OVERLAY_PACKAGE_MISMATCH`
producers stay in `protocol.ts`. The new module gets no entry.
- **Identical output at both ends:** `check-adr-symbol-anchors`,
`check-platform-checklist` (`protocol.ts#objectNamespacePrefixViolation`
resolves on the shell, which stays; not edited),
`check-system-context-census`, `check-tenant-audit-census`,
`check-query-options-erasure-ratchet` (no counted site moves; no file
key added), and spec `check-liveness`.
- **Engine-double contract.** `check-engine-double-contract` differs
only in `productionFiles` +1 (the new file).
- **Governed surface.** `check-governed-merges --branch` on the final
3-path list: NOT governed. 872 changed lines, under the 3,000-line
human-merge bar.
- **Path readers.** Files that name a moved method
(`protocol.restore-doors-save-refusal-family.test.ts`,
`protocol.item-name-every-door.test.ts`,
`protocol.item-name-grammar.test.ts`, objectql
`default-record-page-save-door.test.ts`, service-datasource's
`datasource-admin-service.ts` docblock, the platform checklist) name it
in prose or exercise it through the instance. None reads the moved lines
by path, and all pass.
## Verification
- `tsc --noEmit` (package) exit 0. `eslint` on `protocol.ts` and
`protocol-save-door-refusals.ts` exit 0.
- **`packages/metadata-protocol` suite**, base and head, compared per
test name and status. Base `60d8fd2ea6`: 21,490 tests (21,471 passed, 0
failed, 19 skipped), 266 files. Head: 21,491 (21,472 passed, 0 failed,
19 skipped), 266 files. None lost, none changed status, one added: the
new `PRODUCERS` row, `protocol-save-door-refusals.ts raises no message
opening with a bracketed lowercase tag` (passed).
- **Tests outside the package that read `protocol.ts` by path or name
these methods**, run at head, all pass:
- `core` `row-serving-door-exposure.pin` and
`second-object-read-exposure.pin` (7, at both ends);
- `objectql` `core-boundary.ratchet`, `protocol-publish-canonical-fold`
and `default-record-page-save-door` (46);
- `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, identical output 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`,
`check-durability-degradation-log-level --list`, and spec
`check-liveness`.
- **Derived gates.** `dispatch-gates --commands --changed` derives 59
gates on the final tree (3 changed paths). All 59 exit 0 at head, and
`--ran` reconciles 59 of 59 with 0 NOT-MEASURED. The full list and the
`--ran` reconcile are in the report on this PR.
## Carry-forward
These stay in `protocol.ts` in this series:
- **Public members whose return type is inferred.** Annotating the 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`.
- **Bodies kept by a reader:**
- `probeRecord` (per-file erasure-baseline site);
- `getMetaItemCached` (the #9157 pin reads its body by path);
- `packagelessAddress`, `refuseUnmintableMetaType`,
`metaTypeNamespaceExists` (the durability read-seam census);
- `viewContainerNameCollisionRefusal` and
`overlaidShippedContainerViewNames` (the `lookupArtifactItem(` call-site
pin).
- **Private-static readers.**
The inferred-return `.d.ts` still depends on `protocol.ts` byte offsets
(cut 3's series note), so each cut measures it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01J8pUyVs5eas1AjMdReJM7C
Co-authored-by: Claude <noreply@anthropic.com>
1 parent e8de8a7 commit 9d9a06e
3 files changed
Lines changed: 551 additions & 321 deletions
File tree
- packages/metadata-protocol/src
0 commit comments