Restore dice assignment, fusion, and the commitment counterweights

The ship40 concept pipeline had reversed the proven a-series mechanisms:
the seed's roll decayed into a shortlist nomination that taste functions
(model ranking, candidate floor, simulated user) then argmaxed into the
safest card; the costume check returned as the Translation veto and
carrier-removal test; and the 07-15 rewrite deleted the calibration,
reflex-font lanes, color strategies, and commit-every-atom language that
had held off the cream-editorial default since the alpha era. Five of six
frozen craft directions converged on the same warm-paper family and both
builders obeyed them.

This lands the repair on top of the in-progress simplification:

- new-work.md: the script assigns the build index again on both scopes;
  catalog challengers are fused (challenger supplies form and grammar,
  product supplies every fact, clarity wins conflicts) and weighed on the
  two proven axes only; attended runs present one fully committed
  direction with re-roll and an optional steer instead of a ranked
  lineup; the color-strategy picker, reflex-face list, saturated-look
  calibration, first-viewport thesis and memory test, commit-every-atom,
  scroll pacing, and prove-don't-claim return; the direction contract
  returns as five lean blocks audited by the separate-agent finish.
- concept-seed.mjs: PROMOTED INDEX becomes ASSIGNED INDEX with
  build-assignment semantics; self re-roll only on named factual grounds.
- craft-floor.md: hook-active sessions act on findings instead of
  re-auditing; the Refuse list is framed as category defaults the brief
  can earn; a closing commitment line keeps a ban list from being the
  last word before code.
- codex.md / shape.md: contract references restored for flow coherence.

Adopts the concurrent session's ceremony cuts, softened challenger
instruction, seed SOURCE IDs and --candidate-count, detector-ownership
fix, and the removal of the hook-side contract audit (the audit now
belongs to the separate reviewer at finish).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-21 10:43:44 -07:00
co-authored by Claude Fable 5
parent a9540b5fe3
commit 36e3c05ca7
11 changed files with 165 additions and 629 deletions
+4 -133
View File
@@ -26,7 +26,6 @@
* loadDetector() -> Promise<{ detectText, detectHtml }>
* matchesAnyGlob(filePath, globs)
* normalizeScanTargets(primaryTargets, projectCwd)
* extractDirectionContract(content) / renderContractAudit(entries, opts)
* runHook(deps) -> { exitCode, stdout, audit, reason? }
* runStopHook(deps) -> { exitCode, stdout, audit, emission? }
*
@@ -1888,100 +1887,6 @@ export async function runHook({ stdinJson, env = {}, cwd = process.cwd(), now =
}
}
// ── Direction-contract audit ─────────────────────────────────────────────
// The skill's decide-then-build step opens the built HTML artifact with a
// DIRECTION CONTRACT comment (THESIS / OWN-WORLD / STORY / FIRST VIEWPORT /
// BAR-RAISER / FORM blocks). At Stop time the deep pass extracts that
// comment and feeds it back so the model audits the render against its own
// promises. Proven in the eval harness: sample contracts promised radical
// compositions and the build shipped the standard template anyway, because
// nothing ever judged the build against the contract. Zero extra API calls:
// this is a message, not a judge. It fires at most once per file per session
// (a `contractAudited` flag on the session cache entry, the same state the
// deep pass uses for finding dedupe) and rides the Stop pass's existing
// emission rather than adding another block round.
// How far into the file to look for the leading comment. A contract lives at
// the very top of the artifact; anything deeper is not the contract.
export const CONTRACT_HEAD_CHARS = 6000;
// The contract/concept marker must appear early in the comment body, so a
// license header or unrelated note does not get mistaken for a contract.
export const CONTRACT_MARKER_CHARS = 200;
// Cap the extracted contract so a rambling comment cannot blow up the
// Stop message.
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 = ['THESIS', 'OWN-WORLD', 'STORY', 'FIRST VIEWPORT', 'BAR-RAISER', 'FORM'];
/**
* 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 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);
});
}
/**
* Render the contract-audit section of the Stop message. `entries` is
* [{ filePath, contract }]; at most CONTRACT_AUDIT_MAX_FILES are shown.
* The two failure shapes named here are the ones observed in practice:
* a promise the pixels do not deliver, and a contract whose own plan is
* the standard template wearing the concept's nouns.
*/
export function renderContractAudit(entries, opts = {}) {
if (!Array.isArray(entries) || entries.length === 0) return '';
const cwd = opts.cwd || process.cwd();
const shown = entries.slice(0, CONTRACT_AUDIT_MAX_FILES);
const blocks = shown.map(({ filePath, contract }) => {
const display = relativize(filePath, cwd);
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.`,
'',
blocks.join('\n\n'),
'',
'Two failure shapes to check honestly:',
'1. A promise that is not in the pixels: the contract describes a composition or structure the built page does not deliver, because the build fell back to a standard arrangement, possibly one the contract explicitly rejects. Rebuild that part until the render matches the promise.',
"2. A contract whose own section plan is the standard template wearing the concept's nouns: if a neighboring product could ship the same sequence of sections under different labels, revise the plan and the page together.",
'State each promise and whether the render delivers it, and fix every gap before finishing.',
].join('\n');
}
// Cap on files the Stop deep pass will scan. The touched-file list is
// session-scoped and already capped per edit, but a very long session could
// accumulate more than the 30s hook timeout comfortably covers.
@@ -1990,10 +1895,7 @@ export const STOP_MAX_FILES = 20;
/**
* Run the Stop-event deep pass: the FULL detector rule set over every UI
* file touched this session, surfaced once, deduped against everything the
* per-edit hook already reported. Touched HTML artifacts that open with a
* direction-contract comment additionally get a one-time contract-audit
* section appended after the detector findings (see extractDirectionContract
* above). Same result contract as runHook():
* per-edit hook already reported. Same result contract as runHook():
* { exitCode, stdout, audit, emission? }
*
* Never throws; exits silent (and fast) when the session touched no UI
@@ -2060,7 +1962,6 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
const scanOptions = designSystemOptions(config, det, projectCwd);
const freshGroups = [];
const contractEntries = [];
let scanned = 0;
for (const filePath of touched) {
if (scanned >= STOP_MAX_FILES) break;
@@ -2082,22 +1983,6 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
? configuredExt.engine === 'html'
: (ext === '.html' || ext === '.htm');
// 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.
const contractCapable = useHtmlEngine || CONTRACT_EXTS.has(ext);
if (contractCapable) {
const fileEntry = ensureFile(cache, sessionId, filePath);
if (!fileEntry.contractAudited) {
const contract = extractDirectionContract(content);
if (contract) {
fileEntry.contractAudited = true;
ensureSession(cache, sessionId).updatedAt = Date.now();
contractEntries.push({ filePath, contract });
}
}
}
if (useHtmlEngine && typeof det.detectHtml === 'function') {
try { findings = await det.detectHtml(filePath, scanOptions); } catch { findings = []; }
} else {
@@ -2116,41 +2001,27 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
}
audit.scannedFiles = scanned;
if (freshGroups.length === 0 && contractEntries.length === 0) {
if (freshGroups.length === 0) {
return result({ emitted: false, skipped: 'stop-clean', durationMs: Date.now() - started });
}
// Fresh findings and first-time contract audits earn the cache write;
// both mark this batch as surfaced so the next Stop fire is silent
// Fresh findings earn the cache write so the next Stop fire is silent
// unless new issues appear.
persistCache(projectCwd, cache);
// Detector findings first, then the contract audit. Both ride the same
// single Stop emission: the audit never adds an extra block round.
const parts = [];
if (freshGroups.length > 0) {
parts.push(renderGroupedTemplate(freshGroups, config, { cwd: projectCwd }));
}
if (contractEntries.length > 0) {
parts.push(renderContractAudit(contractEntries, { cwd: projectCwd }));
}
const text = appendDesignSystemNote(parts.join('\n\n'), scanOptions);
const text = appendDesignSystemNote(renderGroupedTemplate(freshGroups, config, { cwd: projectCwd }), scanOptions);
return {
exitCode: 0,
stdout: payload(text, 'Stop', harness),
emission: {
kind: 'stop-deep-pass',
groups: freshGroups,
...(contractEntries.length > 0
? { contractFiles: contractEntries.map((entry) => entry.filePath) }
: {}),
},
audit: {
...audit,
emitted: true,
freshFiles: freshGroups.length,
freshFindings: freshGroups.reduce((sum, group) => sum + group.findings.length, 0),
...(contractEntries.length > 0 ? { contractAudits: contractEntries.length } : {}),
chars: text.length,
durationMs: Date.now() - started,
},