Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packs/spec-driven-product/RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ code produces every actual, and the product ships on green.**
- **Regenerate, never hand-edit.** The gallery is derived output of a committed generator; fixing it
means fixing the source (or the generator) and regenerating — a hand-touched render lies about the
product until the next regeneration overwrites it.
- **The deterministic golden-image method this leans on is canon in the writing-tests skill** —
matching the render engine to the surface (a bit-exact rasterizer for inline-styled/SVG surfaces, a
headless browser for pages that use grid/vars/emoji/form-widgets), bundled fonts, capturing a
host-page surface with styles inlined, and a drift gate on the embedded gallery. The pack states the
*what* (approving the gallery is approving the product); the skill owns the *how*.

## 8. Ship automatically while `main` stays green

Expand Down
4 changes: 4 additions & 0 deletions skills/git-github-advanced/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Conflict size scales with how long a branch lives and how far it drifts from the

A GitHub API/UI (or any remote-side) merge does **not** advance your local `origin/main` — it stays at the pre-merge commit until you `git fetch`. Branching off `origin/main` immediately after a remote merge forks the pre-merge state, silently missing the just-merged work; symptoms surface later as a missing file or a failed `git mv` on the new branch. Fix: `git fetch origin main` before creating the branch.

## A conformance finding on history you didn't write may be a stale diff base — refresh before fixing

A Stop-hook or CI conformance check diffs your branch against `origin/main`. In a fresh cloud sandbox that ref can be **stale** — behind real `main` by whole merged PRs — so the check reads the wrong base and can flag findings on commits or code you never touched. Before acting on a finding you don't recognize, `git fetch origin <default-branch>` and re-run: a stale-base phantom disappears, and whatever survives against the current base is real — fix that. (The same stale ref bases new work on outdated product code, so fetch before building against `main`, too.)

## In a squash-merge repo, "commits ahead of main" does not mean "unmerged"

A squash-merge creates a new commit on `main` that the branch's own commits are unreachable from, so a branch whose work has already landed still shows ahead by N. **"Ahead by N" never alone means unmerged.** Determine real status by content, not raw count:
Expand Down
2 changes: 2 additions & 0 deletions skills/writing-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ Portable practices for writing tests you can actually trust — proving a test f
- When a snapshot/golden test fails because the output *legitimately* moved (the pixels or bytes changed for a real reason), don't quietly regenerate the baseline to go green — an unreviewed baseline change is an unreviewed behavior change. Surface the diff (committed **expected**, newly-rendered **actual**, highlighted **diff**) and get owner approval before re-baselining; until then keep the *reverted* baseline committed so the branch honestly shows the test red-pending — never commit the new baseline first.
- When a test asserts exact values extracted from a captured artifact (a cached page, a recorded response), record and commit the artifact *first*, then read the expected values off the committed file — don't hand-write the expectations from memory or a live view and hope they match. Guessing the value desyncs the test from the real fixture; reading it off the committed bytes can't.
- A test that maintains a committed artifact should regenerate it into the working tree deterministically (no timestamps, so an unchanged run yields no diff) and skip the write under CI — never shell out to git from a test. Commit the artifact through the normal review flow, like a snapshot.
- Render a UI *image* golden with the engine that matches the surface, and prefer the deterministic one. A surface that is inline-styled SVG, or flexbox-only markup authored for it, renders **bit-exact** through a headless rasterizer (e.g. satori → SVG, resvg → PNG) driven by the shipped code, using **bundled** fonts, never system fonts, and a pinned locale — demand a **zero-pixel** diff there. But that rasterizer has no CSS engine and draws no native widgets: a full shipped page using CSS **grid**, custom properties (`var()`), `@media`, **emoji**, or **form controls** (a range slider, radio, `<select>`) is beyond it — screenshot that with a **headless browser** instead, and allow a *small* diff tolerance (browser antialiasing varies across machines, so it isn't bit-exact). Match the engine to the surface; never reshape the product to fit the rasterizer. (A rasterized popup golden works only because the popup was authored flexbox-only — the moment a surface needs grid/vars/widgets, it needs a browser.) Since the browser goldens aren't gate-able bit-exact and a runner may lack the browser, let those cases **self-skip** where it's absent so the deterministic cases still gate.
- To image-golden a surface your code **injects into a host page** (a control mounted into a third-party toolbar), render it against a **committed capture of the real host DOM with its computed styles flattened inline** — the deterministic rasterizer reads only inline styles, and the host's own stylesheet is not yours to ship. Mount it with the **shipped injector** (so the golden proves the placement, not a hand-placed copy), and name the model's boundary honestly: substituted icon-font glyphs, an approximated host chrome (a captured sample is spec, not folklore — the origin lesson of a supported-targets matrix).

Loading