styleproof 3.20.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +192 -0
- package/README.md +437 -321
- package/bin/styleproof-capture.mjs +4 -0
- package/bin/styleproof-diff.mjs +192 -27
- package/bin/styleproof-init.mjs +75 -7
- package/bin/styleproof-map.mjs +23 -9
- package/bin/styleproof-report.mjs +6 -0
- package/dist/capture-url.js +5 -0
- package/dist/capture.d.ts +59 -0
- package/dist/capture.js +127 -5
- package/dist/change-groups.d.ts +91 -0
- package/dist/change-groups.js +471 -0
- package/dist/coverage.d.ts +7 -0
- package/dist/data-residue.d.ts +70 -0
- package/dist/data-residue.js +105 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/map-store.d.ts +37 -1
- package/dist/map-store.js +103 -10
- package/dist/report.d.ts +1 -4
- package/dist/report.js +100 -353
- package/dist/runner.d.ts +20 -0
- package/dist/runner.js +63 -9
- package/example/styleproof-approve.yml +108 -0
- package/package.json +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,198 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.0.0] - 2026-07-07
|
|
11
|
+
|
|
12
|
+
The first major since v3. Three breaking defaults make StyleProof strict out of
|
|
13
|
+
the box — an unapproved change **blocks**, a silently-failing data endpoint
|
|
14
|
+
**gates**, and a manifest-less map bundle is **refused** rather than compared on
|
|
15
|
+
faith. Pin `BenSheridanEdwards/StyleProof@v4` to adopt; `@v3` stays on 3.x. Each
|
|
16
|
+
breaking entry below carries its one-line migration.
|
|
17
|
+
|
|
18
|
+
### Removed
|
|
19
|
+
|
|
20
|
+
- **BREAKING: a manifest-less map bundle is no longer compared — it fails with exit
|
|
21
|
+
`2`.** Before, a two-directory `styleproof-diff`/`styleproof-report` where a side
|
|
22
|
+
shipped captured maps but no `styleproof-manifest.json` (the legacy committed-map
|
|
23
|
+
workflow) printed a one-line stderr notice and **compared anyway** (the tolerance
|
|
24
|
+
added in #200). The same-environment guard can't be enforced without a manifest, so
|
|
25
|
+
captures from different browser builds or platforms could diff as false changes. For
|
|
26
|
+
**v4** that tolerance is removed: a side that ships maps with no manifest now fails
|
|
27
|
+
loudly with exit `2` (usage/capture error), naming the bare side(s) and the remedy —
|
|
28
|
+
re-capture with current StyleProof; maps without a manifest are unsupported. A dir
|
|
29
|
+
with _no maps at all_ is unchanged: it is "no baseline yet", still the first-adoption
|
|
30
|
+
review path (exit `3`), not a bare bundle. **Migration:** re-capture both sides —
|
|
31
|
+
`styleproof-map` for spec-driven surfaces, or `styleproof-capture` for a one-shot
|
|
32
|
+
design diff; both now write a `styleproof-manifest.json` into their output dir
|
|
33
|
+
(`styleproof-capture` previously wrote none, which would have made the design-match
|
|
34
|
+
flow fail under this change — it now stamps one, degrading the git SHA/dirty fields
|
|
35
|
+
gracefully when run outside a git repo).
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **BREAKING: `dataResidue` now defaults to `'gate'` instead of `'warn'`.** A
|
|
40
|
+
data-boundary request (`replayUrl`, default `**/api/**`) that fails during a
|
|
41
|
+
spec-driven capture means the endpoint's _fallback_ branch shipped as the certified
|
|
42
|
+
state — its response-driven states were never captured. Warn-only was the
|
|
43
|
+
backwards-compatible launch choice, not the correct one; the default is now to BLOCK.
|
|
44
|
+
`'warn'` remains fully supported as the explicit opt-out (record + warn without
|
|
45
|
+
gating); the acknowledgement ledger and stale-acknowledgement rot protection are
|
|
46
|
+
unchanged. **Migration:** if a capture now fails on a data endpoint you expect to be
|
|
47
|
+
down, either acknowledge the intentional failures in `styleproof.data-residue.json`
|
|
48
|
+
(`{"<surface·endpoint>": "why"}`), or set `dataResidue: 'warn'` in the capture spec to
|
|
49
|
+
restore the previous non-gating behaviour. A capture with no failing data request is
|
|
50
|
+
unaffected. (#205)
|
|
51
|
+
|
|
52
|
+
- **BREAKING: `blocking` now defaults to `true`.** In review-gate mode
|
|
53
|
+
(`require-approval: true`), an **unapproved** visual change now **fails the
|
|
54
|
+
report job** (red ✗) out of the box, so the check blocks a merge even on a repo
|
|
55
|
+
without a branch-protection rule requiring the `StyleProof` status (which needs
|
|
56
|
+
GitHub Pro or a public repo). Previously the default was `false` — advisory-only,
|
|
57
|
+
where only the commit status went red. The approve→re-run flow is unchanged: tick
|
|
58
|
+
**Approve all changes**, re-run the job, and the re-run sees the sign-off and
|
|
59
|
+
passes. Certify mode (`fail-on-diff: true`) is unaffected. **Migration:** to keep
|
|
60
|
+
the old advisory-only behaviour, set `"blocking": false` in
|
|
61
|
+
`styleproof.config.json` at your repo root.
|
|
62
|
+
- **Pre-push guidance no longer commits maps to the PR branch** (docs and repo
|
|
63
|
+
hygiene only; no change to the published package, CLI, or Action). The
|
|
64
|
+
pre-push recipe previously ended with `git add stylemaps` + a map commit on
|
|
65
|
+
the branch — so maps appeared as changed files in every PR, and because all
|
|
66
|
+
PRs wrote the same `stylemaps/` paths, each merge forced every other open PR
|
|
67
|
+
to rebase. The recipe now captures and publishes to the SHA-keyed
|
|
68
|
+
`styleproof-maps` store branch (what `styleproof-map` already does outside
|
|
69
|
+
CI) and never touches the PR branch; `stylemaps/` is gitignored as a
|
|
70
|
+
guardrail, and the README states the maps-never-in-PR rule explicitly.
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- **Data-residue guard — a capture that embeds an unprovoked data-fault state now
|
|
75
|
+
says so.** During a spec-driven capture, any request matching the data boundary
|
|
76
|
+
(`replayUrl`, default `**/api/**`) that FAILS — a network error, or a 4xx/5xx —
|
|
77
|
+
means the captured state rendered that endpoint's _fallback_ branch, so the states
|
|
78
|
+
its real responses would drive are uncaptured and unproven (the failure mode
|
|
79
|
+
documented in #202). StyleProof now names each such failure on stderr at capture
|
|
80
|
+
time (what failed, what it means, what to do: fixture it via `page.route`/
|
|
81
|
+
`liveStates`, or acknowledge it), records it on the capture (`StyleMap.dataResidue`),
|
|
82
|
+
and surfaces it in `styleproof-diff` and the report's certification block. **Gate by
|
|
83
|
+
default:** an _unacknowledged_ failing endpoint blocks the diff (exit 1); acknowledge
|
|
84
|
+
intentional ones in `styleproof.data-residue.json` (`key → reason`), and a stale
|
|
85
|
+
acknowledgement (the endpoint no longer fails) also fails so the ledger can't rot — the
|
|
86
|
+
same discipline as `exclude` and the inventory guard. Set `dataResidue: 'warn'` to opt
|
|
87
|
+
down to record-and-warn without gating. A 2xx endpoint that merely wasn't fixtured is
|
|
88
|
+
**never** flagged (recording mode legitimately records live responses). `--json` gains
|
|
89
|
+
an additive optional `dataResidue` field. A capture with no failing data request is
|
|
90
|
+
byte-identical whichever mode you run. Fixes #205.
|
|
91
|
+
- **`styleproof-init` now installs the pre-push publish hook by default.** The
|
|
92
|
+
capture-locally/publish-to-store flow is the out-of-the-box path, not an
|
|
93
|
+
opt-in recipe: init scaffolds a `pre-push` hook (into `.husky/` when present,
|
|
94
|
+
else `.githooks/` with a one-line activation hint) that runs `styleproof-map`
|
|
95
|
+
— capture this commit, publish the bundle to the SHA-keyed `styleproof-maps`
|
|
96
|
+
branch — plus an advisory `styleproof-diff`, so CI restores by SHA and stays
|
|
97
|
+
report-only. `STYLEPROOF_SKIP_CAPTURE=1 git push` skips a push that can't
|
|
98
|
+
affect render. Never overwrites an existing hook; maps never get committed
|
|
99
|
+
to the PR branch.
|
|
100
|
+
- **`styleproof-init` now installs the approval workflow.** The generated report
|
|
101
|
+
workflow runs with `require-approval: true`, but the `issue_comment` handler
|
|
102
|
+
that flips the `StyleProof` status when a reviewer ticks **Approve all changes**
|
|
103
|
+
previously had to be copied from `example/` by hand — leaving the review gate
|
|
104
|
+
inert until someone did. `styleproof-init` now scaffolds
|
|
105
|
+
`.github/workflows/styleproof-approve.yml` alongside the report workflow
|
|
106
|
+
(copied verbatim from the packaged example, never overwriting an existing file),
|
|
107
|
+
so the gate is complete out of the box. It activates once the init PR merges,
|
|
108
|
+
since GitHub runs `issue_comment` workflows only from the default branch.
|
|
109
|
+
- **Enforced quality gates and an agent context layer** (repository tooling only;
|
|
110
|
+
no change to the published package, CLI, or Action). A `commit-msg` commitlint
|
|
111
|
+
hook and PR-title/body validation enforce Conventional Commits; gitleaks
|
|
112
|
+
(staged-diff hook + full-history CI, fail-closed), CodeQL, and
|
|
113
|
+
`npm audit --audit-level=high` add secret/SAST/dependency scanning; a machine
|
|
114
|
+
`pull_request` check validates the PR template shape. `AGENTS.md` is now the
|
|
115
|
+
tool-agnostic source of truth (previously a symlink to `CLAUDE.md`, now a thin
|
|
116
|
+
vendor adapter), with `.agents/project/` documenting architecture, conventions,
|
|
117
|
+
tech stack, glossary, the gate matrix, PR quality, and the Definition of Done
|
|
118
|
+
(moved from `.agents/DEFINITION_OF_DONE.md`). Adds `.agents/decisions/` ADRs, a
|
|
119
|
+
root `TODO.md`, and a `.claude/` PreToolUse hook that blocks `--no-verify`.
|
|
120
|
+
|
|
121
|
+
### Docs
|
|
122
|
+
|
|
123
|
+
- **README catches up with the shipped gates.** A new _What a green certifies_
|
|
124
|
+
section surfaces the coverage, determinism, and inventory verdicts (3.9–3.14)
|
|
125
|
+
that previously lived only in the CLI reference bullet, linking
|
|
126
|
+
`docs/what-it-catches.md` and `docs/inventory-guard.md`; `styleproof-capture`
|
|
127
|
+
joins the CLI reference (with `--until-covered`); the policy table gains
|
|
128
|
+
`gateInventoryRemovals`; and the layout-equivalent-margin wording reflects the
|
|
129
|
+
one-sided-imbalance fix below. The repo's Claude Code skills
|
|
130
|
+
(`.claude/skills/styleproof*`) are fact-checked against the current CLI/API
|
|
131
|
+
surface: dead cross-references removed; the gate-contract exit codes, crawl
|
|
132
|
+
`expected` guard, browser-build compatibility key, and ledger verdicts added.
|
|
133
|
+
|
|
134
|
+
### Fixed
|
|
135
|
+
|
|
136
|
+
- **A two-directory `styleproof-diff`/`styleproof-report` no longer skips the
|
|
137
|
+
same-environment guard in silence.** The guard (`assertCompatibleMapDirs`) compares
|
|
138
|
+
platform/arch/node/Playwright/browser-build across both maps, but no-ops when either
|
|
139
|
+
side carries no `styleproof-manifest.json` — so a committed-map workflow that ships
|
|
140
|
+
maps but no manifest (exactly the flow most likely to compare captures across
|
|
141
|
+
machines) got zero protection with nothing said. Both CLIs now print a one-line
|
|
142
|
+
notice to stderr naming the bare side(s) — `before`, `after`, or `both` — pointing
|
|
143
|
+
at `styleproof-map` to record a manifest, then compare anyway. It is a notice, not a
|
|
144
|
+
failure: **exit codes are byte-identical** (plenty of legitimate manifest-less flows
|
|
145
|
+
exist, e.g. `styleproof-capture` one-shots), and a pair where both sides carry a
|
|
146
|
+
manifest behaves exactly as before, silently. `--json` is unchanged.
|
|
147
|
+
|
|
148
|
+
## [3.21.0] - 2026-07-07
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- **Shared-chrome tier in the report and the `styleproof-diff` CLI.** When one
|
|
153
|
+
change rides the frame every view draws — a persistent nav rail, header, or
|
|
154
|
+
footer that moved on every surface that renders it — it is promoted to a single
|
|
155
|
+
"🧱 Global chrome change" callout at the top, with the detail folded beneath,
|
|
156
|
+
instead of repeating across a long surface list on several entries. The reviewer
|
|
157
|
+
reads "the nav changed everywhere" once. The threshold is **structural, not a
|
|
158
|
+
tunable knob**: an element path is chrome only when it is hosted on more than one
|
|
159
|
+
surface base and changed on _every_ base that hosts it (full coverage of its
|
|
160
|
+
hosting surfaces). A change on merely some surfaces, or a view's own content
|
|
161
|
+
change entangled with the frame change, is never promoted — the view-specific
|
|
162
|
+
detail always stays visible. Purely presentational: grouping keys, findings,
|
|
163
|
+
counts, exit codes, and `--json` are unchanged.
|
|
164
|
+
|
|
165
|
+
### Changed
|
|
166
|
+
|
|
167
|
+
- **`styleproof-diff` human output now reuses the report's grouping.** One real
|
|
168
|
+
change no longer prints once per surface with its derived-longhand echo: the CLI
|
|
169
|
+
groups surfaces that changed identically into one finding (with the per-surface
|
|
170
|
+
count on the header line), summarises longhands into shorthands, and folds the
|
|
171
|
+
size/position-derived longhands (`transform-origin`, `width`/`height`, cascaded
|
|
172
|
+
ancestor heights…) behind a `(+N derived longhands)` count. A one-view button
|
|
173
|
+
restyle at one width that used to fill dozens of raw lines now reads as a single
|
|
174
|
+
grouped finding. `--json` stays the complete, byte-stable machine contract (every
|
|
175
|
+
surface, every raw longhand); exit codes are unchanged.
|
|
176
|
+
|
|
177
|
+
### Fixed
|
|
178
|
+
|
|
179
|
+
- **The report's certification block no longer contradicts the diff on inventory
|
|
180
|
+
additions.** For the same capture pair, `styleproof-diff` correctly prints a
|
|
181
|
+
navigable addition (additive, non-gating), but `styleproof-report`'s certification
|
|
182
|
+
block still read `Inventory — ✓ navigable set unchanged` — telling a reviewer the
|
|
183
|
+
navigable set didn't change when it did. The inventory line now echoes additions as
|
|
184
|
+
an informational, still-✓-class clause (`✓ N navigable affordance(s) added: <keys>
|
|
185
|
+
(additions don't gate)`), with the same truncation and key-escaping discipline as
|
|
186
|
+
the removals line. Removals still drive the ⚠/✗ gate semantics; additions are
|
|
187
|
+
appended. The diff and the report can no longer disagree about the navigable delta.
|
|
188
|
+
- **The unit suite no longer flakes on spawned-CLI tests (test-infra only, no
|
|
189
|
+
consumer-visible change).** The package-smoke test packed the live checkout with
|
|
190
|
+
`npm pack`, which runs the `prepare` lifecycle (`tsc`) even under `--ignore-scripts`.
|
|
191
|
+
`tsc` truncates each `dist/*.js` to zero bytes before rewriting it, so a CLI spawned
|
|
192
|
+
by a _different_ test running concurrently under `node --test` could read a
|
|
193
|
+
half-written `dist` module and die with a static ESM link error
|
|
194
|
+
(`does not provide an export named …`) — surfacing as an "impossible" exit code (a
|
|
195
|
+
flag-rejection test that pins exit `2` seeing exit `1`, or a spawned bin printing a
|
|
196
|
+
missing-export `SyntaxError`). The smoke test now packs a staged copy of the package
|
|
197
|
+
whose manifest carries no lifecycle scripts, so pack can never rebuild — the shared
|
|
198
|
+
`dist` is never mutated mid-suite. Same coverage (the packed tarball is still
|
|
199
|
+
installed and its API + every bin's `--help` exercised); the packed artifact is
|
|
200
|
+
identical.
|
|
201
|
+
|
|
10
202
|
## [3.20.0] - 2026-07-07
|
|
11
203
|
|
|
12
204
|
### Fixed
|