Frontend: site chrome, demo shell, pages, and the contract gates

Five parallel lanes plus an integration pass. The header, gallery, router and
sitemap are all generated from the demo registry, so adding src/demos/<slug>/
puts a demo everywhere with zero edits to shared files — which is the whole
reason demo nine cannot break demo one.

check-demos enforces the twelve contract rules: 142 checks over one live demo.
Two worth naming. The shell may not mention a specific slug, because an
'if (slug === wordle)' in src/components/demo/ is a contract bug wearing a
patch. And a spec-status demo must ship a real specification — task, actions,
grader, counterweight, eval command — since a coming-soon card reads worse than
an honest empty gallery.

Bundle budget holds: entry 108.79 kB gzipped against a 160 kB ceiling, the demo
chunk 21.15 kB against 90 kB. recharts is 108 kB gzipped and lives behind a lazy
import so it never touches the entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mt6sHQHEnEYrJZvoMCJSB
This commit is contained in:
karti-ai
2026-08-28 16:09:59 -07:00
parent b601511e7f
commit eb88138d15
31 changed files with 1341 additions and 680 deletions
+1 -1
View File
@@ -329,7 +329,7 @@ for (const slug of slugs) {
const rate = rateSources
.map((s) => s?.solveRate ?? s?.solve_rate)
.find((v) => typeof v === 'number' && Number.isFinite(v));
const rendered = walk(abs('src'), (f) => /\.tsx?$/.test(f)).some((f) => /\bsolve[_R]?ate|solveRate|solve_rate/.test(read(f)));
const rendered = walk(abs('src'), (f) => /\.tsx?$/.test(f)).some((f) => /solveRate|solve_rate/.test(read(f)));
report.check(
typeof rate === 'number' && rendered,
rel(abs('public', 'traces', 'manifest.json')),
+2 -2
View File
@@ -187,8 +187,8 @@ for (const slug of slugs) {
region.some((line) => line.trim() !== ''),
rel(onDisk),
RULE_MARKER,
`marker "${marker}" delimits an empty region (lines ${open + 2}-${close}). The markers are exclusive, ` +
'so a pair on adjacent lines quotes nothing.',
`marker "${marker}" delimits an empty region between lines ${open + 1} and ${close + 1}. The markers are ` +
'exclusive, so a pair on adjacent lines quotes nothing.',
);
}
}
+17 -1
View File
@@ -96,6 +96,12 @@ for (const job of jobs) {
'Refusing to overwrite. Pick another slug, or delete the directory yourself if you meant to start over.',
);
}
// An empty template directory would copy cleanly, report "Created 0 files"
// and leave behind a demo that the registry quarantines for a reason nobody
// connects back to this command.
if (countFiles(job.from) === 0) {
fail(`${rel(job.from)} is empty.`, 'There is nothing to scaffold from. Fill in the template first.');
}
}
/* -------------------------------------------------------------------- copy */
@@ -132,11 +138,21 @@ console.log(dim(`The demo will 404 until meta.ts, demo.tsx and public/og/${slug}
/* ----------------------------------------------------------------- helpers */
/** Files in a tree, recursively. Used only to reject an empty template. */
function countFiles(dir) {
return fs.readdirSync(dir, { withFileTypes: true }).reduce((total, entry) => {
if (entry.name === '__pycache__' || entry.name === 'node_modules') return total;
if (entry.isDirectory()) return total + countFiles(path.join(dir, entry.name));
return total + (entry.isFile() ? 1 : 0);
}, 0);
}
function capitalise(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
}
/** Applies the substitution table, longest token first so prefixes cannot win. */
/** Applies the substitution table. No token is a prefix of another, so order
* does not matter here — but keep it that way if you add one. */
function substitute(text, bareName) {
let out = text;
for (const [token, value] of substitutions) out = out.split(token).join(value);
+5 -5
View File
@@ -34,12 +34,12 @@ if (errors.length) die(`route enumeration failed:\n - ${errors.join('\n - ')}`
/* ------------------------------------------------------------- robots.txt */
// Kept byte-identical to the committed public/robots.txt so re-running this
// script is a no-op in the diff. If you change the wording, change it here —
// this is the generator, and the committed file is its output.
const robots = [
'# demo.primeintellectgrowth.com',
'#',
'# This site is meant to be found. Every page is public, static and safe to',
'# crawl; the source it documents is public too.',
'',
'# The inverse of primeintellectgrowth.com, deliberately: being found is the',
'# entire point of this site.',
'User-agent: *',
'Allow: /',
'',