Skip to content

test(spec): the third ui/ file group's test titles state each cited decision in words instead of a tracker number (stage 22) - #21931

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

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20749
Clause-②: no

Stage 22 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 third name-ordered ui/ group: the 29 id-bearing test files directly under packages/spec/src/ui/ from dataset-filter-nested-relation-list.test.ts to view-inline-object-binding.test.ts. Those files carried 96 messages and 102 tracker ids, citing 52 records. 100 of those ids now either state what their record decided, in words (form D), or are dropped where the title already says it. Two stay: they are needles, ids that an assertion reads in another file's text (below). Text only: no assertion, identifier, test count or code comment changes, and no file is renamed.

Census at the base (be97cf3c93)

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 21 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 be97cf3c93, four commits past the claim's 3dbd084209. At the claim's base both instruments read 665 messages / 702 ids, the seat's reading and stage 21's head reading. At be97cf3c93 they read 665 / 704 in 154 files: the two extra ids are in system/metadata-form-zod-reconciliation.test.ts (22 to 24 ids), a ledger why string that #21901 rewrote. No ui/ file moved.

directory files messages / ids titles other
ui/ (this PR: 29 of the 48 files) 48 201 / 213 186 / 198 15 / 15
api/ 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
ai/ 1 2 / 2 0 2 / 2
contracts/ 1 1 / 1 0 1 / 1
total 154 665 / 704 612 / 648 53 / 56

The group reads 96 messages / 102 ids in 29 files, the seat's figures file for file:

file (under ui/) messages / ids titles other
dataset-filter-nested-relation-list.test.ts 5 / 5 5 / 5 0
door-reachability.testkit.test.ts 4 / 4 3 / 3 1 / 1
expression-scope-app-root.pin.test.ts 1 / 1 1 / 1 0
form-layout-inline-grid-retired.test.ts 4 / 4 3 / 3 1 / 1
form-option-enum-derive.test.ts 1 / 1 1 / 1 0
i18n-label-resolver.test.ts 5 / 6 5 / 6 0
i18n.test.ts 6 / 6 5 / 5 1 / 1
inline-action-type.test.ts 1 / 1 1 / 1 0
inline-action.test.ts 3 / 3 3 / 3 0
interaction-config-retirement.test.ts 4 / 4 2 / 2 2 / 2
joined-report-block-type.test.ts 1 / 1 1 / 1 0
master-detail-detail-sort-field-retirement.test.ts 1 / 1 1 / 1 0
notification-embed-retirement.test.ts 1 / 1 1 / 1 0
notification.test.ts 4 / 4 3 / 3 1 / 1
page.test.ts 2 / 3 2 / 3 0
react-blocks.test.ts 3 / 4 3 / 4 0
report-joined-block-dataset.test.ts 1 / 1 1 / 1 0
report.test.ts 3 / 3 3 / 3 0
responsive.test.ts 1 / 1 1 / 1 0
section-group-reference.test.ts 2 / 2 2 / 2 0
strictness-batch14.test.ts 4 / 5 3 / 4 1 / 1
view-authoring-wire-split.test.ts 11 / 11 11 / 11 0
view-console-round-trip-keys.test.ts 5 / 5 5 / 5 0
view-field-order-composition.pin.test.ts 1 / 1 1 / 1 0
view-filter-rule-value-shape.test.ts 8 / 9 8 / 9 0
view-filter-rule-wire-id.test.ts 4 / 5 4 / 5 0
view-form-features-root.test.ts 2 / 2 2 / 2 0
view-gantt-tree-config-closed-15469.test.ts 4 / 4 4 / 4 0
view-inline-object-binding.test.ts 4 / 4 4 / 4 0
29 files 96 / 102 89 / 95 7 / 7

Seventeen more test files sit in the same name range and carry no id. The seven "other" strings are the two needles below and five strings rewritten and declared to the text-only tool: the expect messages at door-reachability.testkit.test.ts:216, i18n.test.ts:166-167 (the id is on :167), interaction-config-retirement.test.ts:148 and :189, and the door name at form-layout-inline-grid-retired.test.ts:61, which describe(door.name, …) prints as a title.

  • Controls. Lit: ui/view.test.ts, outside the group, reads 43 ids at the base and at the head. Dark: view-authoring-wire-split.test.ts reads 0 at the head while 11 of its comment lines still carry a number. Planted in scratch copies of head files: an id put into an inline-action-type.test.ts title reads 1 / 1, and an id put into a report.test.ts comment reads 0.
  • A wider pattern (any # plus digits) reads the same as the gate pattern in all 29 files at the base.
  • At the head: 571 messages / 604 ids in 127 files. The 29 files read 2 / 2 (the two needles), ui/ reads 107 / 113, and no other file moved.

How the area was chosen

ui/ has no subdirectory test file with an id, so it is taken in name-ordered file groups near the ~100-id bound. Stage 21's re-cut named this group at 102 ids, and this census reads 102, so no re-cut was needed.

Named for the next stages (cut from the head census, 571 / 604):

  • ui/ 113 ids. 106 sit in the last group, the 16 files from view-item-config-type.test.ts to widget.test.ts (100 messages / 106 ids; view.test.ts alone 43, view-strictness-batch18.test.ts 11, view-overlay-viewkind-arm.test.ts 10). The other 7 are kept items: stage 20's component-props-unknown-members.pin.test.ts:322, stage 21's four colour literals, and this stage's two needles.
  • api/ 201, two stages. system/ 167, two. The files directly in src/, 120, one.
  • The needles: the three docblock needles (ai/build-progress.test.ts x2, contracts/approval-service.test.ts), the kept :322, and this stage's two. One stage, with an at-tier review.

The two needles, kept

  • notification.test.ts:123, source.indexOf('// [#4610]'). The ./ui notification tombstone pins read ui/notification.zod.ts and slice it at this anchor, the comment that opens the tombstone at ui/notification.zod.ts:94; :134 then asserts the slice starts with it. The id is the anchor text of a source comment, so it can only leave together with that comment.
  • strictness-batch14.test.ts:395, expect(source).toContain('#5015'). It reads ui/notification.zod.ts and ui/sharing.zod.ts and asserts that both record the retirement by citing the record. Those citations sit in source comments at ui/notification.zod.ts:48 and :103, and ui/sharing.zod.ts:22 and :106.

The five other "other" strings are failure messages of assertions whose expected values carry no id, plus one door name. None is a needle.

What each id became

  • 24 literals (29 ids) now state a decision in words.
  • 22 literals (22 ids) get their subject back in words, where the number stood for a thing.
  • 48 literals (49 ids) drop a number the title already explains.

Every cited record was read with its comments through REST: 51 answer 200 and 1 answers 404. Three citations are cross-repo, objectui#3907, ui#6206-B and objectui#6262, and were read from objectui. Two records closed with no comment, #3916 and #4413; their decisions were read from what landed: f752ee3 ("give reports a sort declaration") with a831df1 ("report.order is live"), and ebb209c ("withdraw the record:* blocks from the react tier — no renderer read the props it published"). #11284 answers 404; it was read from its landing commit 5383fa6 (PR #11695) and that commit's CHANGELOG entry.

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

Stated in words:

record literal (under ui/) now reads the decision
#20080 dataset-filter-nested-relation-list.test.ts:116 "§1 — both analytics carriers refuse a list inside a nested relation, at save" Remedy A (triage 5825670610): the two analytics carriers refuse the list when the filter is saved, not when it is charted; the shared FilterConditionSchema stays as ruled.
#5056 door-reachability.testkit.test.ts:156 "regression — the any-one-shared-property bridge stays dead; a share of the shape decides" The derived-clone bridge stops firing on any one shared property and requires a whole-shape overlap of at least 0.5.
#5828 door-reachability.testkit.test.ts:216 (expect message) "the residual false-reachable case — no threshold excludes it" Closed not planned: no threshold separates a small all-shared-leaf shape from a real derivation that also scores 1.0, so the KNOWN BOUND pin is the record.
#17203 expression-scope-app-root.pin.test.ts:84 "no UI prose face advertises app as an expression-scope root — the renderer no longer mounts it" Option B of decision batch #67: objectui stopped binding app, and the engine's SCOPE_ROOTS is the contract.
#6761, #6765 i18n-label-resolver.test.ts:281 "resolveI18nLabel — rule parity with objectui pickLocalized (ruled: one shared resolver, on the server)" Maintainer ruling B on #6761: an inline locale map is resolved to a string server-side, by one shared resolver in packages/spec; #6765 is that resolver, held to pickLocalized's rule.
objectui#3907 i18n-label-resolver.test.ts:340 "… the rule departures converged once objectui read only own, string-valued entries; one departure survives" pickLocalized gained the own-property check and the string filter on every limb.
#10492 i18n.test.ts:99 "rejects a lone key, which used to parse as a locale map" A lone { key } parsed as a map for a language called key; it is refused by name, under the retired key-reference ruling.
#6828 inline-action.test.ts:225 "object-form params prescribes per action type — its url meaning is retired, not re-keyed" Maintainer ruling 2026-08-10: retire the third meaning; no new key, and the refusal guidance branches by action type.
#4988 interaction-config-retirement.test.ts:60, :189 (expect message) "ui/ interaction config family retirement — renderer behaviour, not authored metadata"; "… being undone — these are renderer behaviour, not authored metadata" Maintainer ruling A (2026-08-04): the five files are retired; they are renderer built-in behaviour, not per-page metadata.
#21768 master-detail-detail-sort-field-retirement.test.ts:489 "the narrowing exempts only an inline grid field's own sortField, a key the grid widget declares" The object-form runtime form field declares the grid widget's eight camelCase keys, sortField among them.
#4610 notification.test.ts:78 "does not re-expose the bare Notification/NotificationConfig names from ./ui — the bare Notification belongs to ./api alone" The ./ui names were deleted; ./api's Notification is the live contract.
#11027 page.test.ts:494 "PageComponentSchema — retired responsive, which no renderer read" Maintainer ruling B (2026-08-22): retire it, since its renderer hook had zero callers.
ui#6206-B, #15442 page.test.ts:696 "ElementDataSourceSchema filter — one filter orthography platform-wide, the ViewFilterRule array" Ruling B on objectui#6206 (one orthography), and ruling A on #15442: the binding-level dataSource.filter converges on ViewFilterRule[].
#4413 react-blocks.test.ts:92 "REACT_BLOCKS — the record:* family is out, since no renderer read the props it published" ebb209c: the record:* blocks are withdrawn from the react tier.
#11284 react-blocks.test.ts:147 "REACT_BLOCKS — vocabulary converges on the metadata tier, and the ListView alias retirement" 5383fa6: the react tier adopts the metadata-tier spelling. #14791 in the same literal is dropped: the title names its retirement.
#3916 report.test.ts:334 "Report ordering — a report declares its own sort" f752ee3: the time axis is ordered by default, and a report gets its own sort declaration.
#13855 section-group-reference.test.ts:86, :181 "… the field-group reference form, members derived from the group" Maintainer ruling B (2026-08-31): a section names a field group and inherits its members through deriveFieldGroupLayout.
#5011 (and #4001) strictness-batch14.test.ts:206 "dashboard compareTo: no longer a union but the executor contract — the strictness arm-error limit does not apply to it" Maintainer ruling 2026-08-04: compareTo converges on the executor's { kind, dimension? }. #4001 becomes its subject, the strictness campaign.
#5074 view-authoring-wire-split.test.ts:105 "the two doors, which is the whole point of the split: strict at authoring, reopened on the wire" Maintainer ruling A (2026-08-04): a strict authoring shape, and a reopened wire member in the union.
#19514 view-filter-rule-value-shape.test.ts:249 "the scalar arm, in both directions: a single-valued operator refuses an array" The protocol half of objectui#9050's ruling C′.
#5114, #5074 view-filter-rule-wire-id.test.ts:107 "a console-written filter row, judged per door: refused by name when authored, stripped on the wire" #5114's provisional reopen ended when #5074's split landed.
#15811 view-form-features-root.test.ts:208 "an AST-only envelope no longer reaches this scanner — an evaluated slot requires a source, so it is refused one layer up" Ruling A (decision batch #122): every engine-evaluated expression slot requires a non-blank source.

Subject back in words (22 literals): "#5056 premise" becomes "the derived-clone bridge premise"; "the #5068 props gate" becomes "the props gate"; "the #19331 shape" becomes "as its form row writes it" (object.form.ts's labelled sharingModel select); "the producer call shape #6761 needs" becomes "… the dataset compiler needs"; "the one departure objectui#3907 did NOT touch" becomes "… the objectui map-limb fix did NOT touch"; "the calls that caused #6761" becomes "the calls behind the dropped dataset label"; "retired at #4988" becomes "retired with the interaction-config family"; "after #4988" becomes "after the family retirement"; "#4738 left it to ./ui alone" becomes "the connector-side rename left it to ./ui alone"; "the #4610 note" becomes "the tombstone note"; "(#5015 took the other half)" becomes "(EmbedConfig, the other half, was retired)"; "#4721, the silently REVERSED sort" becomes "it once parsed as a silently REVERSED sort"; the four #5599 — titles become "the identity precondition …" / "identity precondition — …" where the title needs the subject (:272, :278, :298); "the census record (#20456)" becomes "the census record of the keys the console reads back"; "#6227 — the reported shape" becomes "the reported shape — a set operator carrying a scalar —"; "recorded as ACCEPTED at #6227" becomes "recorded as ACCEPTED by the first value-shape rule"; "#6227 — the refinement" becomes "the value-shape refinement"; "the card's probe … (#15469)" becomes "the probe that found the gap"; "the #14471 typo" becomes "the colourField typo", the key the test writes; "#6391's union membership" becomes "its union membership".

Dropped where already stated (48 literals, 49 ids). A number goes only where the title already says its decision. Examples: the three #20080 §2 / §3 / §4 prefixes (the §n markers stay: the file's own header numbers its sections with them); "[#19920] InlineAction is an inline action body, not unknown"; "… the retired arms are refused with the prescription (#20221)"; "InlineActionSchema — bodyExtra is the payload key, params is not (#5777)"; "ListView: objectName / viewType are RETIRED — … (#14791)"; the six #5074 — prefixes beyond the first; the four [#7741] / #5114 — prefixes; "what stays accepted (the #5685 side: never stricter than the runtime)", which keeps "(never stricter than the runtime)", #5685's ruling in words. The batch labels 批 14, 批 16 and (batch 13) stay in the earlier stages' form, and ADR-0089 D3a stays as a decision-record citation.

No file is renamed. view-gantt-tree-config-closed-15469.test.ts keeps its name; its four title strings are rewritten.

Readers

  • Test-name filters: none. No tracked script, workflow or package config passes -t / --testNamePattern (the 31 hits are mapfile -t, docker build -t, type -t, a create-objectstack -t template flag and a self-test's probe strings).
  • Snapshots: none. No __snapshots__ directory is tracked under packages/spec, and none of the 29 files calls a snapshot matcher.
  • Projects: master-detail-detail-sort-field-retirement.test.ts is in the repo project (packages/spec/vitest.repo-tests.json:50); its base and head runs below include it. The other 28 run in local.
  • By substring: every old literal, its id-bearing fragment and a window around each id (283 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 4 hits are two code comments that quote the page.test.ts:494 title verbatim: ui/dashboard.test.ts:585 and ui/responsive.test.ts:14, both reading ("[ADR-0049 enforce-or-remove: page.components[].responsive is wired into no renderer — and four shipped author-facing texts redirect authors to it as the live alternative (cloud leg unmeasured) #11027] PageComponentSchema — retired responsive"). Code comments are not this card's share. The new title keeps "PageComponentSchema — retired responsive" as its prefix, so a reader following either comment still finds it.

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 five lines: door-reachability.testkit.test.ts:216, form-layout-inline-grid-retired.test.ts:61, i18n.test.ts:167, and interaction-config-retirement.test.ts:148 and :189.
  • Result: 29 of 29 files SAME on all three legs, with the per-file counts predicted in writing before the run.
  • Totals: 94 changed string leaves in 94 literals: 89 titles and 5 declared. The diff's + and - lines are exactly the 94 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 kept needle edited VIOLATION; a kept needle's id dropped VIOLATION.
  • Templates and tables: one .each title changes, view-filter-rule-value-shape.test.ts:255, a %s template (refuses %s — …): its placeholder and rows are untouched, and the printed names below match the plan. One template-literal title loses only its tail (form-layout-inline-grid-retired.test.ts:141).

Test counts: the 29 files were run at the base, in a separate base worktree, and at the head, with --project local --project repo. Both sides read 858 tests in 29 files, all passed, with the same count and status sequence per file in 29 of 29. 596 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.

Changeset: skip-changeset

Measured, not assumed:

  • npm pack --dry-run of @objectstack/spec lists 2068 files. 0 of the 29 touched files are in it, and no *.test.ts at all. The controls src/ui/view.zod.ts, src/ui/report.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 612375dc0c)

  • 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 29 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 set as stage 21, and 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 whose rosters sit under a touched directory were also run, and each exits 0: check:meta-url-spelling, check:spec-changes, check:authz-resolver, check:error-code-casing and check:filter-alias-parity.
  • ESLint, a proven narrowing: --no-inline-config over the 29 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 29 configured, 0 ignored. No file sets parserOptions.project or projectService, so no untouched file's verdict can move.
  • check-governed-merges --test: NOT governed, 188 changed lines (+94 / -94).
  • A control-byte scan over the 29 changed files finds none.

main since the base

Re-fetched just before this PR opened, origin/main was two commits past the base (faf8dce482: #21917, #21906). Neither touches packages/spec or any of the 29 files, so main was not merged. git merge-tree onto faf8dce482 is clean, and none of the 8 open PRs touches any of the 29 files.

Acceptance notes


Generated by Claude Code

…ecision in words instead of a tracker number (stage 22)

Stage 22 of the spec lane's share of the runtime-string burn-down: the
test strings shipped under packages/spec/src, the third name-ordered
ui/ group (dataset-filter-nested-relation-list.test.ts through
view-inline-object-binding.test.ts).

94 literals in 29 files (89 test titles and 5 declared strings: four
expect messages and one door name that becomes a describe title) lose
100 tracker ids: 24 literals now state the cited decision in words, 22
get their subject back in words, and 48 drop a number the title already
explains. Two needles stay: notification.test.ts:123 slices the source
tombstone at its '// [#4610]' anchor, and strictness-batch14.test.ts:395
asserts that two source modules cite '#5015'.

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
@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 faf8dce482c862311f844ada6b70f515378dfd54 → packageMentionDocs.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 6, 2026 02:13
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 6, 2026 02:13
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit cc2300b Oct 6, 2026
41 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20749-test-strings-m branch October 6, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

protocol:ui 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