Move the slop defects back into the craft floor

The detector-blind slop review existed because the AI-tell rules had been
stripped out of SKILL.md and nothing carried them. The floor is a better
home: it loads after concept ideation and immediately before editing UI,
which is the placement that made stripping them necessary in the first
place. Models tread lightly when a ban list is present during ideation;
by the time the floor loads, the direction is already committed.

- Rename build-floor.md to craft-floor.md and restore the absolute bans
  (side-stripes, gradient text, glassmorphism, hero-metric, identical card
  grids, eyebrow-on-every-section, numbered markers, text overflow), the
  codex and gemini defect lists, and the reflexes no scanner catches.
  Rule ids match the ones the ablation catalog already knows.
- Delete lib/slop-review.mjs and both injections. The Stop hook is now
  purely a mechanical pass and stays silent with nothing to report.
- context.mjs replaces AI_SLOP_REVIEW_REQUIRED with the narrower
  MANUAL_DETECTOR_REQUIRED, emitted only when a session has no hook at
  all. A per-edit hook already covers the mechanical gap, and the floor
  covers the judgment one either way.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-21 02:04:36 -07:00
co-authored by Claude
parent d7d10277d1
commit 153b416f2e
9 changed files with 87 additions and 118 deletions
+15 -12
View File
@@ -32,7 +32,6 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { parseTargetOptions } from './lib/target-args.mjs';
import { IMPECCABLE_COMMAND, IMPECCABLE_PROVIDER_ID } from './lib/provider.mjs';
import { renderLlmOnlySlopReview } from './lib/slop-review.mjs';
import { resolveSurfaceBrief } from './lib/surface-briefs.mjs';
const PRODUCT_NAMES = ['PRODUCT.md', 'Product.md', 'product.md'];
@@ -1127,7 +1126,7 @@ async function cli() {
];
appendSurfaceBriefContext(parts, ctx);
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
appendHookFallback(parts, ctx);
appendDetectorFallback(parts, ctx);
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
parts.push(buildMissingTargetDirective());
}
@@ -1141,7 +1140,7 @@ async function cli() {
}
appendSurfaceBriefContext(parts, ctx);
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
appendHookFallback(parts, ctx);
appendDetectorFallback(parts, ctx);
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
parts.push(buildMissingTargetDirective());
}
@@ -1244,15 +1243,19 @@ function automaticHookMode(ctx) {
return 'none';
}
function appendHookFallback(parts, ctx) {
const hookMode = automaticHookMode(ctx);
if (hookMode === 'stop') return;
const native = ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive';
parts.push(renderLlmOnlySlopReview({
automaticDetector: hookMode === 'per-edit',
manualDetector: hookMode === 'none' && !native,
scriptsPath: path.dirname(fileURLToPath(import.meta.url)),
}));
// reference/craft-floor.md carries the detector-blind reflexes on every build,
// so the only gap left here is the mechanical pass. A hook covers it, per-edit
// or Stop; a session without one has to run the detector by hand. The detector
// reads HTML and CSS, so native projects get nothing.
function appendDetectorFallback(parts, ctx) {
if (automaticHookMode(ctx) !== 'none') return;
if (ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive') return;
const scriptsPath = path.dirname(fileURLToPath(import.meta.url));
parts.push([
'MANUAL_DETECTOR_REQUIRED: No automatic Impeccable design hook is active this session.',
`Once the changed web UI is finished, run the mechanical detector over it: \`node ${scriptsPath}/detect.mjs --json <changed targets>\`.`,
'Run it once, and not earlier during concept selection.',
].join(' '));
}
function buildResolvedContextDirective(ctx, options, { targetExists = null } = {}) {