Skip to content

test(metadata-protocol): lock-one-resolution runs as four shards under the 10 s budget (#23182 row 1, step B) - #23790

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-23182-lock-one-resolution-shards
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-23182-lock-one-resolution-shards

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

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 check:engine-double-contract has no ratchet on its DISCOVERED population — deleting a pinned double's delete() member takes 319 pinned to 318 and the gate stays green #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

…les over one shared helper (#23182 row 1, step B)

Claude-Session: https://claude.ai/code/session_01ADzJtzYTLUfgrRZHxkagkX
Co-authored-by: Claude <noreply@anthropic.com>
…ows the double into the shared helper (#23182 row 1, step B)

Claude-Session: https://claude.ai/code/session_01ADzJtzYTLUfgrRZHxkagkX
Co-authored-by: Claude <noreply@anthropic.com>
…d split (#23182 row 1, step B)

Claude-Session: https://claude.ai/code/session_01ADzJtzYTLUfgrRZHxkagkX
Co-authored-by: Claude <noreply@anthropic.com>
…r the 10 s budget (#23182 row 1, step B)

The table's 16 320 rows run in four shard files over one shared helper
(protocol.lock-one-resolution.kit.test.ts). The rows that share a read
request stay in one shard, so step A's four-to-one read memo holds in each.
A pin in the helper fails when a row is in no shard or two, a read group is
split, or a shard file is missing, renamed or empty. Same 16 360 test titles,
plus the pin's two tests; the engine double moves into the helper with its
ledger row.

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 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 d3df3ba24bbbb280d138d98fed7af5fe05f4a9ce → packageMentionDocs.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 03:05
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 03:05
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 609d07a Oct 16, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23182-lock-one-resolution-shards branch October 16, 2026 03:34
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