Skip to content

test(spec): the last system/ file group's test titles state each cited decision in words instead of a tracker number (stage 27) - #21997

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20749-test-strings-r
Oct 6, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20749-test-strings-r

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20749
Clause-②: no

Stage 27 of this card: the next area of class (e), the test strings shipped under packages/spec/src, as ruled in 5902360492 on #20513. This stage takes the second and last name-ordered system/ group: the 16 id-bearing test files under packages/spec/src/system/ from metadata-form-zod-reconciliation.test.ts to worker.test.ts. Those files carried 63 messages and 70 tracker ids. All 70 now either state what their record decided, in words (form D), or are dropped where the string already says it. No needle sits in this group. Text only: no assertion, identifier, test count or code comment changes, and no file is renamed. This finishes system/ for this class.

Census at the base (aa09db58c9)

Instruments: census10.cjs (md5 9d08602ab972b4b8643c90d64d40fa41), census.cjs (md5 6e42a45a926d375013c32d62f16a296e), census-wide.cjs (md5 c98410a19529c439adb0afbfb00026a2) and dirtable.cjs (md5 dda605c54745b4a60cc14c9a686e4eff), byte-identical to the copies stages 10 to 26 used. A literal counts as a test title when its folded message is argument 0 of a describe / it / test call, .each / .skip / .only chains included. Everything else is an "other" string.

The worktree was cut from origin/main at aa09db58c9, the claim's base and stage 26's landing. Both instruments read 191 messages / 200 ids in 53 files, the seat's reading and stage 26's head reading.

directory files messages / ids titles other
(files directly in src/) 30 118 / 120 117 / 119 1 / 1
system/ (this PR: all 16) 16 63 / 70 45 / 49 18 / 21
ui/ 5 7 / 7 0 7 / 7
ai/ 1 2 / 2 0 2 / 2
contracts/ 1 1 / 1 0 1 / 1
total 53 191 / 200 162 / 168 29 / 32

The group reads 63 messages / 70 ids in 16 files, the seat's figures file for file:

file (under system/) messages / ids titles other
metadata-form-zod-reconciliation.test.ts 21 / 24 4 / 4 17 / 20
metadata-persistence.test.ts 1 / 1 1 / 1 0
metrics.test.ts 4 / 5 4 / 5 0
notification-event-migration-retirement.test.ts 3 / 3 2 / 2 1 / 1
notification.test.ts 1 / 1 1 / 1 0
object-storage.test.ts 1 / 1 1 / 1 0
operation-message.test.ts 3 / 3 3 / 3 0
registry-config.test.ts 1 / 1 1 / 1 0
settings-manifest.test.ts 5 / 5 5 / 5 0
stack-server.test.ts 2 / 2 2 / 2 0
tenant-provisioning-family-retired.test.ts 1 / 2 1 / 2 0
tenant.test.ts 3 / 5 3 / 5 0
tracing.test.ts 3 / 3 3 / 3 0
translation.test.ts 12 / 12 12 / 12 0
validation-message.test.ts 1 / 1 1 / 1 0
worker.test.ts 1 / 1 1 / 1 0
16 files 63 / 70 45 / 49 18 / 21

Five more test files sit in the same name range and carry no id (migration, search-engine, security-context, supplier-security, translation-typegen). The 18 "other" strings are declared to the text-only tool: the 17 ledger reasons in metadata-form-zod-reconciliation.test.ts (LEDGER rows :256, :263, :270, :283, :426, :433, :440, :447, :454, :470, :477, :484, :491, :507, :514, :521, and the TOP_LEVEL_DEFERRED.view reason at :880), and one expect failure message at notification-event-migration-retirement.test.ts:165.

  • Controls. Lit: ai/build-progress.test.ts (2 / 2) and three files directly in src/ (assembled-package-body 4 / 4, compose-key-dispositions-export.pin 5 / 5, compose-stacks-action-collision-shape 3 / 3), outside the group, read the same at the base and at the head. Dark: the 16 files read 0 at the head while 141 of their lines still carry # plus digits, every one of them a comment line. Planted in a scratch tree: an id put into the rewritten "page component copy, keyed by component id" title reads 1 / 1 (title:describe), the base text put back into the :440 ledger reason reads 1 / 1 (other), and an id put into a metrics.test.ts comment reads 0.
  • A wider pattern (any # plus digits) reads the same as the gate pattern in all 16 files at the base, and 0 in all 16 at the head.
  • At the head: 128 messages / 130 ids in 37 files. The 16 files read 0 / 0, system/ is absent, and no other file moved.

How the area was chosen

system/ is taken in name-ordered file groups near the ~100-id bound, the rule stages 20 to 26 used. Stage 26 named this group at 70 ids, and this census reads 70, so no re-cut was needed.

Named for the next stage (cut from the head census, 128 / 130):

  • The files directly in src/: 30 files, 118 messages / 120 ids (117 / 119 titles, 1 / 1 other, at stack-cross-reference-envelope.test.ts). The largest file is stack-inline-action-crossref.test.ts at 13, and no file needs splitting. It fits one PR and one text-only proof at 120, 20% over the ~100 bound. If the seat holds to "within about 10%", the name-order cut is two groups: assembled-package-body.test.ts through inline-grid-column-carriers.test.ts (18 files, 61 ids) and root-entry-migrations-split.pin.test.ts through stack.test.ts (12 files, 59 ids).
  • The needles: one stage, with an at-tier review. The four colour literals stay, as stage 21 decided.

What each id became

  • 22 literals (24 ids) now state a decision in words.
  • 1 literal (1 id) gets its subject back in words.
  • 40 literals (45 ids) drop a number the string already explains.

Every cited record was fetched with all its comments through REST. 37 records are cited, plus one decision-batch number (below): 35 answer 200, and 2 answer 404. The two that answer 404 were read from what landed, through the commits endpoint (this checkout is shallow):

The ledger reasons in metadata-form-zod-reconciliation.test.ts (17 "other" strings). Before any was rewritten, every reader of the ledger and of the file was found:

"ruled" appears in two rewritten strings, both on #19330's ruling A (5754204415): :433 and :880 above.

The same-id titles stage 26 listed:

Stated in words (22 literals):

record literal (under system/) now reads the decision
#19332, #19330 metadata-form-zod-reconciliation.test.ts:433 "(ruling record 5861442317; per-arm view forms, ruled: one registered form per view kind)" Above.
#3786 metadata-form-zod-reconciliation.test.ts:886 "metadata form ↔ Zod reconciliation — a hand-written form held to its schema by a gate" The template for the hand-copied-list pattern: derive from the one source, and where it cannot be derived, a coverage assertion is the gate.
#15679 (#14478 ruling B) metrics.test.ts:500, object-storage.test.ts:864, registry-config.test.ts:215, tracing.test.ts:524, worker.test.ts:561 "… carry their unit in the key name" / "… carries its unit in the key name" Above.
#15939, #14478 metrics.test.ts:584 "metrics JSDoc-only durations carry their unit in the describe and the key name" #15939's ruling (5564447683, option 2): a key whose JSDoc names a unit its describe does not is a divergence, refused; the unit moves into the describe, where #14478's rule puts it in the key name. Ruling A (5635659224) remediates per file.
#17785 tracing.test.ts:565 "the OTel exporter and performance durations carry their unit in the describe and the key name" The tracing file's remediation under #15939's ruling A: the four keys renamed with their unit, and the unit published in the describe.
#16194 notification-event-migration-retirement.test.ts:165 (expect message) "… — its runner was retired, with no operator door and no boot-time invoker" The ruling (5582372148, batch #88): retire; no operator door and no platform invoker.
#7414 operation-message.test.ts:101 "operation message catalog — permission_denied, the 403 refusal as localized user copy" The 403 refusal renders through the operation message catalog in the caller's locale, naming no object, operation or position.
#7451 operation-message.test.ts:193 "operation message catalog — the row-level user copy, a sentence per situation" The row-level denials get their own keys (record_access_denied, record_change_not_allowed), not the grant denial restated.
#12493 (404) operation-message.test.ts:306 "… sharing write denial and approvals recall, two keys of their own" What landed in aa5994e17a, above.
#5933 settings-manifest.test.ts:230 "Specifier.valueDomain — a declared standard domain is the boundary, options a UI list" When valueDomain is declared, the standard domain is the enforcement boundary and options degrades to a UI convenience list.
#5131 settings-manifest.test.ts:246 "is optional — an undeclared specifier keeps exhaustive-options semantics, enforced at save" A select value outside its options is refused at save. #5933 keeps that for an undeclared specifier.
#7327 settings-manifest.test.ts:306 "visible — the settings visibility grammar, narrowed to what the save-time evaluator runs" Direction (b): narrow the declared type to the grammar the save-time evaluator implements, not CEL.
#15811 settings-manifest.test.ts:338 "REFUSES an ast-only envelope — an evaluated slot requires a non-blank source" Ruling A (5644350409, batch #122 item 2): every engine-evaluated expression slot requires a non-blank source.
#4938 stack-server.test.ts:61 "server: carries only keys with a consumer — the retired HttpServerConfig keys stay out" The maintainer ruling A (5173147201): the unreachable HttpServerConfigSchema and its seven dead keys are retired.
#16772 translation.test.ts:840 "dashboard global-filter copy, addressable from a bundle by filter name" Finding B: dashboards.NAME.globalFilters.KEY becomes a bundle group, keyed by the filter name.
#6080 translation.test.ts:901 "page component copy, keyed by component id" Page component copy gets a bundle address by component id.
#7646 translation.test.ts:1082 "screen-flow copy — a flows bundle group, runner chrome kept out" The recorded ruling (5253154523): a flows surface for flow, screen and field copy; runner chrome stays in the console's own catalog.
#3957 validation-message.test.ts:90 "renderValidationMessage — English output is unchanged, the field label in place of the API name" Messages name the field by its label, through the message catalog. The describe pins the English output as before, label for API name.

Subject back in words (1 literal): translation.test.ts:713 "should reject the retired shape …" now names it, "the retired object-first o. shape". #3778 retired that shape for the translation type.

Dropped where already stated (40 literals, 45 ids). A number goes only where the string already says its decision. Examples: the 15 ledger reasons above; :880's "(the #19330 ruling, letter A)"; the tails (#5280), (#14327), (#19332), (#18124) x2, (#5933), (#4001) x3, (#14478, #14519), (#14519), (#15939, #14478) on "→ schemaCacheTtlSeconds", (#10926), (#21257), (#11287), (#15178), (#19620), (#4667); and the prefixes #18118 x2 (before "the retired CEL arm"), [#16194] x2, [#4616] and [#4739 / #16325]. The one 404 number among them (#10926) goes only where the title already states what landed.

No file is renamed.

Readers

  • Needles: none. The 17 ledger reasons are data the file's own assertions read for their class phrase, record id and editor names, all kept (above); none reads an id. The one declared expect message is a failure message (the second argument of expect), not an expected value. notification-event-migration-retirement.test.ts reads the NOTIFICATION_EVENT_MIGRATION_ID docblock for a claim matrix's absence and for RETIRED / os migrate / boot-time invoker / files-to-references, none of them an id. No title or message in the group is matched against a source docblock or another file's text.
  • Test-name filters: none. No tracked script, workflow or package config passes -t / --testNamePattern to vitest; the one vitest -t hit is a README example under packages/qa/dogfood filtering its own fixture.
  • Snapshots: none. No __snapshots__ directory is tracked under packages/spec, and none of the 16 files calls a snapshot matcher.
  • Projects: all 16 files run in local; none is in packages/spec/vitest.repo-tests.json. The base-versus-head run below takes both projects anyway.
  • By substring: every old literal, its id-bearing fragment and a window around each id (193 needles) was searched with git grep at the base, across the tracked tree outside its own file. No gate, doc, filter, snapshot, QA checklist entry or scripts/check-*.mjs self-test reads one. The 26 hits are 16 published CHANGELOG lines, which quote "form ↔ Zod reconciliation (排查「手抄 spec 清单 + "keep in sync" 注释」模式:一天内确认三例,全部曾静默漂移 #3786)" and "strict from birth (未知键静默剥离仍是全仓默认:把 #3405 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) #4001)" as release text, and 10 sibling hits among the five (#15679) titles of this group, all rewritten here.
  • One code comment quotes a title: tracing.test.ts:560 says "a describe headed Span.duration carries its unit". The new title keeps that prefix.

Text-only proof

Stage 10's scratch tool (textonly10.cjs, md5 d5e4801dbb4329ab1984da91e92fc47c) compares base and head file by file on three legs:

  1. Skeleton: the full AST, with string pieces masked. It must be identical.
  2. Comments: every comment, byte-equal.
  3. Strings: each changed string leaf must sit in a test-call title position or on a declared line, must carry a tracker id before, and must carry no # plus digits after. This stage declares the 18 lines named above.
  • Result: 16 of 16 files SAME on all three legs, with the per-file counts predicted in writing before any edit (2026-10-06T13:25:38Z).
  • Totals: 63 changed string leaves in 63 literals: 45 titles and 18 declared. The diff's + and - lines are exactly the 63 planned lines as multisets, and every file keeps its line count.
  • Controls (14 of 14 as predicted on the first run, on scratch copies, each anchor hit once): identifier rename DIFF; numeric literal DIFF; comment edit COMMENT DIFF; a non-title string given an id VIOLATION; a rewritten title given a new id VIOLATION; a title that was id-free at base edited VIOLATION; one title reverted to base SAME; an it.each row given an id VIOLATION; an undeclared expect message changed VIOLATION; a title re-split into a + chain DIFF; a declared ledger reason reverted to base SAME; the declared deferral reason given a new id VIOLATION; the declared expect message given a new id VIOLATION; a template-literal title given a new id VIOLATION.
  • Templates and tables: no .each title, no $name / %s placeholder and no table row changes.

Test counts: the 16 files were run at the base, before the edit, and at the head, in the same worktree, with --project local --project repo. Both sides read 747 tests in 16 files, all passed, with the same count and status sequence per file in 16 of 16. 302 full test names change, and each changed name equals the base name with the planned replacements applied: 0 mismatches. One full name repeats on each side, the same one: an it.each pair under "translation unknown-key strictness" that already printed alike at the base. No head name carries # plus digits (302 base names did). No source escape sits in a planned anchor, so the comparison tool met none.

Changeset: skip-changeset

Measured, not assumed:

  • npm pack --dry-run of @objectstack/spec lists 2068 files. 0 of the 16 touched files are in it, and no *.test.ts at all (files[] ships src/**/*.zod.ts, not tests). The controls src/system/translation.zod.ts, src/system/metrics.zod.ts and dist/index.mjs are in it.
  • In the built dist/, two new phrases and an old one each read in 0 files. The control Unrecognized key reads in 42.

So this PR publishes nothing, and no changeset is added.

Verification (at 320cf687c7)

  • pnpm turbo run build over all packages: 71 / 71, through the shared verify lock (turbo exit 0, recorded to a file).
  • @objectstack/spec:
    • vitest run --project local: 619 files, 18485 passed, 1 todo.
    • typecheck: exit 0, including check:test-typecheck (52 files / 246 errors / 135 pinned signatures held). Its program holds all 16 group files, counted by path with tsc --listFilesOnly -p tsconfig.test.json.
    • check:generated: all 15 generated artifacts up to date, against the dist/ the build above wrote.
  • Gates: dispatch-gates --commands derived 79 families, the same 79 as stage 26. All 79 exit 0. --ran reconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN, every family with its exit code recorded. The five roster families marked as sharing a directory with this diff (check:meta-url-spelling, check:spec-changes, check:authz-resolver, check:error-code-casing, check:filter-alias-parity) each exit 0.
  • ESLint, a proven narrowing: --no-inline-config over the 16 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 16 configured, 0 ignored. No file sets parserOptions.project or projectService, so no untouched file's verdict can move.
  • check-governed-merges --test: NOT governed, 126 changed lines (+63 / -63).
  • A control-byte scan over the 16 changed files finds none.

main since the base

Re-fetched just before this PR opened, origin/main was one commit past the base (6befe19c6e, #21990). It touches 4 files in packages/metadata-protocol and .changeset/, none of the 16 and none under packages/spec/src/system/, so main was not merged. git merge-tree onto 6befe19c6e is clean, and none of the 4 open PRs touches any of the 16 files.

Acceptance notes


Generated by Claude Code

…d decision in words instead of a tracker number (stage 27)

Stage 27 of the spec lane's share of the runtime-string burn-down: the
test strings shipped under packages/spec/src, the second and last
name-ordered system/ group (metadata-form-zod-reconciliation.test.ts
through worker.test.ts).

63 literals in 16 files (45 test titles and 18 declared strings: 17
reconciliation-ledger reasons and one expect message) lose 70 tracker
ids: 22 literals now state the cited decision in words, 1 gets its
subject back in words, and 40 drop a number the string already
explains. The ledger reasons keep every substring the file's own
assertions read, the ruling record id included. No needle sits in this
group.

Text only: one line per literal, no assertion, identifier, test count,
code comment or file name changes.

Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ
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 6, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 6, 2026
@github-actions github-actions Bot added the size/m label Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

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 6befe19c6e391ae655e1cc8a1c0589ba926d4592 → packageMentionDocs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

protocol:system size/m 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