Skip to content

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

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

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

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Part of #20749
Clause-②: no

Stage 21 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 name-ordered ui/ group: the test files directly under packages/spec/src/ui/ from component-record-blocks.test.ts to dashboard.test.ts. Those files carried 103 messages and 109 tracker-shaped ids, citing 58 records. 105 of those ids now either state what their record decided, in words (form D), or are dropped where the title already says it. Four stay: they are CSS colour literals in two widget fixtures, not citations (below). Text only: no assertion, identifier, test count or code comment changes, and no file is renamed.

Census at the base (1e18a0735c)

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 20 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 base is 1e18a0735c, stage 20's landing and the claim's base. Both instruments read 764 messages / 807 ids in 159 files, the seat's reading and stage 20's head reading.

directory files messages / ids titles other
ui/ (this PR: 7 of the 53 files) 53 300 / 318 284 / 302 16 / 16
api/ 40 189 / 201 181 / 193 8 / 8
system/ 34 154 / 165 128 / 138 26 / 27
(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 159 764 / 807 710 / 752 54 / 55

The group reads 103 messages / 109 ids in 7 files, the seat's figures file for file:

file (under ui/) messages / ids titles other
component-record-blocks.test.ts 6 / 6 6 / 6 0
component-reference-rail.test.ts 2 / 2 2 / 2 0
component-type-vocabulary.test.ts 3 / 3 3 / 3 0
component.test.ts 65 / 70 65 / 70 0
dashboard-chart-structure-refusal.test.ts 2 / 2 0 2 / 2
dashboard-compareto.test.ts 5 / 5 5 / 5 0
dashboard.test.ts 20 / 21 17 / 18 3 / 3
7 files 103 / 109 98 / 104 5 / 5

component-report-items-action-members-typed.pin.test.ts sits in the same name range and carries no id. The five "other" strings are the four colour literals and dashboard.test.ts:205.

  • Controls. Lit: ui/view.test.ts, outside the group, reads 43 ids at the base and at the head. Dark: component.test.ts reads 0 at the head while 200 of its comment lines still carry a number. Planted in scratch copies of head files: an id put into a component-record-blocks.test.ts title reads 1 / 1, and an id put into a dashboard-compareto.test.ts comment reads 0.
  • A wider pattern (any # plus digits) reads the same as the gate pattern in 6 of the 7 files at the base. component.test.ts reads one more: decision batch #77, a two-digit batch number the gate pattern does not count. It leaves with the id beside it, as stages 9, 13 and 15 did with theirs.
  • At the head: 665 messages / 702 ids in 154 files. The 7 files read 4 / 4 (the four colour literals), ui/ reads 201 / 213, 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 20's re-cut named this group at 109 ids, and this census reads 109, so no re-cut was needed.

Named for the next stages (cut from the head census, 665 / 702):

  • ui/ 213 ids. One is stage 20's kept component-props-unknown-members.pin.test.ts:322, four are this group's colour literals, and 208 sit in the 45 files after dashboard.test.ts. The next group nearest 100 runs from dataset-filter-nested-relation-list.test.ts to view-inline-object-binding.test.ts: 29 files, 96 messages / 102 ids, 7 of them "other". Cutting two files earlier gives 98. The last ui/ group is then the 16 files from view-item-config-type.test.ts to widget.test.ts: 100 messages / 106 ids, view.test.ts alone 43.
  • api/ 201, two stages. system/ 165, two. The files directly in src/, 120, one.
  • The three docblock needles plus the kept :322, one stage, with an at-tier review.

The five "other" strings: four kept, one rewritten

  • '#111' / '#222' at dashboard-chart-structure-refusal.test.ts:94 and dashboard.test.ts:124 are kept. They are three-digit CSS hex colours, not placeholders for a record: colors: ['#111', '#222'] in a widget's chartConfig, and palette: ['#111', '#222'] inside the free-form options bag. They cite nothing. But they are not input and expected value at once, the case stage 12 dropped. Each is input that the schema under test reads (ChartConfigSchema.colors is a string-array or string-map union), and the assertions read other things: the first parse must succeed, the second asserts options.stacked. So by the claim's rule they stay, and are reported. They match the gate pattern only because a short hex colour can be all digits. They are the only four such literals in the whole census.
  • dashboard.test.ts:205 is the label argument of the file's orderPin helper, which passes it to it(). So it is a test title one call down, and no assertion reads it. It is rewritten and declared to the text-only tool.

No string in the group is a needle (an id that is the expected value of an assertion over a docblock or another file's text). The three known needles are in ai/ and contracts/.

What each id became

Every cited record was read with its comments through REST: 54 answer 200 and 4 answer 404. Four citations are cross-repo: ui#6206 (also spelled ui#6206-B), ui#6207 and objectui#8221 were read from objectui and answer 200. framework#2501 was read under the repository's current name, as stage 18 read framework#2536. #5042 is a pull request, #4001 batch 14. The four 404s were read from what landed, through the commits the stage-5 comment sweep (#20576) re-anchored them to:

Each of those titles already carried its decision, so the number is dropped. component.test.ts:3037 also gets its subject back: "the ruling" becomes "the open-vocabulary ruling".

Stated in words:

record literal (under ui/) now reads the decision
#8744 component-record-blocks.test.ts:355 "the record:discussion / record:chatter pair — one shared row" record:discussion is wired to the chatter row on purpose: one renderer, one accept face.
#7702 component.test.ts:63 "accepts a header without title — the synthesized shape, headed from the record" Ruling A/B: title becomes optional, and an omitted title means the renderer derives the heading from the record.
#6776 component.test.ts:89, :262 "PageHeaderProps recordChrome / showStar / showCopyId — declared because the header renderer reads them"; "PageAccordionProps variant — declared because the accordion renderer reads it" Route A: declare the five author keys objectui's renderer reads.
#6776 component.test.ts:235 "PageTabsProps tabStyle — renamed from type, which collides with the component type" Route A: rename type to tabStyle, because in a flat node type is the component's own dispatch key.
#6946 component.test.ts:122 "PageHeaderProps icon is retired — no renderer reads it" Maintainer ruling: retire three keys with zero renderer read points, this one among them.
#5775 component.test.ts:406, :2932 "… items[].value / items[].count — declared because the tabs renderer reads them"; "RecordPathProps stages[].terminal — declared because the path renderer reads it" Ruling A: retire the dead keys and declare the keys the renderers honour.
#5775 component.test.ts:649 "PageContainerProps — page:section / page:footer / page:sidebar compose through children" Same ruling: the three containers declare children as their one composition key, and body is not declared.
#11289 component.test.ts:768 "preserves the section presentation keys the renderer honours, verbatim" Direction 1: declare hideEmpty / collapsible / showBorder; the renderer is unchanged.
#11661 component.test.ts:889 "still refuses title, deliberately withheld as a second spelling of label" Three more renderer-honoured keys are declared; title stays out because label already names the heading slot.
#9220, #9249 component.test.ts:2078, :2142, :2899, :2908 "Interactive Elements — element:filter (retired, no renderer)", the same for element:form, and "… through the kept map row (retired, no renderer)" twice Both elements are retired at element grain: no renderer or reader in any repository.
#4001 component.test.ts:3325 "batch A, unknown keys refused — the prescriptions, each backed by a measured producer" Every authorable surface refuses unknown keys; spelled as stage 15 spelled #4001 batch D.
#7751 component.test.ts:3419 "object-* block props schemas — declared, so the props gate has a schema to dispatch" Ruling A: the object-* block family enters ComponentPropsMap.
ui#6207 component.test.ts:3468 "object-grid data takes the ViewDataSchema provider object — the two spec authorities converged" Option A: object-grid.data converges on ViewDataSchema, and the bare array is refused.
#19228 component.test.ts:4499 "row caps on the object-bound blocks — a bound view fills limit only when the authored one is not a usable cap" Ruling D: one row bound per view; the component face keeps an undefaulted limit, which a bound view's page size fills whenever the authored one is not a usable cap (the gate's !isUsableRowLimit(authored)).
#4614 dashboard.test.ts:419 "date-range preset vocabulary — one source, in the spec" Ruling A: the preset names move into the spec as their one source, and a date filter's default is checked against them.
#16458 dashboard.test.ts:850 "control — columns still declares no default … (the renderer infers it from widget spans)" Item 4 was not landed: a .default(12) would retire the renderer's span inference and switch every auto-flow dashboard to the positioned grid.

Subject back in words (15 literals): "the #5068 gate" becomes "the props gate" (component-reference-rail.test.ts:34); "the three #18305 blocks" / "object blocks" become "object-map / object-gantt / object-tree" (component-type-vocabulary.test.ts:88, component.test.ts:4295); the four "#11661 keys" titles name defaultCollapsed / icon / description (component.test.ts:832, :848, :860, :875), because id-free sibling titles already say "the section presentation keys"; "#18639 scope fences" becomes "scope fences of the columns widening"; "the twin of the #14406 census pin" becomes "the twin of the census pin that no door refuses the rule array"; "the #7750 specimen shape" becomes "the my-work specimen shape"; the four #5011 — prefixes in dashboard-compareto.test.ts become compareTo — where the title needs a subject, and go where it already has one (:61); "the words #5042 measured" becomes "every word authors were measured spelling … reaches …".

Dropped where already stated (63 literals, 69 ids). A number goes only where the title already says its decision. Examples: "ComponentPropsMap["record:alert"] (#8744)"; "user:profile is not author-placeable (#14159, ruling B)"; "ai:chat_window is retired, refused by name (#21504)"; the six "(#6276)" picker titles, each already naming what the declaration does; "the four object-* sort doors — one sort orthography, the array (objectui#8221, decision batch #77, option B; #18305)"; the [#4876], [#5010], [#17779], [#20958] and [#21293] prefixes on dashboard.test.ts, each in front of the rule it names; "drill branch (#5022): …", whose sibling labels already read "… branch: …". 批 17 stays as a batch label in stage 18's form, and ADR-0021 / ADR-0049 style citations are untouched.

No file is renamed. None of the 7 file names carries a number.

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 one line, dashboard.test.ts:205.
  • Result: 7 of 7 files SAME on all three legs, with the per-file counts predicted in writing before the run.
  • Totals: 99 changed string leaves in 99 literals: 98 titles and 1 declared. The diff's + and - lines are exactly the 99 planned lines as multisets, and every file keeps its line count. dashboard-chart-structure-refusal.test.ts is untouched.
  • Controls (13 of 13 as predicted, 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 orderPin label changed VIOLATION; a title re-split into a + chain DIFF; the declared label reverted to base SAME; the declared label given a new id VIOLATION; a kept colour literal edited VIOLATION. The first run predicted VIOLATION for the declared-label revert: putting (#5022) back where it was reproduces the base text exactly, so SAME is the right answer, and a control that gives the label a new id was added. That run read 11 of 12.
  • Templates and tables: no .each title, %s / $name placeholder or table row changes.

Test counts: the 7 files were run at the base, in a separate base worktree, and at the head, with --project local --project repo. Both sides read 677 tests in 7 files, all passed, with the same count and status sequence per file in 7 of 7. 469 full test names change, and each changed name equals the base name with the planned replacements applied (0 mismatches). One full name repeats 5 times on both sides: an it.each row in dashboard.test.ts whose printed name is cut at the same point for 5 rows. Only its describe prefix changed.

Changeset: skip-changeset

Measured, not assumed:

  • npm pack --dry-run of @objectstack/spec lists 2068 files. 0 of the 6 touched files are in it, and no *.test.ts at all. The controls src/ui/component.zod.ts and dist/index.mjs are in it.
  • In the built dist/, a new phrase and an old literal each read in 0 files. The control Unrecognized key reads in 42.

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

Verification (at ec96327761)

  • pnpm turbo run build over all packages: 71 / 71, through the shared verify lock (VERDICT command-exit 0).
  • @objectstack/spec:
    • vitest run --project local: 618 files, 18450 passed, 1 todo.
    • typecheck: exit 0, including check:test-typecheck (52 files / 246 errors / 135 pinned signatures held). Its program holds all 7 group files, counted 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 20, 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. So does check:platform-checklist, for the checklist entry above.
  • ESLint, a proven narrowing: --no-inline-config over the 7 files reads 0 errors and 0 warnings. The population comes from ESLint's own config: 7 configured, 0 ignored. No file sets parserOptions.project or projectService, so no untouched file's verdict can move.
  • check-governed-merges --test: NOT governed, 198 changed lines (+99 / -99).
  • A control-byte scan over the 6 changed files finds none.
  • Review round 1, at 69ea423302: two titles reworded, one line each: the row-cap describe (component.test.ts:4499) now states the gate's guard, and the offset-alias title (dashboard-compareto.test.ts:160) reads straight. Text-only proof against the base: 7 of 7 SAME, 99 changed leaves (98 title, 1 declared). The 7 files at base and head: 677 / 677 passed, count and status sequence identical in 7 of 7, 469 changed full names, 0 mismatches against the plan. ESLint over the 7 files: 0 errors, 0 warnings. The group census still reads 4 / 4. typecheck exit 0, and check:nul-bytes OK. The derived gate set is the same 79 families; they were not re-run for a two-literal change.

main since the base

Re-fetched just before this PR opened, origin/main was four commits past the base (cab6396715: #21875, #21896, #21893, #21900). None touches any of the 7 files. #21893 touches 8 packages/spec files under automation/ and migrations/, and the census over packages/spec/src at 866683f96f (after #21893) still reads 764 / 807 with no file moved, so the merged tree reads this PR's 665 / 702. #21900 touches two more packages/spec files, both non-test migration entries, which this census does not count. So main was not merged. git merge-tree onto cab6396715 is clean.

Acceptance notes


Generated by Claude Code

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

Stage 21 of the spec lane's share of the runtime-string burn-down: the
test strings shipped under packages/spec/src, the second name-ordered
ui/ group (component-record-blocks.test.ts through dashboard.test.ts).

99 literals in 6 files (98 test titles and one orderPin label that
becomes an it() title) lose 105 tracker ids: 21 now state the cited
decision in words, 15 get their subject back in words, and 63 drop a
number the title already explains. The four CSS hex colour literals
'#111' / '#222' in two widget fixtures stay: they cite no record and are
input the schema under test reads, never an expected value.

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 5, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 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 e6dc7a240617eaeef9a64e788bf6e5561c107f1b → packageMentionDocs.

…'s real guard, and the offset-alias title reads straight

The row-cap describe in component.test.ts said a bound view fills `limit`
"only when it is unset", which is the narrower sentence the record behind
it corrected: the gate fills `limit` whenever the authored one is not a
usable cap (`!isUsableRowLimit(authored)`). The title now says that. The
offset-alias title in dashboard-compareto.test.ts is reworded so it
parses on first read.

Text only: two title literals, one line each.

Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ
Co-authored-by: Claude <noreply@anthropic.com>
claude added 2 commits October 5, 2026 19:45
Brings the branch current with main for a full CI run; the merged range touches none of this branch's six test files.

Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ
Co-authored-by: Claude <noreply@anthropic.com>
Brings the branch current with main for a fresh CI run; the merged commit touches none of this branch's six test files.

Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 5, 2026 23:39
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 5, 2026
Merged via the queue into main with commit 3dbd084 Oct 6, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20749-test-strings-l branch October 6, 2026 00:16
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