Commit 3fa850c
test(spec): automation test titles state each cited decision in words instead of a tracker number (stage 10) (#21713)
Part of #20749
Clause-②: no
Stage 10 of this card, and the first area of class (e): the test strings
shipped under `packages/spec/src`, as ruled in `5902360492` on #20513.
This stage takes the whole `automation/` directory. Its 105 test-title
and test-message literals carried 110 tracker ids citing 55 records.
Each id now either states what its record decided, in words (form D), or
is dropped where the title already says it. Text only: no assertion,
fixture value, test count or code comment changes.
## Census at the base (`7e0066af7a`, the claim's base)
Instrument: stage 9's `census.cjs` (md5
`6e42a45a926d375013c32d62f16a296e`, byte-identical), plus one added
classification pass. 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.
Reference: the same instrument reads **1803 messages / 1919 ids in 425
files at `9b8c7f38d7`**, stage 9's reading exactly. Since then, #21699
added 1 / 1 (`ui/component-props-unknown-members.pin.test.ts:143`) and
#21700 moved 3 / 3 (the two reader literals it re-anchored), which gives
1801 / 1917 at the base.
| directory | files | titles msg / ids | other msg / ids | total msg /
ids | excluded files |
|:--|--:|--:|--:|--:|:--|
| `data/` | 95 | 445 / 475 | 23 / 26 | 468 / 501 | |
| `ui/` | 81 | 374 / 397 | 18 / 18 | 392 / 415 | `report.test.ts` 3 / 3
|
| `api/` | 40 | 181 / 193 | 8 / 8 | 189 / 201 | |
| `system/` | 34 | 128 / 138 | 26 / 27 | 154 / 165 | `job.test.ts` 4 / 4
|
| (files directly in `src/`) | 30 | 117 / 119 | 1 / 1 | 118 / 120 | |
| **`automation/`** (this PR) | 21 | 101 / 106 | 4 / 4 | **105 / 110** |
|
| `kernel/` | 36 | 92 / 96 | 10 / 10 | 102 / 106 | |
| `shared/` | 21 | 73 / 81 | 12 / 14 | 85 / 95 | |
| `contracts/` | 25 | 59 / 70 | 4 / 4 | 63 / 74 | |
| `conversions/` | 9 | 34 / 34 | 0 | 34 / 34 | |
| `security/` | 8 | 28 / 28 | 0 | 28 / 28 | |
| `ai/` | 9 | 13 / 15 | 5 / 5 | 18 / 20 | |
| `identity/` | 6 | 14 / 14 | 1 / 1 | 15 / 15 | |
| `integration/` | 4 | 13 / 13 | 1 / 1 | 14 / 14 | |
| `migrations/` | 2 | 9 / 12 | 0 | 9 / 12 | |
| `marketplace/`, `meta-spelling/`, `studio/` | 5 | 7 / 7 | 0 | 7 / 7 |
|
| **total** | **426** | **1688 / 1798** | **113 / 119** | **1801 /
1917** | 7 / 7 |
- **Excluded, in flight under this seat:** `system/job.test.ts` carries
#16292 (`:92`), #14478 (`:471`), #4667 (`:836`) and #19184 (`:881`), and
`ui/report.test.ts` carries #20161 (`:233`), #3916 (`:334`) and #5013
(`:426`). All seven sit in titles. They wait for a later stage, after
#21703 and #21702.
- **Controls.** Lit, single line: `automation/approval.test.ts:135`
reads one title with #3508. Lit, multi-line:
`api/discovery-environment-subset.pin.test.ts:63-66`, a `+` chain, reads
as ONE message with its id on `:65`. Dark: the `// #3508` comment at
`automation/approval.test.ts:131` reads 0. Planted in a scratch copy of
the head file: an id in a title reads 1 / 1, and an id in a comment
reads 0.
- **A wider pattern** (any `#` plus digits, so two-digit and six-digit
numbers too) reads the same 105 / 110 in `automation/` at the base, and
0 / 0 at the head.
- **At the head:** 1696 messages / 1807 ids in 405 files. `automation/`
reads 0 / 0. Nothing else moved.
## How the area was chosen
The directories are ranked by id count, and a stage takes whole
directories up to about 100 ids. The four busiest each exceed that bound
alone: `data/` (501), `ui/` (415), `api/` (201) and `system/` (165). The
files directly in `src/` (120) are 20% over. `automation/` (110) is the
busiest whole directory within about 10% of the bound, so it is this
stage. The rule picked it before any card was read.
Its 55 records (53 in this repository, 2 in objectui) were all readable
in one pass. 54 answer 200. #6362 answers 404, and its decision was read
from its landing commit `b5404f496`.
**Named for the next stages** (by directory, from the table): `data/`
(about five stages, by subdirectory or file group; `data/driver/` alone
is 52), `ui/` (about four), `api/` (two), `system/` (two), the files
directly in `src/` (one), `kernel/` (one), `shared/` (one), `contracts/`
with `conversions/` (one, 108), and `security/`, `ai/`, `identity/`,
`integration/`, `migrations/`, `marketplace/`, `meta-spelling/` and
`studio/` together (one, 96). The seven excluded ids join `system/` and
`ui/` once their owners land.
## What each id became
38 literals (40 ids) now state a decision in words. 67 literals (70 ids)
drop a citation the title already explains. Each record was read with
its comments through REST, and where a record has no comments, from what
landed.
| record | ids | result |
|:--|--:|:--|
| #3508 | 2 | `APPROVER_VALUE_BINDINGS`: "an approver value is picked
from the records the engine resolves". `APPROVER_VALUE_SOURCES` (the
follow-up): "where each picker finds its candidates, published on the
wire". |
| objectui#2955 | 1 | "for the decision dialog to render and enforce":
both decision entry points collect the typed outputs, and `required` is
enforced. |
| #3810 | 1 | "names the match-everything-write hazard": a filter
emptied by interpolation matches every row, and the node is refused
instead. The test pins the words `match-everything write`. |
| #4001 | 13 | "strict as of #4001 批 9" becomes "an unknown key is
refused, not stripped" (5 titles). Also "refused, not stripped", "an
unknown key is refused, per shape" and "the unknown-key gate". Dropped
from 5 titles that already read "unknown keys are rejected, not
stripped". |
| objectui#2670 | 1 | "so the flow designer renders it as a template":
the designer's loop and region rendering reads this marker. |
| #4396 | 2 | "a function that writes says so; pure is the default", and
"the authoring surface where a function declares its effect" (landed
`eb4204b`). |
| #4697 | 2 | `defaultValue`: "a declared variable is bound on every
path" (ruling A). Dropped once. |
| #3896 | 3 | "outputSchema retired: declared, never validated" (the
audit close-out's reason, as `flow.zod.ts`'s tombstone records it).
Dropped twice. |
| #4247 | 1 | "maxRetries — one default, and no zero-attempt “retry”"
(landed `a648e96`). |
| #16134, #15713 | 7 | "a region node reusing a top-level id is refused
— one node-id space now spans every region" (ruling, batch 61). Dropped
from 5 titles that state uniqueness. |
| #9205 | 5 | "template reference — notify content localized through an
email template" (the ruled emailTemplates route). Three titles say "the
template path" where they said "pre-#9205". Dropped once. |
| #7086 | 1 | "severity — the closed info \| warning \| critical
vocabulary" (the enum route). |
| #4415 | 3 | "FlowNodeSchema parses its own regions" (ruling
2026-08-07, direction 1). Dropped from 2 titles that already say it. |
| #4347 | 1 | "collectFlowGraphs — every region is walked, not only the
top level" (landed `31e0be9`). |
| #4401 | 2 | "FLOW_REGION_SLOTS, the one declaration of where regions
live" (landed `4bfd455`). Dropped once. |
| #4414 | 1 | "`condition` is pointed at the out-edges, NOT given the
one-edit rename" (one working routing model, landed `5293114`). |
| #15429 | 1 | "taking every true branch must be declared" (ruling item
2: explicit `inclusive`). |
| #14149 | 3 | "every entry older than the value role" (ruling A: a
value-role CEL slot on `assignment`). Dropped twice. |
| #19938 | 4 | "the CRUD `fields.*` value slots added exactly two rows".
Dropped three times. |
| #15572 | 3 | "predicateSlotRefusal — a predicate slot holds bare CEL
text", and "the other two doors refuse it". Dropped once. |
| #15662 | 1 | "structuralConditionRefusal — a structural condition is
CEL text or an expression". |
| #15792, #15807 | 4 | "REFUSES an `ast`-only envelope — admitted at
first, refused once an evaluated slot required a `source`". Dropped from
2 titles that state the rule. |
| #17493 | 3 | Table row "a blank string — blanks are refused" (ruling
A). Dropped twice. |
| #14945 | 4 | "EndConfigSchema — the `end` node contract: it may refuse
the run with a message" (ruling 2′). Dropped three times. |
| #15617 | 4 | "`failed` is the fold INCLUDING what a delegating node
rolled up from its child — it answers what the run caused" (ruling
option 1). Dropped three times. |
| dropped only | 36 | #3196, #3266, #4158, #4277, #4343 (2), #4389,
#4525, #4738, #4964 (2), #6758, #7085, #9106, #12278, #14964, #15430,
#15646 (3), #16752, #17306, #17852, #18102, #18112 (2), #18847, #19151,
#19961 (4), #20316 (2): each title already states the pinned decision.
For #4988 and #6414, the two expect messages already say what was
retired. |
| #6362 (404) | 1 | Dropped. The title "PRESERVES all seven envelope
keys — measured, not assumed" carries the decision recorded in
`b5404f496` (`webhook` was measured, and all seven keys survive). |
## Readers
- **Test-name filters:** none. A tracked-tree search for `-t` and
`--testNamePattern` finds only `packages/qa/dogfood/README.md:142` (`-t
"owner-scoped"`), which is unrelated.
- **Snapshots:** none. `automation/` has no `__snapshots__` and no
`toMatchSnapshot`.
- **Titles by substring:** every old title, plus a window around each id
(250 needles), was searched across the tracked tree outside its own
file. No gate, doc or script matches one. The hits are other files' own
titles with the same words: `identity/`, `security/` and `automation/`
siblings, a later stage's lot. There are also two code comments in
`flow.zod.ts` and `flow-function.zod.ts`, which belong to the comment
lane.
- **Twin tables, not readers:**
`packages/lint/src/validate-expressions.test.ts:4442/4445` and
`packages/services/service-automation/src/decision-branch-expression-absent.test.ts:61/64`
repeat the `flow-decision-branch-expression-absent` table's row names.
Nothing compares them mechanically: the "same table" parity is prose in
the headers, and it covers assertions, not names. They are outside this
stage's surface (see Acceptance notes).
## Text-only proof
A scratch tool (`textonly10.cjs`) 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 string leaf that changed must sit in a test-call
title position, or on one of the 4 declared lines
(`flow-decision-branch-expression-absent.test.ts:63` and `:66`, table
`name` values that feed `$name` titles; `sync-retirement.test.ts:120`
and `:158`, expect messages). It must carry a tracker id before and no
`#` plus digits after.
- **Result:** 21 of 21 files SAME, 105 changed (101 title, 4 declared),
on all three legs.
- **Diff hunks:** exactly the 105 planned lines, with every file keeping
its line count.
- **Controls (10 of 10 as predicted, on scratch copies, each anchor hit
once):** identifier rename DIFF; numeric literal DIFF; comment edit
COMMENT DIFF; a non-title string with 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 (104 changed); a declared
string keeping an id VIOLATION; an undeclared expect message changed
VIOLATION; a title re-split into a `+` chain DIFF.
**Test counts:** the 21 files run at the base (in a separate base
worktree) and at the head: 801 / 801 tests on both sides, with the same
count and status sequence per file in 21 of 21. 560 full test names
change, and each equals the base name with the planned replacements
applied.
## Changeset: `skip-changeset`
Measured, not assumed:
- `npm pack --dry-run` of `@objectstack/spec` lists 2068 files, under
`files[]` (`dist`, `src/**/*.zod.ts` and the rest). 0 of the 21 touched
files are in it, and 0 `*.test.ts` at all. The control
`src/automation/flow.zod.ts` is in it.
- In `dist/`, three new phrases and three old ones each read in 0 files.
The control `A predicate slot holds BARE CEL TEXT` reads in 2.
So this PR publishes nothing, and no changeset is added.
## Verification (at `f3dc3fab03`)
- `pnpm turbo run build` over all packages: 71 / 71.
- `@objectstack/spec`: `vitest run --project local`, 612 files and 18185
passed, 1 todo. `typecheck` exit 0, including `check:test-typecheck`,
whose program holds all 21 touched files.
- **Gates:** `dispatch-gates --commands` derived 79 families, and all 79
exit 0. `--ran` reconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN.
- **ESLint, a proven narrowing:** `--no-inline-config` over the 21
files, 0 errors and 0 warnings. The population comes from ESLint's own
config: 21 configured, 0 ignored. No `parserOptions.project` or
`projectService`, so no untouched file's verdict can move.
- `check-governed-merges --test`: NOT governed, 210 changed lines.
## Acceptance notes
- **Twin row names in other packages:** the lint and service-automation
copies of the decision-branch table keep their `the #19961 shape` and
`the #17493 control` row names, and their twin `describe` titles keep
their ids. The lint copy is this card's own later share (the
`packages/lint` test strings). The service-automation copy belongs to
that package's lane.
- **Code comments still carry ids** in these 21 files (for example
`approval.test.ts:56`, `:69` and `:131`). They are the comment lane's,
untouched here.
- **`origin/main` moved** three commits past the base before this PR
opened (#21701, #21707, #21706). None touches `packages/spec`, so
nothing was merged.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent ed15448 commit 3fa850c
21 files changed
Lines changed: 105 additions & 105 deletions
File tree
- packages/spec/src/automation
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
135 | | - | |
| 135 | + | |
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
| |||
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
176 | | - | |
| 176 | + | |
177 | 177 | | |
178 | 178 | | |
179 | 179 | | |
| |||
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
312 | | - | |
| 312 | + | |
313 | 313 | | |
314 | 314 | | |
315 | 315 | | |
| |||
486 | 486 | | |
487 | 487 | | |
488 | 488 | | |
489 | | - | |
| 489 | + | |
490 | 490 | | |
491 | 491 | | |
492 | 492 | | |
| |||
512 | 512 | | |
513 | 513 | | |
514 | 514 | | |
515 | | - | |
| 515 | + | |
516 | 516 | | |
517 | 517 | | |
518 | 518 | | |
| |||
540 | 540 | | |
541 | 541 | | |
542 | 542 | | |
543 | | - | |
| 543 | + | |
544 | 544 | | |
545 | 545 | | |
546 | 546 | | |
| |||
607 | 607 | | |
608 | 608 | | |
609 | 609 | | |
610 | | - | |
| 610 | + | |
611 | 611 | | |
612 | 612 | | |
613 | 613 | | |
| |||
Lines changed: 10 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
88 | | - | |
| 88 | + | |
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| |||
204 | 204 | | |
205 | 205 | | |
206 | 206 | | |
207 | | - | |
| 207 | + | |
208 | 208 | | |
209 | 209 | | |
210 | 210 | | |
| |||
249 | 249 | | |
250 | 250 | | |
251 | 251 | | |
252 | | - | |
| 252 | + | |
253 | 253 | | |
254 | 254 | | |
255 | 255 | | |
| |||
397 | 397 | | |
398 | 398 | | |
399 | 399 | | |
400 | | - | |
| 400 | + | |
401 | 401 | | |
402 | 402 | | |
403 | 403 | | |
| |||
430 | 430 | | |
431 | 431 | | |
432 | 432 | | |
433 | | - | |
| 433 | + | |
434 | 434 | | |
435 | 435 | | |
436 | 436 | | |
| |||
568 | 568 | | |
569 | 569 | | |
570 | 570 | | |
571 | | - | |
| 571 | + | |
572 | 572 | | |
573 | 573 | | |
574 | 574 | | |
| |||
627 | 627 | | |
628 | 628 | | |
629 | 629 | | |
630 | | - | |
| 630 | + | |
631 | 631 | | |
632 | 632 | | |
633 | 633 | | |
| |||
688 | 688 | | |
689 | 689 | | |
690 | 690 | | |
691 | | - | |
| 691 | + | |
692 | 692 | | |
693 | 693 | | |
694 | 694 | | |
| |||
807 | 807 | | |
808 | 808 | | |
809 | 809 | | |
810 | | - | |
| 810 | + | |
811 | 811 | | |
812 | 812 | | |
813 | 813 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | | - | |
| 64 | + | |
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| |||
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
80 | | - | |
| 80 | + | |
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
| |||
272 | 272 | | |
273 | 273 | | |
274 | 274 | | |
275 | | - | |
| 275 | + | |
276 | 276 | | |
277 | 277 | | |
278 | 278 | | |
| |||
438 | 438 | | |
439 | 439 | | |
440 | 440 | | |
441 | | - | |
| 441 | + | |
442 | 442 | | |
443 | 443 | | |
444 | 444 | | |
| |||
491 | 491 | | |
492 | 492 | | |
493 | 493 | | |
494 | | - | |
| 494 | + | |
495 | 495 | | |
496 | 496 | | |
497 | 497 | | |
| |||
540 | 540 | | |
541 | 541 | | |
542 | 542 | | |
543 | | - | |
| 543 | + | |
544 | 544 | | |
545 | 545 | | |
546 | 546 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
127 | 127 | | |
128 | 128 | | |
129 | 129 | | |
130 | | - | |
| 130 | + | |
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
| |||
217 | 217 | | |
218 | 218 | | |
219 | 219 | | |
220 | | - | |
| 220 | + | |
221 | 221 | | |
222 | 222 | | |
223 | 223 | | |
| |||
278 | 278 | | |
279 | 279 | | |
280 | 280 | | |
281 | | - | |
| 281 | + | |
282 | 282 | | |
283 | 283 | | |
284 | 284 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
204 | 204 | | |
205 | 205 | | |
206 | 206 | | |
207 | | - | |
| 207 | + | |
208 | 208 | | |
209 | 209 | | |
210 | 210 | | |
| |||
415 | 415 | | |
416 | 416 | | |
417 | 417 | | |
418 | | - | |
| 418 | + | |
419 | 419 | | |
420 | 420 | | |
421 | 421 | | |
| |||
440 | 440 | | |
441 | 441 | | |
442 | 442 | | |
443 | | - | |
| 443 | + | |
444 | 444 | | |
445 | 445 | | |
446 | 446 | | |
| |||
457 | 457 | | |
458 | 458 | | |
459 | 459 | | |
460 | | - | |
| 460 | + | |
461 | 461 | | |
462 | 462 | | |
463 | 463 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | | - | |
| 66 | + | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
| 70 | + | |
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| |||
0 commit comments