Skip to content

docs: rebuild the social preview from the package, and fail CI when it drifts - #77

Merged
open-coder-ai merged 2 commits into
mainfrom
docs/social-preview
Aug 30, 2026
Merged

docs: rebuild the social preview from the package, and fail CI when it drifts#77
open-coder-ai merged 2 commits into
mainfrom
docs/social-preview

Conversation

@open-coder-ai

@open-coder-ai open-coder-ai commented Aug 30, 2026

Copy link
Copy Markdown
Owner

What

chock's social preview was a static image. It is now derived, and checked in CI.

The card shows real content in three columns — the 14 agents by name, the 8 enforcement
surfaces, the 8 everyday commands — plus the everyday loop as real commands and a footer of
counts. Every one of those facts is read at render time:

On the card Read from
agents chock.config.SURFACE_AGENTS
surfaces the Surface enum (and INSTALLED_SURFACES for the alt text)
commands chock.cli.EVERYDAY
version, dependency count, Python range pyproject.toml

Each count printed beside a list is len() of that list. Nothing on the card is hand-typed, so
nothing on it can be typed wrong.

The problem this actually solves

Derivation stops the card being wrong. It does not stop it being stale: add an agent, skip
the regenerate, and the committed PNG quietly claims the old number. The image is what a link
preview shows to someone who has not read the repo yet, so being quietly wrong there is worse
than in prose nobody has opened.

So the card is held to the same drift discipline as the other compiled artifacts. --check
re-derives it, compares, and fails naming what moved:

social-preview.svg is out of date
  now present: 15, some-new-agent
  no longer:   14

The card is derived from the repository, so this means the repository changed.
Regenerate it:  python docs/assets/gen_brand_assets.py

The comparison is on the SVG, never the PNG. The SVG is text produced only from repository
data, so it is byte-identical on any machine; a PNG additionally depends on the font installed on
the renderer, which CI does not have. Any drift in the facts reaches the SVG first, so checking
the SVG catches everything that matters without making CI's font a dependency of the build
passing.

This also removes the need to remember anything at release time. main is correct continuously,
so a release just picks up a card that is already right.

Definition of done

  • ruff check . → All checks passed; ruff format --check . → clean
  • No emitted or installed artifact changes, so chock sync --check, chock check --only verify, the registry scan and the acceptance suite have nothing to re-verify — no manifest,
    pack, lockfile, compiled artifact or matrix input is touched
  • No check added or extended, so there are no artifacts to migrate
  • No manifest touched, so no manifest version bump or changelog entry is due
  • pytest -q not re-run: nothing under src/ or tests/ is touched
  • Commits signed off

Verified directly:

  • python gen_brand_assets.py then --check → "social-preview.svg is current"
  • rendering twice produces byte-identical output
  • the new brand-assets CI job pins actions/checkout and actions/setup-python to the same
    SHAs the rest of this workflow uses, and pins cairosvg==2.9.0 — the repo's own
    pin-github-actions discipline applies to the job that checks the artwork too

Claims

  • No surface is described as enforcing more than it installs. The card lists surfaces by
    name from the Surface enum without grading them, and the alt text distinguishes all 8
    surfaces from the 3 that chock sync installs. INSTALLED_SURFACES, the coverage table
    and docs/enforcement-surfaces.md are untouched.

Two guards live in the renderer itself, because both caught real defects while this was being
built:

  • a row longer than its panel raises rather than running silently out into the next column
  • the left column asserts it clears the footer rule

cairosvg is asset tooling a maintainer runs by hand; it is not a dependency and
dependencies in pyproject.toml is unchanged.

Notes for the reviewer

  • Merging does not set the preview. GitHub's social preview is a Settings upload. After merge,
    upload docs/assets/social-preview.png under Settings → General → Social preview. The CI
    check is also the signal for when a re-upload is due.
  • The hand-drawn wheel-and-wedge logo.svg is untouched. The card's header reuses its shape
    without the spokes, which turn to mud at 38px.

Generated by Claude Code

Summary by CodeRabbit

  • Tests

    • Added automated Linux-based validation for generated social-preview assets.
    • Ensures generated SVG artwork remains consistent with the repository’s source data.
  • Chores

    • Standardized the asset verification environment with pinned dependencies and required rendering support.

…t drifts

chock's social preview was a static image. It is now derived: the agent list
comes from config.SURFACE_AGENTS, the surfaces from the Surface enum, the
commands from cli.EVERYDAY, and the version, dependency count and Python range
from pyproject.toml. Every count printed beside a list is len() of that list.
Nothing on the card is hand-typed, so nothing on it can be typed wrong.

It can still be stale, which is the real risk: add an agent, skip the
regenerate, and the committed image quietly claims the old number. The image is
what a link preview shows to someone who has not read the repo yet, so being
quietly wrong there is worse than in prose nobody has opened. So the card is now
held to the same drift discipline as the other compiled artifacts -- a
`--check` mode plus a CI job that re-derives it and fails with what moved:

    social-preview.svg is out of date
      now present: 15, some-new-agent
      no longer:   14

    Regenerate it:  python docs/assets/gen_brand_assets.py

The comparison is on the SVG, never the PNG. The SVG is text produced only from
repository data, so it is byte-identical on any machine; a PNG additionally
depends on the font installed on the renderer, which CI does not have. Facts
reach the SVG first, so checking it catches everything that matters without
making CI's font a dependency of the build passing.

Two guards live in the renderer itself, because both caught real defects while
this was being built: a row longer than its panel raises rather than running
silently into the next column, and the left column asserts it clears the footer
rule.

The hand-drawn wheel-and-wedge logo is untouched; the header reuses its shape
without the spokes, which turn to mud at 38px.

Signed-off-by: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e2f53e3e-7acd-416a-962b-a48f6ba1105c

📥 Commits

Reviewing files that changed from the base of the PR and between b1f16cc and a99e1cb.

⛔ Files ignored due to path filters (4)
  • docs/assets/brandkit.py is excluded by !docs/assets/**
  • docs/assets/gen_brand_assets.py is excluded by !docs/assets/**
  • docs/assets/social-preview.png is excluded by !**/*.png, !docs/assets/**
  • docs/assets/social-preview.svg is excluded by !**/*.svg, !docs/assets/**
📒 Files selected for processing (1)
  • .github/workflows/ci.yml

📝 Walkthrough

Walkthrough

The CI workflow adds a Linux-based brand-assets job. The job installs pinned dependencies and CairoSVG, then verifies the committed social-preview SVG with gen_brand_assets.py --check.

Changes

Brand asset validation

Layer / File(s) Summary
Brand asset check
.github/workflows/ci.yml
The workflow sets up Python 3.12, installs hashed dependencies and CairoSVG, and validates the committed social-preview SVG.

Estimated code review effort: 2 (Simple) | ~10 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/social-preview

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

test_repo_standards.py::test_no_file_exceeds_line_budget failed on the previous
commit: docs/assets/gen_brand_assets.py was 333 lines against a 300-line budget
whose stated remedy is "split by activity". The other 851 tests passed.

Split exactly as the rule asks, along the seam that was already there:

- brandkit.py (225 lines) is the drawing language -- palette, text, panels, the
  card layout, the write/check pair. It knows nothing about chock; it takes
  lists and labels and returns SVG.
- gen_brand_assets.py (124 lines) is what this repository has to say: the mark,
  the facts read from SURFACE_AGENTS, the Surface enum, cli.EVERYDAY and
  pyproject.toml, and the card built from them.

Two activities, two files, both well inside the budget. The rule was worth
following rather than exempting the file from: the halves genuinely belong
apart, and the drawing half is the part a sibling repo can be read against.

Verified: test_repo_standards.py passes, ruff check and format clean across the
repo, and `gen_brand_assets.py --check` still reports the committed card current
-- the split changed no output, only where the code lives.

Signed-off-by: Claude <noreply@anthropic.com>
@open-coder-ai
open-coder-ai marked this pull request as ready for review August 30, 2026 03:38
@open-coder-ai
open-coder-ai merged commit 562dd02 into main Aug 30, 2026
14 of 15 checks passed
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.

2 participants