From 236869adf3ccb7eb138c8caa8816a18b2d4a9eec Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 26 Oct 2026 10:19:48 +0000 Subject: [PATCH] fix: pre-landing review fixes after main merge: claim rule covers repo files, craft temp var, guard tests (GSTA-92) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 2 +- design-review/sections/craft-audit.md | 4 ++-- design-review/sections/craft-audit.md.tmpl | 4 ++-- test/design-craft-resolvers.test.ts | 2 +- test/design-craft.test.ts | 4 +++- test/external-host-carve.test.ts | 2 +- test/helpers/carve-guards.ts | 4 ++-- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e08456b33..39cbe57d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## [Unreleased] ### Changed -- **/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 is judged by eye too; 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. +- **/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 is judged by eye too; 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`; 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`. diff --git a/design-review/sections/craft-audit.md b/design-review/sections/craft-audit.md index 4a4d2365a..c35813bc0 100644 --- a/design-review/sections/craft-audit.md +++ b/design-review/sections/craft-audit.md @@ -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}.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`. 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. With no running app, use the page's HTML file in the repo. +With a URL, save the page in the script that opens it. Aside: add `await fs.writeFile(path.join(pwd, ".{page}.html"), await pg.evaluate(() => document.documentElement.outerHTML));`. Fallback engine: `_CR=$(mktemp -d "${TMPDIR:-/tmp}/gstack-craft.XXXXXX"); $B js 'document.documentElement.outerHTML' --out "$_CR/{page}.page.html" --raw`. A saved page holds session data: whatever the exit code, `rm -rf` it (or `${_CR:?}`) in the block that checks it, and never copy it to the report directory. With no running app, use the page's HTML file in the repo. ```bash ~/.claude/skills/gstack/bin/gstack-design-craft ``` -Each `CRAFT_CHECK: ` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source or an empty or unreadable file) or a mount-node shell: 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. +Each `CRAFT_CHECK: ` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source or an empty or unreadable file) or a mount-node shell: 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. Never mark or cut a claim as the rules below say: file it and ask for the proof. ### 2. What the check cannot see diff --git a/design-review/sections/craft-audit.md.tmpl b/design-review/sections/craft-audit.md.tmpl index 219537aaa..6d49d0df3 100644 --- a/design-review/sections/craft-audit.md.tmpl +++ b/design-review/sections/craft-audit.md.tmpl @@ -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}.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`. 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. With no running app, use the page's HTML file in the repo. +With a URL, save the page in the script that opens it. Aside: add `await fs.writeFile(path.join(pwd, ".{page}.html"), await pg.evaluate(() => document.documentElement.outerHTML));`. Fallback engine: `_CR=$(mktemp -d "${TMPDIR:-/tmp}/gstack-craft.XXXXXX"); $B js 'document.documentElement.outerHTML' --out "$_CR/{page}.page.html" --raw`. A saved page holds session data: whatever the exit code, `rm -rf` it (or `${_CR:?}`) in the block that checks it, and never copy it to the report directory. With no running app, use the page's HTML file in the repo. ```bash {{BIN_DIR}}/gstack-design-craft ``` -Each `CRAFT_CHECK: ` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source or an empty or unreadable file) or a mount-node shell: 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. +Each `CRAFT_CHECK: ` line is one category 9 finding under that id; `CRAFT_RESULT: clean` adds none; no `CRAFT_RESULT` line (framework source or an empty or unreadable file) or a mount-node shell: 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. Never mark or cut a claim as the rules below say: file it and ask for the proof. ### 2. What the check cannot see diff --git a/test/design-craft-resolvers.test.ts b/test/design-craft-resolvers.test.ts index 8671bb95e..f5d3fa5b4 100644 --- a/test/design-craft-resolvers.test.ts +++ b/test/design-craft-resolvers.test.ts @@ -46,7 +46,7 @@ describe('craft resolvers', () => { 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 mark or cut a claim as the rules below say: file it and ask for the proof.'); expect(audit).toContain('never copy it to the report directory'); }); }); diff --git a/test/design-craft.test.ts b/test/design-craft.test.ts index eee77c2a2..77c4c09d9 100644 --- a/test/design-craft.test.ts +++ b/test/design-craft.test.ts @@ -159,6 +159,7 @@ describe('accepted craft exceptions (finalized.json craft_exceptions)', () => { expect(issues.find(f => f.id === 'round-number')?.fix).toEndWith('(2 accepted earlier: supplied figures)'); expect(issues).toHaveLength(findings.length - 2); expect(acceptFindings([{ id: 'needs-proof', count: 1, fix: 'f' }], [{ id: 'needs-proof', count: 1, reason: 'awaiting logo' }])).toEqual({ issues: [], accepted: [{ id: 'needs-proof', count: 1, reason: 'awaiting logo' }] }); + expect(acceptFindings([{ id: 'needs-proof', count: 2, fix: 'f' }], [{ id: 'needs-proof', count: 1, reason: 'awaiting logo' }])).toEqual({ issues: [{ id: 'needs-proof', count: 2, fix: 'f (1 accepted earlier: awaiting logo)' }], accepted: [] }); expect(formatCraft([], accepted)).toBe('CRAFT_ACCEPTED: placeholder-brand 1 Acme is the real customer\nCRAFT_ACCEPTED: scroll-listener 1 unused\nCRAFT_RESULT: clean (2 accepted)'); const carried = [{ id: 'round-number', count: 1, reason: 'first run' }, { id: 'round-number', count: 3, reason: 'supplied figures' }]; for (const list of [carried, [...carried].reverse()]) { @@ -225,6 +226,7 @@ describe('accepted craft exceptions (finalized.json craft_exceptions)', () => { expect(run(page, '--accepted', record)).toMatchObject({ code: 0, out: 'CRAFT_RESULT: clean\n' }); expect(run(page)).toMatchObject({ code: 0, out: 'CRAFT_RESULT: clean\n', err: '' }); expect(acceptFindings([], [{ id: 'oops', count: 1, reason: 'x' }])).toEqual({ issues: [], accepted: [] }); + expect(acceptFindings([], [{ id: 'lorem', count: 1, reason: 'draft copy' }])).toEqual({ issues: [], accepted: [] }); fs.writeFileSync(page, CLEAN.replace('Halvorsen Freight', 'Acme and Nexus')); expect(run(page)).toMatchObject({ code: 1, out: 'CRAFT_CHECK: placeholder-brand 2 use a supplied customer, or a fitting name in sample data\nCRAFT_RESULT: 1 issue(s)\n' }); fs.writeFileSync(page, CLEAN); @@ -255,7 +257,7 @@ describe('design-shotgun to design-html handoff', () => { }); test('a change to the craft checker selects the design-html-slop-gate E2E that runs it', () => { - for (const file of ['lib/design-craft.ts', 'bin/gstack-design-craft']) { + for (const file of ['lib/design-craft.ts', 'lib/design-catalog.ts', 'bin/gstack-design-craft']) { expect(selectTests([file], E2E_TOUCHFILES).selected).toContain('design-html-slop-gate'); } }); diff --git a/test/external-host-carve.test.ts b/test/external-host-carve.test.ts index a89a8fe4e..665e655fe 100644 --- a/test/external-host-carve.test.ts +++ b/test/external-host-carve.test.ts @@ -1,5 +1,5 @@ /** - * C4 (#2777): ship, plan-ceo-review and office-hours are carved on every host, and no + * C4 (#2777): ship, plan-ceo-review, office-hours and design-review are carved on every host, and no * generated SKILL.md exceeds 160,000 UTF-8 bytes on any host or model overlay * setup can select. Carved sections on external hosts are pointed at relative * to the installed skill directory: `$GSTACK_ROOT//sections/...` does diff --git a/test/helpers/carve-guards.ts b/test/helpers/carve-guards.ts index bda4c3018..2597dac28 100644 --- a/test/helpers/carve-guards.ts +++ b/test/helpers/carve-guards.ts @@ -752,9 +752,9 @@ do not launch the downstream skill or open a browser.`, // periodic census past its 38-slice cap (test/paid-retry-supervision.test.ts). behavioral: 'none', 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 145068 (2026-10-26) + minUnionBytes: 143_300, // measured union 145049 (2026-10-26) mustContain: ['AI Slop Detection', 'Fix Loop', 'gstack-design-craft', 'Proof beside each claim', 'holds session data'], - maxSizeRatio: 1.3707, // first parity guard for design-review: measured 145082 / 105,842 = 1.3708 (2026-10-25; 145077 after the /ship review fixes, 145068 = 1.3707 after the line-13 reword, 2026-10-26), the skeleton's growth since v1.64.1.0 plus the craft audit (Garry 2026-10-25 'Do it' (GSTA-92)). + maxSizeRatio: 1.3705, // first parity guard for design-review: measured 145082 / 105,842 = 1.3708 (2026-10-25; 145077 after the /ship review fixes, 145068 = 1.3707 after the line-13 reword, 145049 = 1.3705 after the post-merge /ship review, 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 ──