Repository navigation
Commit 77dc706
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X7JKgiM29GUcitRvoGGj5BU)_
Part of #25467
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Cut 18 of the `protocol.ts` split (#24586 ruling A, recorded in
`6270097840`). Cuts 1–17 landed as #25494, #25518, #25538, #25589,
#25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972,
#26014, #26104, #26168 and #26264. The claim is `6425711631`. The scope
is the cut 18 proposal of the cut 17 report (`6423385238`), as the
server seat approved it in its dispatch order. The member passed the AST
screen and moved unedited.
One `ObjectStackProtocolImplementation` member moves unedited into a new
module, `packages/metadata-protocol/src/protocol-flow-save-replay.ts`
(#23050 shape B):
- `flowSaveReplaysRetired`: the flow save's retired-spelling replay
verdict (#23903 ruling B′). It answers whether a flow save may keep the
full conversion chain, because every retired spelling its body carries
is one that a stored row already carries.
`protocol.ts` loses 46 net lines (29,290 to 29,244). 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` `0a1061a61c` after cut 17
merged. The branch names no issue, so the claim comment is the identity
record. It holds two commits:
- the move commit `e6ddd60ba6`;
- the merge of `main` `8faba89e69` (`5a7ad6a7b2`).
That merge touches no file of `packages/metadata-protocol/`: the
package's `src/` tree is `23f9f0cc` at both ends. It does change the
root `tsconfig.json` and two other packages' `package.json`, so the
workspace was rebuilt in full and the package re-measured after it.
## Serial with the file's in-flight PRs
Measured just before this PR was opened: of the 23 open PRs, three touch
`packages/metadata-protocol/src/`. Each was checked with `git
merge-tree` against this branch's head (`5a7ad6a7b2`).
**#26138** edits seven `protocol.*.test.ts` files, none of which names
the moved member, `FLOW_FALLBACK_VERDICT_NOT_REPLAYED` or the new
module. Its merge-tree reports one conflict, in
`packages/spec/src/ui/visibility-alias-keys-retirement.test.ts`, which
#26138 has with `main` itself (a merge-tree against `origin/main` alone
reports it too).
**#26305** (head `1267e3cb2b`) adds 26 lines to `protocol.ts`, at `:27`
(imports), `:7145` and `:7540`. The merge-tree is **clean** (exit 0).
**#26244** (draft, head `c33b95d89f`) edits `protocol.ts` (+5 / −2). Its
hunks are the `@objectstack/spec/contracts` import lines at `:166–167`
and a host literal at `:23178`. The merge-tree **conflicts in
`protocol.ts`**, at the import block only. #26244 rewrites lines
166–167. This cut rewrites the adjacent line 168, dropping
`ALL_CONVERSIONS` from the `@objectstack/spec` import. Git refuses
adjacent edits as one conflict. The resolution is the union of both
sides:
```ts
import type { IFieldFileService, IPubSub } from '@objectstack/spec/contracts';
import { FIELD_FILE_SERVICE, RLS_MEMBERSHIP_RESOLVER_SERVICE } from '@objectstack/spec/contracts';
import { applyConversionsToFlow, applyConversionsToStoredItem, type ConversionNotice, type ConversionTodoNotice } from '@objectstack/spec';
```
The `:23178` hunk merges clean. The same merge-tree also conflicts in
`packages/spec/src/type-alias-convention.pin.test.ts`. That conflict is
between #26244 and `main` itself: a merge-tree of #26244 with
`origin/main` alone shows the same conflict. It is not this cut's.
Whichever PR lands second takes the three-line resolution above. The
`ALL_CONVERSIONS` drop is owed, not optional: the moved body was its
last reader in `protocol.ts`, so keeping it would leave an unused
import.
## The order's screen (private statics, `new Error(`)
The member passed both checks:
- **No private-static read.** The AST walk found no access on the
`ObjectStackProtocolImplementation` identifier and none on
`this.constructor`.
- **No error constructed.** The body has no `new Error(` and no other
error constructor, so no `PRODUCERS` row is owed. It has no `try`, no
`catch` and no log line.
## What moves
| Member | Base line | Visibility | Body lines | AST tokens (params +
return + body) |
|---|---|---|---|---|
| `flowSaveReplaysRetired` | `:6599` | private async | 55 | 642 |
The proposal said 55 body lines.
## The shape (#23050 shape B, as cuts 1–17 apply it)
- **The class keeps the member** with its name, docblock, signature and
position. Its body now delegates, marked `[#25467 cut 18]`.
- **Typing.** `FlowSaveReplayHost` types its one member as the class
member itself, `ObjectStackProtocolImplementation['getOverlayRepo']`.
The function types its `this` as `Pick<FlowSaveReplayHost,
'getOverlayRepo'>`. The stub annotates its literal as
`ThisParameterType<typeof flowSaveReplaysRetired>`. No member changes
visibility.
- **Members read**, measured by an AST walk over property and element
accesses on `this`, with `as` casts, parentheses and `!` stripped, and
bare `this` checked too. The body reads `getOverlayRepo` only. It is
handed over as a closure that calls the method on the protocol at call
time. A test that sets `protocol.getOverlayRepo = ...` on the instance
(`protocol.driver-text-disclosure.test.ts` does) still reaches the body.
- **Every other caller still calls the class method.**
## Module-level declarations, by reader
Measured by an AST walk over the body's identifiers, against
`protocol.ts`'s top-level declarations and import bindings. Property
names are excluded.
| Name | Where `protocol.ts` has it | Other readers in `protocol.ts` |
What this cut does |
|---|---|---|---|
| `FLOW_FALLBACK_VERDICT_NOT_REPLAYED` | `const` at `:3358` | 1 (the
save door's flow fallback in `saveMetaItem`, base `:20930`) | gains
`export` in place; the new module imports it at runtime |
| `ALL_CONVERSIONS` | the `@objectstack/spec` import, `:168` | **0**, so
the moved body was its last reader | leaves the import, and the new
module imports it from `@objectstack/spec` |
| `applyConversionsToFlow`, `ConversionNotice` | the same
`@objectstack/spec` import | yes | stay; the new module imports them
from there too |
| `itemDiscriminator` | the `@objectstack/metadata-core` import | yes |
stays; imported from there too |
| `MetadataWriteFace` | exported type alias | yes | already exported;
imported as a type |
`FLOW_FALLBACK_VERDICT_NOT_REPLAYED` is not re-exported from `index.ts`,
so the package's export table and `.d.ts` do not change (see below). The
new module's runtime import of it from `./protocol.js` follows the cycle
that earlier modules already use (`protocol-publish-batch.ts`,
`protocol-stored-overlay-reads.ts`). It reads the constant only at call
time.
The one new statement in `protocol.ts` is the import of the new module.
## The durability `--list`
`check-durability-degradation-log-level` exits 0 at both ends with
identical output. Its `--list` is **identical once `[@:][0-9]+` is
stripped**: 159 lines, and no entry changes file. The body has no
`catch` and makes no engine call. Its two reads are `repo.headAt(...)`
on the overlay repository.
## The published `.d.ts`
The series bar is ruling `6348891160`, sorted-union identity, measured
first.
Base `0a1061a61c` and head `e6ddd60ba6` were built with `pnpm --filter
@objectstack/metadata-protocol build` against one dependency tree. The
closure was built at head by a full `pnpm build` (119/119). For the base
build, the package's `src/` was swapped tree-only to base and restored
from `HEAD` under a trap. Afterwards `git diff HEAD` was empty, `git
status` was clean, and both touched blobs equalled `HEAD`'s.
The readings were taken on the pre-merge tree and again after merging
`main` (head `5a7ad6a7b2`, closure rebuilt by a full `pnpm build`,
119/119). They hold for both:
- **Raw sha256**:
`08914e65f936a2b031c3f3f215481a97f53d132eefd869e4f42d928947ebe173` at
base and at head, on both `dist/index.d.ts` and `dist/index.d.cts`,
775,874 bytes each. **Raw identity holds**, so sorted-union identity
holds too. The member stays a `private NAME;` line, and the newly
exported `FLOW_FALLBACK_VERDICT_NOT_REPLAYED` does not appear.
- **Normalised sha256**:
`46ccd7e5c4db673652513d1801ec9c9f06bf34a0a7fb6ba97fb2531ef0cc544b` at
both ends (80 string-literal union runs sorted, using the cut 12
normaliser).
- **The two builds differ where they should.** `index.js` hashes
`8732ec7d7e0d5cd5…` at base and `74a6c78db7e9bcc6…` at head. The
`.call(host` site of `flowSaveReplaysRetired` occurs 0 times in the base
bundles and once in the head bundles, ESM and CJS alike. `function
flowSaveReplaysRetired(` appears 0 times at base and once at head.
- **Positive control** on the head tree. `private` was dropped from
`flowSaveReplaysRetired` on disk (restored from `HEAD` under a trap) and
the package rebuilt. Both `.d.ts` files move to `bd3b47c8b435f536…`
(normalised `164c324a9516551e…`) and print
`flowSaveReplaysRetired(request: { name: string; item?: unknown;
packageId?: string | null; …`. So the bar can see a change on this
member.
- **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. Neither the moved function,
`FlowSaveReplayHost` nor `FLOW_FALLBACK_VERDICT_NOT_REPLAYED` appears.
No changeset: `skip-changeset`, per ruling `6348891160`.
## Proof of move-only
**Body, by AST token.** The compare reads the TypeScript compiler's AST
leaf tokens, skipping JSDoc, over the parameters (less the added
`this`), the return type and the body. It runs base `protocol.ts` at
`0a1061a61c` against the head module:
```
flowSaveReplaysRetired: base tokens 642, head tokens 642, differ 0, text-equal(ws-collapsed, comments incl.) true
TOTAL tokens=642 differ=0 members=1
CLASS members base=300 head=300 order-same=true byte-identical=299 stubs-with-identical-docblock+signature=1 other=[]
TOP base=246 head=247 byte-identical=244
```
**Negative control.** One token was changed in an in-memory copy of the
head module (`mode === 'draft' ? 'draft' : 'active'` to `mode !==
'draft' ? …`, one occurrence):
```
MUTATED packages/metadata-protocol/src/protocol-flow-save-replay.ts "mode === 'draft' ? 'draft' : 'active'" -> "mode !== 'draft' ? 'draft' : 'active'"
flowSaveReplaysRetired: base tokens 642, head tokens 642, differ 1, text-equal(ws-collapsed, comments incl.) false
TOTAL tokens=642 differ=1 members=1
```
- **Class side.** There are 300 members at base and at head, in the same
order. The 299 that did not move are byte-identical to base, leading
comments included. The stub sits at its base position and keeps its
docblock and signature byte-identical (everything before the body's
opening brace). The base signature spans lines (`(request: {` … `},
mode: …): Promise<boolean> {`). The module splits the two parameters
onto their own lines. The token compare shows that this changes
whitespace only.
- **Top level of `protocol.ts`.** 244 of the 246 base statements are
byte-identical, leading comments included. The other two are the
`@objectstack/spec` import, which loses `ALL_CONVERSIONS`, and
`FLOW_FALLBACK_VERDICT_NOT_REPLAYED`, which gains `export`. Head adds
one statement, the import of the new module.
- **Size.** +123 / −54 over 2 files, 177 changed lines.
`protocol-flow-save-replay.ts` has 115 lines.
## Readers of the moved lines
Every test and script that reads `protocol.ts` by path (70 files) was
grepped for the member name and for the identifiers its body uses:
`ALL_CONVERSIONS`, `applyConversionsToFlow`,
`FLOW_FALLBACK_VERDICT_NOT_REPLAYED`, `getOverlayRepo`, `headAt`,
`excludeConversionIds`, `includeRetired`, `retiredFromLoadPath`, and the
local names. So were all test files in `packages/` and `ui/`, and
`docs/qa/`.
- **`protocol.view-expansion-reconcile-call-sites.test.ts`** reads
`protocol.ts` by path. It holds a census of stored-row WRITES
(`repo.put/delete/promoteDraft/restoreVersion(`, raw `sys_metadata`
engine writes). It also pins that a repository is bound only as `const
repo = this.getOverlayRepo();`. The moved body binds `repo` that way and
calls only `repo.headAt(`, a read. So the census loses no write, and no
pin edit is owed. Six earlier seam modules already bind
`this.getOverlayRepo()` outside `protocol.ts` on the same footing
(`protocol-drafts.ts`, `protocol-publish-batch.ts`,
`protocol-save-door-refusals.ts` and others). The pin passes at both
ends, in the package suite.
- **No other by-path reader reads a moved body.**
`protocol.driver-text-disclosure.test.ts` and
`protocol.object-registry-write-through-spelling.test.ts` match on
`getOverlayRepo`, but as an instance override or call, not the moved
text.
- **Behaviour through the class method, no edit owed.**
`packages/rest/src/meta-flow-save-retired-spelling.test.ts` names
`flowSaveReplaysRetired` in its header and drives it through the save
door. It was run at head after the full build: 1 file, 10 tests passed.
- No hit in `docs/qa/`.
- **ADR anchors.** `check-adr-anchors` exits 0 with identical output at
both ends. The body cites `[#23903, ruling B′]`, an issue citation that
moves with it, and no ADR.
- **Engine-double contract** (`check-engine-double-contract`). It exits
0 at both ends. The `updateData`/`deleteData` seams keep their entries
at new line numbers (13976 → 13930, 14001 → 13955). `productionFiles` is
3,739 at base and 3,741 at head. Of the +2, one is the new file and one
is the gitignored `packages/spec/src/migrations/registry.ts` that the
spec build writes in the head tree.
- **Identical output at both ends:** `check-adr-symbol-anchors`,
`check-system-context-census`, `check-tenant-audit-census`,
`check-query-options-erasure-ratchet`, `check-filter-alias-parity` 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 `0a1061a61c`.
- **Governed surface.** `check-governed-merges --branch
claude/project-thread-ybjm3h` finds 0 of 2 paths in the register, so the
change is NOT governed. At 177 changed lines it is under the 3,000-line
human-merge bar.
## Verification
- `tsc --noEmit` in `packages/metadata-protocol` exits 0 before and
after the merge. `pnpm exec eslint --no-inline-config
packages/metadata-protocol` exits 0 with no output. It covers the whole
touched package, which has no `lint` script; these are the root `lint`
script's flags.
- **`packages/metadata-protocol` suite**, base and head, compared per
test name and status. Each run used vitest `--maxWorkers=2` with the
JSON reporter under the shared verify lock, and both legs gave `VERDICT
command-exit 0`. The runs are on the pre-merge tree; the merge changed
no file of the package.
- Base `0a1061a61c`: 21,558 tests (21,539 passed, 0 failed, 19 skipped),
269 files.
- Head `e6ddd60ba6`: 21,558 tests (21,539 passed, 0 failed, 19 skipped),
269 files.
- None lost, none added, none changed status. The base leg is the
package `src/` swapped tree-only from `0a1061a61c` (the new module
removed) and restored from `HEAD` under a trap.
- `check-platform-checklist --changed-from origin/main` on the merged
tree: OK, with 1 anchored file in the change set, 29 anchors judged and
0 lost.
- **Derived gates.** `dispatch-gates --commands --repo
objectstack-ai/objectstack` derives 51 gates on 2 changed paths from the
merged tree `5a7ad6a7b2`; all 51 exit 0 after the full `pnpm build`
(119/119). `dispatch-gates --ran`: 51 derived, 51 run, 0 NOT-MEASURED, 0
UNRUN, exit 0. The derivation flags the tree as behind `main`, but only
for `scripts/check-cli-test-child-env.mjs` and
`scripts/sdui-manifest.sources/i18n.json`; neither feeds one of these 51
families. Re-deriving against the newer `main` gives the same 51-line
list, so `main` was not merged again.
## Carry-forward
Unchanged from cut 17. These stay in `protocol.ts`:
- Public members whose return type is inferred.
- The bodies kept by a reader: `probeRecord`, `getMetaItemCached`,
`findReferencesToMeta`, `packagelessAddress`,
`refuseUnmintableMetaType`, `metaTypeNamespaceExists`,
`viewContainerNameCollisionRefusal` with
`overlaidShippedContainerViewNames`, `reportPageRequiresAbsentAtLoad`,
the 7 `applyRegistryWriteThrough` callers,
`readCodeLayerForCarryForward` and `ensureObjectStorage`.
- The private-static readers: `refusePackagedBaseRemoval`,
`packagedBaseRefusal`, `runPublishSideEffects`,
`promoteDraftForPublish`, `publishPackageDrafts` and
`discardPackageDrafts`.
- The field writers: `warnClosureReadUnavailable`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 46255b1 commit 77dc706
2 files changed
Lines changed: 123 additions & 54 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
166 | 166 | | |
167 | 167 | | |
168 | 168 | | |
169 | | - | |
| 169 | + | |
170 | 170 | | |
171 | 171 | | |
172 | 172 | | |
| |||
400 | 400 | | |
401 | 401 | | |
402 | 402 | | |
| 403 | + | |
| 404 | + | |
403 | 405 | | |
404 | 406 | | |
405 | 407 | | |
| |||
3356 | 3358 | | |
3357 | 3359 | | |
3358 | 3360 | | |
3359 | | - | |
| 3361 | + | |
3360 | 3362 | | |
3361 | 3363 | | |
3362 | 3364 | | |
| |||
6604 | 6606 | | |
6605 | 6607 | | |
6606 | 6608 | | |
6607 | | - | |
6608 | | - | |
6609 | | - | |
6610 | | - | |
6611 | | - | |
6612 | | - | |
6613 | | - | |
6614 | | - | |
6615 | | - | |
6616 | | - | |
6617 | | - | |
6618 | | - | |
6619 | | - | |
6620 | | - | |
6621 | | - | |
6622 | | - | |
6623 | | - | |
6624 | | - | |
6625 | | - | |
6626 | | - | |
6627 | | - | |
6628 | | - | |
6629 | | - | |
6630 | | - | |
6631 | | - | |
6632 | | - | |
6633 | | - | |
6634 | | - | |
6635 | | - | |
6636 | | - | |
6637 | | - | |
6638 | | - | |
6639 | | - | |
6640 | | - | |
6641 | | - | |
6642 | | - | |
| 6609 | + | |
| 6610 | + | |
| 6611 | + | |
6643 | 6612 | | |
6644 | | - | |
6645 | | - | |
6646 | | - | |
6647 | | - | |
6648 | | - | |
6649 | | - | |
6650 | | - | |
6651 | | - | |
6652 | | - | |
6653 | | - | |
6654 | | - | |
6655 | | - | |
6656 | | - | |
6657 | | - | |
6658 | | - | |
6659 | | - | |
| 6613 | + | |
6660 | 6614 | | |
6661 | 6615 | | |
6662 | 6616 | | |
| |||
0 commit comments