fix: craft audit live-page limits, claim handling and guards (GSTA-92)

- craft-audit: linked CSS/JS is unchecked on a saved page (judge by eye);
  a mount-node shell is framework source; --accepted takes that screen's
  finalized.json or none; on a live page a claim without proof is filed and
  asked about, never marked or cut; the saved page is removed whatever the
  exit code; shorter fix-order and Tailwind prose keeps the union under cap
- tests: exact-lead red cases, autoFixEntries in the checkerOnly union, the
  audit's outcome/exception/session-data clauses; carve guard checks the
  session-data rule and records measured sizes (skeleton cap 137_767)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-26 02:09:01 +00:00
1 parent 31ee450399
commit bed645a20e
6 files changed
+31 -18

No files matched your search

+2 -2
View File
@@ -5,7 +5,7 @@
### Changed
- **The archetype the user picks on the /design-shotgun board now reaches /design-html.** Captions name the archetype id (`classic-hero`, `long-form-story`, `minimal-conversion`, `comparison`). On approval, approved.json also gets the chosen `archetype` and its `sections` outline, added with the Edit tool so no free text reaches a shell command. /design-html reads both in Case A, and the craft section uses them as given instead of choosing again or asking.
- **Accepted craft exceptions persist.** /design-html's finalized.json records each accepted `CRAFT_CHECK` finding in `craft_exceptions` (`id`, `count`, `reason`) and carries forward earlier ones. A later run passes that file with `--accepted`, so a finding the user already accepted is reported as accepted instead of flagged again. A higher count is still flagged as a new issue.
- **/design-review audits a Persuade page or a redesign for craft, or on request** (`sections/craft-audit.md`, read in Phases 1-6; design-review is now carved on every host, so the audit is one lazy section, not inlined text). It runs `bin/gstack-design-craft` on each page's served HTML (or the repo file when no app runs) and files each `CRAFT_CHECK` line as a category 9 finding (no `CRAFT_RESULT` line means the check was unavailable; the saved page holds session data, so it is deleted in the block that checks it and never copied to the report; `--accepted` applies only to a page /design-html finalized, and never to `needs-proof` or `lorem`; a live page never gets a `[Needs proof: …]` marker); checks what the tool cannot see (claims only from the user, realistic sample content, the ship floor, a designed 404, cookie consent where required, the motion rules); files a failed Persuade check (one primary action, named objections, proof beside each claim, a real risk reversal, an index/noindex decision) as High impact; and in Phase 8 breaks impact ties with Elaya's fix order and reads the installed Tailwind major version before touching its config. The audit's rules render from /design-html's craft section, so the build and the audit cannot drift.
- **/design-review audits a Persuade page or a redesign for craft, or on request** (`sections/craft-audit.md`, read in Phases 1-6; design-review is now carved on every host, so the audit is one lazy section, not inlined text). It runs `bin/gstack-design-craft` on each page's served HTML (or the repo file when no app runs) and files each `CRAFT_CHECK` line as a category 9 finding (no `CRAFT_RESULT` line means the check was unavailable, and a framework mount-node shell counts as framework source; the saved page holds only inline CSS and JS, so tells in linked files are judged by eye; it also holds session data, so it is deleted in the block that checks it, whatever the exit code, and never copied to the report; `--accepted` takes that screen's finalized.json, only for a page /design-html finalized, and never covers `needs-proof` or `lorem`; on a live page a claim without proof is filed and asked about, never marked or cut); checks what the tool cannot see (claims only from the user, realistic sample content, the ship floor, a designed 404, cookie consent where required, the motion rules); files a failed Persuade check (one primary action, named objections, proof beside each claim, a real risk reversal, an index/noindex decision) as High impact; and in Phase 8 breaks impact ties with Elaya's fix order and reads the installed Tailwind major version before touching its config. The audit's rules render from /design-html's craft section, so the build and the audit cannot drift.
- **/plan-design-review**: a Persuade plan gets the same five checks in Pass 1, Pass 4 rejects unsourced proof, and the runner checklist names them.
- **The craft tells are catalog entries.** Placeholder people and brands, lorem, round sample numbers, `[Needs proof:` markers, "Oops" errors, scroll-listener reveals, dead `href="#"`, `alert()`, images without alt, `100vh`, and a missing title, description, favicon, skip link or `aria-current` live in `lib/design-catalog.ts` as `checkerOnly` entries: one id, one short line and the fix, reported by the craft check and kept out of Methodology category 9, `review/design-checklist.md` and the consultation bullets, so no skill carries their prose. `lib/design-craft.ts` prints only catalog ids, with each entry's `fix` text; `transition: all` now reports under the existing `layout-transition` id instead of `transition-all`.
@@ -18,7 +18,7 @@
- `test/helpers/placeholder-allowlist.ts` lists `<path-to-page.html>` (path grammar), the saved page the craft audit passes to the check.
- The design-review and plan-design-review paid cases and judges that read a design resolver now also select on `scripts/resolvers/design-craft.ts`, and `design-html-slop-gate` on `lib/design-catalog.ts`, where the craft check's ids and fixes now live.
- `test/design-craft.test.ts`: every id the check prints is a grep-detectable catalog entry, and the fix it prints is the catalog's. design-review gets its first carve guard (skeleton, union and parity ratio at their measured sizes).
- `test/design-craft.test.ts` also pins that `checkerOnly` entries reach no rendered list while the craft check prints each one, that a change to `scripts/resolvers/design-craft.ts` selects the design-review and plan-design-review cases, and the exception cells a stale record, an over-count tell without `--accepted` and a malformed record on disk reach. New `test/design-craft-resolvers.test.ts`: `{{DESIGN_CRAFT_RULE}}` renders one paragraph with its bullets and fails generation on a missing or ambiguous lead, and both skills carry the same five Persuade checks.
- `test/design-craft.test.ts` also pins that `checkerOnly` entries reach no rendered list while the craft check prints each one, that a change to `scripts/resolvers/design-craft.ts` selects the design-review and plan-design-review cases, and the exception cells a stale record, an over-count tell without `--accepted` and a malformed record on disk reach. New `test/design-craft-resolvers.test.ts`: `{{DESIGN_CRAFT_RULE}}` renders one paragraph with its bullets and fails generation on a missing or ambiguous lead, and both skills carry the same five Persuade checks; the generated craft audit keeps its outcome, exception and session-data rules (and the design-review carve guard checks the last one).
### Gate integrity
- Size budgets raised to measured sizes only (Garry 2026-10-25 "Do it" (GSTA-92)): the SKILL.md pins of design-review on 12 hosts (+578 Claude, +608 on the 11 external hosts: the Section index the carve test requires and the STOP pointer) and plan-design-review on the 11 external hosts (+1,082: the five Persuade plan checks). The craft tells are catalog entries the craft check reports with their fix, kept out of every rendered skill list, so design-consultation and the review checklist do not grow. No other threshold, budget, timeout, retry or trial count changed.
+5 -5
View File
@@ -6,13 +6,13 @@ Run this in Phases 1-6, on every audited page, when a page is Persuade (the clas
### 1. Run the craft check on each page
With a URL, save the page in the script that opens it. Aside: add `await fs.writeFile(path.join(pwd, "{page}.page.html"), await pg.evaluate(() => document.documentElement.outerHTML));`. Fallback engine: `_TMP=$(mktemp -d "${TMPDIR:-/tmp}/gstack-craft.XXXXXX"); $B js 'document.documentElement.outerHTML' --out "$_TMP/{page}.page.html" --raw`. With no running app, use the page's HTML file in the repo. A saved page holds session data: `rm -f` it in the block that checks it, and never copy it to the report directory.
With a URL, save the page in the script that opens it. Aside: add `await fs.writeFile(path.join(pwd, "{page}.page.html"), await pg.evaluate(() => document.documentElement.outerHTML));`. Fallback engine: `_TMP=$(mktemp -d "${TMPDIR:-/tmp}/gstack-craft.XXXXXX"); $B js 'document.documentElement.outerHTML' --out "$_TMP/{page}.page.html" --raw`. With no running app, use the page's HTML file in the repo. A saved page holds session data: whatever the exit code, `rm -rf` it (or `$_TMP`) in the block that checks it, and never copy it to the report directory.
```bash
~/.claude/skills/gstack/bin/gstack-design-craft <path-to-page.html>
```
Each `CRAFT_CHECK: <id> <count> <fix>` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source, an empty or unreadable file): say the check was unavailable for that page and judge the tells below by eye. For a page /design-html finalized, add `--accepted <its finalized.json>` (under `$GSTACK_STATE_ROOT/projects/$SLUG/designs/`): a `CRAFT_ACCEPTED` line is a finding the user accepted, listed with its reason, not filed again, except `needs-proof` and `lorem`, which a live page cannot carry. After a `cannot use exceptions` warning, file every line. A hit the user's real content explains (a customer named Nexus, a supplied 50% figure) is noted, not filed. Never add a `[Needs proof: …]` marker to a live page: file the claim, then cut it or ask.
Each `CRAFT_CHECK: <id> <count> <fix>` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source, including a mount-node shell, or an empty or unreadable file): say the check was unavailable for that page and judge the tells below by eye. A saved page holds only inline CSS and JS: judge `100vh`, `transition: all`, scroll listeners and `alert()` in linked files by eye. For a page /design-html finalized, add `--accepted` with that screen's finalized.json (under `$GSTACK_STATE_ROOT/projects/$SLUG/designs/`; unsure: omit it): a `CRAFT_ACCEPTED` line is a finding the user accepted, listed with its reason, not filed again, except `needs-proof` and `lorem`, which a live page cannot carry. After a `cannot use exceptions` warning, file every line. A hit real user content explains (a customer named Nexus) is noted, not filed. On a live page, never mark or cut a claim as the rules below say: file it and ask for the proof.
### 2. What the check cannot see
@@ -39,7 +39,7 @@ Beyond the document: a made-up path returns a designed 404 with a way back, ever
### 3. Persuade pages
A failed check costs the page its one job: file it as a High-impact finding.
File a failed check as High impact.
1. **One primary action**, named; nothing competes with it above the fold, and the closing CTA repeats it.
2. **Named objections**: the visitor's top objections, each answered where it arises (FAQ of real questions, comparison, guarantee).
@@ -56,8 +56,8 @@ A failed check costs the page its one job: file it as a High-impact finding.
### 4. Fix order and stack (Phase 8)
Within one impact level, take the biggest visible gain at the least risk first: typeface and type roles; color and surfaces; hover, active and focus states; layout and spacing (grid, max width, spacing scale, nested radius); motion; generic components; loading, empty and error states; copy; type-scale polish.
Within one impact level, take the biggest visible gain at the least risk first: type, color, hover/active/focus states, layout and spacing, motion, components, loading/empty/error states, copy, type-scale polish.
Work inside the existing stack: no framework or styling migration, and check the dependency file before importing a library. With Tailwind, read the installed major version (`tailwindcss` in package.json or the lockfile) before touching its config: v3 configures in `tailwind.config.*`, v4 in CSS (`@import "tailwindcss"` and `@theme`). Write for that version only.
Work inside the existing stack: no framework or styling migration; check the dependency file before importing a library. With Tailwind, write for the installed major (`tailwindcss` in package.json or the lockfile): v3 configures `tailwind.config.*`, v4 CSS (`@import "tailwindcss"`, `@theme`).
Adapted from Elaya's [redesign-skill](https://github.com/elayadesign/redesign-skill) and [ai-design-skills](https://github.com/elayadesign/ai-design-skills) (MIT, © 2026 Elaya), rewritten for gstack. See NOTICE.md.
+5 -5
View File
@@ -4,13 +4,13 @@ Run this in Phases 1-6, on every audited page, when a page is Persuade (the clas
### 1. Run the craft check on each page
With a URL, save the page in the script that opens it. Aside: add `await fs.writeFile(path.join(pwd, "{page}.page.html"), await pg.evaluate(() => document.documentElement.outerHTML));`. Fallback engine: `_TMP=$(mktemp -d "${TMPDIR:-/tmp}/gstack-craft.XXXXXX"); $B js 'document.documentElement.outerHTML' --out "$_TMP/{page}.page.html" --raw`. With no running app, use the page's HTML file in the repo. A saved page holds session data: `rm -f` it in the block that checks it, and never copy it to the report directory.
With a URL, save the page in the script that opens it. Aside: add `await fs.writeFile(path.join(pwd, "{page}.page.html"), await pg.evaluate(() => document.documentElement.outerHTML));`. Fallback engine: `_TMP=$(mktemp -d "${TMPDIR:-/tmp}/gstack-craft.XXXXXX"); $B js 'document.documentElement.outerHTML' --out "$_TMP/{page}.page.html" --raw`. With no running app, use the page's HTML file in the repo. A saved page holds session data: whatever the exit code, `rm -rf` it (or `$_TMP`) in the block that checks it, and never copy it to the report directory.
```bash
{{BIN_DIR}}/gstack-design-craft <path-to-page.html>
```
Each `CRAFT_CHECK: <id> <count> <fix>` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source, an empty or unreadable file): say the check was unavailable for that page and judge the tells below by eye. For a page /design-html finalized, add `--accepted <its finalized.json>` (under `$GSTACK_STATE_ROOT/projects/$SLUG/designs/`): a `CRAFT_ACCEPTED` line is a finding the user accepted, listed with its reason, not filed again, except `needs-proof` and `lorem`, which a live page cannot carry. After a `cannot use exceptions` warning, file every line. A hit the user's real content explains (a customer named Nexus, a supplied 50% figure) is noted, not filed. Never add a `[Needs proof: …]` marker to a live page: file the claim, then cut it or ask.
Each `CRAFT_CHECK: <id> <count> <fix>` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source, including a mount-node shell, or an empty or unreadable file): say the check was unavailable for that page and judge the tells below by eye. A saved page holds only inline CSS and JS: judge `100vh`, `transition: all`, scroll listeners and `alert()` in linked files by eye. For a page /design-html finalized, add `--accepted` with that screen's finalized.json (under `$GSTACK_STATE_ROOT/projects/$SLUG/designs/`; unsure: omit it): a `CRAFT_ACCEPTED` line is a finding the user accepted, listed with its reason, not filed again, except `needs-proof` and `lorem`, which a live page cannot carry. After a `cannot use exceptions` warning, file every line. A hit real user content explains (a customer named Nexus) is noted, not filed. On a live page, never mark or cut a claim as the rules below say: file it and ask for the proof.
### 2. What the check cannot see
@@ -26,7 +26,7 @@ Beyond the document: a made-up path returns a designed 404 with a way back, ever
### 3. Persuade pages
A failed check costs the page its one job: file it as a High-impact finding.
File a failed check as High impact.
{{DESIGN_PERSUADE_CHECKS}}
@@ -34,8 +34,8 @@ A failed check costs the page its one job: file it as a High-impact finding.
### 4. Fix order and stack (Phase 8)
Within one impact level, take the biggest visible gain at the least risk first: typeface and type roles; color and surfaces; hover, active and focus states; layout and spacing (grid, max width, spacing scale, nested radius); motion; generic components; loading, empty and error states; copy; type-scale polish.
Within one impact level, take the biggest visible gain at the least risk first: type, color, hover/active/focus states, layout and spacing, motion, components, loading/empty/error states, copy, type-scale polish.
Work inside the existing stack: no framework or styling migration, and check the dependency file before importing a library. With Tailwind, read the installed major version (`tailwindcss` in package.json or the lockfile) before touching its config: v3 configures in `tailwind.config.*`, v4 in CSS (`@import "tailwindcss"` and `@theme`). Write for that version only.
Work inside the existing stack: no framework or styling migration; check the dependency file before importing a library. With Tailwind, write for the installed major (`tailwindcss` in package.json or the lockfile): v3 configures `tailwind.config.*`, v4 CSS (`@import "tailwindcss"`, `@theme`).
Adapted from Elaya's [redesign-skill](https://github.com/elayadesign/redesign-skill) and [ai-design-skills](https://github.com/elayadesign/ai-design-skills) (MIT, © 2026 Elaya), rewritten for gstack. See NOTICE.md.
+13
View File
@@ -25,6 +25,8 @@ describe('craft resolvers', () => {
expect(DESIGN_CRAFT_RULE(ctx, ['Claims come from the user'])).toStartWith('**Claims come from the user, never from you.**');
expect(read('design-html', 'sections', 'craft.md')).toContain(motion);
expect(() => DESIGN_CRAFT_RULE(ctx, ['No such lead'])).toThrow('No such lead');
expect(() => DESIGN_CRAFT_RULE(ctx, ['Claims'])).toThrow('0 paragraphs');
expect(() => DESIGN_CRAFT_RULE(ctx, ['Mot'])).toThrow('need exactly one');
expect(() => DESIGN_CRAFT_RULE(ctx, [])).toThrow('requires the bold lead');
expect(() => DESIGN_CRAFT_RULE(ctx)).toThrow('requires the bold lead');
});
@@ -35,4 +37,15 @@ describe('craft resolvers', () => {
expect(read('design-review', 'sections', 'craft-audit.md')).toContain(checks);
expect(read('plan-design-review', 'sections', 'review-sections.md')).toContain(checks);
});
test('the design-review craft audit settles each check outcome and exception kind, and keeps the saved page private', () => {
const audit = read('design-review', 'sections', 'craft-audit.md');
expect(audit).toContain('line is one category 9 finding under that id');
expect(audit).toContain('no `CRAFT_RESULT` line (framework source');
expect(audit).toContain('add `--accepted` with that screen\'s finalized.json');
expect(audit).toContain('a `CRAFT_ACCEPTED` line is a finding the user accepted, listed with its reason, not filed again, except `needs-proof` and `lorem`');
expect(audit).toContain('After a `cannot use exceptions` warning, file every line.');
expect(audit).toContain('On a live page, never mark or cut a claim');
expect(audit).toContain('never copy it to the report directory');
});
});
+2 -2
View File
@@ -4,7 +4,7 @@ import * as os from 'os';
import * as path from 'path';
import { acceptFindings, BUZZWORDS, CRAFT_IDS, checkCraft, formatCraft, parseCraftExceptions, visibleText } from '../lib/design-craft';
import { catalogEntry, DESIGN_SLOP_CATALOG, detectorSlopEntries, judgmentTellEntries, renderCatalog, selectCatalog } from '../lib/design-catalog';
import { checklistSlopEntries } from '../scripts/resolvers/design-checklist';
import { autoFixEntries, checklistSlopEntries } from '../scripts/resolvers/design-checklist';
import { selectTests } from './helpers/test-selection';
import { E2E_TOUCHFILES, LLM_JUDGE_TOUCHFILES } from './helpers/touchfiles-data';
@@ -64,7 +64,7 @@ describe('design-craft check', () => {
test('checker-only catalog entries are craft ids that no rendered list carries; catalog entries with a fix still render', () => {
const checkerOnly = DESIGN_SLOP_CATALOG.filter(e => e.checkerOnly);
expect(checkerOnly.length).toBeGreaterThan(0);
const rendered = new Set([selectCatalog({}), detectorSlopEntries(), judgmentTellEntries(), checklistSlopEntries()].flat().map(e => e.id));
const rendered = new Set([selectCatalog({}), detectorSlopEntries(), judgmentTellEntries(), checklistSlopEntries(), autoFixEntries()].flat().map(e => e.id));
const prose = renderCatalog({ kind: 'slop' });
for (const e of checkerOnly) {
expect(CRAFT_IDS, e.id).toContain(e.id);
+4 -4
View File
@@ -751,10 +751,10 @@ do not launch the downstream skill or open a browser.`,
// No section-loading paid case yet: a new periodic case would push the
// periodic census past its 38-slice cap (test/paid-retry-supervision.test.ts).
behavioral: 'none',
maxSkeletonBytes: 137_773, // measured 137773 (2026-10-25): the Section index the external-host carve test requires, its craft-audit row, and the STOP pointer (GSTA-92; Garry 2026-10-25 'Do it' (GSTA-92)).
minUnionBytes: 143_300, // measured union 145082
mustContain: ['AI Slop Detection', 'Fix Loop', 'gstack-design-craft', 'Proof beside each claim'],
maxSizeRatio: 1.3708, // first parity guard for design-review: measured 145082 / 105,842 = 1.3708 (2026-10-25), the skeleton's growth since v1.64.1.0 plus the craft audit (Garry 2026-10-25 'Do it' (GSTA-92)).
maxSkeletonBytes: 137_767, // measured 137767 (2026-10-26; 137773 on 2026-10-25 before the shorter craft-audit trigger): the Section index the external-host carve test requires, its craft-audit row, and the STOP pointer (GSTA-92; Garry 2026-10-25 'Do it' (GSTA-92)).
minUnionBytes: 143_300, // measured union 145077 (2026-10-26)
mustContain: ['AI Slop Detection', 'Fix Loop', 'gstack-design-craft', 'Proof beside each claim', 'holds session data'],
maxSizeRatio: 1.3708, // first parity guard for design-review: measured 145082 / 105,842 = 1.3708 (2026-10-25; 145077 after the /ship review fixes, 2026-10-26), the skeleton's growth since v1.64.1.0 plus the craft audit (Garry 2026-10-25 'Do it' (GSTA-92)).
},
// ── Token-reduction Phase 4 wave 4 (v1.69.x branch): design doctrine carve ──