Repository navigation
Commit 609d07a
Part of #23182 (row 1)
Clause-②: no
This PR is step B of row 1 of #23182: `@objectstack/metadata-protocol`,
`src/protocol.lock-one-resolution.test.ts`. Step A (#23755,
`4fe8b3def0`) took each read once and left the single file at about 8 s
alone and 21 to 28 s in a CI-shaped package run. This step splits the 16
320 generated rows over four shard files, as the seat answered in
comment 6204945326 (A+B, K=4). It changes test files and one ledger row,
and no production file. #23182 stays open: this PR does not close row 1
by itself (its pin is the next refresh's list, owed to the refresh), and
rows 5 and 6 are separate.
## What the split is
| file | holds | tests |
|:--|:--|--:|
| `protocol.lock-one-resolution.kit.test.ts` (new) | the shared helper:
table, oracle, engine and registry doubles, door, reads, `readScenario`,
`agree`, the partition, and the shard-set pin | 2 |
| `protocol.lock-one-resolution.shard-1.test.ts` to `shard-4.test.ts`
(new) | one call each, `registerRowShard()`; the shard a file is comes
from its own name | 4080 each |
| `protocol.lock-one-resolution.test.ts` (kept) | the 40 named tests
(completeness, subset, lit controls, pins 2 to 10), unchanged, importing
the helper | 40 |
- **Titles are unchanged.** The 16 360 tests of the single file all run
under the same full titles (describe, then test): compared as sets, base
16 360 unique titles, branch 16 362 unique, 0 only in base, and the only
two in the branch alone are the new pin's. No shard prefix was needed,
so there is no old-to-new mapping.
- **The partition.** The rows that share a read request differ only in
`requestScope` and `operation`, which no read takes: one read group is a
row's title with those two axes blanked (`readGroupOf`). Groups are
numbered in the table's own order, and group n is run by shard (n mod 4)
+ 1. A group is never split, so step A's four-to-one read memo holds
inside every shard. It is a pure function of the table, so a row, slice
or axis added later lands in a shard by the same rule. Each shard holds
1 020 groups, 4 080 rows.
- **The pin (`kit`, always run: it is a test file).** Two tests. The
first: the shards' rows are the table's, once each (counted with
repeats, as a set, and by identity against the table's titles), no shard
is empty, and every read group is whole, in one shard, and of exactly
scope times verb rows. The second: the shard files on disk are exactly
the four expected names, and each one calls `registerRowShard()` on a
line of its own. A shard file whose name is not one of the four fails at
collection (the count is read from the file name, so a rename cannot
leave rows unrun).
- **Why the helper is a `.test.ts` file.** Three gates read engine
doubles and each walks `*.test.ts` files only
(`check:engine-double-contract`, `check:where-matcher`,
`check:objectql-double-limit`). A double in a `*.testkit.ts` file would
have left all three, and `check:engine-double-contract` would have
called the leaving row the #9680 defect. Sharing a double through a test
file is already this repository's practice
(`impersonation-bearer-rotation.test` is imported by fifteen plugin-auth
tests). What an import must not do is run the helper's own tests in the
importer: the helper registers its two tests only when it is the file
vitest was started on (`expect.getState().testPath`).
- **The ledger row moves with the double.**
`scripts/engine-double-contract.pinned.json` changes by one row, the
`findOne` row, from `protocol.lock-one-resolution.test.ts` to the kit.
`check:engine-double-contract --write` printed "922 (file, verb) row(s),
1 added or grown, 1 lost"; the one lost is the old path, and the double
it names is the one the new row names, so coverage is unchanged.
`check:where-matcher` and `check:objectql-double-limit` read the moved
double and report none new.
## Wall time
Vitest module line in ms, a shared 4-core box under `os-verify-lock`,
default reporter, `--maxWorkers=2`, each file alone. BASE is the single
file on `origin/main` `6362c66ca8` (a copy run beside the branch's
files); the branch readings are at `c19398bd2f`, and the final commit
`7686410907` changes comments only.
| | BASE | AFTER |
|:--|:--|:--|
| single file, 3 runs | 8289 / 8016 / 8397 | n/a |
| shard 1 | n/a | 2609 / 2532 / 2582 |
| shard 2 | n/a | 2622 / 2404 / 2697 |
| shard 3 | n/a | 2505 / 2374 / 2581 |
| shard 4 | n/a | 2528 / 2497 / 2672 |
| the 40 named tests, the pin | n/a | 238, 101 |
| all six files together, `--maxWorkers=4` (each shard beside the
others) | n/a | 4648 to 4867 per shard |
| whole package, `--maxWorkers=8` (2x oversubscribed), the slowest file
| 21305 | 3739 to 3966 per shard (named tests 714, pin 253) |
- **No shard is near 4 s alone**, so K stays at 4. K=6 would be about
1.7 s a shard by proportion; that is not measured. K is one constant
(`ROW_SHARDS`) plus the shard files, and the pin stays red until the two
agree.
- **The cost of five more files.** The whole-package run took 198 s at
BASE and 211 s on the branch, with the vitest import phase at 1395 s and
1483 s of worker time; 241 files and 20 579 tests against 236 and 20
577. That is one reading each, on a shared box, and not a figure to
quote closer than "a few percent".
- **CI after the split: NOT MEASURED here** (job logs redirect to a blob
host the egress proxy refuses). The card's 113 s CI reading was 5.4
times the local reading of the single file at that time; at that ratio
one shard would read about 14 s, and at this box's 8-worker reading (1.5
times alone) about 4 s. The next refresh PR's list is the reading to
trust.
- **Test count:** 16 362 pass in the six files, 16 360 plus the pin's
two.
## Ablation: the rows still go red on the same titles, and the pin goes
red on a lost row
Each leg mutated production source through
`scripts/ablation-replace.mjs` (anchor 1 to 0, a unique replacement,
blob changed on disk), ran a copy of the single file on `origin/main`
and the six branch files in one vitest run, and restored the path to its
HEAD blob with `git diff HEAD` empty. The subject is imported by
relative path from `src`, so no dist is in play. Red sets are compared
by full title.
| leg | mutation | red, single file | red, shard set | sets |
|:--|:--|--:|--:|:--|
| A1 | the item lock joins only the first shipping package's answer
(`item-lock.ts`) | 2384 | 2384 | equal |
| A2 | the write doors ignore the stored rows (`item-lock.ts`) | 1823 |
1823 | equal |
| A3 | the served body no longer carries the resolved lock family
(`item-lock.ts`) | 7744 | 7744 | equal |
| A4 | an organization-scoped write is not refused first (`protocol.ts`,
temporary, restored) | 8160 | 8160 | equal |
The pin stays green under all four, since none of them touches the
partition. These counts are the ones step A measured.
The pin's own legs (kit tests plus the four shards; the first three by
deleting, renaming or editing a tracked file and restoring it with `git
checkout HEAD`):
| leg | change | what goes red |
|:--|:--|:--|
| P1 | `shard-4` deleted | the pin's file test (3 files on disk, 4
expected); the three shards left stay green |
| P2 | `shard-2` renamed to `shard-9` | the pin's file test, and
`shard-9` itself at collection (the name is not one of the four) |
| P3 | `shard-3` loses its `registerRowShard()` call | the pin's file
test (names the file), and `shard-3` ("No test suite found") |
| M1 | the partition drops 169 rows (index mod 97) | the pin's row test:
"expected [ ...(16151) ] to have a length of 16320 but got 16151"; every
row that did run is green |
| M2 | the partition numbers groups by full row, splitting the read
groups | the pin's row test: 4080 read groups split over shards |
| M3 | the partition uses three shards of four | the pin's row test
("shard 4 runs no row") and `shard-4` at collection |
M1 is the case the pin exists for: a lost quarter-percent of the table,
with every remaining test green.
## Verification at `7686410907`
- **Typecheck:** `pnpm --filter @objectstack/metadata-protocol
typecheck` exits 0; `tsc --listFiles` names all six files.
- **Lint (narrowed to the six files):** `eslint --no-inline-config
--format json`: 6 files, 0 errors, 0 warnings. `--print-config` returns
a config for the kit, with parserOptions `ecmaVersion` and `sourceType`
only: type-aware linting is off, so this diff cannot move any other
file's result.
- **Gates:** `dispatch-gates` over the 7 changed paths derives 59
commands. All 122 distinct commands (the 59, plus the 53 artifact-roster
and 11 wide-population families it names, one shared) ran at this head
after a full `turbo run build` (74 tasks): 118 exit 0 and 4 exit
non-zero. The four are PR-context guards that judged nothing and say so
(`check-closing-target-claim`, `check-single-claim-paths`,
`check-partof-closing-keyword`, `check-governed-queue-guard`): NOT
MEASURED, not red. `dispatch-gates --ran` with exit codes: 59 derived,
59 run, 0 NOT-MEASURED, 0 UNRUN.
- **Stale tree:** the derivation reports this tree 5 commits behind
`origin/main`, with two files it derives from changed upstream
(`scripts/check-route-envelope.mjs` and an adr-anchors file for
`packages/rest/src/discovery-routes.ts`: the `check:route-envelope`
family, whose population is non-test sources in `packages/rest`, which
this diff does not touch). I did not merge `main`, as the card says.
- **Bytes:** a control-byte scan of the six files and the ledger finds
none; `check:nul-bytes` exits 0.
## No changeset
This diff changes only test files under `packages/metadata-protocol/src`
and one repository ledger under `scripts/`; the package's `files`
(`dist`, `README.md`, `CHANGELOG.md`) ships none of it. `skip-changeset`
is the label, as on step A.
## Acceptance notes
- Step A's note still holds inside each shard: up to four rows' doors
run on one shared protocol instance, in sequence, after its reads. The
split adds no new coupling.
- Each shard's partition depends on the table's order (group number in
table order); the pin is computed from the same function, so a reorder
moves rows between shards without losing any.
- Each extra test file imports `protocol.ts` once (see the import-phase
reading above); that cost is carried by this split and is the price the
seat's answer named.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01ADzJtzYTLUfgrRZHxkagkX)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent b485122 commit 609d07a
7 files changed
Lines changed: 867 additions & 633 deletions
File tree
- packages/metadata-protocol/src
- scripts
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
0 commit comments