feat(udg): code primitive + client boundary (fixes toilville blocks leaking into 4 brands) #111
No reviewers
Labels
No labels
priority
P1
priority
P2
priority
P3
priority
P4
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Toilville/toilville-design!111
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/toilville-source-regressions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Re-opens the second half of #110. That PR merged at its first commit and
this one never landed. Clean merge, one commit.
It fixes a live defect on main
Before the client boundary existed,
forgeblock_patternimported the toilvilleclient directly and applied it to every brand. On
maintoday:Four brands ship patterns referencing
toilville/*blocks from a plugin theirsites may not run —
tctdserves truechiptilldeath.com on a theme with noToilville plugin at all. It's generated preview output rather than a deployed
site, so it's wrong output, not an outage. This PR makes it clean.
Vocabulary
code— a monospaced literal.of: [text],enums: kind: [terminal, source].There was no way to say "terminal transcript";
diagramrenders towp:codebut means Mermaid.
column_set—variant: [plain, cards, table, list]declared and flippedto
used: true. It was the most important composite in the design whilemarked unused, and a client had no way to ask what kind of grid it had.
Adding one block here is deliberately not a one-line change. The repo demanded,
and this supplies: renderers in the WP pattern, email and ASCII
clients; text · BBS · SMS · RCS · Apple Business Chat reductions; a mock in
the Ritual Blocks catalog; and the count tripwire bumped 32 → 33.
wcag.py reportshows all 33 blocks reducing to every channel.The client boundary
forgeblock_patternnow takes aclientand no longer imports one.build_surfaceslooks it up per brand, so a brand without one gets theuniversal rendering.
render_sequencegives the client first refusal at everydepth — a choice that only held at the top level meant the Contact form, which
lives inside a column, silently reverted.
forgeblock_toilvillebecomes two levels:render_block(one universal blockrendered richer —
code→ terminal,column_set{cards}→ card-grid) andrender_run(composites that are not any single vocabulary block, still keyedon types).
Converter
<article>joins the container tags — the design puts the grid on the articlefor news rows, so those never registered as a
column_set.column_setrecordsits variant and chrome so the client doesn't guess. Card fields are read in
order — reading purely by type put the tag in the body and left the real
body on the floor.
Guards worth keeping: the card renderer refuses a column carrying inputs, a
terminal, a nested grid, or a long repeated run. Without them the Contact form
rendered as a card and the ritual demo's steps and signed history were
dropped. Both were caught by measuring rendered output, not by reading code.
Verification
just checkgreen; 270 tests passspelwork 98%, news 94%, contact 92% — remainder is a few contractions)
wp:toilville/in any other brand's patternshttps://claude.ai/code/session_01Kbzfscp4w5enUrZxMnDt78
codeprimitive; clients decide how ForgeBlocks renderRitual blocks are universal; a client decides how they look. This makes that true in the pipeline instead of asserted in a comment. VOCABULARY (udg/config/forgeblock.yml) code — a monospaced literal, of: [text], enums kind: [terminal, source]. There was no way to say "this is a terminal transcript"; `diagram` renders to wp:code but means Mermaid. column_set — variant: [plain, cards, table, list] declared, and used: true. It was the most important composite in the design while marked unused, and a client had no way to ask what KIND of grid it was looking at. Adding one block to the vocabulary is not a one-line change here, by design. The repo demanded, and this commit supplies: - a renderer in the WordPress pattern client - a renderer in the email client - a renderer in the ASCII client - text · BBS · SMS · RCS · Apple Business Chat reductions in artifact.py - a card mock in the Ritual Blocks catalog - the deliberate count tripwire in test_block_coverage bumped 32 -> 33 `wcag.py report` again shows all 33 blocks reducing to every channel. CLIENT BOUNDARY forgeblock_pattern is now brand-agnostic in fact, not just intent: it takes a `client` and no longer imports one. build_surfaces looks the client up per brand, so a brand without one gets the universal rendering — verified: no toilville block leaks into the other five brands. render_sequence gives the client first refusal at EVERY depth. A choice that only held at the top level meant the Contact form, which lives inside a column, silently reverted to the universal rendering. forgeblock_toilville is rewritten from bespoke run-matchers into two levels: render_block(block) one universal block, rendered richer code -> toilville/terminal column_set{cards} -> toilville/card-grid + card render_run(blocks, i) composites that are not any single vocabulary block (a hero is a context, a header, a section and an actions row), still keyed on TYPES CONVERTER - `code` is produced from `data-term` or a mono container with several lines. - column_set records its variant AND its chrome (a 1px gap over a hairline parent is the design's seam idiom) so the client does not have to guess. - <article> joins the container tags. The design puts the grid ON the article for news rows, so those never registered as a column_set at all. - card fields are read in ORDER, not purely by type: a short run BEFORE the heading is the mono slot, prose after it is the body. Reading by type put the tag in the body and left the real body on the floor. Multiple paragraphs now concatenate instead of the first one winning. - a fact_set inside a card becomes the card's feature list, not a flattened body string. Guards worth keeping: the card renderer refuses a column carrying inputs, a terminal, a nested grid, or a long repeated run. Without them the Contact form rendered as a card and the ritual demo's step list and signed history were dropped past the first paragraph. RESULT 98% of design copy survives all the way to rendered HTML (landing and rituals 100%, spelwork 98%, news 94%, contact 92% — the remainder is a handful of contractions). Every page emits toilville blocks; Contact renders the real wish-form with Name, Email, Organization, Interested in and the custom message label. `just check` green, 270 tests pass. Claude-Session: https://claude.ai/code/session_01Kbzfscp4w5enUrZxMnDt78