v4.6.0
Added
- Yarn Berry support in the cold path.
styleproof-cipinned yarn 1 for any
yarn.lock; on a Yarn 2+ repo that either refuses (thepackageManager
field) or cannot parse the lockfile, so every base-miss run failed. A
.yarnrc.ymlor apackageManager: "yarn@2+"pin now routes installs
through corepack (corepack yarn install --immutable), which provisions the
repo's own pinned release. styleproof.config.jsonwarns on unknown keys. A typo'ddirtyallowor
cache_branchwas silently dropped — exactly the "config the user wrote must
never be silently dropped" failure the validator forbids. Unknown top-level
andaffectedkeys now produce a loud stderr warning listing the known keys
(a warning, not an error, so a newer release's key doesn't brick older CLIs
during version skew).styleproof-map --helpalso now documents that
dirtyAllowaccumulates across config + env + flags instead of being
overridden.
Fixed
-
styleproof-cireads project config from the HEAD checkout, and each side
resolves its own spec. Config was loaded before the flow pinned the
consumer to--head— in the generated workflow that pre-checkout tree is
the PR merge commit — so a head that moved the spec via
styleproof.config.jsonran with the stale path and failed exit 2 with the
cause invisible. Config now loads after the head checkout, and when--spec
is not explicit, base-side probes and captures resolve the spec from the
BASE checkout's own config while head-side ones use the head's — a
config-only spec move now works end to end. -
styleproof-cifailure taxonomy tightened. A required upload's
map-store/network fault exited 2 — the code reserved for usage errors — so
exit-code triage retried the wrong thing; store faults now exit 5 (the same
retryable class as restore faults) while consumer-state preconditions (dirty
tree, missing manifest) keep 2, since retrying those can never succeed. A
failedstyleproof-map --restorespawn (ENOENT) now prints the underlying
error instead of "fault (exit null), re-run the job". Worktree residue from
hard kills is reclaimed: every session start runsgit worktree prune, and
SIGINT/SIGTERM now dispose live worktrees before exiting. -
styleproof-affected --rootworks from a monorepo.git diffprints
repo-root-relative paths, which the CLI resolved against--rootand matched
against a package-relative graph — every changed file was unplaceable, so
every monorepo invocation degraded to'all'. The--rootprefix is now
stripped when resolving git paths into the graph (files outside the package
still fail closed), andstyleproof.config.json,--graph, and
--surfacesnow load relative to--rootinstead of the invoking cwd. -
REPORT_PUBLICATION_FAILEDnow names its actual failure domain. The
Action's terminal trust step treated any non-successpublish outcome —
including a merely skipped step — as a publication failure, and conversely a
failed PR-comment or commit-status delivery after a successful publish
reported the diff verdict as if the reviewer had seen it. The trust state now
distinguishes publishfailure(→REPORT_PUBLICATION_FAILED), publish
skipped/cancelled (→ the diff verdict,CERTIFICATION_FAILEDwhen absent),
and delivery failure after a successful publish (→
REPORT_PUBLICATION_FAILED). The verdict'sDEGRADED_BASELINEcheck also
acceptsbase-capture-failedcase-insensitively, matching the downstream
GitHub-expression gate. -
--tolerate-surface-failuresno longer promotes unledgered failures. A
nonzero Playwright exit with maps on disk but NOTHING in the surface-failure
ledger (a self-check, nondeterminism, or harness failure) used to publish as
a "partial baseline"; promotion now requires at least one ledgered surface
failure, and anything else keeps the failing exit. Ledger filenames also
gained a content digest so two surface keys that sanitize to the same
filename can no longer clobber each other's entries. -
styleproof-cidiscards base-capture debris instead of keeping it as a
baseline. With ledgered failures now exiting 0, a nonzero base capture
exit means an UNtolerated failure — any maps left on disk have no
publishable manifest, and keeping them reported real regressions as
approvable "new surfaces". The base dir is cleared and the run proceeds as a
bare baseline withbase-capture-failed=true(DEGRADED_BASELINE). -
styleproof-init --check/--upgradenow treat both generated workflows as
marker-owned. The CI and approval workflow templates carry an ownership
marker (like the pre-push hook already did), so a consumer-authored
workflow at the same path reportsunmanagedand is never overwritten by
--upgrade, instead of being flagged stale and clobbered. -
The generated pre-push hook no longer bakes the default spec path. With
the default spec, the hook execs barestyleproof-prepush, which resolves
the spec at run time (flag > env >styleproof.config.json> built-in) — so
moving the spec via config alone can't strand a stale baked--spec. A
non-default--diris still baked explicitly. -
Cold-base captures resolve Playwright from the base worktree's own install.
styleproof-cibuilt PATH once from the consumer head'snode_modules/.bin,
so the base capture ran the head's Playwright CLI against the worktree's
@playwright/testlibrary — a version-mixing failure ("did not expect test()
to be called here") on exactly the PRs that bump rendering dependencies,
silently degrading them to a bare baseline. Base-side spawns now prepend the
cold-base worktree's ownnode_modules/.bin; head-side spawns keep the
consumer's. -
Symbolic
--spec-refvalues resolve in the consumer checkout. Inside the
detached base worktreeHEADis--base(so--spec-ref HEADsilently
overlaid the base's own spec — a no-op defeating the flag) and
FETCH_HEAD/MERGE_HEADare per-worktree pseudo-refs that don't resolve
there at all. The ref is now resolved to a commit SHA in the consumer
checkout before any worktree is entered, and an unresolvable ref fails loudly
up front even when the base restore would have hit. -
A derived-only change now renders as reviewable evidence instead of failing
closed with none. When a surface's only differences are size/position
longhands (width,inline-size,transform-origin, offsets…) — typically
content-length drift widening a text span, or a pure sizing rule change — the
noise-cleaning strip removed every finding, so 4.5.3's consistency guard
correctly refused to claim "identical" but classified the run
CERTIFICATION_FAILEDwith nothing for the reviewer to look at. Cleaning now
keeps a surface's findings when stripping would silence a gating change
(cleanFindingsForDisplay), titles them "size/position only, no styling
property changed (often content-length drift…)", and the truth contract counts
them reviewable — so the verdict isVISUAL_APPROVAL_REQUIREDwith rendered
evidence. The raw-onlyCERTIFICATION_FAILEDbackstop remains for shapes
that truly cannot render (state-strip-only deltas). Reflow casualties next to
a real driver fold exactly as before; exit codes are unchanged. -
Cached-map diffs now see the baseline's tolerated-failure ledger. The
no-arg/<baseRef>forms read the base manifest AFTER cached-restore cleanup
had deleted the directory, sosurfaceCaptureFailuresalways read empty and a
PARTIAL_BASELINErun silently degraded into approvable greenfield "new
surfaces" (exit 3). The manifest is now read while the restored dirs exist,
matching every other ledger read. -
A surface captured only on base renders as
REMOVED surface 🗑️, not "new
surface 🆕". The report/summary previously framed a disappearing surface as
an addition with approve-forward guidance; removals now get their own heading,
summary line ("approving accepts the disappearance"), andisRemovedin
report.json. -
A fresh capture clears any stale surface-capture-failures ledger in the
reused output dir (same hazard class as the browser-build sidecar): a failure
recorded by a prior run no longer stamps a phantom "partial baseline" into a
healthy recapture's manifest. -
"gateInventoryRemovals": falsenow reaches the verdict. The opt-out
previously only skipped the job-fail step while the classification and commit
status stayed an unclearable red; removals now downgrade to ordinary
approval-required changes when opted out. -
styleproof-diffandstyleproof-reportreadstyleproof.config.json
(spec,cacheBranch,remote) like every other CLI — without it, a repo
whose config moved the spec or store branch computed a different compatibility
key on the compare side than the capture side, and the no-arg diff (including
the pre-push advisory diff) always missed.