Give every user-facing docs page its own search and social metadata - #508
Conversation
…ixes #482) `mkdocs-material` reuses `site_description` for any page without `description:` front matter, so all ~140 built pages shipped the same meta description and the sitemap presented mostly internal specs as the site's subject matter. Add a unique description to all 41 user-facing pages: getting started, the user guide, every tutorial, and every cookbook recipe. Enable the built-in `social` plugin, in the homepage's ink-and-caution-yellow palette, so a shared docs URL unfurls with that page's own title and summary rather than one site-wide sentence. Keep the design specs, test specs, and benchmark records published and searchable on the site, but drop them from the sitemap and mark them `noindex, follow` through theme overrides. The sitemap now lists 41 user-facing pages instead of ~140. Card rendering needs the `imaging` extra plus cairo and friends, so the docs group and the docs workflow install them, and the workflow caches the plugin's font and rendered cards between runs. A new test fails if a user-facing page is added without a description or reuses another page's wording. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0195Fkk63xics9zBvjFgYz8T
Social-card rendering adds an image toolchain and a cold-cache font download to the docs build, but the docs workflow only ran on pushes to main, so that build was first exercised on the deploy path. Run the same build job on pull requests and skip the artifact upload and deploy steps there. The concurrency group becomes per-ref so a pull-request build cannot cancel a deploy running for main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0195Fkk63xics9zBvjFgYz8T
|
What failed Why it is not this PR's
Root cause
Proposed patch def _drain_capture(self) -> None:
+ # The interval timer keeps firing while the app tears down, after the
+ # widget tree is gone; touching it then raises NoMatches from the
+ # refresh helpers. Nothing is left to draw at that point, so stop.
+ if not self.is_running:
+ return
capture = self._capture
if capture is None:
returnVerified locally: TUI suites ( I have not pushed this: it is production TUI code, unrelated to a docs-metadata change, and this repo tracks work through issues. I also could not re-run the failed job — the API returns Awaiting the maintainer's call on whether the fix rides along here or lands as its own change. Generated by Claude Code |
`unittest (python 3.13)` failed on this branch in test_capture_replacement_waits_for_previous_worker, from a race in the TUI's capture drain timer that this PR's diff does not touch. The fix is #510; it is ported here so this PR can reach green without waiting on that one to merge, and it no-ops once main carries it. Original commit message follows. --- `on_mount` starts a 0.1s interval that drains the capture queue and refreshes the status line. Textual does not stop interval timers synchronously on exit, so that drain could still run once the screen was unmounted, reaching `query_one("#bus-status", Static)` with nothing to match and raising NoMatches from a timer callback. Skip the drain once the app is shutting down, and look the widgets up through a helper that returns None when the node is absent, so the status line, the J1939 ribbon, and the alert log survive the same window regardless of when Textual clears `is_running`. The regression test drives the refresh helpers after the `run_test` context has exited; it raises NoMatches without this change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0195Fkk63xics9zBvjFgYz8T
|
Filed as #509 and fixed in #510. The same commit is ported here ( The regression test raises Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 195dd2c20e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if not self.is_running: | ||
| return |
There was a problem hiding this comment.
Reference #509 in this commit
This commit implements the TUI teardown-race fix that its new test and changelog identify as issue #509, but the commit message references only #482. The repository's hard acceptance gate requires every implementing or fixing commit to reference its relevant issue with closes, fixes, or refs, so add refs #509 or split this fix into a properly referenced commit.
AGENTS.md reference: AGENTS.md:L32-L36
Useful? React with 👍 / 👎.
Summary
mkdocs-materialreusessite_descriptionfor any page withoutdescription:front matter, so all ~140 built pages shipped the identical meta description ("CLI-first CAN security research toolkit documentation"), and the sitemap presented mostly internal specs as the site's subject matter. Zero pages carried front matter before this change.Closes #482
Changes
socialplugin, styled in the homepage's ink-and-caution-yellow palette. A shared docs URL now unfurls with that page's own title and summary. 143 cards render at build time.docs/design/,docs/tests/, anddocs/benchmarks/stay published and stay in the site's own search, but two theme overrides drop them from the sitemap (overrides/sitemap.xml) and mark themnoindex, follow(overrides/main.html). The docs sitemap went from ~140 entries, mostly internal, to exactly the 41 user-facing pages.mkdocs-material[imaging]; the docs workflow installs cairo and friends via apt and caches.cache/plugin/social, so the plugin's font download and rendered cards persist between runs.tests/test_docs_metadata.py) fails if a user-facing page is added without a description, exceeds 200 characters, or reuses another page's wording — and checks the two override files cover the same internal prefixes.benchmarks/is included in the internal set beyond the three items in the issue: it is the same kind of internal record, and it was the single remaining sitemap page still inheriting the site-wide description.Test plan
uv run pytest -q— 1637 passed, 1 skipped, 293 subtests passed (44 new)uv run ruff checkanduv run ruff format --check— cleanbash scripts/build_pages_site.sh— builds clean under--strictdescription,og:description, andog:image; a design spec carriesnoindex, followassets/images/social/cookbook/decode-spn-110.png) for correct title, description, and paletteuv sync --group docs --frozenresolves, and cairosvg/pillow importDocumentation
CHANGELOG.mdupdated under[Unreleased]docs/command_spec.mdupdated (if the command surface changed) — no command surface changedocs/event-schema.mdupdated (if the structured-output shape changed) — no schema changedocs/design/spec updated (EARS syntax) — none toucheddocs/tests/spec updated (Gherkin Given/When/Then) — none touchedAGENTS.md/docs/agents.mdupdated (if agent workflows changed) — no agent workflow changemkdocs.ymlnav updated (if any new docs pages were added) — no new pagesdocs/docs_site.mdgains "Page Metadata and Social Cards" and "Internal Pages" sections covering the front-matter requirement, the imaging dependencies, and the noindex/sitemap policy.Safety
Not applicable — no active-bus behaviour is introduced or changed.
Note for the reviewer
One thing I could not verify locally: on a cold cache the social plugin downloads its font from Google Fonts, which is blocked from this sandbox. To check the cards actually render I converted a Roboto woff2 from npm into the plugin's font cache and built against that — the card image above is from a real build. On GitHub runners the download works normally, and the new cache step keeps later builds off the network. If a future air-gapped build is wanted, the fix is to vendor the font into
.cache/plugin/social/fonts/Roboto/; I did not commit a font binary for that.🤖 Generated with Claude Code
https://claude.ai/code/session_0195Fkk63xics9zBvjFgYz8T
Generated by Claude Code