Skip to content

docs(web): record that the OG image does not go live with the deploy - #43

Closed
MatheusKindrazki wants to merge 3 commits into
mainfrom
chore/og-image-docs-and-email-runbook
Closed

MatheusKindrazki wants to merge 3 commits into
mainfrom
chore/og-image-docs-and-email-runbook

Conversation

@MatheusKindrazki

Copy link
Copy Markdown
Owner

Caught while verifying the #42 deploy, and worth writing down precisely because it looks exactly like a flaky CDN and is not one.

Work-Control-ID: 01a01008-16a5-7456-afa3-819c024716a7

What happened

Origin (fastshared-web.pages.dev) ✅ new card immediately — sha256 matched local, saturation 0.157, #0f0f12 at 85.3%
Apex (fastsha.red) ❌ old card — cf-cache-status: HIT, age: 68244, old content-length

Nothing was wrong with the deploy. /og-image.png is listed in APP_PATH_PREFIXES (backend/src/index.ts), so routeRequest() does not proxy it to Pages — the Worker serves it itself from backend/src/routes/assetsPublic.ts, out of caches.default with Cache-Control: public, max-age=86400, immutable.

That cache is deliberate; the code says why: it keeps Slack/iMessage/Discord unfurlers off the Pages origin on every scrape. The consequence is that a regenerated card is invisible at the apex for up to 24 hours per edge, and immutable tells scrapers not to revalidate, so anything that unfurls during the window keeps the old card for longer still.

What this adds

The README now carries the two commands to compare origin against apex, says to purge the URL in Cloudflare and then re-scrape in the platform's own validator (the unfurlers cache separately from Cloudflare), and brand/og-image.sh prints the same warning right after it installs — which is where someone will be standing when they need it.

It also records the underlying weakness rather than just the workaround: the cache key is ${SHORT_LINK_HOST}${pathname}, with no content or version component, so every future OG change repeats this window. Three fixes are named — shorten CACHE_MAX_AGE_SECONDS for this one asset, key the cache on a build id, or add a purge step to web-deploy.yml, which already holds a CLOUDFLARE_API_TOKEN. The caveat is recorded too: whether that token carries cache-purge scope has not been checked, so nobody assumes a purge step would just work.

Docs only — no behaviour change. The purge itself needs dashboard access.

🤖 Generated with Claude Code

MatheusKindrazki and others added 3 commits August 17, 2026 11:11
The old og-image.png was the pre-redesign purple identity: a gradient wash with
no solid ground, a wordmark and nothing else. It had drifted four months behind
the site, and the reason it could is that it was a loose PNG with no source —
nothing in a diff ever showed it disagreeing with the palette.

It also became urgent rather than cosmetic. Until #39 the file was unreachable
(the OG URL named a host with no DNS) and until #40 the CTAs went to TestFlight,
so nobody saw the card. Both are fixed, which means this image is now what
appears when the link is shared.

Measured, before and after:

                  lum      std      sat    dominant ground
  before        37.99    35.99    0.584    #130a2c at  8.6%
  after         27.09    41.43    0.157    #0f0f12 at 85.3%

The card is now built from the same tokens and the same typefaces as the site —
Bricolage Grotesque with the site's 'ss02','cv11','ss01' alternates and the opsz
axis, JetBrains Mono for labels — so it reads as the same product rather than
something adjacent to it. It carries the tagline (the old one carried no message
at all) and the hero's transfer manifest as product proof, with violet-hot used
once, on the 410 Gone state: ephemerality shown as a data state instead of
claimed as an adjective.

Committed as source, not just output. brand/og-image.html is the card and
brand/og-image.sh renders it through headless Chrome, refusing to install
anything that is not 1200x630 or that misses the pixel targets. Chrome rather
than ImageMagick because the card is typographic: `magick` would reproduce the
layout but not the typeface or its axes.

One target is not a flat number, and the reasoning is in both files. HSV
saturation is a ratio, so it is ill-conditioned in deep shadow: the ground token
#0f0f12 is a 3/255 blue lift that HSV reports as 0.167 saturated, which makes the
skill's flat <= 0.15 unreachable while using the site's own colour — the only way
to pass it would be to invent a ground the site does not use, which is the drift
this rebuild exists to end. The gate asks the question the metric was reaching
for instead: is the mean at or below the ground's own saturation, meaning every
non-ground pixel is net-desaturating. It is (0.157 vs 0.167).

Also drops the `<-- TODO confirm inbox` marker that shipped visibly next to
press@fastsha.red on the press page. The address stays; the dev note leaking to
journalists does not. The underlying problem it was pointing at is real and
bigger than one address — see the email DNS runbook.

Work-Control-ID: 01a01008-16a5-7456-afa3-819c024716a7
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
web/.impeccable.md declares itself the single source of truth for design and is
loaded by every design skill before touching this site, so its errors are not
inert — they get built. Two were load-bearing: it said "Theme: dark" and
described the retired --ink #070318 ground with two radial glows, and its
out-of-scope list said light mode was decided against and a toggle should not be
proposed. The site's :root IS the light theme, it is the default, and the toggle
shipped. Corrected surgically rather than rewritten: the retired out-of-scope
line is kept visible and marked reversed, so nobody re-argues it from memory.

Measuring rather than assuming turned up five further stale facts, none of which
were in the brief. The motion sequence it documents (pa-frame-in, pa-arc-draw,
pa-plane-in, pa-particle) does not exist — what ships is pa-mark-in and
pa-ambient-in, and the Island cycles at 4s, not 2s. Its line references pointed
at rules that have since moved. --amber/--ember/--warning have zero measured
consumers, and the roles the file assigns them are violet-hot on the published
site. --milk survives only as an alias to --charcoal, and now inverts, which is
the easiest way to ship a light-on-light bug here.

Two defects are recorded as OPEN and explicitly not fixed: violet-hot as text on
the light ground is 2.97:1 across 10 audited occurrences plus every published
mailto link, and the contrast falloff after the hero (band 26.9, footer 29.5
against a floor of 40) is real. A third was found while checking the file's own
accessibility claim: --tin measures 2.43:1 light and 3.77:1 dark, failing the
body floor in BOTH poles, and it is used as text in the pricing feature table.
The focus-ring entry also claimed a 2px offset; the shipped offset is 4px, which
matters because at 4px the ring lands on the page ground, so the ratio governing
it is the same 2.97:1.

The press page published the retired palette as a swatch table — ink #070318 as
"ground", milk #fafaff as "typography", nightshade, violet-soft, warning. That is
the version a journalist quotes. Replaced with the shipped tokens, listing only
those with measured consumers in src/, and publishing both pole values for the
ones that invert.

One claim was walked back after measuring it: the Nav's .nav-on-dark rule does
hardcode the retired ink, but it is dead code, not a live use. The string occurs
once in all of src/ — its own selector — nothing adds the class (hero.ts toggles
nav-scrolled, a different rule), and it has zero applied occurrences in a built
dist/. The bytes still ship inside the inlined CSS; the rule never activates.

docs/ops/email-dns-setup.md is new and is the reason any of this surfaced.
fastsha.red has zero MX, zero SPF and zero DMARC — confirmed against 1.1.1.1,
8.8.8.8 and 9.9.9.9, which agree — so privacy@, support@, abuse@ and press@ do
not receive mail. That is a privacy policy with no route for a data-subject
request, an abuse address that cannot take an abuse report for a file-sharing
service, and the address App Review is given. The runbook records the measured
state with the commands to re-measure it, the exact records from Fastmail's own
documentation, the two Cloudflare traps (DKIM CNAMEs must be grey; the existing
google-site-verification TXT must survive the SPF change, and only one v=spf1
record may exist), and an order that never leaves an intermediate state worse
than today's.

It also states what it cannot promise: DNS alone does not restore delivery. The
MX records only hand mail to Fastmail — the domain still has to be verified there
and each address to exist as a real mailbox, and only that half is invisible to
dig. Delivery counts as restored when a test message lands, not when records
resolve.

Also drops the visible `<-- TODO confirm inbox` from the press page. The address
stays, per the owner's decision to keep the addresses and fix them at Fastmail.

Work-Control-ID: 01a01008-16a5-7456-afa3-819c024716a7
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Caught while verifying the #42 deploy. Pages served the new card immediately, but
the apex kept answering with the old one — and the cause is not a flaky CDN, it
is designed behaviour that is easy to misread.

/og-image.png is listed in APP_PATH_PREFIXES, so routeRequest() does not proxy it
to Pages; the Worker serves it from backend/src/routes/assetsPublic.ts out of
caches.default with `Cache-Control: public, max-age=86400, immutable`. That cache
exists on purpose — it keeps Slack/iMessage/Discord unfurlers off the Pages origin
on every scrape — but it means a regenerated card is invisible at the apex for up
to 24 hours per edge, and `immutable` tells scrapers not to revalidate, so anything
unfurling during the window holds the old card for longer still.

Measured at the time: origin sha256 matched the new file with saturation 0.157 and
#0f0f12 at 85.3%, while the apex returned cf-cache-status HIT, age 68244, and the
old content-length. Nothing was wrong with the deploy, which is exactly why this
needed writing down rather than retrying.

The README now carries the two commands to compare origin against apex, says to
purge the URL in Cloudflare and then re-scrape in the platform's own validator
(the unfurlers cache separately), and records the underlying weakness: the cache
key has no content or version component, so every future OG change repeats the
window. Three possible fixes are named, including that web-deploy.yml already
holds a CLOUDFLARE_API_TOKEN — with the caveat that its scope has not been
checked, so nobody assumes a purge step would work.

brand/og-image.sh now prints the same warning after it installs, because that is
where someone will be standing when they need it.

Work-Control-ID: 01a01008-16a5-7456-afa3-819c024716a7
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@MatheusKindrazki

Copy link
Copy Markdown
Owner Author

Fechando em favor de um PR limpo (#44): esta branch já havia sido squash-mergeada como #42, então re-propunha o conteúdo do #42 sobre um main que já o tinha, e ficou CONFLICTING. Erro meu — empurrei um commit de follow-up numa branch já mergeada em vez de sair do main novo. O mesmo commit, sozinho e sem conflito, está no #44.

Sign up for free to 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