Loose ends: a social card that can be rebuilt, validate-before-write, and a current mutation record - #175
Merged
Merged
Conversation
The repo already documents ways a TEST reported green while proving nothing. This week produced a different and more expensive shape: briefs that told an agent something false with enough confidence to be taken on trust. Five in one week, all mine. The Nix floor is the clearest. A 44-second figure was handed over as fact and had already propagated into five files as the justification for design decisions; measured, it is 4.6-5.0 s and clean-vs-dirty is not the variable. It had been real once — during a crash loop fixed hours earlier. A wrong number stated once became load-bearing in four other files within a day. The others: git-lfs framed as that floor's fix (it makes `git status` truthful and changes no timing); a vacuity guard removed on the theory that a no-op preview lists nothing, which made the two assertions after it pass instantly against a page that never rendered; "the devcontainer can drive k3d", which mounts no Docker socket; and a liveness-probe consequence that stopped being true when the landing page learned to catch its own gRPC failures. Every one was caught because the brief said VERIFY THIS rather than transcribe it, and named what would count as disproof. The failure mode is not a lie — it is a true-once observation restated after its context moved, which is exactly the shape nobody re-checks. Hence the two habits recorded with it: attribute a number to the run that produced it, and when handing over a diagnosis, hand over the measurement that would falsify it.
…d it The premise needed correcting first: og-default.jpg was already a branded typographic card, not the stock photo I assumed. But dbbc8c8's own message says it was "rendered once with satori + resvg-js in a throwaway script, not a project dependency" — so the real gap was reproducibility, not design. The template and build script now live in the repo and print dimensions, size, alpha, headline fill and grid contrast on every run. Kept the established design language rather than restyling: static/social/ {banner,square,story}.png are the same design at three other sizes, and changing only the OG card would desync the set. The SDSC mark is placed and scaled, never restyled — it is a real organisation's identity. What changed is the words and one repetition. The mark carried a "Hackathons" lockup that the headline then repeated, so it is the bare mark now, as the app's own footer uses it. The subline was a feature list — "Propose projects, form teams, and build solutions together" — and is now an invitation: "Bring an idea, or join one. Then build it together." Set in sans, per the theme's rule that mono carries labels and sans carries sentences; an invitation in a typewriter face reads as a terminal banner. Event pages pass NO image to <Seo>, so this card is literally what appears when a hackathon link is shared — the title carries the event, so the image carries the platform. ## Two bugs found while building it My own headline check was VACUOUS: it measured 1056px, which is exactly 1200 − 144 of padding, because #headline is a block. It was asserting on the padding and would have passed in any font. It measures the text itself through a Range over the element's contents now (882px, 83% of the content box). And `oklch()` colour stops render as NOTHING inside repeating-linear-gradient in Playwright's Firefox — no error, no console message, and getComputedStyle happily reports the fully-resolved gradient. The grid was invisible in the first two renders and was found only by sampling pixels out of the PNG. The template uses each token's measured sRGB with the oklch source in a comment, and the renderer asserts the grid's 60px period IN THE FINISHED JPEG, because a wash can render and still be destroyed by the downscale or the quantiser. 1200×630 exactly, opaque, 56.8 KiB, identical md5 across runs. The lfs clean filter's pointer oid and size match the file's sha256, and the file starts ff d8 — a real content change, not a pointer mismatch. og:image resolves absolute at runtime, which matters because most clients ignore a relative one. Playwright and sharp are borrowed from the e2e skill's node_modules at render time rather than added to the frontend's package.json — no dependency or lockfile change for a build-time-only tool. Note the running :8081 server still serves the old card: build/ snapshots static/ at build time, and it was left alone deliberately because two servers have been running off it for hours and a concurrent agent depends on them. It needs a rebuild and restart to serve this.
…tion record `embed-run-report.mjs` had the same bug `build-quality-report.mjs` was fixed for in 226d201: it wrote `recipe-player.html` and only then ran its read-back, spec-count and close-tag checks. A bad splice corrupted the player and the validator reported it afterwards — the corrupt file existed either way. Same treatment, reusing that file's approach rather than inventing a second one: assemble in memory, run every check against the string, and only on a clean pass write a same-directory temp, fsync, rename (retrying EPERM — 9p, container trap 5), then re-read the destination and throw unless it matches. Note the invariant differs by file: the player asserts THREE literal close-script tags, the quality report asserts one. Both now say "checked first, then written" on success. ## The mutation record is current again `verify.json` held 23 EXACT / 11 GAP from 2026-08-13, two days behind a manifest that declares 37 EXACT / 1 GAP — so the quality report was printing a derived callout about its own stale input. Re-run: **38 run, 36 exact, 1 known gap, 0 untested properties, 1 other failure.** That confirms from a fresh run what the manifest had only claimed: the eleven gaps closed by the 28 backend specs are genuinely closed, and no property is untested. `EXIT=1` is the runner working — any non-EXACT verdict fails the run, which is what stops a quiet regression sliding past. The single other failure is the known shape rather than a new one: `capacity.oversell-by-one`'s witness is a declared-flaky concurrency spec, so it can come back MISMATCH when the flake fires rather than when anything is wrong. A second run was started to separate those two; the record here is the first run's, and the entry stays listed as flaky-witnessed rather than quietly excused. Journal empty and `components/` clean afterwards, verified — a mutation left applied and then committed is the worst thing this tooling can do, and it is why nothing was staged while the sweep was running.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three items left deliberately from #174, each recorded at the time rather than forgotten.
The social card, and a script that can rebuild it
The premise needed correcting first:
og-default.jpgwas already a branded typographic card, not the stock photo the task assumed. Butdbbc8c81's own message says it was "rendered once with satori + resvg-js in a throwaway script, not a project dependency" — so the real gap was reproducibility, not design.The template and renderer now live in
components/frontend/design/og/. The design language is unchanged (thestatic/social/set carries it at three other sizes and would otherwise desync); what changed is the mark no longer carrying a lockup the headline repeated, and a feature list becoming an invitation. Event pages pass no image to<Seo>, so this card is literally what appears when any hackathon link is shared.Two bugs found while building it:
#headlineis a block, so it asserted on the padding and would have passed in any font. It measures the text through aRangenow.oklch()colour stops render as nothing insiderepeating-linear-gradientin Playwright's Firefox — no error, no console message, andgetComputedStylereports the fully-resolved gradient. The grid was invisible in two renders, caught only by sampling pixels out of the PNG. The renderer now asserts the grid's 60px period in the finished JPEG, because a wash can render and still be destroyed by the downscale.1200×630, opaque, 56.8 KiB, identical md5 across runs,
og:imageabsolute at runtime, LFS pointer matching the file's sha256.Validate before writing
embed-run-report.mjshad the bugbuild-quality-report.mjswas fixed for in226d2016— it wrote the player and then checked it, so a bad splice corrupted the file and the validator reported it afterwards. Same treatment: assemble in memory, check the string, write via temp/fsync/rename only on a clean pass. The invariant differs per file (three close-script tags for the player, one for the report) and both are kept correct.A current mutation record
verify.jsonheld23 EXACT / 11 GAPfrom two days earlier, against a manifest declaring37 EXACT / 1 GAP— so the quality report was printing a derived callout about its own stale input.Re-run: 38 run, 36 exact, 1 known gap, 0 untested properties, 1 other failure. That confirms from a fresh run what the manifest had only claimed — the eleven gaps closed by the 28 backend specs are genuinely closed. The remaining failure is the known shape:
capacity.oversell-by-one's witness is a declared-flaky concurrency spec, so it can come back MISMATCH when the flake fires rather than when anything is wrong. Left listed as flaky-witnessed rather than quietly excused.Also: a lesson worth more than the fixes
.claude/CLAUDE.mdgains "Ways a HANDOVER was confidently wrong", next to the existing section on tests that passed while proving nothing — because it is the same disease in a different host.Five times in one week a brief asserted something false with enough confidence to be taken on trust: a 44-second Nix floor that did not exist (and had already propagated into five files as justification for design decisions), git-lfs framed as its fix, a vacuity guard removed on a wrong theory that made two neighbouring assertions pass instantly against a page that never rendered, "the devcontainer can drive k3d" when it mounts no Docker socket, and a liveness-probe consequence that stopped being true when the landing page learned to catch its own failures.
Each was caught because the brief said verify this rather than transcribe it. The failure mode is not a lie — it is a true-once observation restated after its context moved, which is exactly the shape nobody re-checks.
Verification
Generators both report "checked first, then written";
just check::formatclean at 0 changed; mutation journal empty andcomponents/clean after the sweep; player at 477 lines / 465 actions.Note the running
:8081server still serves the old card —build/snapshotsstatic/at build time, and it was left alone because two servers were running off it and the mutation sweep depended on them. A rebuild and restart picks it up.