Blog
[open PR, not merged; binds only PRs opened or pushed after the merge; checks that a post file changed, not what it says] The T27 work report check now refuses a trinity PR that changes a course without adding or modifying a blog post body in the same PR. The rule's words live only in a t27 spec, specs/policy/course_post.t27, which the checker reads and fails closed on. Renamed lessons count by old and new path, renamed posts do not count, and an incomplete file list is reported as not decided. Seven planted mutants each failed their own test.

Every trinity PR already carries a work report, and a merged PR later becomes a blog draft. A course change could still land with no post at all, so a reader could meet a new lesson before anything explained it. trinity#1461 closes that gap: a PR that changes a course now has to carry its blog post, English body and Russian ruBody, in the same PR, or the "T27 work report" status turns red. The PR is open and not merged yet.
The words of the rule are in one file, apps/website/specs/policy/course_post.t27. It holds the rule sentence, the course directory (apps/website/specs/course/), the post directory (apps/website/src/data/blog/bodies/) and the two file statuses that count as a written post, "added" and "modified". Three test blocks pin those values. The spec sits under specs/policy/, not under specs/course/, so editing the rule is not itself a course change.
scripts/pr_blog_report.py does not restate the rule. It reads the spec's str constants and its one string list, and it fails closed: a missing constant, a directory without its trailing slash, or a POST_STATUSES list whose length differs from its declared length stops the check. The script checks that length itself because t27 does not check a declared array length yet (gHashTag/t27#7395). The refusal message is the spec's RULE sentence followed by the file that triggered it.
previous_filename as well, so moving a lesson out of the course still counts.changed_files and the listed part does not settle the rule, the script prints that the rule is "not decided" instead of passing or failing silently.The PR adds 10 tests for the rule; the pipeline suite now runs 71 tests, and a rerun on 7 October gave OK. To check that the tests can see a bug, seven mutants were planted in pr_blog_report.py, one at a time, each restored with git afterwards. Each one failed the test named for it.
It checks that a post body file changed, not that the post describes the course change; review and the blog checks still judge the content. The workflow runs the script from main (pull_request_target), so the rule binds only PRs opened or pushed after the merge. A manual re-run of the report for an older course PR that shipped without a post will now turn red.
Work with me
I audit RTL and build independent, bit-exact models, then take the result through synthesis and, when useful, onto an Artix-7 board. The first conformance module is free.