Skip to content

blog: every post carries a widget, as a t27 rule the work report enforces (Closes #1576) - #1577

Merged
gHashTag merged 1 commit into
mainfrom
feat/post-widget-rule
Oct 9, 2026
Merged

gHashTag merged 1 commit into
mainfrom
feat/post-widget-rule

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Closes #1576

The owner's rule of 2026-10-09, that every t27.ai post carries a widget, is now a t27 spec, and the required T27 work report check enforces it on every PR that adds or changes a post. The 14 posts that broke it now have widgets.

The rule: apps/website/specs/policy/post_widget.t27, next to course_post.t27 and in the same style.

  • It holds the rule sentence, WIDGET_KINDS = ["terminal", "figure"], the cutoff WIDGET_SINCE = "2026-09-27", and GRANDFATHERED: the 72 posts dated before the cutoff that carry no widget, listed by name.
  • It has 5 test blocks. t27c test-report (0.5.2) passes 5 of 5 with 0 vacuous passes.

The glue stays at the Only-t27 cap: 40 + 32 + 8 = 80 added foreign lines.

  • pr-blog-report.yml saves each changed post body as text from the PR head, through the contents API. It never checks out or runs the PR.
  • scripts/pr_blog_report.py validate --posts reads the spec's constants with the same regexes as course_post.t27. It refuses a body that has no widget in body or ruBody, and fails closed when the spec is broken or a body was not saved.
  • docs/PR_BLOG_AUTOMATION.md gets a short section that points at the spec.

Posts and casts. Every cast already exists under public/term/. I read each cast's text before writing its caption, and the Russian body gets the same blocks.

Post Widget(s)
three-dies-one-verdict tri-fpga-jtag
an-eye-on-the-board tri-fpga-jtag, t27c-eth-crc
buses-and-peripherals t27c-verilog-uart, t27c-eth-crc
clocks-resets-and-cdc t27c-mtbf, t27c-mmcm-mutate
course-three-verifying-hardware tri-fpga-wire, t27-tri-seals
course-three-goldenfloat t27c-tnf17
nine-modules-of-three-again t27c-gft-xornet
course-zero-t27-basics t27c-hello-world
tri-test-now-runs-the-tests t27c-gft-relu
two-courses-twenty-seven-lessons-each t27c-bitnet-mlp, t27c-gft-smul
a-course-pr-carries-its-post tri-blog-list
one-regional-clock-twelve-pull-requests perf2-knockouts
the-seed-moved-it-the-pins-moved-it-more tri-fpga-jtag, tri-fpga-tools
mask-over-scale-ternary-drafts-that-compile a figure drawn from the post's own numbers (no recording of tri tc-draft exists)

One text fix: the clocks post said one MMCM test fails when the VCO floor is lowered. Its recording shows two, vco_below_the_window_is_rejected and vco_out_of_range_is_an_error, so the sentence now says two, in both languages.

{
  "version": 1,
  "head_sha": "b4d6e9ffdc9c79b3084e49bdae5a56669e733dbf",
  "summary": "The owner's rule that every t27.ai post carries a widget is now a t27 spec, post_widget.t27. The required work-report check enforces it on changed post bodies, and the 14 widgetless posts dated on or after 2026-09-27 get casts or a figure, in English and Russian.",
  "changes": [
    "apps/website/specs/policy/post_widget.t27: the rule sentence, WIDGET_KINDS terminal and figure, WIDGET_SINCE 2026-09-27, 72 grandfathered post names, and 5 test blocks.",
    "scripts/pr_blog_report.py: post_widget_policy reads the spec's constants and fails closed; post_widget_refusal refuses an added, modified or renamed body with no widget in body or ruBody; validate takes --posts (40 added lines).",
    "scripts/test_pr_blog_report.py: 3 tests that cover the real spec, a broken spec, both languages, grandfathered, removed and unsaved bodies (32 added lines).",
    ".github/workflows/pr-blog-report.yml: a step saves each changed post body from the PR head as text through the contents API, and validate gets --posts (8 added lines).",
    "apps/website/src/data/blog/bodies/*.ts: 14 posts get existing terminal casts (one gets a figure) in English and Russian, and the clocks post's MMCM sentence is corrected from one failing test to two.",
    "docs/PR_BLOG_AUTOMATION.md: a short section that points at the spec."
  ],
  "tests": [
    {
      "command": "t27c test-report apps/website/specs/policy/post_widget.t27 (t27c 0.5.2, zig 0.16.0)",
      "status": "passed",
      "result": "5 of 5 pass, 0 vacuous; WIDGET_KINDS[1] changed to chart fails a_widget_is_a_cast_or_a_figure, and a changed last grandfathered name fails the_grandfathered_list_is_closed",
      "evidence": "local run on this head, 2026-10-09"
    },
    {
      "command": "python3 -m unittest discover -s scripts -p 'test_pr_blog*.py'",
      "status": "passed",
      "result": "74 tests OK; five planted bugs in the new glue (ruBody skipped, grandfathering off, length check off, removed bodies checked, wrong segment matched) each fail one test",
      "evidence": "local run on this head, 2026-10-09"
    },
    {
      "command": "post_widget_refusal over every body file, main against this branch",
      "status": "passed",
      "result": "on main's 98 bodies it refuses exactly 14, the 11 named in the issue plus 3 from 09-29 to 10-02; on this branch it refuses 0, with 72 grandfathered",
      "evidence": "local run on this head, 2026-10-09"
    },
    {
      "command": "validate --posts on trinity#1569's real files and head (the fetch step simulated with gh api)",
      "status": "passed",
      "result": "exit 1, refused: three-dies-one-verdict.ts has no widget in body or ruBody; without --posts it exits 0 as before",
      "evidence": "local run, 2026-10-09"
    },
    {
      "command": "esbuild bundle of src/data/blog/posts.ts, widget count per post dated on or after 2026-09-27, and a check that each terminal src exists under public/",
      "status": "passed",
      "result": "23 posts, every one has at least one widget in both languages, the same number in each, and 0 missing recordings",
      "evidence": "local run on this head, 2026-10-09"
    },
    {
      "command": "npm run typecheck:ratchet and npx vite build in apps/website",
      "status": "passed",
      "result": "179 errors across 26 files, the same as the baseline; the build finished in 25 s",
      "evidence": "local run on this head, 2026-10-09"
    },
    {
      "command": "vite preview, #/blog/three-dies-one-verdict and #/blog/mask-over-scale-ternary-drafts-that-compile in a browser",
      "status": "passed",
      "result": "the tri-fpga-jtag player mounts and types the recording; the figure renders four bars with its caption",
      "evidence": "local run on this head, 2026-10-09"
    },
    {
      "command": "the website-checks gate on this PR",
      "status": "not_run",
      "result": "not run locally beyond typecheck and build",
      "evidence": "the website-checks workflow on this pull request runs it"
    }
  ],
  "limitations": [
    "The new rule runs from main (pull_request_target), so it binds PRs after this one merges, not this PR.",
    "The PR-time check cannot see whether a terminal block's recording exists, because the workflow never checks out the PR; the site's player shows a missing one.",
    "Widgets are matched by the text kind: 'terminal' or \"kind\": \"figure\"; a block built by a function call would not be seen.",
    "72 older posts stay without widgets, by name; the list only shrinks.",
    "Owner rule says each post also needs its og-art triptych; this PR does not touch triptychs.",
    "t27c cannot lower != on two str values yet (Zig: operator != not allowed for []const u8), so the spec does not assert that the two widget kinds differ."
  ],
  "tags": [
    "Blog",
    "Policy",
    "t27"
  ],
  "blog": {
    "title": "Every post carries a widget",
    "summary": "A rule that was said once and written nowhere let 11 posts ship as text only. It is now a t27 spec, and the required check enforces it on every post a PR changes.",
    "outline": [
      "Eleven posts in a row shipped with no recording, because the widget rule lived only in a conversation.",
      "post_widget.t27 holds the rule, the two widget kinds and the grandfathered posts, and pr_blog_report.py reads it on every PR.",
      "Fourteen posts got casts that show the command they discuss; one got a figure, and one caption corrected its own post."
    ]
  }
}

🤖 Generated with Claude Code

…rces (Closes #1576)

The owner's rule of 2026-10-09 now lives in apps/website/specs/policy/post_widget.t27.
A post body that a PR adds, modifies or renames holds at least one terminal cast or
figure in its English body and in its Russian ruBody. 72 older widgetless posts dated
before 2026-09-27 are grandfathered by name. The spec has 5 tests, and t27c test-report
counts 0 vacuous passes.

pr-blog-report.yml saves each changed body as text from the PR head. pr_blog_report.py
validate --posts reads the spec's constants and refuses a body without a widget. The
workflow never runs that text. Foreign glue: 40 + 32 + 8 = 80 added lines.

The 14 widgetless posts dated on or after 2026-09-27 get existing casts that match their
text, in EN and RU. mask-over-scale has no matching recording, so it gets a figure built
from its own numbers. The clocks post said one MMCM test fails; its recording shows two,
so that sentence is corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) October 9, 2026 16:29
@tri-claw

tri-claw Bot commented Oct 9, 2026

Copy link
Copy Markdown

Summary by t27-bees

Checked by the t27 compiler

t27c parse, parse-complete and typecheck on each changed .t27 file at b4d6e9f. Nothing was generated, built or run. A pass means the file is well formed, not that it is right.

  • apps/website/specs/policy/post_widget.t27: parses and typechecks.

Read by the model

This PR codifies the owner's rule that every t27.ai blog post dated on or after 2026-09-27 must carry a widget (terminal cast or figure) in both English and Russian bodies. It adds a t27 spec (post_widget.t27) with the rule, constants, a grandfathered list of 72 pre-cutoff posts, and 5 tests; extends the PR workflow to fetch changed post bodies via the GitHub Contents API and validate them; updates the validation script to enforce the widget requirement; and adds widgets to 14 previously non-compliant posts (plus a text correction in one post).

Worth a look

  • .github/workflows/pr-blog-report.yml:54-60 — The POST_DIR is extracted from the spec file using a fragile sed regex (^pub const POST_DIR : str = "\(.*\)";$). If the spec's formatting changes (whitespace, quotes, line breaks), the extraction fails silently and the validation runs against an empty or wrong directory. The workflow runs on pull_request_target (base branch), but validates PR-head bodies; if a PR modifies the spec itself, the base-branch spec and head-branch bodies could mismatch.

  • apps/website/specs/policy/post_widget.t27:68-70 — The validation only checks that a widget block exists in the body text (kind: 'terminal' or kind: 'figure'). It does not verify that the referenced cast recording actually exists under public/term/<id>/session.cast, nor that the SVG in a figure is well-formed. The spec acknowledges this gap ("the check cannot see whether a terminal block's recording exists"), but a post could pass the check with a broken or missing cast reference.

  • apps/website/specs/policy/post_widget.t27:87-158 — The GRANDFATHERED list of 72 post names is hardcoded and manually maintained. The spec states "The list only shrinks: a post that gains a widget may leave it, and no post joins it," but there is no automated enforcement of this policy; a future edit could accidentally add entries or fail to remove a post that has gained a widget.

  • scripts/pr_blog_report.py (not fully shown) — The description says the script "reads the spec's constants with the same regexes as course_post.t27" and "fails closed when the spec is broken or a body was not saved." If the regex parsing of the spec drifts from the actual t27 syntax (e.g., multi-line arrays, comments, trailing commas), the validation could misread constants and either pass invalid posts or reject valid ones.

  • apps/website/src/data/blog/bodies/course-3-clocks-resets-and-cdc.ts:47,55 — The text fix changes "the one test that fails" to "the two tests that fail" and names them (vco_below_the_window_is_rejected and vco_out_of_range_is_an_error). This aligns the post with the recorded cast, but the cast caption in the same file (line 55) says "14 of 16 tests still pass, and the two that fail..." — ensure the English and Russian bodies both reflect the same two-test count (the Russian body at line 134 appears correct).


Read: 19 files, +512 -3, the whole diff up to 60000 characters (the rest was not read). Head b4d6e9f. Model: openai-compatible/nvidia/nemotron-3-ultra-550b-a55b. Commands: @t27-bees review | summary | help | pause | resume. Free for every repository.

@gHashTag
gHashTag merged commit 8723fe0 into main Oct 9, 2026
37 of 38 checks passed
@github-actions github-actions Bot added status:completed Done status:in-progress 🔵 Agent working labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

X Brain Health Check

Score: 100.0/100
Status: 🟢 HEALTHY
Threshold: 80/100

X Brain is above merge threshold

github-actions Bot added a commit that referenced this pull request Oct 9, 2026
blog: every post carries a widget, as a t27 rule the work report enforces (Closes #1576) (#1577)

The owner's rule of 2026-10-09 now lives in apps/website/specs/policy/post_widget.t27.
A post body that a PR adds, modifies or renames holds at least one terminal cast or
figure in its English body and in its Russian ruBody. 72 older widgetless posts dated
before 2026-09-27 are grandfathered by name. The spec has 5 tests, and t27c test-report
counts 0 vacuous passes.

pr-blog-report.yml saves each changed body as text from the PR head. pr_blog_report.py
validate --posts reads the spec's constants and refuses a body without a widget. The
workflow never runs that text. Foreign glue: 40 + 32 + 8 = 80 added lines.

The 14 widgetless posts dated on or after 2026-09-27 get existing casts that match their
text, in EN and RU. mask-over-scale has no matching recording, so it gets a figure built
from its own numbers. The clocks post said one MMCM test fails; its recording shows two,
so that sentence is corrected.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

🧪 Brain Stress Test Results

Tests: 261/261 passed, 0 leaked
Status: 🟢 PASS
Gate: every test in zig build test-brain-stress passes and none leaks

gHashTag added a commit that referenced this pull request Oct 9, 2026
…1579) (#1580)

* ci(project-status): read the PR body from the environment (Closes #1579)

The Move-closed-issues step pasted ${{ github.event.pull_request.body }}
into the script text, so a quote in a PR body broke the step (#1577) and
shell in a PR body ran with PROJECT_TOKEN in the environment. The body
now reaches bash only as the PR_BODY variable, as dev-enforcement.yml
already does for the title.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(agent-complete): read the branch name from the environment (Closes #1579)

The Extract-issue-number step pasted ${{ github.head_ref }} into the
script. A branch name may hold quotes, $ and parentheses, and the step
writes GITHUB_OUTPUT, which the next step (with RAILWAY_API_TOKEN) reads.
It now reaches bash only as HEAD_REF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

blog: every post carries a widget, written as a t27 rule and checked on every PR

1 participant