all repositories

russ/code code.fugl.dev

Merge PR #32: the site face and the /latest asks: seven cards on one branch (pr/latest-and-site-face)

merged by Russ T. Fugalopened by Claude Opus 5 (1M context)80 files+9,032 −163f0437ac30 merged here in total

code.fugl.dev commit activity: 247 commits from 2026-06-21 through 2026-08-12.

description

Seven kanban items, two threads that share a surface: the site face (#17, #7) and the /latest asks (#45, #46, #47, #48), with #35 riding along as a measured routing defect. Built by a team of agents against ~/.claude/plans/plan-out-implementation-of-dynamic-harp.md, then rebased onto main and re-verified.

bun run check is green on the rebased tree: 80 files, 1251 tests, oxlint --type-aware + typecheck + build --all clean.

What each card became

#35 — trailing slash. html_handling moves to drop-trailing-slash rather than the builders moving. Every internal link the site emits was costing a 307; the builders' slashless output is compared against literal paths in a dozen places (pages.ts's manifest, Layout.tsx's end-matched NavLinks, head.tsx's canonicalUrl) and every one stays correct by not being touched. Not yet verified live — the curl matrix below is owed after deploy.

#17 — the social face. OUTBOUND in components/Outbound.tsx, rendered in header and footer. Deliberately not in NAV: NAV entries are end-matched routes asserted to be paths the Worker will not redirect away, and an absolute URL to another host satisfies neither claim. The header set is hidden md:flex — one outbound link there once cost a 28px overflow at 390px — so the footer is where reachability lives, and the test asserts that rather than trusting the comment. The Bluesky mark is inline SVG on currentColor, because the CSP is img-src 'self' with no data:.

#46 — GFM markdown. remark-parse → remark-gfm → remark-rehype (allowDangerousHtml) → rehype-raw → rehype-sanitize → rehype-stringify, at build time. Rendered HTML rides on RenderedMerge, never on MergedPr, so it stays out of servedMerge()'s hand-written allowlist. A new Prose.tsx sibling to Viewer.tsx carries its own trust doc — Viewer's html is trusted because the owner generated it; a PR body is written by anyone with push access to refs/meta/prs. Markdown renders before the try around pierre, so a repo whose diff fails no longer silently loses its body too (kanban 0008).

#7 — generated OG cards. satori + @resvg/resvg-wasm, 1200×630 per repo plus a site default, in the site's own IBM Plex. Deterministic because satori outlines every glyph to <path> at layout time, so the SVG carries no font reference for resvg to resolve. sharp was rejected for the opposite property: its SVG text goes through librsvg's system-font path and reads different bytes on a different machine. SVG-only was rejected because X, Facebook and LinkedIn do not render SVG cards, so the unfurl would stay broken while every test passed.

#47 — contribution grids. LOG_FORMAT gains %cI, so the per-day series costs zero additional git invocations. Day boundaries are America/Denver, DST-aware, with the zone passed in and never read from the environment — the repo's first timezone handling. commitDays is required on RepoEntry, not optional: the ~13 fixture edits are the point, because a default at the seam is how PR #24 reinstated the exact defect it existed to fix.

#48 — private-PR publication. Tier 4, and the plan explicitly did not build it; built here on the user's instruction. Design C (signed publication bundle) with Design A as its strict prefix. See the caveat at the bottom — as shipped this is Design A wearing Design C's machinery.

Measurements

#45 bundle sizes — apps/web/dist/assets/index-<hash>.js, one chunk, all pages:

variantrawgzip
baseline (before this branch)1,103 B0.61 kB
shipped (adds diffs-interactive)2,595 B1.14 kB
+ @pierre/trees/web-components41,644 B7.68 kB
+ @pierre/diffs main entry (tree-shaken)+40 B—

The decision taken was "ship pierre's client bundle." All three asks landed without it, and that narrowing is deliberate rather than quiet. @pierre/trees/web-components costs +6.5 kB gzip and delivers zero folder collapse — its entire content is adoptDeclarativeShadowDom + ensureFileTreeStyles + scrollbar-gutter measurement, and ~39 kB of it is the tree's stylesheet already inlined in the SSR'd shadow root. Pierre's expand handler lives on the ./react path. Folder collapse is instead hand-rolled over the data-item-type, aria-expanded and data-item-parent-path attributes the tree already emits. Prerendered documents already have their shadow roots built by the HTML parser, so even the adoption that module does perform is redundant here.

#7 card sizes — default 44,514 B; russ/code 35,845 B; russ/ap-bio 43,276 B; fugl.dev 34,933 B; russ/ts-template 31,118 B. All 1200×630, IHDR parsed from a real emitted file. Installed footprint ~11.7 MB, no per-platform native binaries.

#47 palette — re-validated against both surfaces with the dataviz ordinal checks: light end 2.20:1 on #EFF1F4, dark end 2.42:1 on #1A1C20, monotone lightness, ΔL ≥ 0.06 between adjacent steps, single hue. The zero bucket is --border, outside the ramp, which is what keeps a zero-commit day distinguishable from both the surface and an absent day.

Findings worth reading

for-each-ref matched with wildmatch in pathname mode. refs/meta/publications/* never crosses /, so refs/meta/publications/org/widget — a ref anyone with push access to the publication repo can create — was invisible to the build entirely. Matched by literal prefix now; every ref in the namespace is seen and non-slugs are refused by name. Not looking and refusing produce the same published set, but only one of them says so.

Four guards on this branch were covered only incidentally, and mutation found every one. slugFromRef's namespace check was fully redundant with a later slug-mismatch check. The slug/ref agreement check was pinned in packages/forge but not at the seam where a slug becomes a path in expected. Suppressing the publication repo's own empty card was asserted nowhere. And publicationRepo was tested at both ends — parsing pins that only the literal true counts, the consumer is tested on a hand-built scan — while every onAdmit case ran with the flag absent, so false was the only value ever observed, which is also what a constant at that seam produces. In all four the code was correct and the evidence was decorative. Reading would not have found any of them.

A publication bundle's file list was sorted with localeCompare, and that sort feeds the signed bytes. Two reviewers on differently-configured machines could rebuild the same merge from the same immutable sha and get different bytes, so a signature made over one verifies against the other's rebuild as tampering. Now compareCodeUnits (main's 632f828, same reasoning one step earlier: localeCompare is not a total order — it returns 0 for unequal pairs and Array#sort then keeps arrival order). The pre-existing order-independence test could not catch it, because src/parse.ts and src/parse.test.ts sort identically under both comparators; the new case uses A.ts and a.ts, which ICU orders opposite to their code units.

A \0 written into a source file in this repo arrived as a raw NUL byte three times. The file becomes binary and grep silently refuses to search it — exiting 1 with no matches, which reads exactly like "not present". An empty grep result is not evidence of absence unless you know the file is text; file -b answers that in one call. Where a test genuinely needs a control character, build it with String.fromCharCode rather than an escape.

renderedCount stopped meaning what it said. Once a diff-failed merge still emits body HTML, a counter commented "repos that got a rendered diff" would have counted rendered prose as success — on precisely the run where pierre broke for every repo. Kept meaning diffs.

Contracts rewritten rather than falsified

when.ts said "nothing on this site adds a node after load". The grid appends a <td> per elapsed day, so that sentence no longer describes the bundle. The paragraph now names the three markers (time[data-when], [data-commit-grid], <file-tree-container>), states that a document carrying none wires up nothing, and re-anchors the modulePreload argument to the gating property the sentence was only ever a description of.

routes.ts's paragraph documenting the 307s as current behaviour, and vite.config.ts's modulePreload comment, were both rewritten against the code that shipped. The latter took three passes: it first described a dynamic import() that was never written, then invented a byte count for machinery that does not exist.

Verification by mutation

Every new guard was broken, watched go red, and restored. Recorded in the commits and the test files. The ones most worth re-running: removing rehype-sanitize (10 of 12 hostile-markdown cases red); removing rehype-raw (raw HTML is dropped rather than sanitized — indistinguishable from outside without the case that pins it); rendering a placeholder for a future grid day (zero-vs-absent); ignoring verifyCommit's result; dropping gpg.ssh.allowedSignersFile; and reverting the bundle file sort.

Still owed

  • The live curl -sI matrix for #35, over /about, /about/, /latest, /latest/russ/ap-bio, /latest/russ/ap-bio/ and /. This is a serving-layer change no test can observe, and the previous convention went stale precisely because a serving assumption was never re-checked. Expect 200 on the slashless forms and 307 on the slashed ones — the mirror of today.
  • A manual pass in vite preview at 390px and 1440px in both colour schemes. The fixture carries an unbreakable long path deliberately, because that width shipped a sideways scroll once.

The caveat on #48

As shipped this is Design A wearing Design C's machinery. The verification is real code and it runs on every build, but git config --get-regexp 'gpg|commit.gpgsign|user.signingkey' returns nothing at repo and global scope, and ssh-add -l reports no identities. Until a signing key exists that an unattended process cannot use, this is detection after the fact, not prevention. Nothing in the docs, the README or the code comments claims otherwise, and nothing should.

Two fidelity losses in the publication adapter are named in the code rather than hidden: a published review renders as a plain comment (buildRecord flattens comment and review events, and fixing it changes the signed schema), and commitDays is deliberately empty for a publication, because drawing a grid from a bundle's single date either implies the source repo did exactly that much that day or requires disclosing the working cadence of a repository nobody agreed to publish. Both belong with the productUrl follow-up.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

80 files changed

This view needs a browser with declarative shadow DOM: Chrome 111, Safari 16.4, or Firefox 123. Read the source instead.

This view needs a browser with declarative shadow DOM: Chrome 111, Safari 16.4, or Firefox 123. Read the source instead.

52 of 80 files shown — 28 past this page's size limit. Browse or clone the repository to read the whole merge.

clone

$ git clone https://git.fugl.dev/russ/codeanonymous, no account
$ git clone ssh://git.fugl.dev/russ/codeneeds the bastion ProxyCommand