mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 07:36:50 +03:00
skill: drop quality tiers, keep the real brand-craft guardrails
Codex's craft/brand pass introduced fast/ship/showpiece "quality bars" plus brand-specific build gates, asset ledgers, sub-agent review, and self-graded fallback labels. In practice those tiers became escape hatches rather than craft pressure: the final output should always be 10/10, and the real decision points are splashiness and maximalism, not quality. Removed: - All quality-bar / showpiece / fast / ship framing in shape.md and craft.md - Standalone Brand Direction (#4) and Asset Requirements (#10) sections in shape's brief; renumbered back to 1-10 - The Brand hard rules section in brand.md (folded its real prohibitions into the existing Imagery and Brand bans sections) - Brand-specific build-gate item, mock-fidelity bullet, production-bar bullet, present-step bullet in craft.md - Asset ledger ceremony in craft Step 4 - Review-only sub-agents and "self-reviewed fallback, not independently validated" machinery in craft.md and polish.md - The For brand surfaces, assess hard failures subsection in polish.md and the brand checklist row - tests/brand-showpiece-reference.test.mjs (and its package.json wiring) Kept (the real nuggets): - Asset-substitution prohibition: image-led briefs ship real/generated assets or canvas/SVG/WebGL, not generic CSS panels, cards, bullets, or copy - Repeated tiny uppercase tracked kicker labels as a brand ban - Detector/QA output is defect evidence only, never proof of quality - "What visual assets are real content here?" discovery question - Inspect each major section individually for brand and long-form work - repeated-section-kickers detection rule + fixture - CLI improvements (JSON to stdout, -json/-fast aliases, severity field) - critique.md: npx impeccable detect --json fix Harness output dirs refreshed via bun run build. Full test suite (186) passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
e587004ee4
commit
a8b032d362
@@ -371,6 +371,41 @@ describe('detectHtml — hero-eyebrow-chip', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectHtml — repeated-section-kickers', () => {
|
||||
const SHOULD_FLAG = [
|
||||
'The Future Is Admitted',
|
||||
'A Private Rehearsal',
|
||||
'Reviewed, Not Sold',
|
||||
'Touch the Future',
|
||||
];
|
||||
const SHOULD_PASS = [
|
||||
'Breadcrumb Before Heading',
|
||||
'Form Heading Is Separate',
|
||||
'Step Indicator',
|
||||
'Figure Caption Label',
|
||||
'Normal Case Kicker',
|
||||
'Intentional Brand Label',
|
||||
];
|
||||
|
||||
it('repeated-section-kickers: flags only repeated section scaffolding', async () => {
|
||||
const f = await detectHtml(path.join(FIXTURES, 'repeated-section-kickers.html'));
|
||||
const flagged = new Set();
|
||||
for (const r of f) {
|
||||
if (r.antipattern !== 'repeated-section-kickers') continue;
|
||||
assert.equal(r.severity, 'advisory');
|
||||
const matches = [...(r.snippet || '').matchAll(/"([^"]+)"/g)];
|
||||
if (matches.length) flagged.add(matches[matches.length - 1][1]);
|
||||
}
|
||||
|
||||
for (const text of SHOULD_FLAG) {
|
||||
assert.ok(flagged.has(text), `expected "${text}" to be flagged as repeated-section-kickers`);
|
||||
}
|
||||
for (const text of SHOULD_PASS) {
|
||||
assert.ok(!flagged.has(text), `"${text}" should NOT be flagged as repeated-section-kickers`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectHtml — motion', () => {
|
||||
// jsdom doesn't fully apply class-based styles, so the absolute finding counts
|
||||
// are lower than what a real browser would see. The hardcoded counts below are
|
||||
|
||||
@@ -571,9 +571,18 @@ describe('CLI', () => {
|
||||
});
|
||||
|
||||
test('--json outputs valid JSON', () => {
|
||||
const { stderr, code } = run('--json', path.join(FIXTURES, 'should-flag.html'));
|
||||
const { stdout, code } = run('--json', path.join(FIXTURES, 'should-flag.html'));
|
||||
expect(code).toBe(2);
|
||||
const parsed = JSON.parse(stderr.trim());
|
||||
const parsed = JSON.parse(stdout.trim());
|
||||
expect(parsed).toBeArray();
|
||||
expect(parsed.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('-json alias outputs valid JSON', () => {
|
||||
const { stdout, stderr, code } = run('-json', path.join(FIXTURES, 'should-flag.html'));
|
||||
expect(code).toBe(2);
|
||||
expect(stderr).not.toContain('cannot access -json');
|
||||
const parsed = JSON.parse(stdout.trim());
|
||||
expect(parsed).toBeArray();
|
||||
expect(parsed.length).toBeGreaterThan(0);
|
||||
});
|
||||
@@ -923,9 +932,9 @@ describe('CLI -- Next.js + Tailwind project', () => {
|
||||
});
|
||||
|
||||
test('--json produces clean JSON without framework message', () => {
|
||||
const { stderr, code } = run('--json', dir);
|
||||
const { stdout, code } = run('--json', dir);
|
||||
expect(code).toBe(2);
|
||||
const parsed = JSON.parse(stderr.trim());
|
||||
const parsed = JSON.parse(stdout.trim());
|
||||
expect(parsed).toBeArray();
|
||||
expect(parsed.length).toBeGreaterThanOrEqual(6);
|
||||
});
|
||||
@@ -1041,9 +1050,9 @@ describe('CLI -- Next.js + CSS-in-JS (styled-components) project', () => {
|
||||
});
|
||||
|
||||
test('--json produces clean JSON without framework message', () => {
|
||||
const { stderr, code } = run('--json', dir);
|
||||
const { stdout, code } = run('--json', dir);
|
||||
expect(code).toBe(2);
|
||||
const parsed = JSON.parse(stderr.trim());
|
||||
const parsed = JSON.parse(stdout.trim());
|
||||
expect(parsed).toBeArray();
|
||||
expect(parsed.length).toBeGreaterThanOrEqual(6);
|
||||
// Verify importedBy is present in JSON
|
||||
@@ -1147,9 +1156,9 @@ describe('CLI -- multi-file scan', () => {
|
||||
});
|
||||
|
||||
test('--json multi-file scan includes import context', () => {
|
||||
const { stderr, code } = run('--json', path.join(FIXTURES, 'multifile'));
|
||||
const { stdout, code } = run('--json', path.join(FIXTURES, 'multifile'));
|
||||
expect(code).toBe(2);
|
||||
const parsed = JSON.parse(stderr.trim());
|
||||
const parsed = JSON.parse(stdout.trim());
|
||||
expect(parsed.length).toBeGreaterThan(0);
|
||||
// Findings from Card.tsx should mention being imported by App.tsx
|
||||
const cardFindings = parsed.filter(f => f.file?.includes('Card.tsx'));
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Repeated Section Kickers Fixture</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f6f2ec;
|
||||
color: #171411;
|
||||
}
|
||||
main {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 32px;
|
||||
padding: 32px;
|
||||
}
|
||||
.col {
|
||||
min-width: 0;
|
||||
border: 1px solid #c9bfb2;
|
||||
padding: 24px;
|
||||
}
|
||||
.case {
|
||||
min-height: 120px;
|
||||
margin: 0 0 24px;
|
||||
padding: 16px;
|
||||
background: #fffaf3;
|
||||
}
|
||||
.kicker,
|
||||
.pass-kicker {
|
||||
display: block;
|
||||
width: 240px;
|
||||
min-height: 16px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.11em;
|
||||
color: #5b5046;
|
||||
}
|
||||
.kicker {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 32px;
|
||||
line-height: 38px;
|
||||
font-weight: 700;
|
||||
}
|
||||
p,
|
||||
label,
|
||||
figcaption,
|
||||
a,
|
||||
li {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
nav,
|
||||
form,
|
||||
figure,
|
||||
ol {
|
||||
margin: 0 0 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
min-height: 80px;
|
||||
}
|
||||
.brand-system {
|
||||
min-height: 120px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<section class="col" aria-label="Should flag">
|
||||
<h1>Should flag</h1>
|
||||
|
||||
<section class="case">
|
||||
<span class="kicker">Invitation protocol</span>
|
||||
<h2>"The Future Is Admitted"</h2>
|
||||
<p>Repeated tracked labels carry the hierarchy instead of a stronger structure.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<p class="kicker">Preview sequence</p>
|
||||
<h2>"A Private Rehearsal"</h2>
|
||||
<p>The same scaffolding appears again before another section heading.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<div class="kicker">Access window</div>
|
||||
<h2>"Reviewed, Not Sold"</h2>
|
||||
<p>The pattern is now the page's default section grammar.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<small class="kicker">Material briefing</small>
|
||||
<h2>"Touch the Future"</h2>
|
||||
<p>Four repeated kickers should be enough to flag the page-level smell.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="col" aria-label="Should pass">
|
||||
<h1>Should pass</h1>
|
||||
|
||||
<nav class="case" aria-label="Breadcrumb">
|
||||
<span class="pass-kicker">Home / Journal</span>
|
||||
<h2>"Breadcrumb Before Heading"</h2>
|
||||
<a href="/">Home</a>
|
||||
</nav>
|
||||
|
||||
<form class="case">
|
||||
<label class="pass-kicker" for="guest">Guest name</label>
|
||||
<input id="guest" name="guest" style="width: 220px; height: 40px;">
|
||||
<h2>"Form Heading Is Separate"</h2>
|
||||
</form>
|
||||
|
||||
<ol class="case">
|
||||
<li>
|
||||
<span class="pass-kicker">Step 01</span>
|
||||
<h3>"Step Indicator"</h3>
|
||||
<p>Step indicators in ordered flows should not count as section scaffolding.</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<figure class="case">
|
||||
<span class="pass-kicker">Plate study</span>
|
||||
<figcaption>"Figure Caption Label"</figcaption>
|
||||
</figure>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker">Lowercase label</span>
|
||||
<h2>"Normal Case Kicker"</h2>
|
||||
<p>Not uppercase, not the repeated AI section-label pattern.</p>
|
||||
</section>
|
||||
|
||||
<section class="case brand-system" data-impeccable-allow-kickers>
|
||||
<span class="pass-kicker">Archive code</span>
|
||||
<h2>"Intentional Brand Label"</h2>
|
||||
<p>Deliberate brand systems can opt out with an explicit marker.</p>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user