page-foundry 3.2.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/skills/page-foundry/SKILL.md +34 -10
- package/skills/page-foundry/TESTS.md +12 -0
- package/skills/page-foundry/references/design-direction.md +9 -6
- package/skills/page-foundry/references/ship-gates.md +11 -5
- package/skills/page-foundry/references/voice.md +6 -0
- package/skills/page-foundry/scripts/run_audit.py +455 -6
- package/skills/page-foundry/tests/build_fixture.sh +74 -1
- package/skills/page-foundry/tests/run_audit_test.sh +197 -0
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ It is slower. It will refuse to hand you the page a one-shot prompt would have g
|
|
|
83
83
|
| **A page that makes an argument** | Structure and copy follow the objections your buyer actually raises, in the order they raise them, with proof placed beside the claim it supports. |
|
|
84
84
|
| **One voice across everything** | Your writing rules live in a file a scanner enforces, so the fortieth page sounds like the first. |
|
|
85
85
|
| **Nothing invented** | No fabricated testimonial, number, command, or staged screenshot of something that never happened. Thin proof gets named and worked around. |
|
|
86
|
-
| **Does not read or look AI-made** |
|
|
86
|
+
| **Does not read or look AI-made** | Two kinds of check, because rejecting the tells is not enough on its own. Absence: the scan rejects the vocabulary and sentence patterns that mark machine-written copy (including ones a word list cannot catch), and a deterministic design detector rejects the visual defaults that give an AI page away, against a design system saved for the property. Presence: because a clean page can still be a flat, generic wall of text that nobody reads, a **blocking** cross-family (or human) taste judge fails a page that reads flat or could belong to any product, the conversion audit scores whether a cold reader would actually scan the page, and a copy-craft check requires the copy to be compelling, not just clean. Engagement is treated as a conversion requirement, not decoration. |
|
|
87
87
|
| **Accessible and fast** | Contrast, keyboard access, semantic markup, a weight budget, and a load target are gates rather than good intentions. |
|
|
88
88
|
| **Yours** | Static HTML you host anywhere, or a copy-and-design package for the tool of your choice. You are not tied to a platform and you do not need an account with anyone. |
|
|
89
89
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "page-foundry",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "An orchestrator Claude Code skill: one brief in, a finished marketing page (or design-handoff package) out, built on real positioning and gated so it does not read or look AI-made. Recommended install: npx skills add taylorbanks/page-foundry",
|
|
5
5
|
"bin": {
|
|
6
6
|
"page-foundry": "bin/page-foundry.js"
|
|
@@ -48,10 +48,13 @@ Nothing installs, updates, or gets skipped silently.
|
|
|
48
48
|
|---|---|---|---|
|
|
49
49
|
| product-marketing | core | present | npx skills list |
|
|
50
50
|
| customer-research | core | present | ~/.claude/skills |
|
|
51
|
-
| impeccable |
|
|
51
|
+
| impeccable | core | present | npx impeccable |
|
|
52
52
|
...one row per companion in the tables below...
|
|
53
|
-
|
|
53
|
+
voice: {configured | default | samples-supplied}
|
|
54
|
+
design-reference: {supplied: <what> | committed-theme | none}
|
|
55
|
+
override: {none | the core companions AND missing taste inputs the user approved building without, verbatim}
|
|
54
56
|
```
|
|
57
|
+
The `voice` and `design-reference` lines record the external taste inputs (step 6). `voice: default` with no samples, or `design-reference: none`, means that input is missing; unless the matching name appears on the `override:` line, Gate 0 marks the run PARTIAL and the banner fires.
|
|
55
58
|
2. **Check freshness.** If the skills CLI is present, run `npx skills check` and note outdated companions. Plugin-installed companions update via `claude plugin marketplace update <marketplace>` then reinstalling the plugin. Outdated is a reportable gap like missing: report, offer, act only on approval; what declining means per tier is defined in step 3.
|
|
56
59
|
3. **Report and ask, once. This stop is mandatory.** Show one table: present / outdated / missing, each row carrying its tier from the companion tables below, with the exact install or update command per gap and one line on what this run loses without it. Ask a single question: install and update now, or proceed without? On approval, run the commands, then RE-RUN detection and confirm every name resolves before continuing. What declining means depends on the tier:
|
|
57
60
|
- **Core companion missing: the run does not start.** There is no silent degrade to the reference files; the condensed rules are weaker summaries of mechanisms the real skills apply with deeper and more current logic, and the eight core companions (product-marketing, customer-research, marketing-psychology, cro, copywriting, frontend-design, humanizer, impeccable) are what separates page-foundry from running a design skill alone. impeccable is core, not an enhancer: it is the design engine this skill orchestrates, and a page built without its craft references and its deterministic detector is exactly the generic AI page the skill exists to prevent. A run without impeccable is not a lesser page-foundry run, it is a different and worse tool. The only way forward without one is an explicit per-run override: the user, in chat, told what this run loses, saying build anyway. An overridden run is marked PARTIAL, loudly: a banner at the top of the gate report naming every overridden core companion, and the same names in the foundry-log `degraded` field prefixed `PARTIAL:`. A partial run is a draft, not a page-foundry page.
|
|
@@ -63,6 +66,10 @@ Nothing installs, updates, or gets skipped silently.
|
|
|
63
66
|
- **build** (default): this skill carries the page through Phase 5 and ships code.
|
|
64
67
|
- **explore**: design variants first. Phases 0 through 3 run normally; Phase 4 produces multiple committed design directions instead of one (gstack `/design-shotgun` when installed; otherwise this skill generates 3 contrasting token plans, each with a static hero mockup, built one at a time). The user picks; the winner proceeds through Phase 5 as a normal build. Use when the property has no theme yet or the user wants options.
|
|
65
68
|
- **handoff**: this skill produces copy plus a complete design package for Claude Design (or another design tool) to build. Phases 0 through 4 run normally; Phase 5 is replaced by the handoff package in `references/handoff.md`; gates split as described there.
|
|
69
|
+
6. **External taste inputs, or the run is PARTIAL.** This is the difference between producing generic competence and producing something distinctive, and it is the most load-bearing input the skill has. Left to itself, the pipeline asks the model to invent voice and design taste from its own priors, and those priors are the current AI aesthetic, so the output converges on the sameness this skill exists to break. Two inputs prevent that, and their absence is reported here at preflight the same way a missing companion is:
|
|
70
|
+
- **Voice.** A configured `references/voice.md` (`owner:` is not `default`), or operator-supplied writing samples for the copy to match. `owner: default` and no samples at Phase 3 means the copy has no human voice to anchor to.
|
|
71
|
+
- **Design reference.** An operator-supplied reference the design is steered from: a real site, brand, publication, place, or object (reverse-engineered into tokens by the taste companion when installed), OR a committed `theme.css`/`DESIGN.md` for the property. Model-derived anchors alone do not satisfy this: "name two products this should feel like" answered by the model is the model choosing from its own priors again.
|
|
72
|
+
When either is missing, report it at the preflight stop beside the companions, with what the run loses. Absent an in-chat override, a run that reaches Phase 3 with `owner: default` and no samples, or Phase 4 with no supplied reference and no committed theme, is marked PARTIAL, loudly: a gate-report banner ("built without an external taste anchor; distinctiveness is not guaranteed") and a `PARTIAL:` prefix on the foundry-log `degraded` line, exactly like an overridden core companion. Distinctiveness cannot be enforced mechanically; requiring the input that produces it is the closest the skill can get.
|
|
66
73
|
|
|
67
74
|
### Controlling the run
|
|
68
75
|
|
|
@@ -115,7 +122,7 @@ Install commands by source: coreyhaines31/marketingskills companions via `npx sk
|
|
|
115
122
|
| cro | coreyhaines31/marketingskills | 0 (rewrites), 2, Gate 1 | on a rewrite, the live page URL plus whatever analytics, search, or heat data exists; then the compiled contract, message architecture, candidate skeletons | on a rewrite, `rewrite-diagnosis.md`, the current page's leak diagnosis; skeleton pre-reads and spec structure; on the form-centric archetypes, the form design (fields justified, order, step count, labels, error messages, button) in the spec's form entry; at Gate 1, `conversion-audit.md` with the MECLABS score | Phase 1 answers the diagnosis; Phase 2 spec; Phase 3 takes the form copy input; Gate 1 verdict, including the built form audited against the form entry | `cro:` invoked, diagnosis written on rewrites, form entry written on form-centric archetypes, audit written, spec changes applied |
|
|
116
123
|
| copywriting | coreyhaines31/marketingskills | 3, copy fit | page spec, message architecture, `voice.md`, `voc.md` | full draft copy, section by section, plus the `<title>` and meta description from its meta-content output, all refined by the voice chain into `copy-approved.md` | Phase 3 voice chain; Phase 5 builds it verbatim | `copywriting:` invoked, sections drafted, headline candidates scored |
|
|
117
124
|
| frontend-design | anthropics/skills | 4 | brand assets from the brief, the compiled contract, the page spec, any existing theme or `DESIGN.md` | the token plan: named hex palette, type pairing, layout concept with its grid spec (containers, columns, gutters per breakpoint), signature element, critique against the generic default; recomposition notes for the hero and densest section added after the shape confirmations; persisted as `theme.css` | Phase 4 shape confirmations; Phase 5 build; Gate 5 grid check; handoff `03-design-direction` | `frontend-design:` invoked, tokens persisted, grid specced, alternatives considered |
|
|
118
|
-
| humanizer | blader/humanizer (GitHub) | 3, copy fit, Gate 2 | final copy, after the word scan and the pattern pass | the rewrites that survive meaning arbitration, applied to the copy | Gate 2; `copy-approved.md` snapshots the result | `humanizer:` ran once, what it changed, accepted WARNs each with a reason |
|
|
125
|
+
| humanizer | blader/humanizer (GitHub) | 3, copy fit, Gate 2 | final copy, after the word scan and the pattern pass | the rewrites that survive meaning arbitration, applied to the copy, and `copy/humanizer.md`: the before/after of each rewrite plus WARNs kept with reasons | Gate 2; `copy-approved.md` snapshots the result; Gate 0 requires `copy/humanizer.md` to carry real diffs | `humanizer:` ran once, what it changed, accepted WARNs each with a reason |
|
|
119
126
|
|
|
120
127
|
#### Enhancer tier (graceful fallback)
|
|
121
128
|
|
|
@@ -198,8 +205,11 @@ impeccable (pinned source pbakaus/impeccable) is a design-fluency skill with per
|
|
|
198
205
|
- **PRODUCT.md and DESIGN.md are singletons: merge, never clobber.** Both live at the product's repo root and belong to the product rather than to this skill. When one exists that page-foundry did not write, read it and merge: add what the brief knows and the file lacks, keep what its owner wrote, and never regenerate the file wholesale. Two competing context docs is the failure this rule prevents.
|
|
199
206
|
- **Edit-time hooks stay off during foundry runs.** impeccable can install a detector hook that fires on every design-relevant file edit. Inside a foundry run the phase gates own enforcement, so the hook stays off while one is running (`/impeccable hooks off`, or `hook.enabled: false` in the product's `.impeccable/config.json`); a product that uses the hook for its own development turns it back on after the run.
|
|
200
207
|
- **`document` and `detect` are one loop: Phase 4 writes the system, Gate 5 enforces it.** Phase 4 step 6 has `/impeccable document` persist the property's `DESIGN.md` against the published design.md spec (eight sections, `version: alpha` pinned; the profile decision and the six-versus-eight nuance live in that step), and Gate 5 runs the detector over the built page with that file in force. On greenfield properties with no brand color anywhere, `palette.mjs` supplies the OKLCH brand-seed before frontend-design generates plans.
|
|
201
|
-
- **Detector findings are floors, and accepted findings live in the product's config.** Gate 5's mechanical design scan (`detect.mjs --json`, mechanics in `references/ship-gates.md`) runs from the product's repo root so `.impeccable/config.json` and `DESIGN.md` apply.
|
|
208
|
+
- **Detector findings are floors, and accepted findings live in the product's config.** Gate 5's mechanical design scan (`detect.mjs --json`, mechanics in `references/ship-gates.md`) runs from the product's repo root so `.impeccable/config.json` and `DESIGN.md` apply. **Persist the detector's JSON output to `.impeccable/detect-scan.json`** (redirect `detect.mjs --json` into it): this is the design gate's artifact, and Gate 0 requires it because it is a deterministic tool's output that a run which "never ran it" cannot produce (#42). A clean run stores the empty array the detector emits; a run with findings stores them, and each is then fixed or accepted. Acceptance means an entry in the product's `.impeccable/config.json` under `detector.ignoreValues` carrying a `reason`: the detector already honors that file, so the record of deliberate choices and the mechanism that waives findings cannot drift apart. An ignore without a reason is a suppressed finding, not an accepted one. Gate 0 (`run_audit.py`) validates the stored scan's shape but does not re-run the detector — that is a Node tool and `run_audit.py` is stdlib-only with no subprocess (README, SECURITY.md); the live re-run is Gate 5's own job with the tool in hand.
|
|
202
209
|
- **Advisory invocations; MECLABS stays the arbiter.** `critique` when a page needs a UX-heuristics read beyond conversion: its Nielsen-scored snapshot is advisory input to the design decisions, and on a conversion page a critique finding never overrides a conversion rule. The snapshot has two standing consumers. At the comp stage (Phase 4.5), `critique` runs each round's review and its snapshot is the round's record. At the Gate 5 fix loop, a failed render review runs `critique` and then `polish`, which opens by reading the latest snapshot for the target as its fix backlog (mechanics and the contract-deferral rule in `references/ship-gates.md`). Anywhere else, critique is advisory only. `live` during explore mode, for picking variants inside the user's running page (web only; needs a dev server). `overdrive` rarely, when the spec's motion slot justifies a technically extraordinary hero. Keep copy away from impeccable's `clarify`: it has no voice enforcement, and UX microcopy belongs to copywriting under the voice gate.
|
|
210
|
+
- **Taste gets an independent judge, cross-family or human, never same-family, and it BLOCKS.** Conversion has one (Gate 1's cold MECLABS re-score); taste (voice + design) did not, so a same-family critique was Claude blessing Claude's slop. At Gate 5 a fresh context — a cross-family model (the codex/GPT gut-check path, or a configured alternative) or a human — is handed only the rendered page and the design reference, never the author, and scores two structured axes in `taste-judge.md`: `visual-engagement:` (structured, or a flat wall of text?) and `property-specificity:` (only-this-product, or a generic skeleton?), naming the tells. A FAIL on either axis is a **blocking Gate 5 failure** (#48), acceptable only by the user in chat (`accepted: <reason>`), never the builder's own — this is the fix for the 2026-07-27 dogfood, where the judge flagged the flat page and it shipped anyway because the verdict was advisory. Where no cross-family or human judge is reachable, the artifact says so rather than faking independence. Verify layout on an accurate capture (`getBoundingClientRect` + a pixel-true shot), not the racy DOM-render, before judging (#53). Mechanics (voice_scan, detect) are floors; this is the arbiter (`references/ship-gates.md` Gate 5, issues #44/#48/#53).
|
|
211
|
+
- **Engagement is a blocking conversion requirement, not a beauty nicety (#52).** The mechanical scans verify absence (no banned words, no known tells); they cannot verify presence of quality. A flat wall of text is clean AND does not convert, because design decides whether the copy is read at all (`voc.md`). So a page that is visually flat or whose copy is generic fails three judgment lines: Gate 1's reading-experience score (#50), Gate 2's copy-craft check (#51), and Gate 5's blocking taste judge (#48). "Clean" was never "compelling," and the README no longer claims the gates guarantee a beautiful page unless these lines pass.
|
|
212
|
+
- **Selling the outcome, not the plumbing (soft).** A recurring AI tell is a page selling its own MECHANICS — gates, phases, "9 gates", the spec, companion names — as the value, instead of the buyer's outcome. This is not a hard rule, because some products ARE their mechanics; the per-product call is made once in the Design-Strategy step and recorded as `mechanics-as-value: yes|no` in `design-strategy.md`. Gate 2 carries a soft WARN (never an auto-fail) that `run_audit.py` raises when process language is prevalent and that decision is not yes, so a human reframes or confirms it (issue #45).
|
|
203
213
|
- **Division of authority.** page-foundry owns the brief, message, conversion, voice, integrity, and measurement; impeccable owns visual craft depth and mechanical design detection. A finding on either side never waives the other's gates.
|
|
204
214
|
|
|
205
215
|
## Phase 0: Intake
|
|
@@ -271,20 +281,32 @@ Artifacts: reads the brief, `message-architecture.md`, `persuasion-map.md`, `fou
|
|
|
271
281
|
|
|
272
282
|
Get user sign-off on the spec before writing copy; the skeleton pick lands here, so present the candidates with their pre-reads alongside the spec, lead with the recommendation, and rebuild the spec on the alternative if the user picks one. The per-job shape confirmations land here too: once signed, the shapes are what Phase 3 writes the copy to, and a later change is Phase 4's recorded override, with the re-triggering that entails. When gstack is present, invoke `/plan-design-review` on the spec here; its inline mockups catch structural problems before copy is written. With impeccable installed, write the product's root `PRODUCT.md` immediately after sign-off, per the impeccable integration notes: the signed spec is the first moment every field the file takes exists (the CTA set from the contract, the belief ladder from Phase 1) and nothing it takes depends on Phases 3 or 4, so holding the write until Phase 4 entry bought nothing and left a window where an interrupted run, or an impeccable command the user runs between phases, triggers the interview the file exists to prevent.
|
|
273
283
|
|
|
284
|
+
## Phase 2.5: Design strategy
|
|
285
|
+
|
|
286
|
+
Default on; a user may decline it in chat, in which case record `design-strategy` on the preflight `override:` line and proceed with the steering weaker. It exists only because it GATES the two phases after it — if it does not, it is Phase 4 renamed, and this build was pointless. Write `design-strategy.md` to the run artifact directory, before any copy or design, holding:
|
|
287
|
+
|
|
288
|
+
- **The mechanics-vs-outcome decision, explicit:** `mechanics-as-value: yes|no`. Are this product's mechanics the value (a testing or security tool, where the pipeline *is* the pitch) or the plumbing (most products, where the buyer's outcome is)? This one line is consumed by the Gate 2 soft check (a `yes` silences the outcome-vs-mechanics WARN; a `no` leaves it live), so it is a real downstream gate, not a note.
|
|
289
|
+
- **Directions grounded in the external reference, not model priors.** Draw the candidate directions from the operator's supplied reference (Phase -1 step 6, issue #41) and the product's own world — name the reference the strategy is grounded in. This is the antidote to the killed trend list (#43) and to an LLM told only to "avoid tropes" rotating to the next predictable set (the quirky-serif pivot): a direction traced to a real reference is not a trope rotation.
|
|
290
|
+
- **An anti-trope kill-list:** the specific looks this property must not become, named, so Phase 4 rejects them on sight.
|
|
291
|
+
- **At least one named candidate direction**, in enough detail that Phase 4 can build from it.
|
|
292
|
+
|
|
293
|
+
Consumed, not referenced: Phase 3 writes the copy under the mechanics-vs-outcome decision, and Phase 4 draws its direction from the strategy's directions and kill-list. `run_audit.py` requires the artifact (unless declined at preflight), checks it carries those four things, and treats the copy draft and the theme postdating it as the evidence it steered them rather than being written after the fact.
|
|
294
|
+
|
|
274
295
|
## Phase 3: Copy
|
|
275
296
|
|
|
276
297
|
Goal: full page copy, in the owner's voice, passing the voice scan.
|
|
277
298
|
|
|
278
299
|
Artifacts: reads `page-spec.md`, `message-architecture.md`, `persuasion-map.md`, `voc.md`, `references/voice.md`; writes drafts and the approved draft to `copy/`. The frozen `copy/copy-approved.md` comes later, from the copy-fit pass, once a design direction exists.
|
|
279
300
|
|
|
280
|
-
1. Read `references/voice.md` first. If its config block still says `owner: default`, or the user asks to set up or change the voice, run the Voice wizard (below) before writing.
|
|
301
|
+
1. Read `references/voice.md` first. If its config block still says `owner: default`, or the user asks to set up or change the voice, run the Voice wizard (below) before writing. Voice is one of the two external taste inputs (Phase -1 step 6): reaching this phase with `owner: default` and no operator-supplied writing samples means the copy has no human register to match and will default to the model's own, so absent an in-chat override the run is PARTIAL and the gate report says so. Configuring the voice or being handed samples is the fix, not writing anyway.
|
|
281
302
|
2. Hero first, framing before wording. **Invoke the copywriting skill to draft 2 or 3 complete hero candidates** (headline, subhead, CTA label, and the proof element the spec placed beside them), each leading with a different objection or entry state from the Phase 1 objection map; candidates differ on what the hero answers, never on phrasing alone. Score each as a unit against the 5-second test, message match with the traffic source, and the headline budget. Inside the winning framing, draft at least 6 headline variants, score each against the budget, message match, and specificity, and present the top 3 with one line of reasoning each. Both picks land together (ask only in interactive runs), and `copy/hero-candidates.md` records every candidate with its scores and the reasons for the pick; a selection that lives only in the transcript is invisible to the next run. Then **invoke copywriting to write the body**, section by section against the spec and the message architecture; it does the writing. In the same invocation, request copywriting's meta-content output: the `<title>` a search result or share card shows, and the meta description under it, both written to the message match the winning hero framing carries and short enough that neither truncates in a search result. They are page copy, read before any of the rest, and everything that follows in this phase applies to them: copy-editing, the scan, the pattern pass, the humanizer, the step 5 re-trigger, and the freeze at the end of the copy-fit pass. A title first written during the build has skipped the voice gate, the retrofit-at-gate failure Phase 2 already names for the answer block. Then **invoke copy-editing** on what copywriting produced, naming three of its sweeps in the invocation. The cutting pass belongs to copy-editing, not to a later step: every sentence faces the question of what the reader loses if it dies, and a sentence that costs the reader nothing dies. The So-What sweep runs with it: every surviving claim must answer "so what?" with the deeper benefit, or be rewritten until it does. So does the Specificity sweep: vague quantities and hedged outcomes become concrete numbers, named results, and real nouns, conversion rule 9 applied sentence by sentence. An invocation that only cuts leaves unused the two sweeps that sharpen the copy the cut spared. Copy-editing returns a changelog of what it cut, what it tightened, and what it sharpened, and that changelog goes on the gate report's `copy-editing` line. For archetype-specific copy, invoke the matching companion on that section (**signup** for a registration flow, **popups** for an exit or scroll offer, **launch** for a launch page, **lead-magnets** for a gated offer). If copywriting is absent, write the copy yourself against the spec and `references/voice.md`, cut by the same question, and mark Phase 3 degraded.
|
|
282
|
-
3. Red-team read: adopt one skeptical reader per segment x entry state from the brief and walk the draft as each of them. Each reader arrives carrying the brief's Switching Dynamics: the Habit force is their reason to close the tab, the Anxiety force is their doubt at the CTA, and the walk checks that the copy answers both where they arise, not in a section the reader already scrolled past. Every reader must reach the CTA; a qualified reader concluding "not for me" is a defect (conversion rule 10). Then walk one more reader, built from the brief's anti-persona, whose correct ending is the opposite: this reader should conclude the product is not for them, and an anti-persona reaching the CTA convinced means the page is promising something the product does not do for them. Fix bounce points now, while the copy is still upstream of the voice pass; the same check re-runs at the gates.
|
|
303
|
+
3. Red-team read: adopt one skeptical reader per segment x entry state from the brief and walk the draft as each of them. Each reader arrives carrying the brief's Switching Dynamics: the Habit force is their reason to close the tab, the Anxiety force is their doubt at the CTA, and the walk checks that the copy answers both where they arise, not in a section the reader already scrolled past. Every reader must reach the CTA; a qualified reader concluding "not for me" is a defect (conversion rule 10). Then walk one more reader, built from the brief's anti-persona, whose correct ending is the opposite: this reader should conclude the product is not for them, and an anti-persona reaching the CTA convinced means the page is promising something the product does not do for them. Fix bounce points now, while the copy is still upstream of the voice pass; the same check re-runs at the gates. **Write the walk to `red-team.md` in the run artifact directory**: one entry per reader (segment x entry state), each naming where they bounce or convert, plus the anti-persona and their self-disqualification. This is a required artifact, not a note in the transcript: a walk with no `red-team.md` on disk is a walk Gate 0 cannot prove happened, and it fails there. Carry the specifics only a real walk produces (the actual bounce points, the actual reader states from the brief), because that is what makes the artifact costly to backfill.
|
|
283
304
|
4. Run `python3 scripts/voice_scan.py <draft files>`. The script reads its rules from `references/voice.md`, so wizard changes take effect immediately. Fix every FAIL; zero FAILs is the bar.
|
|
284
305
|
Then the **pattern pass** (do not skip it): the word scan catches vocabulary, not grammar, and the most common reason a page passes the word scan yet still reads as AI is a language pattern. Work through every `AI language pattern` WARN the scanner flags (negative parallelism "not X, it's Y"; copula avoidance "serves as"; tailing negation "no X, no Y"; authority tropes; significance inflation; three-verb-clause runs "runs X, gates Y, and hands Z"; parallel-list uniformity in prose): rewrite it, or accept it with a recorded reason on the gate report's `humanizer` line. The patterns are deliberately WARN, not FAIL, because some flagged sentences are right as written.
|
|
285
|
-
Then **invoke the humanizer skill on the final copy. This is required, not optional.** The scanner catches lexical and single-sentence tells, but structural uniformity spread across separate elements (a roster where every item opens the same way, "Finds... / Pulls... / Structures...") is beyond regex; only a semantic read catches it. The humanizer proposes; meaning arbitrates. Every rewrite it proposes must preserve the claim and the register, with `references/voice.md` as the arbiter; a rewrite that changes what a sentence claims is a defect, not a fix, and is rejected. Apply the rewrites that survive arbitration
|
|
306
|
+
Then **invoke the humanizer skill on the final copy. This is required, not optional.** The scanner catches lexical and single-sentence tells, but structural uniformity spread across separate elements (a roster where every item opens the same way, "Finds... / Pulls... / Structures...") is beyond regex; only a semantic read catches it. The humanizer proposes; meaning arbitrates. Every rewrite it proposes must preserve the claim and the register, with `references/voice.md` as the arbiter; a rewrite that changes what a sentence claims is a defect, not a fix, and is rejected. Apply the rewrites that survive arbitration and **write the pass to `copy/humanizer.md`**: the before/after of every rewrite it applied, and each WARN it kept with the reason. This artifact is the proof the pass ran, and Gate 0 requires it to carry real before/after diffs — a diff-less note ("humanizer ran, reads clean") is indistinguishable from a pass that never happened, which is the exact backfill this closes (#42). The `humanizer` line on the gate report still summarizes; `copy/humanizer.md` is the evidence. Stop at one pass, not iterate-to-zero-tells: over-processing copy to chase zero tells is the failure mode this guardrail exists to prevent. A scanner PASS without the humanizer pass is an incomplete Gate 2. A page is not voice-clean until both the words and the patterns are clean, by the scanner and by the humanizer.
|
|
286
307
|
5. Final copy means final. Any edit that touches copy after the pattern pass and the humanizer (a red-team fix from the gates, a cut during build, a spec-driven rewrite) re-triggers the scan and the humanizer on the edited sections before Gate 2 reports. The last edit precedes the last scan, or Gate 2 has not run.
|
|
287
308
|
6. Approve the copy. Once the copy has passed the scan, the pattern pass, and the humanizer, write it in page order to `copy/approved-draft.md` in the run artifact directory, opening with the `<title>` and meta description as labeled entries. Approval is real: the claims, the voice, and the section copy are settled, and the passes that follow fit them rather than re-argue them. The freeze waits: this copy has never met a design direction, and a snapshot frozen before form exists turns every fit fix into an unplanned trip back through step 5. The copy-fit pass, after Phase 4 and its comp rounds, makes the one planned trip and writes `copy/copy-approved.md`, the snapshot the gates diff against.
|
|
309
|
+
7. **Judge the copy for craft, not just cleanliness (#51).** The scan and the humanizer prove the copy is voice-*clean* — no banned words, no AI patterns. They cannot prove it is voice-*compelling*, and clean-but-generic is what the dogfood shipped. Write `copy-craft.md` scoring the copy on at least three of four dimensions, each with a specific from the page: **specificity** (real numbers, named results, concrete nouns, not "unlock your potential"), a memorable **through-line / model-phrase** (the reference sales page had "Build the list. Email the list. Repeat."; page-foundry has "the spec before the page"), **varied pacing** (short punchy sentences next to longer context), and **objection pre-emption** (doubts answered where they arise). All in the property's register — dry for a skeptical dev audience, never hype. Gate 0 requires this artifact; Gate 2 reads it. Generic copy that is voice-clean still fails here.
|
|
288
310
|
|
|
289
311
|
### Voice wizard
|
|
290
312
|
|
|
@@ -297,14 +319,16 @@ Run when: the user says anything like "set up my voice", "update the voice", "th
|
|
|
297
319
|
|
|
298
320
|
## Phase 4: Design direction
|
|
299
321
|
|
|
300
|
-
Goal: a committed aesthetic and a token set, chosen for this property, before any markup.
|
|
322
|
+
Goal: a committed aesthetic and a token set, chosen for this property, before any markup. Read `references/design-direction.md` first; the direction is derived from the property, never picked from a trend menu (there is deliberately no trend list, for the reason that file states: a menu of current trends is how pages converge on the AI-default look).
|
|
323
|
+
|
|
324
|
+
**External design reference, or the run is PARTIAL (Phase -1 step 6).** The direction is steered by an operator-supplied reference: a real site, brand, publication, place, or object that carries the feeling this property should have, reverse-engineered into tokens by the taste companion when installed, or a committed `theme.css`/`DESIGN.md`. Model-derived anchors alone do not count: "name two products this should feel like," answered by the model, is the model choosing from the same priors that produce the default aesthetic. Reaching this phase with no supplied reference and no committed theme means the taste is invented from those priors; absent an in-chat override the run is PARTIAL and the gate report says distinctiveness is not guaranteed. The fix is to ask the user for a reference (or run the taste companion against one they name), not to invent a direction and hope.
|
|
301
325
|
|
|
302
|
-
Artifacts: reads the brief's brand assets, `page-spec.md`, **and the research the design must answer to: `voc.md` for who the reader is and how they talk, `message-architecture.md` for what the page has to prove and in what order, `persuasion-map.md` for the levers the layout has to make room for** (a Pratfall admission needs a place to sit, a proof-adjacency lever constrains where proof lands); and any existing theme or `DESIGN.md`. The design is downstream of the buyer, not just the brand palette: a look chosen without the research is the failure this skill exists to prevent, a page that is beautiful and speaks to no one. Writes the token plan to `tokens/` and the winning tokens to `theme.css` in `pages/<product>/`, where the page ships it; with impeccable installed, step 6 also persists the property's `DESIGN.md` at the product's repo root.
|
|
326
|
+
Artifacts: reads the brief's brand assets, the external design reference (or the record of its absence and the override), `page-spec.md`, **and the research the design must answer to: `voc.md` for who the reader is and how they talk, `message-architecture.md` for what the page has to prove and in what order, `persuasion-map.md` for the levers the layout has to make room for** (a Pratfall admission needs a place to sit, a proof-adjacency lever constrains where proof lands); and any existing theme or `DESIGN.md`. The design is downstream of the buyer, not just the brand palette: a look chosen without the research is the failure this skill exists to prevent, a page that is beautiful and speaks to no one. Writes the token plan to `tokens/` and the winning tokens to `theme.css` in `pages/<product>/`, where the page ships it; with impeccable installed, step 6 also persists the property's `DESIGN.md` at the product's repo root.
|
|
303
327
|
|
|
304
328
|
1. **Invoke web-design-guidelines** and treat it as authoritative on accessibility, typography, imagery, and interaction mechanics. `references/design-direction.md` carries the marketing-page and anti-slop layer (this skill wins on structure, conversion, and anti-slop calls) and is the fallback for the mechanics when web-design-guidelines is absent, which marks the design degraded.
|
|
305
329
|
2. **Invoke the frontend-design skill to produce the token plan** (palette as named hex values, display plus body pairing, a layout concept backed by a grid spec: container max-widths, column count, and gutters per breakpoint, per `references/design-direction.md`; one signature element, and a critique against the generic default before building); use its output as the design direction. Token source priority when they exist: brand assets from the brief, then the property's `DESIGN.md` (written by a prior run's step 6, gstack `/design-consultation`, or the product's own team), then frontend-design's plan. When frontend-design is the source, because no brand tokens and no committed theme exist, it produces 2 or 3 token plans in every mode, not just explore: each a committed direction with its own critique, differing on a real axis (temperature, type contrast, density), never three tints of one palette. When the property is greenfield in the strictest sense, no brand color anywhere, and impeccable is installed, run its palette script first (`node <impeccable skill dir>/scripts/palette.mjs`) and hand frontend-design the OKLCH brand-seed color it prints as a starting constraint; the seed anchors the plans without deciding among them. Pick one (ask only in interactive runs); the pick is a design decision, and the losing plans recorded in step 7 are the evidence it was made. If frontend-design is absent, build the token plan yourself from `references/design-direction.md` and mark Phase 4 degraded. When direction is genuinely undecided and gstack is present, invoke `/design-shotgun`.
|
|
306
330
|
3. **Confirm or override each section's shape.** The spec arrived with a confirmed shape per job: the compiler recommended it from the section-shape lexicon in `references/archetypes.md`, sign-off fixed it, and the copy was written to it. This step revisits those shapes with what Phase 2 could not have, the tokens in hand: confirm each one, or override it where the chosen direction genuinely demands a different form. An override is a recorded decision, in the spec, with its reason, and it knowingly enters the re-trigger loop: copy whose obligations change with the shape (an FAQ collapsing to an inline callout, a comparison table becoming prose) is re-worked in the copy-fit pass that follows, whose planned voice-chain re-entry covers it before the snapshot freezes. Re-deriving shapes from scratch here is a defect; the authority this step holds is the override. An off-lexicon shape is fine when the spec records what it is and why; the ordering constraints and proof adjacency bind whatever shape a job takes. With the shapes settled, write the per-breakpoint recomposition notes for the hero and the densest section into the chosen token plan (`references/design-direction.md` holds the format): density follows shape, so the notes cannot precede this step, and Gate 5 verifies the built page against them.
|
|
307
|
-
4. **Plan the imagery.** Write `imagery-plan.md` to the run directory. Imagery has to be decided, not defaulted: a page that falls back to a text-and-CSS wall because nobody planned images reads as AI-made, and that default is the strongest visual tell left once the palette and type are handled. For every spec section that could carry an image (hero, proof, feature, how-it-works), the plan names: whether it carries imagery at all, the source (a real product screenshot, a brand asset from the brief, a generated or stock image, or a deliberate no-image typographic treatment), and the treatment recipe (crop, aspect ratio, grain, duotone or color grade, border or frame, and the consistency rules that make the set look like one art direction rather than a scatter). A page that is intentionally image-light is a valid plan, but
|
|
331
|
+
4. **Plan the imagery.** Write `imagery-plan.md` to the run directory. Imagery has to be decided, not defaulted: a page that falls back to a text-and-CSS wall because nobody planned images reads as AI-made, and that default is the strongest visual tell left once the palette and type are handled. For every spec section that could carry an image (hero, proof, feature, how-it-works), the plan names: whether it carries imagery at all, the source (a real product screenshot, a brand asset from the brief, a generated or stock image, or a deliberate no-image typographic treatment), and the treatment recipe (crop, aspect ratio, grain, duotone or color grade, border or frame, and the consistency rules that make the set look like one art direction rather than a scatter). A page that is intentionally image-light is a valid plan, but "image-light by choice" is not a free pass (#49): the section must **name the engagement mechanism** that carries it instead of imagery — typographic hierarchy, emphasis (bold numbers, italic definitions), pull-quotes or callouts, numbered rhythm, visual breaks, varied pacing — and Gate 5 confirms that mechanism is actually on the built page. Text is not the enemy; flat text is. A bare "no image, the type carries it" with no named mechanism is the loophole that produced the dogfood's wall of text, and it fails. **Invoke the `image` companion** (marketingskills) to art-direct and, where the run generates or treats images, to produce them; when it is absent, write the plan yourself from the direction and mark the imagery degraded. Every image on the shipped page traces to a slot in this file. The integrity rules bind imagery whole: a product screenshot is a real capture of real use, never a mockup dressed as one.
|
|
308
332
|
5. **Design the states and motion.** Write `states-motion.md` to the run directory. Interactive behavior is a designed output, not a browser default. The file specifies: the error, loading, empty, and success states for every interactive element the page has (a form's validation and submitted states, a copy-button's copied state, an accordion's open state), each with what it looks like and what it announces to assistive tech; the focus and hover personality (the ring, the transition, the hover affordance) as a deliberate identity rather than the UA default; and the page-level motion identity (scroll-reveal, if any, its duration and easing; whether the hero moves; the reduced-motion fallback that is mandatory, not optional). Motion earns its slot or is absent by choice, and the choice is recorded. **When impeccable is installed, its animate rules govern the durations and easing**, and its headless-render rule also protects Gate 2's verbatim diff from a page whose text arrives via a reveal animation. A page with no designed states ships browser defaults, which is the behavioral equivalent of the gradient-and-three-cards look; Gate 5 walks the error path to confirm the states exist.
|
|
309
333
|
6. **Explore mode:** produce the stated number of variants (default 3), each a complete committed direction (token plan + static hero mockup), deliberately contrasting along real axes (light/dark, editorial/brutalist, type-led/visual-led), never three flavors of the same idea. Present them, wait for the pick, then proceed as build mode with the winner. With gstack, `/design-shotgun` replaces this step and its comparison board handles the pick.
|
|
310
334
|
7. Record every candidate plan in the run directory's `tokens/`, one file per plan, plus a line on why the winner won (explore mode: the variant files are these same plans, with their mockups noted), and persist the winning tokens as `theme.css` with custom properties. One property, one theme, many pages.
|
|
@@ -75,3 +75,15 @@ Run after any skill edit. Each is a prompt plus the behavior that must hold.
|
|
|
75
75
|
71. **The research reaches the design.** Phase 4 reads `voc.md`, `message-architecture.md`, and `persuasion-map.md` as required inputs, not just the brand palette and the spec → the design direction's scene sentence names the ICP segment and entry state it was drawn from, and that segment exists in the brief or `voc.md`; Gate 5 traces it back. A scene sentence that could describe any page for any buyer means the aesthetic was chosen blind to the reader, which is the failure the required reads exist to prevent, and it sends the design back. A Phase 4 that reads no research artifact, or a scene sentence with no ICP behind it, is a failure.
|
|
76
76
|
72. **Imagery and states are designed outputs, and external facts are re-verified.** Phase 4 writes `imagery-plan.md` (per-slot source and treatment recipe, consistency rules) and `states-motion.md` (error/loading/success states, focus and hover personality, motion identity with a mandatory reduced-motion fallback); both are required by `run_audit.py` in build, explore, and handoff. Gate 5 checks every shipped image traces to a planned slot at its treatment and is not an unplanned text-and-CSS wall, and walks the primary form to its designed error and success states rather than accepting browser defaults. Gate 5 also captures beyond one engine at two widths (768 and 1024, plus WebKit or Firefox) when the tools exist, Gate 3 checks 320px reflow, and Gate 7 drives one real form submit with the measurement event observed plus a post-deploy live check. Gate 8 re-verifies every checkable claim the page makes about a live external project (repo name, install model, license, OS support) against the live source at build, because those facts drift between intake and ship. A page that defaults to a text wall, ships browser-default states, or repeats an external fact that has since drifted, is a failure.
|
|
77
77
|
73. **impeccable is core: the design engine is required, not optional.** impeccable is absent and the invocation does not override it → the run halts at Phase -1 like any missing core companion, reports the `npx impeccable install` command, and does not start; a run that proceeds and ships a page with no `DESIGN.md` and no `detect` scan is the failure this tiering fixes (issue #39). With impeccable present, Phase 4 step 8 persists `DESIGN.md` and Gate 5 runs `detect.mjs`; `run_audit.py` requires `DESIGN.md` (regression case I) and fails without it, while an in-chat override makes its absence advisory and the run PARTIAL (regression case J). A "page-foundry page" whose look was never mechanically checked, shipped as a full (non-PARTIAL) run, is a failure: the skill must not treat its own design engine as skippable.
|
|
78
|
+
74. **The direction is derived from the property, never picked from a trend menu.** Phase 4 reads `references/design-direction.md`, which carries no list of current trends (modern-minimal / bento / brutalist-terminal / dark-mode / glass) to choose from → the direction is built by the file's process: start from the required external reference, mine the product's own world for a metaphor and signature, name the reader in a concrete scene sentence, and choose mechanics last to serve those. A run whose design rationale is a trend name ("we went brutalist because it's a dev tool"), or a `design-direction.md` that reintroduces a pick-from-this-list menu, is the self-seeding failure this fix removes (issue #43): a menu of the moment's trends is exactly how independent runs converge on the AI-default look. The anti-slop rejection list stays intact, and the file still closes on "could this page belong to any other product? If yes, it is not done."
|
|
79
|
+
75. **An external taste input is required, or the run is an honest PARTIAL.** Phase -1 step 6 records two external taste inputs on `preflight.md`: a `voice:` line (`configured` | `default` | `samples-supplied`) and a `design-reference:` line (`supplied: <what>` | `committed-theme` | `none`), where a model-derived anchor does not count as supplied → a run reaching Phase 3 with `voice: default` and no samples, or Phase 4 with `design-reference: none` and no committed theme, is marked PARTIAL: the gate report and the banner say distinctiveness is not guaranteed, and `run_audit.py` emits the taste WARN for each missing input (regression cases K, L, M). A missing taste input is a PARTIAL, not a hard FAIL — declining one is a valid user-approved state — unless the name appears on the `override:` line, which waives its WARN. Failures: a full (non-PARTIAL) run shipped with `voice: default` or `design-reference: none` and no override and no banner; a `design-reference: supplied` line whose only reference is "name two products this should feel like" answered by the model (that is the model choosing from the same priors that produce the default look, not an external anchor); a preflight that omits the taste lines entirely, which `run_audit.py` reads as missing input.
|
|
80
|
+
76. **The judgment passes leave auditable artifacts, and Gate 0 has teeth against backfill.** The humanizer pass writes `copy/humanizer.md` (the before/after of each rewrite, WARNs kept with reasons) and the red-team walk writes `red-team.md` (per-segment reader walks, bounce points, the anti-persona's self-disqualification); both are Gate 0-required. Backfill is made costly or detectable, not merely relocated (issue #42): `run_audit.py` re-runs the voice scan **in-process** over `copy/copy-approved.md` and FAILs if the frozen copy still carries banned phrases or dashes (regression case Q — the un-fakeable half: a deterministic tool's verdict is recomputed, not trusted from a report); it FAILs a `copy/humanizer.md` that carries no before/after diffs (case N — a diff-less "it ran, reads clean" note proves nothing); it FAILs a missing or walk-less `red-team.md` (case O); and it requires `.impeccable/detect-scan.json`, the persisted `detect.mjs --json` output, to exist and be well-formed on a full run (cases P, R), which a run that "never ran" the detector cannot produce. Failures: a green Gate 0 over hand-written judgment artifacts that contradict a re-run; a `humanizer` gate line with no `copy/humanizer.md` diffs behind it; a detector evidence line with no `detect-scan.json` on disk; a copy snapshot that ships over voice FAILs. `run_audit.py` stays stdlib-only with no subprocess (it imports the sibling `voice_scan` module in-process and does not shell out to Node), so it validates the detector's stored output by shape and leaves the live Node re-run to Gate 5; that boundary is the documented limit, not a gap.
|
|
81
|
+
77. **Taste has an independent judge, cross-family or human, and independence is never faked.** Gate 5 hands a FRESH context — a cross-family model (the codex/GPT gut-check path or a configured alternative) or a human — only the rendered page and the design reference, never the author, and asks whether the page could only belong to this property or reads AI-generated, naming the tells; the verdict goes to `taste-judge.md`, which Gate 0 requires (regression case S: missing → FAIL). The verdict is advisory-but-recorded, mirroring Gate 1's cold conversion score, never an auto-fail: a page a same-family generator loves but a cross-family judge flags is a finding for a human to weigh (issue #44). `run_audit.py` requires the artifact to carry a real verdict with named tells OR the honest "no independent judge was available" clause (case T: neither → FAIL; the honest clause → PASS). Failures: a same-family `/impeccable critique` or self-walk presented as the independent judge; a `taste-judge.md` claiming a verdict with no tells and no honest-absence clause; faking independence where no cross-family or human judge was reachable instead of saying so.
|
|
82
|
+
78. **Outcome-vs-mechanics framing is a soft WARN, and mechanics-as-value is a per-product call.** `run_audit.py` scans `copy/copy-approved.md` for prevalent process/mechanics language (gates, phases, "9 gates", the spec, the pipeline, companion or tool names) and emits a WARN when it is prevalent (3+ references) and the Design-Strategy decision is not `mechanics-as-value: yes` (regression case U). It is deliberately soft — a human reads the flag and reframes or confirms — and never blocks ship, because some products ARE their mechanics; setting `mechanics-as-value: yes` in `design-strategy.md` silences it (issue #45). Failures: turning this into a hard "never sell mechanics" gate (the operator explicitly rejected the absolute); a WARN that auto-fails; ignoring the per-product `mechanics-as-value` decision so a testing/security tool selling its own mechanics gets nagged. "Every page clears the gates before it leaves the shop" is the flagged framing; "a page that looks great and converts" is the outcome it points toward.
|
|
83
|
+
79. **The Design-Strategy artifact gates the phases after it, or it should not exist.** Phase 2.5 (default on) writes `design-strategy.md` before copy and design, holding the `mechanics-as-value: yes|no` decision, directions grounded in the external reference (#41) rather than model priors or the killed trend list (#43), an anti-trope kill-list, and at least one named candidate direction. Phase 3 and Phase 4 CONSUME it, not just reference it: the mechanics decision drives the Gate 2 soft check (#78), and the copy draft and theme postdate the strategy as evidence it steered them. `run_audit.py` requires the artifact in build/explore (regression case V: missing → FAIL) and checks it carries those four things (case W: a vague strategy with no decision, no grounding, no kill-list → FAIL). A user may decline the phase in chat, recorded as `design-strategy` on the preflight `override:` line, making its absence advisory (case V override → PASS). Failures: a `design-strategy.md` nothing downstream consumes (then it is Phase 4 renamed, and issue #46 says do not build it); a strategy grounded in model priors or the trend list instead of the supplied reference; a strategy written after the copy and design it claims to have steered.
|
|
84
|
+
80. **voice_scan stays a floor and gains two high-signal patterns; the humanizer owns the tail.** The scanner is a FLOOR, not the judge of voice (its WARN signal — three-verb runs, tailing negation, parallel-list uniformity — is kept, never amputated). Issue #47 adds exactly two high-signal, low-false-positive WARN patterns: the trailing contrast fragment ("Real customer language, not a guess.") and the standalone appositive fragment ("The claims, in the order your buyer raises objections."). Both fire as WARN, exit stays 0, and they stay quiet on clean copy (calibrated against the fixture). The tells a regex cannot pin without false positives — the two-beat aphorism ("Built from it, in your voice."), the full appositive tail — are explicitly left to the humanizer pass (#42), which only helps because it now actually runs and is provable. Failures: amputating the scanner to zero-false-positive tells only (deletes useful signal); chasing the full tail with more regex instead of the humanizer; a new pattern that false-positives on ordinary prose (the patterns are WARN and must stay low-noise).
|
|
85
|
+
81. **The taste judge BLOCKS on a flat or generic verdict.** `taste-judge.md` scores two structured axes on the rendered page: `visual-engagement:` (structured vs a flat wall of text) and `property-specificity:` (only-this-product vs a generic skeleton). A FAIL value on either axis is a blocking Gate 5 failure (regression case X: `visual-engagement: flat` → exit 1), not a logged note — this is the fix for the 2026-07-27 dogfood, where a cross-family "flat/skeleton" verdict shipped anyway because the judge was advisory (#48). Acceptance is the user's call in chat: an `accepted: <reason>` line waives the block (case X2 → PASS). A missing axis line is a failure (case X3): a page with no verdict on an axis was not judged. The honest "no independent judge available" clause still passes. Failures: a negative verdict shipped full (non-PARTIAL) without `accepted:`; a same-family critique presented as the independent judge; judging off the racy DOM-render instead of an accurate capture (#53).
|
|
86
|
+
82. **"Image-light by choice" is not a free pass.** `imagery-plan.md` may declare a section text-only, but it must name the engagement mechanism that carries it (typographic hierarchy, emphasis, pull-quotes/callouts, numbered rhythm, visual breaks, varied pacing), and Gate 5 confirms that mechanism is on the built page. A bare "no image by choice" / "text-only" with no mechanism named is the loophole that produced the dogfood's wall of text, and `run_audit.py` fails it (regression case Y). Text is not the enemy; flat text is (#49). Failures: a text-only section with no engagement mechanism recorded; a page that fell back to an unplanned text-and-CSS wall.
|
|
87
|
+
83. **Gate 1 scores the reading experience, not just the argument.** `conversion-audit.md` carries an explicit scannability / reading-friction assessment against the rendered page: would a cold reader scan it in five seconds and want to continue, or bounce off an undifferentiated text block? A wall of text is high reading-friction even when the argument is sound; the dogfood scored Friction=2 on a page nobody would scan and passed it. `run_audit.py` fails a conversion audit with no reading-experience assessment (regression case Z), because `voc.md` says design decides whether the copy is read at all (#50). Failures: scoring Friction low on a visually-flat page; a conversion audit that never scores the reading experience.
|
|
88
|
+
84. **Gate 2 checks voice-compelling, not just voice-clean.** The scanner and humanizer are absence checks; `copy-craft.md` is the presence check, scoring the copy in the property's dry register on at least three of four dimensions with a specific each: specificity (real numbers, concrete nouns), a memorable through-line/model-phrase, varied pacing, and objection pre-emption. `run_audit.py` requires the artifact in build/explore and fails a version scoring fewer than three dimensions (regression case CC: missing → FAIL; weak one-dimension → FAIL). Voice-clean copy that is generic and flat still fails (#51). Failures: shipping clean-but-generic copy with no craft judgment; hype-register craft on an audience that wants dry.
|
|
89
|
+
85. **Engagement is a blocking conversion requirement, and the claim matches the enforcement.** The doctrine reframes visual + copy engagement as a blocking conversion requirement (Gate 1 reading-experience #50, Gate 2 copy-craft #51, Gate 5 blocking taste judge #48), not an optional beauty nicety, because a flat wall of text does not convert (#52). The README no longer claims the gates guarantee a page that does not look AI-made on absence-checks alone; it names the presence checks. The render review makes an explicit quality call on an accurate capture (`getBoundingClientRect` + a pixel-true shot), never a brokenness check on the racy DOM-render composite, which is how the dogfood's reviewer rubber-stamped a wall of text (#53). Failures: a README or doctrine that promises "beautiful / not AI-made" while only running absence-checks; a render review that confirms the layout is not broken and calls it done.
|
|
@@ -8,13 +8,16 @@ Each property (each product, each brand under the holding company) gets exactly
|
|
|
8
8
|
|
|
9
9
|
## Choosing a direction
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**Do not pick from a menu of current trends. There is no trend list here on purpose.** A trend list is exactly how pages converge on the AI-default look: the models already reach for modern-minimal, bento, brutalist-terminal, dark-mode-dev-tool, and glassmorphism-kinetic without being told, because those are the aesthetic their training converged on. Handing the design phase that vocabulary, and worse, mapping it to audiences ("brutalist is the natural fit for a dev tool"), steers straight into the sameness this skill exists to break. The direction is not chosen from what is working elsewhere; it is derived from what could only belong to THIS property.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
Derive it by interrogating the property, not the market:
|
|
14
|
+
|
|
15
|
+
1. **Start from the required external reference (see the taste-input rule in SKILL.md).** The direction is steered by an operator-supplied reference: a real site, brand, publication, place, or object that carries the feeling this property should have, ideally reverse-engineered into tokens (the taste companion). Absent that reference, the run is PARTIAL and distinctiveness is not guaranteed, because the alternative is the model inventing taste from the same priors that produce the default.
|
|
16
|
+
2. **Mine the product's own world for a metaphor and a signature.** What is this product actually like, physically or conceptually? A foundry casts and stamps; a ledger rules and columns; a trail climbs and marks. That world names a signature element (a stamp, a rule, a marker) that could not transfer to another product. One signature, committed; restraint everywhere else.
|
|
17
|
+
3. **Name the reader concretely and the light they read in.** The scene sentence (below) is a specific person in a specific place and mood, drawn from the ICP, not "a modern user." The direction serves that reader.
|
|
18
|
+
4. **Then, and only then, choose the mechanics** (palette, type pairing, layout, motion) to serve 1-3. The type face is chosen for character and cause, never a default; a face that appears on every AI page (see the overused-font list impeccable enforces) is disqualified unless there is a stated reason it fits this property specifically.
|
|
19
|
+
|
|
20
|
+
If, having done 1-3, the honest answer is that a dark, monospace, terminal treatment truly belongs to this property (not because it is a dev tool and that is what dev tools do), that is a legitimate outcome, but it is arrived at, not defaulted to, and it still needs its own signature so it is not indistinguishable from every other dark-mono AI page. The test is always the same: could this page belong to any other product? If yes, it is not done.
|
|
18
21
|
|
|
19
22
|
## Anti-slop list
|
|
20
23
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Run every gate. Report results as a pass/fail table plus the MECLABS score. A failed gate means fix and re-run, not ship with a caveat. The one sanctioned caveat is an **enhancer** running on its reference-file fallback: that degrades a phase and is recorded on the `degraded` line, and the run still ships. A missing or skipped **core** companion is not a caveat, it is a Gate 0 failure (or, when the user overrode it in chat at preflight, an explicit PARTIAL that the report banners loudly). So "no shipping with a caveat" holds for gates and for core companions; enhancer degradation is the named exception, and nothing else is.
|
|
4
4
|
|
|
5
|
-
One doctrine, adopted whole from impeccable, binds every mechanical check in this file (the voice scanner at Gate 2, the design detector at Gate 5, the on-page audit at Gate 6, a Lighthouse run at Gate 4): a clean scan is a floor, never a verdict. Zero findings means no known tell fired, and the judgment lines that sit beside each scan still run in full.
|
|
5
|
+
One doctrine, adopted whole from impeccable, binds every mechanical check in this file (the voice scanner at Gate 2, the design detector at Gate 5, the on-page audit at Gate 6, a Lighthouse run at Gate 4): a clean scan is a floor, never a verdict. Zero findings means no known tell fired, and the judgment lines that sit beside each scan still run in full. The mechanical scans verify **absence** (no banned words, no known tells); they cannot verify **presence of quality**. So engagement — a page that is visually worth reading and copy worth reading — is enforced by the judgment lines, and it is a **blocking conversion requirement, not an optional beauty nicety** (#52): a flat wall of text does not convert, so it fails Gate 1's reading-experience line, Gate 2's copy-craft line, and Gate 5's blocking taste judge. The 2026-07-27 dogfood shipped a clean, flat page past every absence-check; these judgment lines are why that cannot pass now.
|
|
6
6
|
|
|
7
7
|
Handoff mode: gates 0, 1, 2, and 8 run before the package is delivered; gates 3, 4, 5, 6, and 7 become acceptance criteria in the package and run in full when the built asset comes back, along with a re-run of 1 and 2 on the rendered page. Details in `references/handoff.md`.
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ Handoff mode: gates 0, 1, 2, and 8 run before the package is delivered; gates 3,
|
|
|
10
10
|
|
|
11
11
|
This gate answers a question no other gate asks: did the pipeline actually run, or did an agent write a good-looking page from its own knowledge and fill the evidence lines with plausible sentences? Every other gate audits the page; this one audits the run that produced it. It exists because without it a run that invokes zero companions passes all the others and reports "all companions present".
|
|
12
12
|
|
|
13
|
-
- [ ] **Run the mechanical audit.** `python3 scripts/run_audit.py --mode <mode> --archetype <archetype> .agents/foundry/<product>/` exits 0. It checks that each phase's OUTPUT artifact exists on disk, is non-trivial, and carries the structure its consumer needs (voc.md quotes each with a source, a ranked Themes section; message-architecture.md with a hierarchy and objection map; persuasion-map.md with levers and where each lands; conversion-audit.md with two scores and the divergence; the copy snapshot; the token plans; the comp record; foundry-log.md in the documented format). A non-zero exit is a FAIL: the named artifact is missing or
|
|
13
|
+
- [ ] **Run the mechanical audit.** `python3 scripts/run_audit.py --mode <mode> --archetype <archetype> .agents/foundry/<product>/` exits 0. It checks that each phase's OUTPUT artifact exists on disk, is non-trivial, and carries the structure its consumer needs (voc.md quotes each with a source, a ranked Themes section; message-architecture.md with a hierarchy and objection map; persuasion-map.md with levers and where each lands; conversion-audit.md with two scores and the divergence; `red-team.md` with per-segment reader walks and bounce points; `copy/humanizer.md` with real before/after diffs; the copy snapshot; the token plans; the comp record; foundry-log.md in the documented format). It goes past presence for the judgment passes, which is where backfill-to-pass lives (#42): it **re-runs the voice scan in-process** over the frozen copy and FAILs if that copy still carries banned phrases or dashes (proof the Gate 2 scan actually held, not just that a report says so), requires `copy/humanizer.md` to carry before/after diffs rather than diff-less prose, and validates that `.impeccable/detect-scan.json` (the detector's persisted output) exists and is well-formed on a full run. A non-zero exit is a FAIL: the named artifact is missing, malformed, or contradicted by a re-run, and the phase that owns it did not really run. The script is stdlib-only, no subprocess, no network, and reads only these files; it cannot judge whether an artifact's content is any *good*, only that it is present, shaped right, and consistent with what a deterministic re-run produces (see its limits block). It is the floor, the same way the voice scanner is the floor for Gate 2. It cannot re-run the Node design detector (that would need a subprocess); the live detector re-run is Gate 5's job.
|
|
14
14
|
- [ ] **Present-but-uninvoked is a failure, not a silent pass.** Read `.agents/foundry/<product>/preflight.md`. For every companion that resolved PRESENT there, its phase's OUTPUT artifact must exist. A core companion present at preflight whose artifact is absent means the phase skipped a skill that was available: the run is PARTIAL at best, and unless the user overrode that companion in chat (recorded on the preflight `override:` line), it is a FAIL. This closes the gap the two-tier policy left open: the old rule gated companions at install time, the moment of lowest information; this gates them at ship time, when the artifacts either exist or they do not.
|
|
15
15
|
- [ ] **Every `degraded` claim is checked against the sweep.** A phase reported as degraded because its companion was "missing" is a FAIL if that companion resolves PRESENT in `preflight.md`. The fallback path is only legitimate for a companion the sweep recorded as missing or the user declined; claiming it for a present companion is the honor-system failure this gate replaces.
|
|
16
16
|
- [ ] **The evidence block is derived, not asserted.** The companion evidence lines in the gate report (below) are filled from the artifacts on disk, not from memory of what ran. A line with no artifact behind it is deleted, not written.
|
|
@@ -29,6 +29,8 @@ Gate 0 runs first because the rest of the report is only meaningful if the run b
|
|
|
29
29
|
- [ ] Flagged factors in the independent score (M/V/I low, F/A high) resolved. Two failure floors, not just a diagnosis: a severe flag in the independent score (M, V, or I at 1, or F or A at 5) is a FAIL that blocks ship unless the page is fixed. Acceptance of any lesser flag is the **user's** call in chat, never the builder's or the agent's own; an author accepting their own page's flag is the self-grading this gate exists to stop. `conversion-audit.md` must exist and carry both scores (Gate 0 already requires the file; this line requires the flags in it to be resolved, not merely recorded).
|
|
30
30
|
- [ ] Divergence interpreted, not just measured (the [TK] question). A wide self-versus-cold gap has two causes and they are handled differently. For each divergent factor, the audit says which: **recoverable** — the gap closes when a specific deferred `[TK]` artifact lands at build (name the TK: "I and F recover when the real install command replaces `[TK: install command]`"), so the factor is re-scored on the rendered page at the build-time Gate 1 re-run and only the residual counts; or **unexplained** — no deferred artifact accounts for it, so the builder scored optimistically and the gap is a real finding now, subject to the failure floors above. A divergence left un-attributed is treated as unexplained. On the rendered-page re-run, a factor tagged recoverable whose `[TK]` filled but whose score did not recover becomes an unexplained finding: the prediction was wrong, and the page owns the gap.
|
|
31
31
|
- [ ] Message hierarchy carried onto the page. Every claim in `message-architecture.md`'s hierarchy appears on the built page, in the priority order the hierarchy set, or the spec records the deviation with a reason (a claim cut for length, two claims merged in one section). The lead claim is in the hero. A page that drops or reorders the hierarchy without a recorded reason is not the page the message architecture specified; the fix is the page or a spec amendment, not a silent divergence. Mechanical aid: the claims are short and checkable by string presence, the same shape as the Gate 2 quote search.
|
|
32
|
+
- [ ] Reading experience scored, not just the argument (#50). The Friction factor accounts for whether a cold reader would **scan the rendered page in five seconds and want to keep going**, or bounce off an undifferentiated text block — because `voc.md` says design decides whether the copy is read at all. A wall of text is high reading-friction (F toward 4-5), even when the argument is sound; scoring F low on a visually-flat page is the dogfood's mistake. `conversion-audit.md` carries an explicit scannability/reading-friction assessment against the rendered page; a conversion audit that never scores the reading experience is incomplete and fails Gate 0.
|
|
33
|
+
- [ ] Red-team walk on record. `red-team.md` (Phase 3 step 3) exists and carries a walk per segment x entry state — each qualified reader reaching the CTA (rule 10) and the anti-persona self-disqualifying — with the bounce points named. Gate 0 requires the file; this line requires the bounce points it recorded to be answered on the built page or routed to open items with a reason. A conversion audit with no red-team walk behind it graded the page against no skeptical reader.
|
|
32
34
|
- [ ] Red-team read: one simulated skeptical reader per segment x entry state from the brief walks the page, each carrying the brief's Switching Dynamics (the Habit force as their reason to leave, the Anxiety force as their doubt at the CTA); every reader must reach the CTA. Any "not for me" exit by a qualified reader is a failure (conversion rule 10). One more reader built from the brief's anti-persona walks the page and should self-select out; an anti-persona reaching the CTA convinced means the page promises something the product does not do for them, and that is a failure too. Log bounce points and fix.
|
|
33
35
|
- [ ] Rewrite leaks answered (rewrites only). When the run began from an existing page, `rewrite-diagnosis.md` recorded where that page lost visitors and which conversion factors leaked. Each leak is answered on the new page, or listed in the run's open items with a reason it was not, and the ones the diagnosis said the current page kept because they worked are still present. A leak that the diagnosis named and the new page neither fixed nor consciously carried forward means the rewrite reproduced the old page's failure; that is the point of writing the diagnosis down. Greenfield build: N/A, no diagnosis exists.
|
|
34
36
|
- [ ] Anti-template check: this page's skeleton (the job order plus axis settings the spec records) compared against the `skeleton` lines of the property's last three runs in `foundry-log.md`. A match backed by `conversion data` on the matched run passes: converged because it converts. A match with no conversion data behind it is flagged, and the flag resolves one of two ways: the spec shows why this buyer's objection map landed on the same structure, or the skeleton goes back to Phase 2. No prior log for the property: N/A.
|
|
@@ -36,9 +38,11 @@ Gate 0 runs first because the rest of the report is only meaningful if the run b
|
|
|
36
38
|
## Gate 2: Voice
|
|
37
39
|
|
|
38
40
|
- [ ] `python3 scripts/voice_scan.py <files>` returns zero FAILs (banned phrases, em/en dashes in prose).
|
|
39
|
-
- [ ] Pattern pass done: every `AI language pattern` WARN resolved or accepted with a recorded reason (negative parallelism "not X, it's Y", copula avoidance "serves as", tailing negation "no X, no Y", significance inflation, authority trope, three-verb-clause runs, parallel-list uniformity). The patterns are deliberately WARN, not FAIL; an accepted WARN carries its reason on the `humanizer` line. **The humanizer skill was invoked once on the final copy, the rewrites that survived meaning arbitration applied, and
|
|
41
|
+
- [ ] Pattern pass done: every `AI language pattern` WARN resolved or accepted with a recorded reason (negative parallelism "not X, it's Y", copula avoidance "serves as", tailing negation "no X, no Y", significance inflation, authority trope, three-verb-clause runs, parallel-list uniformity). The patterns are deliberately WARN, not FAIL; an accepted WARN carries its reason on the `humanizer` line. **The humanizer skill was invoked once on the final copy, the rewrites that survived meaning arbitration applied, and the pass written to `copy/humanizer.md`: the before/after of each rewrite plus the WARNs kept with reasons.** That artifact is required by Gate 0 and must carry real diffs — a diff-less note is indistinguishable from a pass that never ran (#42). Humanizer proposes; meaning arbitrates: a rewrite that changes what a sentence claims is a defect, not a fix, and a second humanizer pass chasing zero tells is over-processing, not rigor. The scanner passing is necessary but not sufficient: structural uniformity across separate elements (a parallel roster) is beyond regex, so a scanner PASS with no humanizer pass is a Gate 2 **FAIL**, not a clean pass and not a footnote. humanizer is a core companion; on a full run it must run once on the final copy, and "not run" fails this gate the same way a missing core artifact fails Gate 0. The only way a full run reaches PASS with humanizer not run is the preflight override, which makes the whole run PARTIAL. Final copy means final: any copy edit after the pattern pass (a red-team fix from Gate 1, a build-time cut, a late rewrite) re-triggers the scan and the humanizer on the edited sections before this gate reports PASS.
|
|
40
42
|
- [ ] Verbatim-copy diff done: the built page's rendered text diffed against the approved-copy snapshot (build mode: `copy-approved.md`, frozen at the end of the copy-fit pass; handoff mode: the package's `01-copy.md`, when the built asset comes back). Every snapshot sentence appears in the build verbatim; any wording change went back through the Phase 3 re-trigger and the snapshot was rewritten from the re-scanned copy; prose the build introduced (button labels, microcopy, alt text) was scanned the same way. Drift that ships, or a snapshot edited to match a drifted build, fails this gate.
|
|
41
43
|
- [ ] Read-aloud pass done: no sentence the owner would not say to a client across a table.
|
|
44
|
+
- [ ] Copy-craft judged: voice-**compelling**, not just voice-clean (#51). The scanner and humanizer are ABSENCE checks (no banned words, no AI patterns); a page can pass both and still be generic and forgettable, which is what the dogfood shipped. This is the PRESENCE check, scored in the property's register (dry for a skeptical dev audience, never hype), and written to `copy-craft.md`: **specificity** (real numbers, named results, concrete nouns, not "unlock your potential"), a memorable **through-line / model-phrase**, **varied pacing** (short punchy next to longer context), and **objection pre-emption** (doubts answered where they arise). At least three of the four, each with a specific on the page. Voice-clean copy that is generic and flat still fails this; `run_audit.py` requires `copy-craft.md` to score three-plus dimensions.
|
|
45
|
+
- [ ] Outcome-vs-mechanics framing (SOFT, WARN, human-reviewed — never an auto-fail). For each value claim, does it name a buyer-relevant OUTCOME, or the pipeline's own PROCESS (gates, phases, "9 gates", "the spec", "the pipeline", companion or tool names)? "Every page clears the gates before it leaves the shop" sells the mechanics; "a page that looks great and converts" sells the outcome. This is deliberately not a hard "never sell mechanics" rule: some products ARE their mechanics (a testing or security tool), and that per-product call is made once in the Design-Strategy phase and recorded as `mechanics-as-value: yes` in `design-strategy.md`. `run_audit.py` emits a soft WARN when process language is prevalent (3+ references) and that decision is not set to yes; a human reads the flag and reframes or confirms it is correct for this product. It never blocks ship (#45).
|
|
42
46
|
- [ ] No fabricated specificity: every number and name traces to the proof inventory, and every quote is checked by search, not by memory. Extract each quoted string and testimonial from the rendered page and search `voc.md` for it: the quote must appear character for character in the Verbatim section, or in the brief's proof inventory for proof the buyer handed over directly. A quote the search cannot find does not go on the page.
|
|
43
47
|
|
|
44
48
|
## Gate 3: Accessibility (WCAG 2.2 AA spot checks)
|
|
@@ -71,9 +75,11 @@ With the webapp-testing skill installed, walk the interactive checks below (focu
|
|
|
71
75
|
- [ ] Squint test on the captures: blur each screenshot (or squint at it) and the primary element, the secondary element, and the groupings must still be identifiable within 2 seconds, the hero first, then section by section. A page that fails blurred has a hierarchy problem, and the fix is composition (weight, scale, spacing) inside the committed tokens, not a palette change. The craft rule and its criterion live in `references/design-direction.md`; this line is where the built page faces it.
|
|
72
76
|
- [ ] Design-to-research trace: the design direction's scene sentence names the ICP segment and entry state it was drawn from (`references/design-direction.md`), and that segment exists in the brief or `voc.md`. A scene sentence that could describe any page for any buyer means the aesthetic was chosen without the research, which is the failure Phase 4's required reads exist to prevent; send it back to write the scene from the actual reader. Handoff mode: the manifest carries the scene sentence, checked pre-delivery.
|
|
73
77
|
- [ ] Grid and recomposition check: read the built CSS against the token plan's grid spec. Container max-widths, the column structure of the densest section, and gutter values must match the spec'd custom properties in `theme.css`; a mismatch is fixed in the page, or the spec is amended with the reason recorded in the token plan file, and silent divergence between spec and build fails. Then walk the recomposition notes: at each breakpoint a note names, the hero and the densest section re-form as written, and when a named breakpoint falls between the standard screenshot widths, screenshot that width too instead of inferring the layout from the CSS. Handoff mode: the external tool owns the grid within the manifest geometry (`references/handoff.md`), so on the returned build this line reads N/A with that reason.
|
|
74
|
-
- [ ] Design detect scan (impeccable is core, so this always runs on a full run): run its detector over the built HTML and CSS (`node <impeccable skill dir>/scripts/detect.mjs --json pages/<product>/`, or `npx impeccable detect --json`), from the product's repo root so the property's `.impeccable/config.json` ignores and `DESIGN.md` token enforcement apply; a persisted `DESIGN.md` makes off-palette colors, radii, and fonts findings, which is why Phase 4 step 8 wrote it. The scan prints an empty JSON array and exits 0 when clean, a findings array and a non-zero exit otherwise; the findings list is the array. Resolve every entry one of two ways: fix the page, or accept the finding into the product's `.impeccable/config.json` under `detector.ignoreValues` with a `reason`. That file is the per-property accepted-findings record, and an ignore without a reason is a suppressed finding, not an accepted one. The `impeccable` evidence line carries the finding count, what was fixed, and each accepted finding with its reason. The only run that skips the detector is one where the user overrode impeccable at preflight: that run is already PARTIAL, its design was never mechanically checked, and the anti-slop critique in `references/design-direction.md` is the acknowledged-weaker stand-in, not an equal substitute.
|
|
78
|
+
- [ ] Design detect scan (impeccable is core, so this always runs on a full run): run its detector over the built HTML and CSS (`node <impeccable skill dir>/scripts/detect.mjs --json pages/<product>/`, or `npx impeccable detect --json`), from the product's repo root so the property's `.impeccable/config.json` ignores and `DESIGN.md` token enforcement apply; a persisted `DESIGN.md` makes off-palette colors, radii, and fonts findings, which is why Phase 4 step 8 wrote it. The scan prints an empty JSON array and exits 0 when clean, a findings array and a non-zero exit otherwise; the findings list is the array. **Redirect that JSON into `.impeccable/detect-scan.json`** — it is the design gate's artifact, and Gate 0 requires it because a deterministic tool's output cannot be convincingly hand-faked, so a run that skipped the detector is caught by its absence (#42). Resolve every entry one of two ways: fix the page, or accept the finding into the product's `.impeccable/config.json` under `detector.ignoreValues` with a `reason`. That file is the per-property accepted-findings record, and an ignore without a reason is a suppressed finding, not an accepted one. The `impeccable` evidence line carries the finding count, what was fixed, and each accepted finding with its reason. The only run that skips the detector is one where the user overrode impeccable at preflight: that run is already PARTIAL, its design was never mechanically checked, and the anti-slop critique in `references/design-direction.md` is the acknowledged-weaker stand-in, not an equal substitute.
|
|
75
79
|
- [ ] The header doctrine, applied to the detect scan: zero findings means no known visual tell fired, not that the design is good. The screenshot critique and the squint test above still run in full, and an accepted finding is a recorded style choice, not a waived check.
|
|
76
|
-
- [ ]
|
|
80
|
+
- [ ] Independent taste judge (voice + design), and it is **BLOCKING** (#48). The mechanical scans (voice_scan, detect) are floors; taste needs an arbiter, and a same-family pass (`/impeccable critique`, a self-walk) is Claude blessing Claude's slop — to escape the blind spot the judge must be cross-family or human. Hand a FRESH context — ideally a cross-family model (the codex/GPT path used for gut-checks, or a configured alternative) or a human — only the rendered page and the design reference, never the author or the drafting context, and score TWO named axes as structured lines in `taste-judge.md`: `visual-engagement:` (is the reading experience structured, or a flat wall of text?) and `property-specificity:` (could this only belong to this product, or is it a generic skeleton?). Name the tells. A FAIL on either axis is a **Gate 5 FAIL**, not a logged note: the flat page that shipped on the 2026-07-27 dogfood had a cross-family "flat/skeleton" verdict and shipped anyway because the judge was advisory. Acceptance of a negative verdict is the **user's** call in chat (`accepted: <reason>` in the artifact), never the builder's own. Where no cross-family or human judge is reachable, say so in `taste-judge.md` and do not fake independence. A same-family critique presented as the independent judge, or a negative verdict shipped full without acceptance, is the failure this line exists to prevent.
|
|
81
|
+
- [ ] The render review is a quality call on an ACCURATE capture, not a brokenness check on a racy one (#53). interceptor's default DOM-render screenshot (and `loop/pf-render.sh`) is racy on webfont pages — it paints phantom text collisions that are not in the layout. Verify layout via `interceptor eval --main` + `getBoundingClientRect` (all heading→body gaps positive) and a pixel-true capture (`--pixel`, Chrome focused); do NOT trust the DOM-render composite for QA. Then make the explicit engagement/quality judgment above. A render review that only confirms the page is not broken has not run — that is how the dogfood's reviewer rubber-stamped a wall of text.
|
|
82
|
+
- [ ] Imagery was designed, not defaulted, and "image-light by choice" is not a free pass (#49). `imagery-plan.md` exists and every image on the built page traces to a slot in it, at the treatment the plan specifies (crop, aspect ratio, grade, frame); a set of images that do not share the plan's consistency rules reads as a scatter, not art direction, and fails. Text is not the enemy — flat text is — so a section the plan declares image-light must **name the engagement mechanism** that carries it (typographic hierarchy, emphasis, pull-quotes/callouts, numbered rhythm, visual breaks, varied pacing), and Gate 5 confirms that mechanism is actually present on the built page. A bare "no image by choice" with no mechanism named, or a page that fell back to an unplanned wall of text and CSS boxes, fails: that default is exactly the flat page the dogfood shipped. Product screenshots are real captures of real use (Gate 8 owns that check; this line owns whether the section was art-directed or engagement-designed at all).
|
|
77
83
|
- [ ] States and motion walk, not just render. `states-motion.md` exists, and the built page's designed states are present: with a render tool, drive the primary form to its error state and confirm the designed error (not the browser default) shows and announces via `aria-live`, then to its success state; trigger any copy-button, accordion, or interactive element and confirm its designed state. Focus and hover match the personality the file specifies, not the UA default. Page-level motion respects `prefers-reduced-motion` with the static fallback the file names. A page whose states are browser defaults ships the behavioral equivalent of the generic look and fails; the fix is designing the states in Phase 4, not adding them at the gate. Without a render tool, read the CSS and markup for the state styles and the reduced-motion query and flag any the plan named but the build omitted.
|
|
78
84
|
- [ ] Render breadth beyond one engine at two widths. The 390/1440 Chromium pair is the floor, not the whole review. When webapp-testing or a Playwright install is present, also capture the two mid widths a real audience uses (768 tablet, 1024 small laptop) and one non-Chromium engine (WebKit or Firefox) at 390 and 1440, and diff the non-Chromium captures against the Chromium ones: a layout that only holds in Chromium is a real defect, since the audience does not all use Chrome. Fix anything the extra widths or the second engine surface, or record why a difference is acceptable. When only Chromium is available, capture 768 and 1024 there and note in the report that cross-engine was not run rather than claiming a breadth the environment could not deliver.
|
|
79
85
|
- [ ] Comp record present (build mode): the comp stage ran and left its record, `comp/rounds.md` or the critique snapshots under the product's `.impeccable/critique/`, with the league verdict answered (SKILL.md Phase 4.5). The ceiling question lives there, and this gate checks it was faced: a league-level weakness surfacing here that no round recorded means the stage was skipped or shallow, and the fix is comp rounds against the direction's scene sentence and anchors, not patching at the gate. A build-mode run with no comp record fails this line. Handoff mode: N/A, the tool's revision rounds own comp iteration per `references/handoff.md`.
|
|
@@ -174,6 +174,8 @@ Patterns to kill on sight (from Wikipedia's "Signs of AI writing" and the seo-au
|
|
|
174
174
|
- **Parallel-list uniformity.** A list where every item opens the same way ("Finds... / Pulls... / Structures... / Writes..."). Uniform openings across a set read as machine-made even when each item is fine alone. Vary the grammatical shape item to item. (The scanner flags a plain prose run of these; a list spread across separate DOM elements with labels is beyond regex, which is why the humanizer pass is a hard gate, not a suggestion.)
|
|
175
175
|
- **Aphoristic contrast.** `Not a feature. A platform.` Two clipped sentences manufacturing a contrast. One on a page can be a choice; the cadence is the tell, and three or more is a rewrite, not a review. (Caught by the `aphoristic contrast` regex.)
|
|
176
176
|
- **Aphoristic rebuttal.** A sentence answered by a short `No ...` or `Just ...` sentence: `You ship the page. No guessing.` Same threshold: once reads as voice, a page that keeps landing on the rebuttal reads as generated. The scanner flags every instance; Phase 3 applies the three-per-page line when deciding rewrite versus accept-with-reason. (Caught by the `aphoristic rebuttal` regex.)
|
|
177
|
+
- **Trailing contrast fragment.** `Real customer language, not a guess.` A noun phrase with a `, not a/the/your ...` tail bolted on for emphasis. Write the positive claim as a clause, or cut the tail. (Caught by the `trailing contrast fragment` regex.)
|
|
178
|
+
- **Standalone appositive fragment.** `The claims, in the order your buyer raises objections.` A determiner-noun opener, a comma, then a prepositional modifier, with no main verb — a caption masquerading as a sentence. Give it a verb or fold it into the sentence before it. (Caught by the `standalone appositive` regex; the two-beat aphorism `Built from it, in your voice.` is beyond regex and is the humanizer's catch.)
|
|
177
179
|
|
|
178
180
|
<!-- scan:patterns -->
|
|
179
181
|
# AI language patterns, WARN-level. Format: NAME|||REGEX (case-insensitive). Reviewed and fixed in Phase 3.
|
|
@@ -188,6 +190,10 @@ three parallel verb-clauses|||\b[a-z]+s\b[^,.;:!?]{2,60},\s+[a-z]+s\b[^,.;:!?]{2
|
|
|
188
190
|
# The two aphoristic patterns keep their case sensitivity inside (?-i:...) because sentence casing is the signal.
|
|
189
191
|
aphoristic contrast|||(?-i:\bNot an? [a-z][^.!?]{1,40}[.!]\s+[A-Z][^.!?]{1,60}[.!])
|
|
190
192
|
aphoristic rebuttal|||(?-i:\b[A-Z][^.!?]{4,80}[.!]\s+(?:No|Just)\s+[a-z][^.!?]{2,60}[.!])
|
|
193
|
+
# Two high-signal, low-false-positive fragment tells (#47). The floor catches these two shapes;
|
|
194
|
+
# the appositive-fragment tail and two-beat aphorisms a regex cannot pin are the humanizer's job.
|
|
195
|
+
trailing contrast fragment|||[a-z]{3,},\s+not\s+(a|an|the|your|just|merely|simply|another|more)\b
|
|
196
|
+
standalone appositive|||(?-i:\b(The|A|An|These|Those|Your|Our|Real)\s+[a-z]+(?:\s+[a-z]+){0,2},\s+(in|of|for|with|from|on|by|across|behind|without)\s+(the|a|an|your|its|their|our|every|each|this|that|one)\b[^.!?]{0,45}[.!])
|
|
191
197
|
<!-- /scan:patterns -->
|
|
192
198
|
|
|
193
199
|
## Replacement strategy
|