Add concept world catalog and review workflow

AI-assisted: prepared by Codex at Paul's request.
This commit is contained in:
Paul Bakaus
2026-07-18 14:12:05 -07:00
parent 77c7d8e0fc
commit 2b1f36c43e
576 changed files with 45547 additions and 30979 deletions
+64 -15
View File
@@ -46,6 +46,7 @@ import path from 'node:path';
import { pathToFileURL, fileURLToPath } from 'node:url';
import { extractPlatform, loadContext } from './context.mjs';
import { IMPECCABLE_COMMAND } from './lib/provider.mjs';
import { renderStopSlopReview } from './lib/slop-review.mjs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@@ -1868,22 +1869,42 @@ export const CONTRACT_MAX_CHARS = 1800;
// Cap contract sections per Stop emission so many touched artifacts cannot
// stack an unbounded message.
export const CONTRACT_AUDIT_MAX_FILES = 3;
export const CONTRACT_EXTS = new Set(['.html', '.htm', '.astro', '.svelte', '.vue', '.jsx', '.tsx']);
export const CONTRACT_REQUIRED_FIELDS = ['UNIQUE', 'NOT-TEMPLATE', 'OWN-WORLD', 'STORY', 'FIRST VIEWPORT', 'FORM'];
/**
* Extract the artifact's own direction-contract comment: the first HTML
* comment in the head of the file, when its opening chars identify it as a
* contract/concept block. Returns the trimmed, length-capped body, or null
* when the file carries none (no comment, unclosed comment, marker missing,
* or the comment starts past the head window).
* Extract the artifact's own direction-contract comment from the head of an
* HTML or component file. Supports HTML-family comments and JSX block
* comments so the contract works in the Astro/Svelte/Vue/React scaffolds the
* skill actually builds. Returns the trimmed, length-capped body, or null
* when the file carries no valid contract block.
*/
export function extractDirectionContract(content) {
if (typeof content !== 'string' || !content) return null;
const head = content.slice(0, CONTRACT_HEAD_CHARS);
const m = /<!--([\s\S]*?)-->/.exec(head);
if (!m) return null;
const body = m[1].trim();
if (!body || !/contract|concept/i.test(body.slice(0, CONTRACT_MARKER_CHARS))) return null;
return body.slice(0, CONTRACT_MAX_CHARS);
const candidates = [];
for (const pattern of [/<!--([\s\S]*?)-->/g, /\{\/\*([\s\S]*?)\*\/\}/g]) {
for (const match of head.matchAll(pattern)) {
const index = match.index ?? 0;
const linePrefix = head.slice(head.lastIndexOf('\n', index - 1) + 1, index).trim();
if (linePrefix.startsWith('//')) continue;
candidates.push({ index, body: match[1].trim() });
}
}
candidates.sort((a, b) => a.index - b.index);
for (const candidate of candidates) {
if (!candidate.body || !/direction\s+contract|concept\s+contract/i.test(candidate.body.slice(0, CONTRACT_MARKER_CHARS))) continue;
return candidate.body.slice(0, CONTRACT_MAX_CHARS);
}
return null;
}
export function missingDirectionContractFields(contract) {
const body = typeof contract === 'string' ? contract : '';
return CONTRACT_REQUIRED_FIELDS.filter((field) => {
const label = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s+/g, '\\s+');
return !new RegExp(`\\b${label}\\s*:`, 'i').test(body);
});
}
/**
@@ -1899,7 +1920,11 @@ export function renderContractAudit(entries, opts = {}) {
const shown = entries.slice(0, CONTRACT_AUDIT_MAX_FILES);
const blocks = shown.map(({ filePath, contract }) => {
const display = relativize(filePath, cwd);
return `${display} opens with this direction contract, written when the direction was decided:\n\n${contract}`;
const missing = missingDirectionContractFields(contract);
const integrity = missing.length > 0
? `\n\nContract integrity defect: missing ${missing.join(', ')}. Repair the contract and the implementation together.`
: '';
return `${display} opens with this direction contract, written when the direction was decided:\n\n${contract}${integrity}`;
});
return [
`${ENVELOPE_PREFIX} Direction-contract audit. Before finishing, audit the rendered page against the contract it opens with, promise by promise.`,
@@ -1984,9 +2009,22 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
return result({ skipped: 'native-platform', platform, durationMs: Date.now() - started });
}
const session = ensureSession(cache, sessionId);
const needsSlopReview = session.llmSlopReviewed !== true;
const det = detector || await loadDetector();
if (!det || typeof det.detectText !== 'function') {
return result({ skipped: 'detector-missing', durationMs: Date.now() - started });
if (!needsSlopReview) return result({ skipped: 'detector-missing', durationMs: Date.now() - started });
session.llmSlopReviewed = true;
session.updatedAt = Date.now();
persistCache(projectCwd, cache);
const text = renderStopSlopReview();
return {
exitCode: 0,
stdout: payload(text, 'Stop', harness),
emission: { kind: 'stop-llm-slop-review', llmSlopReview: true },
audit: { ...audit, emitted: true, detectorMissing: true, llmSlopReview: true, chars: text.length, durationMs: Date.now() - started },
};
}
const scanOptions = designSystemOptions(config, det, projectCwd);
@@ -2013,10 +2051,11 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
? configuredExt.engine === 'html'
: (ext === '.html' || ext === '.htm');
// Direction-contract audit: HTML artifacts only, at most once per file
// Direction-contract audit: HTML and component artifacts, at most once per file
// per session. The flag lives on the same session cache entry the
// finding dedupe uses, so a second Stop fire stays quiet about it.
if (useHtmlEngine) {
const contractCapable = useHtmlEngine || CONTRACT_EXTS.has(ext);
if (contractCapable) {
const fileEntry = ensureFile(cache, sessionId, filePath);
if (!fileEntry.contractAudited) {
const contract = extractDirectionContract(content);
@@ -2046,10 +2085,15 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
}
audit.scannedFiles = scanned;
if (freshGroups.length === 0 && contractEntries.length === 0) {
if (freshGroups.length === 0 && contractEntries.length === 0 && !needsSlopReview) {
return result({ emitted: false, skipped: 'stop-clean', durationMs: Date.now() - started });
}
if (needsSlopReview) {
session.llmSlopReviewed = true;
session.updatedAt = Date.now();
}
// Fresh findings and first-time contract audits earn the cache write;
// both mark this batch as surfaced so the next Stop fire is silent
// unless new issues appear.
@@ -2064,6 +2108,9 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
if (contractEntries.length > 0) {
parts.push(renderContractAudit(contractEntries, { cwd: projectCwd }));
}
if (needsSlopReview) {
parts.push(renderStopSlopReview());
}
const text = appendDesignSystemNote(parts.join('\n\n'), scanOptions);
return {
exitCode: 0,
@@ -2074,6 +2121,7 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
...(contractEntries.length > 0
? { contractFiles: contractEntries.map((entry) => entry.filePath) }
: {}),
...(needsSlopReview ? { llmSlopReview: true } : {}),
},
audit: {
...audit,
@@ -2081,6 +2129,7 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
freshFiles: freshGroups.length,
freshFindings: freshGroups.reduce((sum, group) => sum + group.findings.length, 0),
...(contractEntries.length > 0 ? { contractAudits: contractEntries.length } : {}),
...(needsSlopReview ? { llmSlopReview: true } : {}),
chars: text.length,
durationMs: Date.now() - started,
},