Skip to content

test(spec): the second api/ file group's test titles state each cited decision in words instead of a tracker number (stage 25) - #21975

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20749-test-strings-p
Oct 6, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20749-test-strings-p

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20749
Clause-②: no

Stage 25 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 api/ group: the 13 id-bearing test files directly under packages/spec/src/api/ from plugin-rest-api.handler-status-retirement.test.ts to zod-issues-to-fields.test.ts. Those files carried 89 messages and 95 tracker ids, citing 43 records. All 95 now either state what their record decided, in words (form D), or are dropped where the title 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. With this stage, api/ carries no tracker id in a test string.

Census at the base (5a22eb5619)

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 24 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 5a22eb5619, the claim's base and stage 24's landing. Both instruments read 371 messages / 392 ids in 84 files, the seat's reading and stage 24's head reading.

directory files messages / ids titles other
system/ 34 154 / 167 128 / 138 26 / 29
(files directly in src/) 30 118 / 120 117 / 119 1 / 1
api/ (this PR: all 13 files) 13 89 / 95 86 / 92 3 / 3
ui/ 5 7 / 7 0 7 / 7
ai/ 1 2 / 2 0 2 / 2
contracts/ 1 1 / 1 0 1 / 1
total 84 371 / 392 331 / 349 40 / 43

The group reads 89 messages / 95 ids in 13 files, the seat's figures file for file:

file (under api/) messages / ids titles other
plugin-rest-api.handler-status-retirement.test.ts 4 / 4 3 / 3 1 / 1
plugin-rest-api.schema-refs.test.ts 2 / 2 2 / 2 0
plugin-rest-api.test.ts 2 / 2 2 / 2 0
protocol.test.ts 46 / 50 46 / 50 0
registry-retirement.test.ts 2 / 2 1 / 1 1 / 1
rest-api-config-dead-keys-retirement.test.ts 2 / 2 2 / 2 0
rest-server.test.ts 19 / 19 18 / 18 1 / 1
router.test.ts 1 / 1 1 / 1 0
sortability.test.ts 3 / 4 3 / 4 0
storage.test.ts 2 / 2 2 / 2 0
validate-data.test.ts 3 / 3 3 / 3 0
websocket.test.ts 1 / 1 1 / 1 0
zod-issues-to-fields.test.ts 2 / 3 2 / 3 0
13 files 89 / 95 86 / 92 3 / 3

Five more test files sit in the same name range and carry no id (query-adapter.test.ts, realtime-shared.test.ts, realtime.test.ts, retired-error-codes.test.ts, versioning.test.ts). The three "other" strings are expect failure messages, rewritten and declared to the text-only tool: plugin-rest-api.handler-status-retirement.test.ts:179 and rest-server.test.ts:768 (template literals) and registry-retirement.test.ts:89 (one leaf of a + chain).

  • Controls. Lit: ui/notification.test.ts (1 id) and system/book.test.ts (2 ids), outside the group, read the same at the base and at the head. Dark: protocol.test.ts reads 0 at the head while 65 of its lines still carry a number, every one of them a comment. Planted in a scratch tree: an id put into a storage.test.ts title reads 1 / 1 (title:it), and an id put into a sortability.test.ts comment reads 0.
  • A wider pattern (any # plus digits) reads the same as the gate pattern in all 13 files at the base, and 0 in all 13 at the head.
  • At the head: 282 messages / 297 ids in 71 files. The 13 files read 0 / 0, api/ leaves the table, and no other file moved.

How the area was chosen

api/ has no subdirectory, so it is taken in name-ordered file groups near the ~100-id bound, the rule stages 20 to 24 used. Stage 24's cut named this group at 95 ids, and this census reads 95, so no re-cut was needed. protocol.test.ts (50 ids) fits one PR and one text-only proof, so it is not split.

Named for the next stages (cut from the head census, 282 / 297):

  • system/, 167 ids in 34 files (one of them in system/constants/), two stages:
    • first group: auth-config.test.ts through metadata-form-declared-rows.pin.test.ts, 18 files, 91 messages / 97 ids (i18n-resolver.test.ts alone 53 / 56);
    • second group: metadata-form-zod-reconciliation.test.ts through worker.test.ts, 16 files, 63 / 70. Its first file carries 17 "other" strings, its ledger why entries.
  • The files directly in src/, 120, one stage.
  • The needles: the three docblock needles, the kept ui/component-props-unknown-members.pin.test.ts:322 and stage 22's two. One stage, with an at-tier review. The four colour literals stay, as stage 21 decided.

What each id became

  • 10 literals (11 ids) now state a decision in words.
  • 12 literals (16 ids) get their subject back in words, where the number stood for a thing.
  • 67 literals (68 ids) drop a number the title already explains.

Every cited record was fetched with all its comments through REST, and its decision was read from its ruling, ACCEPT and landing comments: a keyword digest of every record, and full reads wherever the new words carry a decision. 43 records are cited: 36 answer 200 and 7 answer 404. Two more were read for context: #14478, whose ruling B #15677 executes, and PR #11426, #11006's landing. The seven that answer 404 were read from what landed, through the commits endpoint (this checkout is shallow), each commit found through the CHANGELOG entry or the commit list of protocol.test.ts:

The same-id titles stage 24 listed in this group:

Stated in words:

record literal (under api/) now reads the decision
#14478 via #15677 plugin-rest-api.test.ts:694, websocket.test.ts:712 "… durations carry their unit in the key name" Ruling B: a z.number() duration key carries its unit in its name; the old spellings are retiredKey() tombstones.
#5672 protocol.test.ts:508 "strips a capability key outside the closed vocabulary" Ruling A (2026-08-06): one closed vocabulary.
#5672 protocol.test.ts:526 "rejects a capability map that is missing part of the vocabulary (ruled: an absent capability is enabled: false, not a missing key)" Ruling A: both producers emit the whole vocabulary.
#9406 protocol.test.ts:1313 "probes is opaque BY DECLARATION (ruled: modeled only once a consumer needs a field): …" Maintainer ruling 2026-08-18 (5322875103): probes gets a deliberately opaque passthrough, upgraded to a modeled schema only when a consumer needs a field of it.
#9343 protocol.test.ts:1383 "PublishPackageDraftsResponseSchema published[].advisories (ruled: advisory findings ride each published element)" Maintainer ruling 2026-08-17 (5321046016): advisories rides each published[] element, with no parallel top-level map.
#9741 protocol.test.ts:1739 "environmentId stays OUT of the meta-read request shape — transport-level by decision, not omission" The 2026-08-18 ruling, as landed in 2a29caa532: environmentId is the transport-level multi-kernel routing key.
#12038 protocol.test.ts:2710 "GetPublishedMetaItemResponseSchema stays opaque (ruled: no shape frozen against the current type registry)" Ruling 1C (5434804846): a thin envelope with the body opaque, no union frozen against today's type registry.
#6037 validate-data.test.ts:25 "ValidateDataRequest — asks the write path for its verdict instead of predicting it" What landed in 18189983dd: the dry run stops predicting the write's verdict and asks for it.
#6037 validate-data.test.ts:57 "ValidateDataResponse — the verdict the write path would reach, persisting nothing" The same commit: validateData reports the write path's verdict on candidate rows and persists nothing.

Subject back in words (12 literals):

Dropped where already stated (67 literals, 68 ids). A number goes only where the title already says its decision. Examples: the two [#13823] describes and the twelve [#14691] / (#14691) retirement titles ("REJECTS patterns with the retirement prescription — …", "the tombstones reject one key each, not the config — …"); [#11983] x3, [#4579] x2, [#4939], [#6361], [#20294] and #3899 —; the #10235 prefixes on "resolveObjectSortability — the closed category set" and "wire validity — …"; the five "transport-level by the #9741 ruling" titles, which now read "transport-level by ruling"; the parenthesized (#5745 — …), (#7294 — …), (#9406 — …), (#10524 — …) x2, (#9726 — …), (#9741 — …) and (#4717 — …) pairs, which keep their words; and the tails (#6239), (#4286), (#9740), (#11006) x2, (#11678) x3, (#9426), (#12005) x3, (#11679) x2, (#12004) x2, (#3718), (#4572), (#4579), (#20294), (#8124/#8055), the five (#12038) and the (#4738, …) aside in one expect message. The 404 numbers among them (#6239, #6361, #9740, #9741, #11006, #14691) go only where the title already states what landed.

No file is renamed.

Readers

  • Needles: none. The three declared strings are assertion failure messages (the second argument of expect), none is an expected value, and no title or message in the group is matched against a source docblock or another file's text. The one self-read in the group, rest-api-config-dead-keys-retirement.test.ts:519, reads its own file for the id-free describe title "tree-scoped absence", which this PR does not touch.
  • 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 13 files calls a snapshot matcher.
  • Projects: rest-api-config-dead-keys-retirement.test.ts is in the repo project (packages/spec/vitest.repo-tests.json:31); the other 12 run in local. The base-versus-head run below takes both projects.
  • By substring: every old literal, its id-bearing fragment and a window around each id (270 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 6 hits are sibling test titles: the two (#15677) describes in this group hit each other (both rewritten here), client/src/client.test.ts:1134 shares "query.distinct ([P2] data: QueryAST declares 12 members no executor runs — the liveness ledger governs metadata types, not the request surface #4286)", and metadata-protocol/src/protocol.validate-data.test.ts:102 shares "the BatchOptions.validateOnly 声明了 dry-run 但从不实现 —— "预演"会真实落库(PD #10) #4052 non-repeat".

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 three expect-message lines named above.
  • Result: 13 of 13 files SAME on all three legs, with the per-file counts predicted in writing before any edit.
  • Totals: 89 changed string leaves in 89 literals: 86 titles and 3 declared. The diff's + and - lines are exactly the 89 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 expect message reverted to base SAME; a declared template expect message given a new id VIOLATION; a declared +-chain leaf given a new id VIOLATION; a template-literal title given a new id VIOLATION.
  • Templates and tables: no .each title and no $name placeholder changes. The two template literals change only their text after the ${…} span.

Test counts: the 13 files were run at the base, in a separate base worktree, and at the head, with --project local --project repo. Both sides read 509 tests in 13 files, all passed, with the same count and status sequence per file in 13 of 13. 250 full test names change, and each changed name equals the base name with the planned replacements applied: 0 mismatches. No full name repeats on either side, and no head name carries # plus digits (250 base names did). router.test.ts:565 writes its arrow as a → escape; the plan's anchor there starts after the escape, so the comparison tool, which reads escapes literally, met none, and vitest prints "RouteDefinition.timeout → timeoutMs …" on both sides.

Changeset: skip-changeset

Measured, not assumed:

  • npm pack --dry-run of @objectstack/spec lists 2068 files. 0 of the 13 touched files are in it, and no *.test.ts at all. The controls src/api/protocol.zod.ts, src/api/rest-server.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 c63eba0adf)

  • pnpm turbo run build over all packages: 71 / 71, through the shared verify lock (VERDICT command-exit 0).
  • @objectstack/spec:
    • vitest run --project local: 619 files, 18480 passed, 1 todo.
    • typecheck: exit 0, including check:test-typecheck (52 files / 246 errors / 135 pinned signatures held). Its program holds all 13 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: stage 24's 80 without check:error-code-casing, whose named sources this diff does not touch. All 79 exit 0. --ran reconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN, every family with its exit code recorded. The same 79 derive from origin/main 230e4944b0 with this diff applied. 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 13 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 13 configured, 0 ignored. No file sets parserOptions.project or projectService, so no untouched file's verdict can move.
  • check-governed-merges --test: NOT governed, 178 changed lines (+89 / -89).
  • A control-byte scan over the 13 changed files finds none.

main since the base

Re-fetched just before this PR opened, origin/main was six commits past the base (c9761cd2fb: #21966, #21951, #21963, #21969, #21965, #21962). They touch 28 files, none of the 13 and none under packages/spec/src/api/, so main was not merged. The two packages/spec/src files they change (data/datasource-credential-redaction.ts and its test) read 0 / 0 in the census at c9761cd2fb: the one id they add is a code comment. git merge-tree onto c9761cd2fb is clean, and none of the 4 open PRs touches any of the 13 files.

Acceptance notes


Generated by Claude Code

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

Stage 25 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 api/ group (plugin-rest-api.handler-status-retirement.test.ts
through zod-issues-to-fields.test.ts). It finishes api/.

89 literals in 13 files (86 test titles and 3 declared expect messages)
lose 95 tracker ids: 10 literals (11 ids) now state the cited decision
in words, 12 (16 ids) get their subject back in words, and 67 (68 ids)
drop a number the title already explains. 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>
@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 f76c6221acd3997dd778fdd3e8e7d43e0bec4851 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

CI note from domain:spec seat 1 (seat post #6017) · session_01T9u38rswFp5Rw8DswRUReJ · 2026-10-06T09:46Z

Failing check on c63eba0adf: Temporal Conformance (live PG + MySQL), job 112194464857, step "Run driver-sql suite against both live servers".

  • Where: packages/drivers/driver-sql/src/sql-driver-11224-update-stamp-precision.test.ts:369 failed with expected 0 to be greater than 0. That is the bulk-door test's non-vacuity guard: none of its six rows carried a created_at with sub-second digits, so the run measured nothing and the guard refused it.
  • Why it is not this PR's: this diff changes 89 test-title and expect-message literals in 13 files under packages/spec/src/api/. It touches no file in driver-sql or under packages/drivers, and nothing the driver suite imports. The same check is green on main's last six commits and on PRs fix(service-settings)!: retire date_format, time_format, number_format and first_day_of_week from the Localization manifest (#21958) #21970 and fix(platform-objects): Setup → Users opens on the All Users list view #21971. Every other check on this head is green: 31 success, 7 skipped.
  • Fix: none exists in an open PR, and the test is outside this PR's scope, so none is ported here.
  • Re-run: this seat has no re-run op. CI is re-triggered by merging the moved main into this branch, which is a real merge and not an empty commit. A second failure of the same check after that is treated as real and reported to the lane that owns driver-sql.

The ACCEPT is 6013649846 on #20749.

Brings main forward to re-trigger CI on the stage-25 PR. The merge
touches none of the 13 test files this branch changes; nothing under
packages/spec/src/api moves.

Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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