I ship measured local-model posts with charts. Generative image tools garble numbers. So the fleet uses one matplotlib renderer under config/visuals/. Exact text. Fixed brand colors.
That still was not enough. A chart could pass "it rendered" and still look sloppy: numbers in corners, tiny labels, digits that never appear in the post. I raised the bar.
What failed before
The first defect class was layout. Step numbers sat in the top-left of a card while the label sat in the center. Peer cards did not share baselines. Long labels shrank below a readable floor.
The second class was honesty. A graphic could invent a comparison that no metrics file contained. Vision QA only checked whether the image looked clean, not whether the numbers were true.
The third class was publish mechanics. Committing a PNG from a feature branch worktree was easy to get wrong. Agents need a path that always targets main for the one asset file.
The gates
Every blog infographic now hits the same chain before an embed line is printed.
- Char budget. Budgets scale with step count. A short chain (n≤3) gets wider cards and longer labels. A four-step row stays tight (18/22). Five or more steps use a two-row grid so cards do not crush.
-
Layout then claims. Numbers, labels, and subs share peer baselines. Step indexes sit in orange pills with clearance so they never paint over the words. Digits in the graphic require
--claims <post or metrics>or publish exits 8. -
Vision log. The vision gate still fail-closes. Full stdout and stderr land under
Reports/Visuals/so a timeout is not a mystery.
Footer text stays at the same readable floor as body labels (7pt minimum). Titles sit on a dark header scrim so ambient textures cannot wash them out.
What I measure
The unit suite under config/visuals/ is at 29 tests as of 2026-07-13. Selftest renders every file in examples/ and specs/ (13 specs after this post). Geometry QA checks containment, min size, peer baselines, and peer line counts. Char lint runs before draw.
I also re-rendered the live vector-migration post asset earlier the same day after the first stack fix. New posts get the full gate set automatically when they use publish_blog_asset.py.
What I will not do
I will not put labels inside a diffusion model. Charts need crisp, correct English. Ambient textures stay under the diagram. Text stays on the matplotlib layer.
I will not ship a PNG that fails any gate. Fail closed means ship text-only or fix the spec. That is intentional.
When a graphic is worth it
Use a chart when the post has a process, a comparison, or a set of numbers. Write the short labels first. Point --claims at the draft. If the story needs long phrases, use fewer steps or a stats/flow template. Do not fight the 4-up width with paragraphs inside cards.
The contract lives in Prompts/Includes/blog-publish.md and config/visuals/README.md. Agents read it before inventing a one-off plot.
Accompanying prompt
What the prompt does: This prompt turns a draft post into a fail-closed infographic publish checklist with char budgets and claims.
Copy/paste this prompt:
Role:
You are a blog infographic publisher for exact-text charts.
Context:
Paste the draft post body, the intended template (steps/stats/flow/bars/compare), and any metrics file path.
Task:
1. Write a JSON spec that fits char budgets (4-up steps: label <=18, sub <=22).
2. List every digit in the graphic and where it appears in the draft or metrics.
3. Run publish with --claims and report geometry/vision outcomes.
Output:
- The JSON spec
- A digit provenance table
- PASS/FAIL for each gate with one-line reasons
Constraints:
- No generative text-in-image for labels
- Fail closed on missing claims when digits exist
- Keep labels short; do not invent metrics
Copy the block above.
I publish measured local-model work and the systems around it in The 5090 Reports. Join the list for the next artifact.
For related layout and local-model posts, see I rebuilt 5,383 embeddings after a dimension change and the num_ctx reload tax.
Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: https://bmdpat.com/newsletter?utm_source=blog_md&utm_medium=aeo&utm_campaign=blog-infographic-layout-qa-gate-2026
Originally published on bmdpat.com. I run a one-person AI agent company and write about what actually works.
Want these in your inbox? Subscribe to the newsletter - no spam, unsubscribe anytime.

Top comments (0)