Repository navigation
docs(blog): lay PR blog drafts out for readers, result first - #1286
Merged
Merged
Conversation
The generated draft opened with a provenance disclaimer and a list of file paths. It now leads with the result and a one-line count of reported checks. The problem and the solution come next, then the changes and a "How we checked" table that keeps failed and not-run checks visible. The draft ends with what the post does not show and how it was made. The work report accepts two optional blog keys. blog.cast names a recording published on the site (term/<id>/session.cast). blog.reproduce lists 1-8 commands for readers to run, which the generator shows and never runs. Any other key is still refused. The blog-post skill gains "How a post reads", a short writing guide distilled from published guidance on engineering blogs. PR_BLOG_AUTOMATION.md points to it instead of copying it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot
added a commit
that referenced
this pull request
Oct 3, 2026
docs(blog): lay PR blog drafts out for readers, result first (#1286) The generated draft opened with a provenance disclaimer and a list of file paths. It now leads with the result and a one-line count of reported checks. The problem and the solution come next, then the changes and a "How we checked" table that keeps failed and not-run checks visible. The draft ends with what the post does not show and how it was made. The work report accepts two optional blog keys. blog.cast names a recording published on the site (term/<id>/session.cast). blog.reproduce lists 1-8 commands for readers to run, which the generator shows and never runs. Any other key is still refused. The blog-post skill gains "How a post reads", a short writing guide distilled from published guidance on engineering blogs. PR_BLOG_AUTOMATION.md points to it instead of copying it. Co-authored-by: Claude Opus 5.5 <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.
Summary
PR blog drafts used to open with a provenance disclaimer and a list of file paths. They now open with the result, the way readers actually read a technical post. The blog-post skill also gains a short, sourced writing guide.
Before: disclaimer → "Work report" → file list → "Context and reasoning" →
[status] Command: … Result: … Evidence: …bullets → limits.After: result → one-line check count (
Open PR. Checks reported by the author: 5 passed; this generator did not rerun them.) → The problem → How it works → See it run (optional) → What changed → How we checked (a table) → Try it yourself (optional) → What this does not show → How this post was made.Changes
scripts/pr_blog_report.pymake_post()follows the new order. Checks are atableblock (Check / Status / Result / Evidence), andfailedandnot_runchecks are shown next to passed ones. The provenance notice is now the last section.blog.castis optional and must matchterm/<id>/session.cast. It adds a "See it run" section and a "Terminal recording" receipt.blog.reproduceis optional: 1–8 commands, rendered as acodeblock. The generator never runs them.make_markdown()renders tables with every cell escaped. Reproduce commands become escaped list items, not a fence, so a command cannot close a fence.scripts/test_pr_blog_report.py: tests for the section order, the table (statuses, pipe escaping, check counts), the optional keys, and refusal of bad cast paths, empty or oversized reproduce lists and unknown keys..claude/skills/blog-post/SKILL.md: a new "How a post reads" section with 12 rules and their sources.docs/PR_BLOG_AUTOMATION.md: documents the optional keys and how the draft is laid out (outline[0]is the problem), and points to the skill instead of copying the guide.Sources for the writing rules
{ "version": 1, "head_sha": "620d9340522958c6ce652c047c3dc3ca81abe852", "summary": "Generated PR blog drafts now lead with the result and a one-line count of reported checks, show checks as a table that keeps failures visible, and move the provenance notice to the end; the blog-post skill gains a sourced writing guide.", "changes": [ "scripts/pr_blog_report.py: make_post() reorders the draft as result, problem, how it works, changes, a checks table, limits and provenance last", "scripts/pr_blog_report.py: optional blog.cast (term/<id>/session.cast) and blog.reproduce (1-8 commands, shown, never run); other blog keys still refused", "scripts/pr_blog_report.py: make_markdown() renders tables with escaped cells and reproduce commands as escaped list items, never a fence", "scripts/test_pr_blog_report.py: tests for section order, check table, check counts, optional keys and refusals", ".claude/skills/blog-post/SKILL.md: new section How a post reads, twelve rules with their sources", "docs/PR_BLOG_AUTOMATION.md: optional keys and draft layout documented, pointing at the skill instead of copying it" ], "tests": [ { "command": "python3 -m unittest discover -s scripts -p 'test_pr_blog*.py'", "status": "passed", "result": "58 tests ran and all passed, including the four new template tests", "evidence": "local run on this head, 2026-10-03" }, { "command": "python3 scripts/pr_blog_report.py validate on the current gHashTag/trinity#1273 event", "status": "passed", "result": "a real report renders in the new order with a five-row checks table and the provenance section last", "evidence": "draft.md and post.json written to a local temp directory and read through, 2026-10-03" }, { "command": "website build rendering a post.json table block", "status": "not_run", "result": "not needed for this change: the table and code blocks already exist in the site schema and Blog.tsx renders them; left to CI", "evidence": "apps/website/src/data/blog/types.ts defines table and code blocks; Blog.tsx has their render cases" } ], "limitations": [ "Existing work reports were written for the old layout, so outline items that state limits can land under How it works until authors follow the new order.", "blog.cast becomes a link and a receipt, not an embedded player: the terminal block is not on main until gHashTag/trinity#1273 merges.", "The writing rules guide the author agent and human writers; nothing checks automatically that a finished article follows them." ], "tags": ["Blog", "Writing", "Automation"], "blog": { "title": "Our PR blog drafts now open with the result", "summary": "The generator that turns a PR's work report into a blog draft now puts the result first and failures in plain view, following published guidance on how engineers read technical posts.", "outline": [ "Every merged PR in this repository gets a blog draft generated from its work report, and those drafts opened with a disclaimer and a list of file paths, so the first thing a reader saw was neither the result nor the reason to care.", "The generator now follows what style guides and experienced engineering bloggers agree on: put the result and its number first, one idea per paragraph, the problem before the solution, and evidence the reader can check themselves.", "Checks became a table with a status column, so a failed or skipped check sits next to the passed ones instead of hiding in a bracketed bullet, and the line under the result counts them before anyone scrolls.", "Two optional fields let an author attach a published terminal recording and the exact commands to reproduce the result, and the guide that explains each section lives in one place, the blog-post skill, with its sources." ] } }🤖 Generated with Claude Code