Skip to content

Slice B: run the test suite on every pull request - #207

Merged
vicmaster merged 3 commits into
masterfrom
ci-slice-b
Sep 2, 2026
Merged

Slice B: run the test suite on every pull request#207
vicmaster merged 3 commits into
masterfrom
ci-slice-b

Conversation

@vicmaster

@vicmastervicmaster commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Second and final slice from docs/specs/CI-SPEC.md. Slice A gave the suite a runner and got it green; this wires it to GitHub Actions.

The workflow

Two jobs, split by cost rather than by kind.

The fast job installs, builds, and runs the Node-only tier — 67 tests, about two minutes locally. It sets PUPPETEER_SKIP_DOWNLOAD because it never launches a browser and Chrome is roughly 150MB of an otherwise quick install. It runs on a Node 22 and 24 matrix: 22 because that is the lower bound the new engines field claims, so the claim is verified by the pipeline instead of asserted in a file nobody checks, and 24 because it is nearest to what development actually runs on.

The browser job runs the full tier on Node 24 only. Doubling a Chrome download to cover a second Node version buys very little. Puppeteer's browser is cached against the lockfile hash, so only a Puppeteer bump pays for the download again.

npm run build serves as the type check. It is the same compile the published package already depends on, so adding a separate lint step would cost time without covering anything new.

Two things worth reviewing

No secrets are required. Slice A verified that all six tests which reach the network or want an LLM API key skip cleanly when no key is present, and that a cold FRAMESMITH_HOME does not break the Node-only font tests. That is exactly the state a fresh runner is in, which is why this works on pull requests from forks as well as your own branches.

The Node 22 leg is the one genuine unknown. There is only one Node installed on the development machine, so there was no way to test the lower bound locally — the matrix leg on this pull request is the first real check of it. If 22 fails, the honest fix is to raise engines to match what actually works rather than to quietly drop the matrix leg.

Not included, on purpose

Branch protection. The checks should run green for a while before they are allowed to block a merge, and turning it on is a one-click change once you trust them. Also still out of scope, as the spec records: a test framework, release automation, and coverage measurement.

After this merges

The badge in the README starts resolving, and master gains its first automated verification. Worth watching the first few runs for flakiness in the browser job specifically — Chrome on a CI runner is the part most likely to need a tweak, though --no-sandbox is already passed at launch, which is the usual culprit.


What the first runs found

The pipeline paid for itself before it merged. Both Node legs passed on the first run, so engines: ">=22" is verified rather than asserted. The browser job failed twice — not on environment, but on two real defects that this machine structurally cannot reproduce.

Both are the same shape: a scaffold element missing the minWidth: 0 and ellipsis hardening that Phase 29 slice C added everywhere else, so a hostile label escapes its box instead of truncating by design. Both passed that sweep because macOS font metrics are narrower than Linux's and the overflow never quite happened here.

The first was the auth submit button — the one button in the library not built from the shared button() helper. Rebuilding it from the helper keeps every property it had and adds the three it lacked.

The second was the data-table role, status and amount cells. Rather than fix the single column the failure named, I audited the library for the pattern: text inside a fixed-width horizontal cell where it cannot wrap and has no designed truncation. Exactly nine hits, all in that one row builder, all now fixed, and the audit comes back empty. The audit was kept deliberately narrow — a broader version returns 113 hits, but those are headlines and body copy that wrap correctly, and truncating them would make the library worse.

Final run: all three jobs green. The Node-only jobs finish in about 75 seconds, the browser job in about three minutes.

Adds .github/workflows/ci.yml with two jobs, split by cost.
The fast job installs, builds, and runs the Node-only tier. It sets
PUPPETEER_SKIP_DOWNLOAD because it never launches a browser and Chrome is
~150MB of the install. It runs on a Node 22/24 matrix: 22 because that is what
the new `engines` field claims, so the claim is verified rather than asserted,
and 24 because it is closest to what development runs on.
The browser job runs the full tier on Node 24 only — doubling the Chrome
download to cover a second Node version is not worth it. Puppeteer's Chrome is
cached on the lockfile hash, so only a Puppeteer bump pays the download again.
`npm run build` is the type check. It is the same compile the published package
depends on, so a separate lint step would add time without adding coverage.
No secrets are required: the tests that would use an LLM API key skip when one
is absent (verified in slice A), so this works on pull requests from forks.
Also adds a CI badge to the README. Branch protection is deliberately not part
of this change — the checks should earn trust before they can block a merge.
The first CI run failed one test: the auth scaffold's submit button clipped
its label under the long-text perturbation, on Linux only.
It was the one button in the library not built from the shared `button()`
helper. Hand-rolled, it missed the minWidth: 0, overflow: hidden and
textOverflow: ellipsis that every other button gets — the hardening Phase 29
slice C added precisely so hostile labels truncate by design instead of
escaping their box.
It passed the Phase 29 scaffold sweep because macOS font metrics left just
enough room. Linux fonts are wider and it overflowed. Building it from
`button()` keeps every property it had (name, full width, accent fill, the
same padding and radius) and adds the three it was missing.
Verified locally: npx tsx test-scaffold-system.ts — all structures pass,
including page/auth stress CLEAN. CI verifies the Linux side.
Second Linux-only stress failure the pipeline caught. Same shape as the auth
button: the identity cell in the data-table row has carried minWidth: 0 and an
ellipsis label since Phase 29, and the three columns beside it never got it.
Rather than fix the one column CI named, I audited the library for the pattern
— text inside a horizontal frame with a fixed or percentage width, where it
cannot wrap out of trouble and has no designed truncation. Exactly nine hits,
all of them these three cells across the three sample rows. Every one is now
hardened and the audit comes back empty.
Note the audit was deliberately narrow. A broader sweep (any text under any
width-constrained ancestor) returns 113 hits, but almost all are headlines and
body copy that wrap correctly; adding ellipsis there would truncate prose that
is currently fine.
Verified locally: test-scaffold-system all pass, test-component-structures
28/28.
@vicmaster
vicmaster merged commit 3a6dea1 into masterSep 2, 2026
3 checks passed
@vicmaster
vicmaster deleted the ci-slice-b branch September 2, 2026 14:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vicmaster