Skip to content

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

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

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20749
Clause-②: no

Stage 24 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 first name-ordered api/ group: the 27 id-bearing test files directly under packages/spec/src/api/ from ai-agents-envelope.test.ts to package-lifecycle.test.ts. Those files carried 100 messages and 106 tracker ids, citing 65 records. All 106 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.

Census at the base (a3bd157730)

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 23 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 a3bd157730, the claim's base and stage 23's landing. Both instruments read 471 messages / 498 ids in 111 files, the seat's reading and stage 23's head reading.

directory files messages / ids titles other
api/ (this PR: 27 of the 40 files) 40 189 / 201 181 / 193 8 / 8
system/ 34 154 / 167 128 / 138 26 / 29
(files directly in src/) 30 118 / 120 117 / 119 1 / 1
ui/ 5 7 / 7 0 7 / 7
ai/ 1 2 / 2 0 2 / 2
contracts/ 1 1 / 1 0 1 / 1
total 111 471 / 498 426 / 450 45 / 48

The group reads 100 messages / 106 ids in 27 files, the seat's figures file for file:

file (under api/) messages / ids titles other
ai-agents-envelope.test.ts 1 / 1 1 / 1 0
analytics.test.ts 3 / 3 3 / 3 0
api-entry-graph.pin.test.ts 1 / 1 1 / 1 0
api-error-code-type.test.ts 1 / 1 1 / 1 0
apis-publish-gates.test.ts 12 / 12 12 / 12 0
auth-endpoints.test.ts 2 / 2 2 / 2 0
auth.test.ts 2 / 2 1 / 1 1 / 1
automation-api.zod.test.ts 4 / 5 4 / 5 0
batch.test.ts 2 / 2 2 / 2 0
contract.test.ts 3 / 3 3 / 3 0
dataset-selection.test.ts 5 / 5 5 / 5 0
discovery-auth-families.pin.test.ts 2 / 2 2 / 2 0
discovery-environment-subset.pin.test.ts 2 / 2 1 / 1 1 / 1
discovery.test.ts 10 / 11 10 / 11 0
dispatcher.test.ts 2 / 2 2 / 2 0
endpoint.test.ts 4 / 4 4 / 4 0
envelope-violations.test.ts 1 / 1 1 / 1 0
error-code-ledger.test.ts 7 / 11 7 / 11 0
errors.test.ts 3 / 3 3 / 3 0
export-job-family-retirement.test.ts 6 / 6 3 / 3 3 / 3
export.test.ts 3 / 3 3 / 3 0
meta-item-response-shapes.test.ts 2 / 2 2 / 2 0
metadata.test.ts 1 / 1 1 / 1 0
odata-orderby-dual-declaration.test.ts 1 / 1 1 / 1 0
package-api.test.ts 10 / 10 10 / 10 0
package-install-one-authority.test.ts 1 / 1 1 / 1 0
package-lifecycle.test.ts 9 / 9 9 / 9 0
27 files 100 / 106 95 / 101 5 / 5

Five more test files sit in the same name range and carry no id (documentation.test.ts, error-catalog-docs.test.ts, events.test.ts, http-cache.test.ts, odata.test.ts). The five "other" strings are expect messages, rewritten and declared to the text-only tool: auth.test.ts:155, discovery-environment-subset.pin.test.ts:65 (one leaf of a + chain) and export-job-family-retirement.test.ts:112 (a template literal), :158 and :349.

  • Controls. Lit: ui/notification.test.ts (1 id) and api/protocol.test.ts (50 ids), outside the group, read the same at the base and at the head. Dark: package-api.test.ts reads 0 at the head while 30 of its comment lines still carry a number. Planted in a scratch tree: an id put into a package-lifecycle.test.ts title reads 1 / 1 (title:describe), and an id put into a batch.test.ts comment reads 0.
  • A wider pattern (any # plus digits) reads the same as the gate pattern in all 27 files at the base, and 0 in all 27 at the head.
  • At the head: 371 messages / 392 ids in 84 files. The 27 files read 0 / 0, api/ reads 89 / 95 in 13 files, 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 23 used. Stage 23's cut named this group at 106 ids, and this census reads 106, so no re-cut was needed.

Named for the next stages (cut from the head census, 371 / 392):

  • The second api/ group: plugin-rest-api.handler-status-retirement.test.ts through zod-issues-to-fields.test.ts, 13 files, 89 messages / 95 ids (86 / 92 titles, 3 / 3 other), protocol.test.ts alone 46 / 50 and rest-server.test.ts 19 / 19. That finishes api/.
  • system/ 167, two stages. The files directly in src/, 120, one.
  • 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

  • 18 literals (22 ids) now state a decision in words.
  • 10 literals (10 ids) get their subject back in words, where the number stood for a thing.
  • 72 literals (74 ids) drop a number the title already explains.

Every cited record was fetched with all its comments through REST (357 comments, #4052's included), and its decision was read from its ruling, ACCEPT and landing comments. 65 records are cited: 59 answer 200 and 6 answer 404. Two of the 200s are PRs (#4049 and #20218), read from their bodies. One citation is objectui's and was read from objectui: objectui#6593. The six that answer 404 were read from what landed, through the commits endpoint (this checkout is shallow), each named by the commit the stage-2 re-anchoring of api/ comments gave it:

One citation names a different record. batch.test.ts:78 read "(#3963 follow-up)"; #3963 is the api.requireAuth retirement. The validateOnly tombstone is #4052's decision, read too: never implemented, so tombstoned rather than half-built. The title already says that ("rejects the retired validateOnly key with its prescription"), so the number is dropped.

Where a record's decision was refined later, the title follows the refined one:

Stated in words:

record literal (under api/) now reads the decision
#18576 api-entry-graph.pin.test.ts:77 "… stays off the assembled package body (ruled: split the entry rather than watch its weight)" Ruling B (batch #145 item 1, maintainer 2026-09-17): the cost is removed, not watched; ./api is split and the assembled-package declarations move to @objectstack/spec/api-assembled.
#4936 apis-publish-gates.test.ts:152 "still accepts an EMPTY and an ABSENT apis: — never refused, even while a non-empty one was" Maintainer ruling 2026-08-04: v17 loudly refuses a non-empty apis: and keeps the vocabulary; an empty or absent one stays publishable, then and after #5111's narrowing.
#4910 apis-publish-gates.test.ts:568 "keeps endpoint-level rateLimit in the vocabulary (ruled: left to the endpoint executor, not the server-level seam)" Q2 = B (2026-08-03): that card wires the server level only; the endpoint-level keys stay, and #4936's ruling has the endpoint executor wire them.
#5189 apis-publish-gates.test.ts:597 "still refuses D6 — the gate with no runtime counterpart, so the per-item publish path runs it too" Triage disposition (E7b, 2026-08-04): publishPackage reuses the same gate function, because D6 alone has no runtime counterpart.
#7481 auth-endpoints.test.ts:112 "AuthFeaturesConfig retired flags (ruled: stop advertising them)" Maintainer ruling 2026-08-11: passkeys / magicLink leave the /api/v1/auth/config payload.
#14788 auth.test.ts:88 "SessionUser.language retirement (ADR-0049 — ruled: gone, with no replacement field)" Maintainer ruling D (2026-09-03): retired under ADR-0049, no producer and no consumer; no replacement field until a real producer exists.
#9378, #9510 automation-api.zod.test.ts:327 "… status, runId and the screen (a pause is the third state, not a failure)" #9510's ruling (2026-08-18): a pause is not a failure, and callers learn the third state deliberately; status: 'paused' + runId + screen is the trigger contract's third state.
#4828 discovery.test.ts:1167 "scoping (ruled: declare what REST actually emits)" Maintainer ruling 2026-08-05, item 3: scoping is declared on DiscoverySchema as an optional key.
#4828 discovery.test.ts:1207 "resolveDiscoveryEnvironment (ruled: an enum, not a passthrough)" Item 4: the schema is authoritative, so every producer's environment is mapped into the declared enum.
#8211 error-code-ledger.test.ts:68 "standard-synonym detection (ruled: refused unless waived)" Option C (triage adjudication, 2026-08-12): the admission gate refuses a semantic synonym of a standard member unless a recorded waiver admits it; the four existing ones are waived.
#10025, #11504 error-code-ledger.test.ts:220 "accepts the definition-level input-schema refusal code (ruled non-retryable: a never-dispatched exit)" Maintainer ruling B (2026-08-20): the refusal is non-retryable and becomes a never-dispatched exit with its own ADR-0112 code.
#16449, #16404 error-code-ledger.test.ts:234 "accepts the nine-code batch — every code that ships in dist, door or no door (ruled: the ledger is the published face)" #16404 option D (batch #62, 2026-09-07): the ledger is the published face, so every code in dist is registered; #16449 registered the nine.
#16649, #16404 error-code-ledger.test.ts:308 "accepts the fourteen remaining door:none codes, each under its stamping package (ruled: the ledger is the published face)" The same ruling; 613bfbd3db registered the fourteen.
#17158 export-job-family-retirement.test.ts:158, :349 (expect messages) "… the retirement is being undone — nothing served, bound or consumed the family" Ruling A (batch #122 item 3, 2026-09-12; landing route A, batch #221 item 2): ADR-0049 retires a declared API that nothing serves, binds or consumes.
#12038 package-api.test.ts:603 "package-rollback-response retirement (ruled: it described the wrong operation on the live path)" Ruling 3A (2026-08-27): the published version-rollback schema, bound to the live commit-rollback path, is retired first.
#12038 package-lifecycle.test.ts:25 "the ruled re-export of PackagePublishResultSchema into the /api namespace" Ruling 5A: re-export the existing schema into the namespace the ledger resolver searches, never a second copy.
#12038 package-lifecycle.test.ts:140 "RollbackToPackageCommitResponseSchema declares the COMMIT-rollback body (ruled: authored once the wrong-operation schema was retired)" Ruling 3A's binding sequence: retire the false declaration, then author the true commit-rollback schema.

Subject back in words (10 literals): "the pre-#4053 bare body" becomes "the bare body from before the envelope relocation" (#4053's end state: both producers relocated the payload under data); "(#3891 shim dialect)" becomes "(the degraded shim dialect)"; "the duplicate-payload drift #4049 removed" becomes "the duplicate-payload drift the /share-links domain stopped emitting", the PR's own title; "zero holders after #17158" becomes "after the export-job family retirement"; "the #10330 TS2353 repro" becomes "the original TS2353 repro"; the three "since PR #20218" titles become "since the door parses its whole body" (twice) and "so does the door, which parses the whole body", the PR's own title; the #17534 title now names "the reverse-domain id rule", that card's ruling A; "the objectui#6593 confusion" becomes "the envelope-vs-payload success confusion", the defect objectui#6593 measured.

Dropped where already stated (72 literals, 74 ids). A number goes only where the title already says its decision. Examples: the eight [#5111] describes ("the flip — a well-formed apis: publishes", "gate (a)" to "gate (e)", …), [#5310], [#19920], the two [#21046], [#5676], [#5672], [#5679] and [#6287] prefixes; the four #17551 / #17550 section prefixes in dataset-selection.test.ts, which keep the file's own §1 to §5; #5384 —, #5227 —, #5950, #5882, #17518, #18058 — and #18605 —; the four #15677 citations on the "→ …Seconds" renames; and the tails (#3878), (#6442), (#19543) x2, (#7359), (#3939), (#18124), (#3842) x3, (#10338), (#6704), (#10330), (#4587), (#17667), (#19116), (#17431), (#19441), (#8211), the five (#12038) and the one (#12038 4A) after "declares the four fixed keys and stays open". (federated ledger, #4805), (ADR-0076 D12, #2462) and (ADR-0112 amendment 2026-08-18, #9266) keep their words and lose the number. The ADR-0087 conversion id api-endpoint-cache-ttl-to-cache-ttl-seconds stays: it is not a tracker id.

No file is renamed.

Readers

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 five expect-message lines named above.
  • Result: 27 of 27 files SAME on all three legs, with the per-file counts predicted in writing before the run.
  • Totals: 100 changed string leaves in 100 literals: 95 titles and 5 declared. The diff's + and - lines are exactly the 100 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 expect message given a new id VIOLATION; a declared +-chain leaf given a new id VIOLATION; a template-literal message given a new id VIOLATION.
  • Templates and tables: no .each title and no $name placeholder changes. The one template literal, export-job-family-retirement.test.ts:112, changes only its text after ${name}.

Test counts: the 27 files were run at the base, in a separate base worktree, and at the head, with --project local --project repo. Both sides read 831 tests in 27 files, all passed, with the same count and status sequence per file in 27 of 27. 325 full test names change, and each changed name equals the base name with the planned replacements applied: 0 mismatches once the plan's text is read the way the source writes it (the comparison tool reads the plan's — escape at errors.test.ts:439 literally, so its first pass reports that title's three names as mismatches; decoding the escape, as vitest does, reads 0). No full name repeats on either side.

Changeset: skip-changeset

Measured, not assumed:

  • npm pack --dry-run of @objectstack/spec lists 2068 files. 0 of the 27 touched files are in it, and no *.test.ts at all. The controls src/api/package-lifecycle.zod.ts, src/api/error-code-ledger.zod.ts and dist/index.mjs are in it.
  • In the built dist/, a new phrase 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 dffd240655)

  • 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, 18471 passed, 1 todo.
    • typecheck: exit 0, including check:test-typecheck (52 files / 246 errors / 135 pinned signatures held). Its program holds all 27 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 80 families: stage 23's 79 plus check:error-code-casing, which the two touched files it names bring in. All 80 exit 0. --ran reconciles: 80 derived, 80 run, 0 NOT-MEASURED, 0 UNRUN, every family with its exit code recorded. The same 80 derive from origin/main 01e0f71ad8 with this diff applied. The roster families stage 23 also ran (check:meta-url-spelling, check:spec-changes, check:authz-resolver, check:filter-alias-parity) each exit 0.
  • ESLint, a proven narrowing: --no-inline-config over the 27 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 27 configured, 0 ignored. No file sets parserOptions.project or projectService, so no untouched file's verdict can move.
  • check-governed-merges --test: NOT governed, 200 changed lines (+100 / -100).
  • A control-byte scan over the 27 changed files finds none.

main since the base

Re-fetched just before this PR opened, origin/main was two commits past the base (01e0f71ad8: #21940, #21953). They touch 31 files, none of the 27 and none under packages/spec, so main was not merged and the census on that tree is the base's. git merge-tree onto 01e0f71ad8 is clean, and none of the 5 open PRs touches any of the 27 files.

Acceptance notes

  • Same-id test titles in this card's later stages go with those stages: 23 lines in packages/spec/src, among them api/protocol.test.ts ([#5672] x2, (#12038) x5, (#12038 1C), (#19543, door ③)), api/plugin-rest-api.test.ts, api/router.test.ts and api/websocket.test.ts ((#15677)), stack-json-stage-package-body.test.ts (#17518 x4), system/book.test.ts ((#12038)) and three system/ titles citing (#18124).
  • Same-id test titles in other packages stay: 96 lines in 12 packages (runtime 37, rest 24, client 9, metadata-protocol 6, service-automation 6, metadata 5, cli 3, objectql 2, and one each in examples/app-showcase, core, plugin-hono-server and verify), each package's share under the [finding] runtime warnings outside the migration ledger print tracker numbers to authors and operators: the AutomationEngine resumeAuthority boot warning (#3801 / #5561 / #3823) and two objectql data-event warnings (#4639 / #4626) #20513 lane children.
  • Code comments with live ids remain in these files and their sources, among them the // package-rollback-response retirement (#12038 3A) banner above its describe, the [#5111 / #5040 E7] and [#5189 / #5040 E7b] headers in apis-publish-gates.test.ts, and the [#17158] header in export-job-family-retirement.test.ts. Code comments are not this card's share.

Generated by Claude Code

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

Stage 24 of the spec lane's share of the runtime-string burn-down: the
test strings shipped under packages/spec/src, the first name-ordered
api/ group (ai-agents-envelope.test.ts through package-lifecycle.test.ts).

100 literals in 27 files (95 test titles and 5 declared expect messages)
lose 106 tracker ids: 18 literals (22 ids) now state the cited decision
in words, 10 (10 ids) get their subject back in words, and 72 (74 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
@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 tests 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 01e0f71ad8518ed208dc95eb7bb6bf2b2fc2fa05 → packageMentionDocs.

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