Repository navigation
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
Conversation
… 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>
Contributor
📓 Docs Drift CheckNothing 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): |
Contributor
Author
|
CI note from Failing check on
The ACCEPT is |
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>
This was referenced Oct 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 in5902360492on #20513. This stage takes the second and last name-orderedapi/group: the 13 id-bearing test files directly underpackages/spec/src/api/fromplugin-rest-api.handler-status-retirement.test.tstozod-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(md59d08602ab972b4b8643c90d64d40fa41),census.cjs(md56e42a45a926d375013c32d62f16a296e),census-wide.cjs(md5c98410a19529c439adb0afbfb00026a2) anddirtable.cjs(md5dda605c54745b4a60cc14c9a686e4eff), 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 adescribe/it/testcall,.each/.skip/.onlychains included. Everything else is an "other" string.The worktree was cut from
origin/mainat5a22eb5619, 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.system/src/)api/(this PR: all 13 files)ui/ai/contracts/The group reads 89 messages / 95 ids in 13 files, the seat's figures file for file:
api/)plugin-rest-api.handler-status-retirement.test.tsplugin-rest-api.schema-refs.test.tsplugin-rest-api.test.tsprotocol.test.tsregistry-retirement.test.tsrest-api-config-dead-keys-retirement.test.tsrest-server.test.tsrouter.test.tssortability.test.tsstorage.test.tsvalidate-data.test.tswebsocket.test.tszod-issues-to-fields.test.tsFive 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:179andrest-server.test.ts:768(template literals) andregistry-retirement.test.ts:89(one leaf of a+chain).ui/notification.test.ts(1 id) andsystem/book.test.ts(2 ids), outside the group, read the same at the base and at the head. Dark:protocol.test.tsreads 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 astorage.test.tstitle reads 1 / 1 (title:it), and an id put into asortability.test.tscomment reads 0.#plus digits) reads the same as the gate pattern in all 13 files at the base, and 0 in all 13 at the head.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 insystem/constants/), two stages:auth-config.test.tsthroughmetadata-form-declared-rows.pin.test.ts, 18 files, 91 messages / 97 ids (i18n-resolver.test.tsalone 53 / 56);metadata-form-zod-reconciliation.test.tsthroughworker.test.ts, 16 files, 63 / 70. Its first file carries 17 "other" strings, its ledgerwhyentries.src/, 120, one stage.ui/component-props-unknown-members.pin.test.ts:322and stage 22's two. One stage, with an at-tier review. The four colour literals stay, as stage 21 decided.What each id became
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:18189983dd(feat(spec,objectql,metadata-protocol): validate-only data operation — DataProtocol.validateData #6474):DataProtocol.validateDataasks the write path for its verdict and persists nothing, Import dry run green-lights a row the write then rejects: structured value shapes (address / location) are not pre-checked #4633 ruling D;f549a0d4ad(refactor(spec)!: ADR-0049 退役 sweep —— server 运行期词表 / ViewProtocol / L2 ETL(#5295 #6239 #6414) #6526):ViewProtocol's five viewId-addressed methods and ten schemas are retired;cursor被静默丢弃(SDK 分页永远第一页),limit默认 20 声明 vs 50 实现 #6361, from90bbf25107(refactor(spec,client)!: retire the notification-listcursoron both halves and drop the fictionallimitdefault (#6361) #6866): the notification-listcursoris tombstoned on both halves (maintainer ruling 2026-08-07, option A);11b779e0f9(fix(spec): declare MetadataProtocol.getMetaItemLayered; drop the dead 'overlay' lockSource arm (#9740) #9773):MetadataProtocol.getMetaItemLayeredis declared, and the dead'overlay'lockSourcearm is dropped;2a29caa532(feat(spec): declare previewDrafts/state on meta-read requests; record environmentId as transport-level; retire REST door casts (#9741) #9804):previewDrafts/stateare declared where the implementation enforces them, andenvironmentIdis recorded as transport-level. Its changeset (packages/spec/CHANGELOG.md:31798) names it "maintainer ruling 2026-08-18", andcccbe51bf7cites "the [finding] Meta-read request schemas still omit previewDrafts / state / environmentId, so the REST call-site casts survive the organizationId catch-up #9741 ruling";MetadataProtocol是否应声明publishMetaItem成员 —— 半声明的门(响应已声明、请求未声明) #11006, fromcccbe51bf7(feat(spec): declare publishMetaItem as an optional MetadataProtocol member with PublishMetaItemRequest #11426):publishMetaItemis declared as an optional member withPublishMetaItemRequest(maintainer ruling 2026-08-22, option B);RestServerConfigrows the liveness ledger now records asdead(#14369's verdicts) —routes.*,crud.patterns,crud.objectParamStyle,metadata.cacheTtl,metadata.endpoints.schema,batch.defaultAtomic,batch.operations.upsertMany#14691, fromb3a63d32c9(feat(spec): retire the ten inertRestServerConfigkeys the liveness ledger recorded asdead(ADR-0049 enforce-or-remove) #14868): the ten inertRestServerConfigkeys the liveness ledger recorded asdeadare retired.The same-id titles stage 24 listed in this group:
[#5672]x2 (protocol.test.ts:508,:526): SDK 的 client.capabilities 声明为 WellKnownCapabilities,但两个 discovery 生产者填的是互不相交的键集 #5672's maintainer ruling A (5199159328): one closed capability vocabulary, emitted in full by both discovery producers, with an absent capabilityenabled: falserather than a missing key.:508now reads "strips a capability key outside the closed vocabulary". The old verb was "rejects", but the body pins the opposite: the parse stays green and the key does not survive it.:526now reads "… (ruled: an absent capability isenabled: false, not a missing key)".(#12038)x5 (:2575to:2686): these five "declares the … body" describes are the describe-only transcriptions that the five-part ruling's implementation plan names (5434804846). None of them pins a lettered sub-ruling, so no letter is named; the title already says the decision, and only the number goes.(#12038 1C)(:2710): now "GetPublishedMetaItemResponseSchema stays opaque (ruled: no shape frozen against the current type registry)", ruling 1C's own reason. Its children pin theunknownbody.(#19543, door ③)(:2726): door ③ is the AI-conversation list, which the schema name already names, and "declares the next-page signal" is that door's spec half (letter A, re-derivation5825819437). Only the number and the door label go.(#15677)inplugin-rest-api.test.ts:694andwebsocket.test.ts:712: now "… durations carry their unit in the key name", spec: duration-shaped number keys carry their unit in describe prose only — twottlkeys with different units in one block, baretimeoutkeys, unit-less tenant timeouts #14478's ruling B (5518649320, population ruling5548763981), which [#14478 stack 2/6]api/: the 12 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers,ApiError.retryAfterwith its own BREAKING note #15677 executes forapi/. Inrouter.test.ts:565the title already shows the rename (RouteDefinition.timeout → timeoutMs), so only the number goes.Stated in words:
api/)plugin-rest-api.test.ts:694,websocket.test.ts:712z.number()duration key carries its unit in its name; the old spellings areretiredKey()tombstones.protocol.test.ts:508protocol.test.ts:526enabled: false, not a missing key)"protocol.test.ts:13135322875103):probesgets a deliberately opaque passthrough, upgraded to a modeled schema only when a consumer needs a field of it.protocol.test.ts:13835321046016):advisoriesrides eachpublished[]element, with no parallel top-level map.protocol.test.ts:17392a29caa532:environmentIdis the transport-level multi-kernel routing key.protocol.test.ts:27105434804846): a thin envelope with the body opaque, no union frozen against today's type registry.validate-data.test.ts:2518189983dd: the dry run stops predicting the write's verdict and asks for it.validate-data.test.ts:57validateDatareports the write path's verdict on candidate rows and persists nothing.Subject back in words (12 literals):
RestApiEndpointSchema.handlerStatusis authorable but has zero runtime consumers — the 501 it is documented to cause comes from somewhere else #13823" becomes "zero holders after its retirement", and "[finding(spec):RestApiEndpointSchema.handlerStatusis authorable but has zero runtime consumers — the 501 it is documented to cause comes from somewhere else #13823] ADR-0087 registration" becomes "handlerStatus retirement — ADR-0087 registration", the form of the repo's other retirement registration describes (finding(spec):RestApiEndpointSchema.handlerStatusis authorable but has zero runtime consumers — the 501 it is documented to cause comes from somewhere else #13823 ruled remove,5494755488);DeleteMetaItemResponseSchemadeclares neitherseqnorprojectionApplied, which its branch sends — the two sibling verbs on the SAME door declare both, and the save side got that by ruling (#5745) #13155 — carries [#5563 附带裁决] SaveMetaItemResponseSchema 补齐实现实际返回的字段(version / seq / state / projectionApplied) #5745 to the third verb)" becomes "(carries the declared = returned discipline to the third verb)", the discipline [finding]POST /meta/:type/:name/publishis a served REST route with NO spec declaration — the #5745 "declared = returned" discipline covers only the save door #7294 and [finding]DeleteMetaItemResponseSchemadeclares neitherseqnorprojectionApplied, which its branch sends — the two sibling verbs on the SAME door declare both, and the save side got that by ruling (#5745) #13155 name [#5563 附带裁决] SaveMetaItemResponseSchema 补齐实现实际返回的字段(version / seq / state / projectionApplied) #5745 for;applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865 anchor category" becomes "the unprovisioned injected-anchor category", the platform anchors injected into an external object whose storage the platform does not provision ([Decision]applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865, ruling B);success: true— the other half of #3675 #3689" storage shapes become shapes "from before the shared success envelope";validateOnlydry-run flag";POST /api/v1/automationanswers 500 INTERNAL_ERROR for a malformed flow body — including the #4277 undeclared-config-key refusal the #7545 ruling leans on #8055-shaped fixture" becomes "every malformed-flow-body fixture".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 ("REJECTSpatternswith the retirement prescription — …", "the tombstones reject one key each, not the config — …");[#11983]x3,[#4579]x2,[#4939],[#6361],[#20294]and#3899 —; the#10235prefixes 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
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.-t/--testNamePatternto vitest; the one vitest-thit is a README example underpackages/qa/dogfoodfiltering its own fixture.__snapshots__directory is tracked underpackages/spec, and none of the 13 files calls a snapshot matcher.rest-api-config-dead-keys-retirement.test.tsis in therepoproject (packages/spec/vitest.repo-tests.json:31); the other 12 run inlocal. The base-versus-head run below takes both projects.git grepat the base, across the tracked tree outside its own file. No gate, doc, filter, snapshot, QA checklist entry orscripts/check-*.mjsself-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:1134shares "query.distinct ([P2] data:QueryASTdeclares 12 members no executor runs — the liveness ledger governs metadata types, not the request surface #4286)", andmetadata-protocol/src/protocol.validate-data.test.ts:102shares "the BatchOptions.validateOnly 声明了 dry-run 但从不实现 —— "预演"会真实落库(PD #10) #4052 non-repeat".Text-only proof
Stage 10's scratch tool (
textonly10.cjs, md5d5e4801dbb4329ab1984da91e92fc47c) compares base and head file by file on three legs:#plus digits after. This stage declares the three expect-message lines named above.+and-lines are exactly the 89 planned lines as multisets, and every file keeps its line count.it.eachrow 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..eachtitle and no$nameplaceholder 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:565writes 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-changesetMeasured, not assumed:
npm pack --dry-runof@objectstack/speclists 2068 files. 0 of the 13 touched files are in it, and no*.test.tsat all. The controlssrc/api/protocol.zod.ts,src/api/rest-server.zod.tsanddist/index.mjsare in it.dist/, two new phrases and an old one each read in 0 files. The controlUnrecognized keyreads in 42.So this PR publishes nothing, and no changeset is added.
Verification (at
c63eba0adf)pnpm turbo run buildover 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, includingcheck:test-typecheck(52 files / 246 errors / 135 pinned signatures held). Its program holds all 13 group files, counted by path withtsc --listFilesOnly -p tsconfig.test.json.check:generated: all 15 generated artifacts up to date, against thedist/the build above wrote.dispatch-gates --commandsderived 79 families: stage 24's 80 withoutcheck:error-code-casing, whose named sources this diff does not touch. All 79 exit 0.--ranreconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN, every family with its exit code recorded. The same 79 derive fromorigin/main230e4944b0with 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.--no-inline-configover the 13 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 13 configured, 0 ignored. No file setsparserOptions.projectorprojectService, so no untouched file's verdict can move.check-governed-merges --test: NOT governed, 178 changed lines (+89 / -89).mainsince the baseRe-fetched just before this PR opened,
origin/mainwas six commits past the base (c9761cd2fb: #21966, #21951, #21963, #21969, #21965, #21962). They touch 28 files, none of the 13 and none underpackages/spec/src/api/, somainwas not merged. The twopackages/spec/srcfiles they change (data/datasource-credential-redaction.tsand its test) read 0 / 0 in the census atc9761cd2fb: the one id they add is a code comment.git merge-treeontoc9761cd2fbis clean, and none of the 4 open PRs touches any of the 13 files.Acceptance notes
system/book.test.ts:413((#12038)).runtime25,objectql13,lint12,metadata-protocol12,rest12,client8,metadata-core4,qa/dogfood2,service-automation2,service-storage2, and one each inexamples/app-crm,examples/app-showcase,driver-sql,plugin-sharingandtypes), each package's share under the [finding] runtime warnings outside the migration ledger print tracker numbers to authors and operators: theAutomationEngineresumeAuthority boot warning (#3801/#5561/#3823) and two objectql data-event warnings (#4639/#4626) #20513 lane children.* #3899 —header inplugin-rest-api.schema-refs.test.ts, the* #8124 —header inzod-issues-to-fields.test.ts, the// [#5672] This fixture used to lead with …comment aboveprotocol.test.ts:508, and the/** [#20294] … */docblock inrest-api-config-dead-keys-retirement.test.ts. Code comments are not this card's share.Generated by Claude Code