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 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