|
67 | 67 | - argTypes: every baseline key, description, default value, and type must survive. |
68 | 68 | A type may only change by normalized deep equality or a clear improvement - a catch-all becoming structured, a literal union gaining members. |
69 | 69 | About half the corpus records `other`, where the legacy engine parked free text it could not resolve (`TreeNode`, `Array([object Object])`, `{ theme: string; dense: boolean }`). |
70 | | - Such a stub accepts a candidate that adds structure or resolves it to the scalar it already named; an unrelated scalar is a lateral change and fails. |
| 70 | + Such a stub accepts a candidate that adds populated structure (an empty enum/union/object is not an improvement) or resolves it to the scalar or single literal it already named; an unrelated scalar or literal is a lateral change and fails. |
71 | 71 | Only the three markers that record nothing at all accept any candidate: `empty-enum`, `undefined`, and the empty string - today's Angular and Vue spellings, so adding a framework means revisiting that list. |
72 | 72 | A resolution the rule cannot recognize (legacy `TSFunctionType` becoming a `function` sbType, say) fails rather than guessing; re-record and review the diff. |
73 | | - `required`, `table.category`, `jsDocTags`, `control`/`action`, and description/default contents are deliberately not compared; each would lock in a recorded lie (#28706) or engine-specific vocabulary. |
| 73 | + A recorded `table.type.summary` must survive (dropping it is a violation), but its text may change freely outside `strictTable`. |
| 74 | + `required`, `table.category`, `jsDocTags`, `control`/`action`, and description/default contents are deliberately not compared (except `required` under `strictTable`); each would lock in a recorded lie (#28706) or engine-specific vocabulary. |
74 | 75 | - Snippets: represented binding names are compared as sets, so formatting can never fail, but a lost binding does. |
75 | 76 | Directive spelling is normalized, so `:x`/`v-bind:x`, `@x`/`v-on:x`, `#x`/`v-slot:x`, and any `.modifier` all read as the same name. |
| 77 | + The Angular comparison additionally gates root-element identity: the tag name must match and bare (valueless) attributes - the mangled attribute-selector markers - must survive. |
76 | 78 | - Acceptance: there is no allowlist file. |
77 | 79 | The committed baseline is the allowlist - accept an intentional change by re-recording with `-u` and reviewing the diff. |
78 | | -- The recorders read each committed file before its snapshot call, so a `-u` re-record still compares the fresh output against the last committed text. |
| 80 | +- The recorders read each committed file and run every gate BEFORE the snapshot call, so a `-u` run refuses to queue a regressed recording and stays red until the code is fixed. |
79 | 81 | Regressions fail with named violations; improvements pass. |
80 | 82 | - The committed `argtypes*.snapshot` files are pretty-format text, not JSON. |
81 | | - `parseArgTypesSnapshot` reads them back and verifies itself by re-serializing every parse byte-for-byte; anything outside that grammar throws. |
| 83 | + `parseArgTypesSnapshot` reads them back, verifies itself by re-serializing every parse byte-for-byte, and rejects any parsed string carrying the writer-ambiguous entry-boundary shape. |
| 84 | + A string whose unescaped write is byte-identical to real entry boundaries cannot be detected at parse time; the recorders' parsed-vs-live proofs guard that case on normal and CI runs, and on `-u` runs against the exact bytes queued for writing. |
82 | 85 | - Adding a framework: extend the `Framework` union and compilation fails at the switch in `snippets.ts` until the new matcher exists. |
83 | 86 |
|
| 87 | +### Trust model |
| 88 | + |
| 89 | +The comparator machine-checks a deliberate subset: baseline arg names, description presence, default presence, `table.type.summary` presence, and type fidelity for argTypes; represented binding names, root-element identity, and bare-attribute survival for Angular snippets. |
| 90 | +Everything else - description/default/summary text, `table.category`, `control`/`action`, per-arg `jsDocTags`, added args - is caught only by the byte-exact snapshot diffs reviewed at `-u` time, or by the sandbox gate's `change` findings. |
| 91 | +Two flags scope trust to where the baseline earns it: `legacyBaseline` (only on legs whose baseline is a legacy compodoc recording) waives the raw `false`/`NaN`/`null` defaults that pipeline invents, and `strictTable` (only on the ACM self-ratchet, whose baseline the same engine recorded) additionally gates `table.type.summary` text changes and `table.type.required` true->false flips. |
| 92 | +The sandbox baseline gate runs in the daily CI tier, so a whole-project regression can merge green and surface up to a day later, detached from the offending PR. |
| 93 | +Known-accepted blind spots: enum members whose quoted and bare spellings collide normalize to the same member (`'"small"'` reads as `small`), and `\r`/`\r\n` in extracted strings are LF-normalized by vitest at write time, so a CR-bearing extraction can never record green (perma-loud, never silent). |
| 94 | + |
84 | 95 | ## The vue-component-meta recorder (vue3) |
85 | 96 |
|
86 | 97 | `vue3-component-meta-baselines.test.ts` replicates the vue3-vite vite plugin's meta processing exactly - checker options, empty-meta skip, nested-schema pruning, exposed de-duplication, and the vue-docgen-api event-description backfill - so the `cm-` snapshots show what a `vue-component-meta` user actually gets today. |
|
0 commit comments