Repository navigation
Commit 8256a4b
test(spec): contracts and conversions test titles state each cited decision in words instead of a tracker number (stage 13) (#21763)
Part of #20749
Clause-②: no
Stage 13 of this card, and the fourth area of class (e): the test
strings shipped under `packages/spec/src`, as ruled in `5902360492` on
#20513. This stage takes two whole directories, `contracts/` and
`conversions/`. Their 97 test-title and test-string literals carried 108
tracker ids citing 78 records. 107 ids in 96 literals now either state
what their record decided, in words (form D), or are dropped where the
title already says it. One id stays, for the reason given below. Text
only: no assertion, identifier, test count or code comment changes.
## Census at the base (`866b4393d0`, the claim's base)
Instruments: `census10.cjs` (md5 `9d08602ab972b4b8643c90d64d40fa41`),
`census.cjs` (md5 `6e42a45a926d375013c32d62f16a296e`) and
`census-wide.cjs` (md5 `c98410a19529c439adb0afbfb00026a2`),
byte-identical to the copies stages 10 to 12 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.
Both instruments read **1509 messages / 1606 ids in 348 files at the
base**, which is stage 12's head reading exactly. `contracts/` reads 63
/ 74 and `conversions/` 34 / 34, also stage 12's figures.
| directory | files | messages / ids | titles | other |
|:--|--:|--:|--:|--:|
| `data/` | 95 | 468 / 501 | 445 / 475 | 23 / 26 |
| `ui/` | 81 | 392 / 415 | 374 / 397 | 18 / 18 |
| `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 |
| **`contracts/`** (this PR) | 25 | **63 / 74** | 59 / 70 | 4 / 4 |
| **`conversions/`** (this PR) | 9 | **34 / 34** | 34 / 34 | 0 |
| `security/` | 8 | 28 / 28 | 28 / 28 | 0 |
| `ai/` | 9 | 18 / 20 | 13 / 15 | 5 / 5 |
| `identity/` | 6 | 15 / 15 | 14 / 14 | 1 / 1 |
| `integration/` | 4 | 14 / 14 | 13 / 13 | 1 / 1 |
| `migrations/` | 2 | 9 / 12 | 9 / 12 | 0 |
| `marketplace/`, `meta-spelling/`, `studio/` | 5 | 7 / 7 | 7 / 7 | 0 |
| **total** | **348** | **1509 / 1606** | **1422 / 1515** | **87 / 91**
|
- **Controls.** Lit, a title: `contracts/data-engine.test.ts:575` reads
one message with four ids. Lit, an `expect` message:
`contracts/metadata-service-roundtrip-conformance.test.ts:142` reads one
message. Dark: the comment at
`contracts/core-service-contracts.test.ts:3` ("[#4127] The map claims a
binding per slot") reads 0. Planted in a scratch copy: an id put back
into a title reads 1 / 1, and an id in an added comment reads 0.
- **A wider pattern** (any `#` plus digits) reads 63 / 75 under
`contracts/` and 35 / 36 under `conversions/` test files at the base.
The extras are `(batch #76)` in the
`resume-failure-report.pin.test.ts:137` title, and `PD #12` (Prime
Directive 12, contract-first) in two `conversions.test.ts` titles,
`:180` and `:785`. None matches the gate's 3-to-5-digit pattern.
- **At the head:** 1413 messages / 1499 ids in 315 files. `contracts/`
reads 1 / 1 (the needle below), `conversions/` 0 / 0. Nothing else
moved. The wider pattern reads that needle and the two `PD #12` titles,
and nothing else.
## How the area was chosen
Stage 10's rule: rank whole first-level directories by ids, and take the
busiest within about 10% of the ~100-id bound. `data/` (501), `ui/`
(415), `api/` (201) and `system/` (165) each exceed it alone, and the
files directly in `src/` (120) are 20% over. No single remaining
directory fits except smaller ones, and `contracts/` with `conversions/`
reads exactly 108, within 10% of the bound. That is the pairing the
stage-10 ACCEPT named, so the rule needed no second pass.
**Named for the next stages:** `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,
120), and `security/`, `ai/`, `identity/`, `integration/`,
`migrations/`, `marketplace/`, `meta-spelling/` and `studio/` together
(one, 96).
## What each id became
32 ids in 21 literals now state a decision in words. 75 ids in 75
literals are dropped where the title already says what the record
decided. Every cited record was read with its comments through REST: 71
answer 200, and 7 answer 404 (#6345, #6523, #11741, #12010, #12248,
#16559, #16786). For those seven the decision was read from what landed:
the landing commit and the CHANGELOG entry.
| record(s) | literal | now reads |
|:--|:--|:--|
| #16293 | `action-confirmation-contract.pin.test.ts:63` |
"action-confirmation contract — an unconfirmed gated action is refused".
The ruling: a gated action without an explicit confirmation is refused
loudly, with the way to confirm. |
| #10331 | `approval-service.test.ts:23` | "approval rows declare the
organization_id they are stamped with". The finding's first reading
landed: both row types declare it, optional and nullable. |
| #19846 | `automation-context-caller-param-keys.pin.test.ts:49` |
"AutomationContext.callerParamKeys — the keys the caller supplied". The
ruling replaced the headless-screen inference with this explicit signal.
|
| #18235 | `automation-service.test.ts:422` | "FlowRuntimeState —
carries the reason a flow is unbound", so a policy-disabled flow reads
differently from a broken binding. |
| #15937 | `confirmed-blueprint-identity-contract.pin.test.ts:52` |
"confirmedBlueprintIdentity — declared on the protocol
ToolExecutionContext". The maintainer chose option 1: declare it in the
protocol, not only on cloud's augmentation. |
| #11493 (2) | `data-driver.test.ts:290`, `data-engine.test.ts:455` |
"introspectSchema — an optional driver member at the spec shape" and
"introspectDatasource — answers the spec introspection shape". Both
ruled steps. |
| #12248, #11833 | `data-engine.test.ts:514` | "datasource resolution
members — declared, and optional". Fork 1 of the #11833 ruling, option
A, landed as `8425c17cc`. |
| #12248, #12010, #12805, #11833 | `data-engine.test.ts:575` |
"datasource lifecycle members — declared at the shape the engine keeps".
Item 4 of the #11833 ruling put `ConnectionEngineLike`'s members on the
contract (`8425c17cc`, `77b91bd`), and #12805 caught the declared def up
to what the engine retains. |
| #12482, #12010, #11833 | `data-engine.test.ts:679` | "syncObjectSchema
— declared, since two services already call it". |
| #5040 | `http-server.test.ts:183` | "optional setFallbackHandler — a
not-found hook, not a wildcard route". The design's option C, so a
declared endpoint never shadows a registered route. |
| #9835 | `http-server.test.ts:316` | "optional afterResponse — a
transport-agnostic response observer". |
| #6617 | `job-service.test.ts:126` | "JobHandler degraded-outcome
channel — optional and additive". |
| #14766, #14501 | `job-service.test.ts:263` | "IJobService.replay force
option — a succeeded window replays only when forced". The A + a2
ruling. |
| #4127 | `notification-service.test.ts:153` | "inbox — declared on the
contract, and optional". |
| #5928 | `objectql-engine-hook-scope.test.ts:41` |
"IObjectQLEngine.registerHook scope faces — global minus excluded
objects". The ruled A shape, `excludeObjects`. |
| #12248, #11833 | `objectql-engine.test.ts:29` | "getObject return
contract — a structured answer, not `unknown`". Fork 3. |
| #12481, #12248, #11833 | `objectql-engine.test.ts:106` | "getSchema
return contract — the same answer as its alias getObject". Fork 3, one
member over. |
| #20157, #19995 | `objectql-engine.test.ts:163` | "judgeFilter contract
— the engine judges a filter without running it". Ruling C. |
| #4539 | `sharing-service.test.ts:35` | "recipient vocabularies, each
under its own name". The same-name, different-form exports were split by
renaming. |
| #5858 | `sharing-service.test.ts:194` | "HierarchyScopeContext tenancy
authority — organizationId is authoritative". |
**Dropped only (75 ids):** #3903, #4045, #4127 (2), #4158, #4251, #4343,
#4347 (2), #4401, #4456 (2), #4538 (2), #4827, #4829, #4923 (5), #5011,
#5122, #5125, #5126, #5493 (3), #5777, #5817, #5945 (4), #6345 (2),
#6428, #6430, #6523, #6775 (2), #6776, #7378 (3), #7616 (2), #8321,
#11122 (2), #11741, #11832, #13700, #13937, #14103, #14244, #14384,
#14945, #14969, #15389, #15429, #16231, #16495, #16559, #16693, #16786,
#19620, #20323, #20390, #20740, #20935, #20940, #21005, #21220, #21458.
- Each title already states the pinned decision. In `conversions/` most
titles are the conversion entry's own id ("action-aria-removed",
"app-hidden-to-unpublished"), which is the decision that landed.
- **Qualified references** were read before dropping: "#13937 shape 4"
(keep the consume order and add an operator exit verb; the title already
names the repairable run), "#4923 house rule" (equal values dedupe,
different values keep both; the title already says "keeps BOTH"), "#4127
batch 3" (the ledger extends past the enum; the title says "beyond the
enum"), "#4251 B3" (`IObjectQLEngine` widens `IDataEngine`; the title
says it), "#5122 shape" (a wrapper that forwards only required members;
the title says it), and "#7378 row 1" / "row 3" (both refusal messages
already state their row's ruling).
- **The 404 records:** #6345 (`e2798fa`: one driver vocabulary, `mongo`
converged to `mongodb`), #6523 (`aa4b90d`: enforcement takes the full
`ExecutionContext`), #11741 (`b706af9`: an optional `organizationId` on
both email inputs), #16559 (`c7aca0dce`: the resume failure declared
once, carried by a success answer), #16786 (`6059b29`: `updateById`
declares the record or `null`). Each title already carries what landed.
- **`(batch #76)`** in `resume-failure-report.pin.test.ts:137` goes with
`#16559` in the same literal. It names the decision batch whose ruling
the title already states ("the resume failure a success answer
carries"). It is outside the gate's pattern, and it is declared here.
- **`PD #12`** stays in `conversions.test.ts:785`. It is a Prime
Directive reference in AGENTS.md, not a tracker number, and the
untouched sibling title at `:180` spells it the same way.
## The one id that stays
`contracts/approval-service.test.ts:274` is
`expect(doc).toContain('#16495')`. It is not a title: it is the expected
value of an assertion that reads the `continueRestoredRun` docblock in
`contracts/approval-service.ts` and pins that the docblock names the
sibling it was ruled to copy. Changing it needs a code comment and
assertion logic, which this claim excludes. It moves with that docblock
when the comment lane rewrites `approval-service.ts:999`.
## 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. Neither directory has `__snapshots__`, and no
`.snap` file is tracked under `packages/spec`.
- **Projects:** none of the 34 files is listed in
`packages/spec/vitest.repo-tests.json`, so all run in the `local`
project.
- **By substring:** every old literal, plus a window around each id (241
needles), was searched across the tracked tree outside its own file. No
gate, doc, filter, snapshot or `scripts/check-*.mjs` self-test reads
one. The 17 needle hits land on 11 lines:
- Sibling test strings in other lanes' packages:
`packages/objectql/src/metadata-service-roundtrip-conformance.test.ts:232`
(the objectql driver of the same table, `register must REFUSE this write
(#7378)`);
`packages/plugins/plugin-security/src/get-queryable-fields.test.ts:136`
and `:165` (`[#20935]`),
`resolve-permission-sets-for-context.pin.test.ts:103` (`[#7616]`),
`authored-row-write-verdict.test.ts:350` (`[#5493]`); and
`packages/metadata-core/src/artifact-forward-conversion.test.ts:277`
(`(ADR-0113, #16693)`).
- Code comments:
`packages/spec/src/contracts/automation-service.ts:1061` (`#13937 shape
4`), `packages/spec/src/contracts/index.ts:44` (`(#4127)`),
`packages/cli/src/utils/view-container-names.ts:11` and
`packages/objectql/src/view-container-name-refusal.ts:13` (`#7378 row
1`).
## 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. The declared lines are the three in
`metadata-service-roundtrip-conformance.test.ts`: the reference double's
two refusal messages (`:68`, `:75`) and the `expect` message at `:142`.
No test asserts on the dropped text: the refusal checks assert `code`,
`status` and the write's coordinates.
- **Result:** 33 of 34 files SAME on all three legs.
`conversions.test.ts` passes the skeleton and comment legs and is
flagged on one string, `:785`, because its rewritten title keeps `PD
#12`. That was predicted in writing before the run. With `PD #12`
spelled `PD-12` in both the base and head copies of that one line, the
file reads SAME with 19 changed titles.
- **Totals:** 96 changed literals, 93 titles and 3 declared. The diff's
`+` lines are exactly the 96 planned lines, and every file keeps 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 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; a declared string keeping an
id VIOLATION; an undeclared `expect` message changed VIOLATION; a title
re-split into a `+` chain DIFF.
**Test counts:** the 34 files were run at the base (in a separate base
worktree at `866b4393d0`) and at the head, in the `local` project. Both
sides read 595 / 595 passed, with the same count and status sequence per
file in 34 of 34. 354 full test names change, and each equals the base
name with the planned replacements applied. One full name repeats on
both sides: two `sqlite` rows of the `stored.test.ts` `it.each` table
share the `%s` name. That predates this PR.
## Changeset: `skip-changeset`
Measured, not assumed:
- `npm pack --dry-run` of `@objectstack/spec` lists 2068 files. 0 of the
34 touched files are in it, and no `*.test.ts` at all. The controls
`src/shared/expression.zod.ts` and `dist/contracts/index.js` are in it.
- In `dist/`, four new phrases and three old ones each read in 0 files.
The control `Unrecognized key(s) on` reads in 42.
So this PR publishes nothing, and no changeset is added.
## Verification (at `72513933ee`)
- `pnpm turbo run build` over all packages: 71 / 71.
- `@objectstack/spec`:
- `vitest run --project local`: 614 files, 18285 passed, 1 todo.
- `typecheck` exit 0, including `check:test-typecheck`. Its program
holds all 34 touched files, counted with `tsc --listFilesOnly`.
- **Gates:** `dispatch-gates --commands` derived 79 families (stage 12's
80 without `check:future-spec-major`, which no touched file feeds), and
all 79 exit 0. `--ran` reconciles: 79 derived, 79 run, 0 NOT-MEASURED, 0
UNRUN.
- 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 34
files, 0 errors and 0 warnings. The population comes from ESLint's own
config: 34 configured, 0 ignored. No `parserOptions.project` or
`projectService`, so no untouched file's verdict can move.
- `check-governed-merges --test`: NOT governed, 192 changed lines.
## Acceptance notes
- **The `#16495` needle** at `approval-service.test.ts:274` stays, with
the `approval-service.ts:999` docblock it pins. The comment lane owns
both.
- **Code comments still carry ids** in these 34 files and in the two
directories' sources. Comments are not this card's share and are
untouched here.
- **Sibling test strings in other packages** repeat ids this PR dropped:
the objectql driver of the round-trip table, three `plugin-security`
test files and one `metadata-core` test (listed under Readers). Each is
its own lane's test-string stage.
- **`origin/main` moved** five commits past the base before this PR
opened (#21752, #21754, #21753, #21751, #21743). None touches
`packages/spec`, so nothing was merged. #21756, which also edits
`contracts/security-service.test.ts`, has no PR yet; whichever lands
later merges `origin/main`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent ebfe658 commit 8256a4b
34 files changed
Lines changed: 96 additions & 96 deletions
File tree
- packages/spec/src
- contracts
- conversions
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
90 | | - | |
| 90 | + | |
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
| 190 | + | |
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | | - | |
| 72 | + | |
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
86 | | - | |
| 86 | + | |
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
| |||
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
118 | | - | |
| 118 | + | |
119 | 119 | | |
120 | 120 | | |
121 | 121 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
302 | 302 | | |
303 | 303 | | |
304 | 304 | | |
305 | | - | |
| 305 | + | |
306 | 306 | | |
307 | 307 | | |
308 | 308 | | |
| |||
419 | 419 | | |
420 | 420 | | |
421 | 421 | | |
422 | | - | |
| 422 | + | |
423 | 423 | | |
424 | 424 | | |
425 | 425 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
52 | | - | |
| 52 | + | |
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | | - | |
| 73 | + | |
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
99 | | - | |
| 99 | + | |
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
287 | 287 | | |
288 | 288 | | |
289 | 289 | | |
290 | | - | |
| 290 | + | |
291 | 291 | | |
292 | 292 | | |
293 | 293 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
213 | 213 | | |
214 | 214 | | |
215 | 215 | | |
216 | | - | |
| 216 | + | |
217 | 217 | | |
218 | 218 | | |
219 | 219 | | |
| |||
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
269 | | - | |
| 269 | + | |
270 | 270 | | |
271 | 271 | | |
272 | 272 | | |
| |||
452 | 452 | | |
453 | 453 | | |
454 | 454 | | |
455 | | - | |
| 455 | + | |
456 | 456 | | |
457 | 457 | | |
458 | 458 | | |
| |||
511 | 511 | | |
512 | 512 | | |
513 | 513 | | |
514 | | - | |
| 514 | + | |
515 | 515 | | |
516 | 516 | | |
517 | 517 | | |
| |||
572 | 572 | | |
573 | 573 | | |
574 | 574 | | |
575 | | - | |
| 575 | + | |
576 | 576 | | |
577 | 577 | | |
578 | 578 | | |
| |||
676 | 676 | | |
677 | 677 | | |
678 | 678 | | |
679 | | - | |
| 679 | + | |
680 | 680 | | |
681 | 681 | | |
682 | 682 | | |
| |||
0 commit comments