feat: share cards, crawler routes, and an AEO brief - #8
Merged
Merged
Conversation
The board had no description, no share card, and nothing for crawlers — a link to it rendered as a bare URL and search or answer engines had to infer what the tool does from a JavaScript-rendered page. Adds to the head: description, canonical, OG and Twitter card metadata with absolute image URLs, theme-color for both schemes, icons, and JSON-LD describing the site and the application. Adds four routes: - /robots.txt points at the sitemap, and disallows /api/ (no prose to index) and ?ops, which is the same page plus operator telemetry and would read as duplicate content. The canonical link covers engines that ignore the query rule. - /sitemap.xml - /llms.txt, a plain-language brief for answer engines: what each status means, how aggregation and post accounting actually work, and the explicit limits — corroboration is not truth, and none of it is investment advice. - the share card, favicon, and touch icon, served from an allowlist so the handler never resolves a caller-supplied path, with a day-long cache while the board itself stays no-store. Also implements do_HEAD. Social scrapers HEAD an og:image before fetching it and the base handler answers 501 for any verb without a do_ method, which reads to them as a broken image. The share card is generated at 1200x630 in the board's own visual language. The icon is a rasterized F with the wordmark's detached caret. Tests cover every route, that share metadata is present and absolute (a relative og:image is the classic silent break — scrapers do not resolve it), that the JSON-LD parses, and that HEAD returns headers with no body. The HTTP server harness moved into a fixture that carries no tests of its own, so the two suites no longer re-run each other's cases. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
What
The board had no description, no share card, and nothing for crawlers. A link to it rendered as a bare URL, and search or answer engines had to infer what the tool does from a JavaScript-rendered page.
Head metadata
Description, canonical, OG and Twitter card metadata with absolute image URLs,
theme-colorfor both schemes, icons, and JSON-LD (WebSite+WebApplication) stating what FinTick does and how.The JSON-LD deliberately claims no more than the tool does — it describes an application that aggregates, extracts, and corroborates. No
NewsArticle, noDataset, nothing implying FinTick is a news publisher or a market-data provider.Routes
/robots.txt/api/(no prose to index) and?ops— the same page plus operator telemetry, which would read as duplicate content. The canonical link covers engines that ignore the query rule./sitemap.xmlchangefreq: hourly./llms.txt/og.png,/favicon.svg,/apple-touch-icon.pngno-store.llms.txtstates the method and the limits: what each status means, that aggregation is the dedup, that every post is preserved by URI, that social posts are stream signal and never corroboration — and that FinTick reports whether an event has been corroborated, not that it is true, and is not investment advice. Answer engines reward a stated method and explicit limits over marketing copy, and it is the honest framing regardless.Bug fixed: HEAD returned 501
Social scrapers HEAD an
og:imagebefore fetching it.BaseHTTPRequestHandleranswers 501 for any verb without ado_method, which reads to them as a broken image.do_HEADnow routes throughdo_GETand drops the body, keeping every header includingContent-Length.Assets
The share card is generated at 1200×630 in the board's own visual language — brand, lede, ticker strip, a breaking card showing
0 external sources · ahead of the wire, and the status pills. The icon is anFwith the wordmark's detached caret, rasterized deterministically so it has no build dependency.pyproject.tomlgainspackage-data; without it the assets are dropped from a built distribution and/og.png404s. Production runs from a git checkout so this is latent, not live.Testing
Seven new tests covering every route, asset content types and caching, that share metadata is present and absolute (a relative
og:imageis the classic silent break — scrapers do not resolve it), that the JSON-LD parses, that the sitemap is well-formed against the real namespace, and that HEAD returns headers with an empty body.The HTTP harness moved into a
ServedBoardFixturethat carries no tests of its own —DiscoverabilityTestspreviously subclassedDashboardHttpTestsand re-ran its entire suite.Verified against a live server: all 10 routes return expected status, content type, and cache headers; no console errors (the CSP admits the favicon); 145 passed locally, up from 138, with the same 13 pre-existing macOS-only failures before and after.
🤖 Generated with Claude Code