fix: craft audit capture, exceptions and trigger from /ship review (GSTA-92)

- craft-audit: no CRAFT_RESULT line means unavailable (exit 2 after a
  malformed --accepted record still printed findings); --accepted only for a
  /design-html finalized page, never for needs-proof or lorem; never add
  [Needs proof] markers to a live page; Aside capture via pg.evaluate; the
  saved raw DOM is deleted in the checking block and never reported
- manifest trigger covers an explicit craft audit (skeleton -6 bytes; pins
  lowered to measured size, union ratio back under its cap)
- autoFixEntries reads RENDERED; DESIGN_CRAFT_RULE needs exactly one lead
- tests: checkerOnly contract, resolver throw paths, Persuade checks in both
  skills, resolver touchfile selection, exception state cells
- CHANGELOG: host counts and the audit's new rules

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 01:58:03 +00:00
1 parent 62c0fa1333
commit 31ee450399
12 files changed
+118 -55

No files matched your search

+2 -2
View File
@@ -12,7 +12,7 @@
*
* Derived in part from pbakaus/impeccable (Apache-2.0), modified. See NOTICE.md.
*/
import { DESIGN_SLOP_CATALOG, RENDERED, BANNED_FONTS, type DesignSlopEntry } from '../../lib/design-catalog';
import { RENDERED, BANNED_FONTS, type DesignSlopEntry } from '../../lib/design-catalog';
import { SENTINEL, DETECT_EXIT_ECHO } from '../../lib/design-detect-contract';
export const DESIGN_CHECKLIST_HEADER =
@@ -34,7 +34,7 @@ export function checklistSlopEntries(): DesignSlopEntry[] {
/** Catalog rules a review may fix without asking: mechanical CSS changes with HIGH confidence. */
export function autoFixEntries(): DesignSlopEntry[] {
return DESIGN_SLOP_CATALOG.filter(e => e.tier === 'auto-fix');
return RENDERED.filter(e => e.tier === 'auto-fix');
}
function endsWithPunctuation(s: string): boolean {
+3 -3
View File
@@ -19,9 +19,9 @@ const CRAFT_SECTION = path.resolve(import.meta.dir, '../../design-html/sections/
export const DESIGN_CRAFT_RULE: ResolverFn = (_ctx, args) => {
const lead = args?.join(':');
if (!lead) throw new Error('{{DESIGN_CRAFT_RULE:<lead>}} requires the bold lead of a craft paragraph');
const paragraph = fs.readFileSync(CRAFT_SECTION, 'utf-8').split(/\n{2,}/).find(p => p.startsWith(`**${lead}`));
if (!paragraph) throw new Error(`{{DESIGN_CRAFT_RULE:${lead}}}: no paragraph starting "**${lead}" in design-html/sections/craft.md.tmpl`);
return paragraph.trimEnd();
const matches = fs.readFileSync(CRAFT_SECTION, 'utf-8').split(/\n{2,}/).filter(p => p.startsWith(`**${lead}.**`) || p.startsWith(`**${lead},`));
if (matches.length !== 1) throw new Error(`{{DESIGN_CRAFT_RULE:${lead}}}: ${matches.length} paragraphs starting "**${lead}.**" or "**${lead}," in design-html/sections/craft.md.tmpl; need exactly one`);
return matches[0].trimEnd();
};
export const DESIGN_PERSUADE_CHECKS: ResolverFn = () => `1. **One primary action**, named; nothing competes with it above the fold, and the closing CTA repeats it.
+3 -2
View File
@@ -25,8 +25,9 @@ const ROOT = path.resolve(import.meta.dir, '..', '..');
export const QA_ASSET_BLOCKER = 'If missing or unreadable, report a QA setup blocker and its affected probes as blocked; continue other safe probes (independent functional/static checks). Missing/unreadable assets block required QA.';
/** Skills carved on every host: QA (portable assets) and those whose external
* render would exceed SKILL_BYTE_CEILING inlined (C4, #2777). */
/** Skills carved on every host: QA (portable assets), those whose external
* render would exceed SKILL_BYTE_CEILING inlined (C4, #2777), and design-review,
* whose on-demand craft audit stays out of every skeleton (GSTA-92). */
const CARVED_ON_EVERY_HOST = ['qa', 'qa-only', 'ship', 'plan-ceo-review', 'office-hours', 'design-review'];
/** Hosts read at most this many UTF-8 bytes of one SKILL.md (~40K tokens). */