Boondoggle Score

System: trust-template generator + Zebonastic tools system integration
SDD Completion: Build complete (generator + 3 site patches). ToolsBrowser.tsx patch not yet written.
Score generated: 2026-03-31
Team Claude fluency: Level III — Claude Code
Deployment target: Vercel (Zebonastic site) — instructor deploys games

Phase Legend

PhaseName
FFoundation — spikes on all experimental components
CCore System Skeleton — apply verified patches
IIntegration Layer — first game deployed, full pipeline tested
BFull Feature Build — student workflow + additional templates
HHardening — error handling, edge cases
RRelease
SPIKE FLAG: All three Zebonastic patches (scanArtifactsDir, tools/page.tsx, tools/[slug]/page.tsx) are unverified against the live codebase. The Foundation phase runs six spike steps — three Claude, three human — before any patch is applied. No C-phase work begins until all Foundation handoff conditions are met.

Step 1 · Phase F · Human Task

Labor: Human · [PF] Problem Formulation

Before Claude Code touches anything, the human must decide what "this spike passed" means for each experimental component. Claude Code will verify against whatever criteria exist; if the criteria are vague, the verification is vague.

Action

Write down — literally, in a text file or a note — the pass/fail condition for each of the three spikes about to run:

  1. scanArtifactsDir spike (Step 4) passes when: scanArtifactsDir() called on a directory containing one flat .html file and one subdirectory with index.html returns exactly two results, both with correct slug, isDirectory, artifactPath, keywords[], and title fields.
  2. PD.js overwrite spike (Step 8) passes when: The browser console shows PEEP_METADATA overwritten with example-game.json values before any Slideshow/PIXI initialization log appears.
  3. ToolsBrowser audit (Step 6) passes when: You have the current props interface in writing and know whether changing it will break any other caller.

Do not proceed to Step 2 without these written down. The spike sequence is only useful if the human can say "pass" or "fail" without ambiguity.

Handoff condition: Spike success criteria exist in writing before Step 2 begins.

Dependency: None.


Step 2 · Phase F · Claude Task

Labor: Claude Code

Context required: trust-template/generate.js, trust-template/example-game.json, a clone of ncase/trust at ./trust-source

Prompt

Create a directory ./example-game/ containing a copy of example-game.json from trust-template/.
Then run:

  node trust-template/generate.js ./example-game ./trust-source ./dist-smoke-test

After the run completes:

1. Verify directory structure: dist-smoke-test/ contains index.html, words.html, js/, css/, assets/

2. Verify meta tag injection in dist-smoke-test/index.html:
   grep -n "description\|keywords\|user-config\|Evolution of Trust" dist-smoke-test/index.html
   Expected: <title>The Evolution of Trust</title>, <meta name="description"...>, <meta name="keywords"...>, <script src="js/user-config.js">

3. Verify user-config.js was generated:
   cat dist-smoke-test/js/user-config.js
   Expected: PEEP_METADATA = { tft: { frame: 0, color: "#4089DD" }, all_d: ... } with all 8 strategy IDs

4. Report the full terminal output from the generator, any errors, and the results of steps 2–3.

Expected output: Terminal output showing all copy steps completing with "done", grep showing all 4 expected lines in index.html, user-config.js showing all 8 strategy keys.

Handoff condition: Generator runs without errors, all 4 expected strings found in index.html, all 8 strategy IDs present in user-config.js.

Dependency: None (runs locally, no Zebonastic site involved).


Step 3 · Phase F · Human Task

Labor: Human · [PA] Plausibility Auditing

Claude Code can verify that strings exist in files. It cannot open a browser and evaluate whether what appears on screen matches the intended character design. This check requires eyes.

Action

cd dist-smoke-test
npx http-server -p 8080

Open http://localhost:8080. Play through the first three slides. Check:

If any character shows the wrong color or the original name ("Copycat" is the original — acceptable here since example-game.json uses original names intentionally), that is not a failure. A failure is: characters all showing a single wrong color, or a JS error in the console before any slide renders.

Handoff condition: Game loads in browser, characters display colors matching example-game.json, no JS errors on load.

Dependency: Step 2.


Step 4 · Phase F · Claude Task

Labor: Claude Code

Context required: trust-template/zebonastic-patches/lib-html-meta-addition.ts, the Zebonastic project's lib/html-meta.ts

Prompt

Write a test script test-scan-artifacts.ts at the Zebonastic project root that spikes scanArtifactsDir() in isolation before it touches the live codebase.

The script should:

1. Create a temporary test directory at /tmp/test-artifacts-spike/ containing:
   - /tmp/test-artifacts-spike/flat-tool.html with:
     <title>Flat Tool</title>
     <meta name="description" content="A flat HTML tool"/>
     <meta name="keywords" content="test, flat, html"/>
   - /tmp/test-artifacts-spike/dir-game/index.html with:
     <title>Directory Game</title>
     <meta name="description" content="A directory-based game"/>
     <meta name="keywords" content="game, directory, trust, ethics"/>

2. Run the scanArtifactsDir() function from lib-html-meta-addition.ts against /tmp/test-artifacts-spike/
   (copy the function inline or import it — whichever compiles faster)

3. Assert all of the following and print PASS or FAIL for each:
   - Result count = 2
   - flat-tool: isDirectory=false, slug='flat-tool', artifactPath='/artifacts/flat-tool.html'
   - flat-tool: keywords includes 'test', 'flat', 'html'
   - dir-game: isDirectory=true, slug='dir-game', artifactPath='/artifacts/dir-game/index.html'
   - dir-game: keywords includes 'game', 'directory', 'trust', 'ethics'
   - dir-game: title = 'Directory Game'
   - Both results: description is non-empty string

4. Run the script with: npx ts-node test-scan-artifacts.ts
   Report the full output and any TypeScript compilation errors.

Clean up /tmp/test-artifacts-spike/ after the test.

Expected output: 7 PASS lines, no FAIL lines, no TypeScript errors.

Handoff condition: All 7 assertions pass. If any fail, the failure mode must be diagnosed before Step 10 begins.

Dependency: Step 1 (success criteria defined before running the spike).


Step 5 · Phase F · Human Task

Labor: Human · [PA] Plausibility Auditing

The test script verifies what it was told to verify. The human checks whether those assertions are sufficient — whether there are failure modes the test didn't cover.

Action

Read the test output from Step 4. Check two things the test didn't:

  1. Keyword parsing edge case: If a keywords meta tag has a keyword with a leading/trailing space ("game, directory"["game", " directory"]), does the slug-derived keyword strip the space? It should. Check the raw output.
  2. Empty directory case: The test only covers two files. What if a subdirectory exists but has no index.html? Confirm that scanArtifactsDir() skips it rather than returning an entry with a null/empty artifactPath.

If either check fails, log it as a bug to fix in Step 10 before the function is added to the live codebase.

Handoff condition: Keyword strings are trimmed. Directories without index.html are skipped. Both confirmed from test output or via a follow-up test.

Dependency: Step 4.


Step 6 · Phase F · Claude Task

Labor: Claude Code

Context required: The Zebonastic project codebase (app/tools/ToolsBrowser.tsx and any files that import it)

Prompt

Read-only audit of ToolsBrowser.tsx. Make no changes.

1. Read app/tools/ToolsBrowser.tsx and paste the full TypeScript props interface (the type or interface that defines what the component accepts as props).

2. Run:
   grep -rn "ToolsBrowser" --include="*.tsx" --include="*.ts" .
   List every file that imports or uses ToolsBrowser and what props it passes.

3. Find the .map() call(s) inside ToolsBrowser that render tool cards. Paste the relevant 10–15 lines showing what fields are accessed on each item (e.g. item.name, item.slug, item.description, etc.).

4. Answer: if we add a new optional prop artifactPath?: string to the item type, does that break any existing caller? (A caller breaks if it passes a prop that no longer exists, or if it omits a prop that becomes required.)

5. The new ToolCard type we need to accept is:
   {
     id: string;
     name: string;
     description: string;
     tags: string[];
     source: 'filesystem' | 'database';
     type: 'artifact' | 'link';
     href: string;
     artifactPath?: string;
     externalUrl?: string;
     openExternal: boolean;
   }
   
   Write the minimal diff to ToolsBrowser.tsx that accepts ToolCard[] while keeping all existing callers working — but do not apply it yet. Return the diff only.

Expected output: The existing props interface, a list of callers, the accessed fields from the .map(), a clear yes/no on breaking change risk, and a minimal diff.

Handoff condition: Existing props interface is documented. All callers identified. Diff produced. The human can read this output and make the decision in Step 7.

Dependency: Step 1.


Step 7 · Phase F · Human Task

Labor: Human · [IJ] Interpretive Judgment

The audit in Step 6 surfaces facts. The decision about what to change — and whether the change is acceptable given how the rest of the codebase was built — requires someone who knows the full site and can be accountable for the result.

Action

Read the Step 6 output. Decide:

Record the decision in a comment in the patch file before Step 11 runs.

Handoff condition: A specific change strategy is chosen. The diff from Step 6 is either approved as-is or annotated with modifications.

Dependency: Step 6.


Step 8 · Phase F · Claude Task

Labor: Claude Code

Context required: dist-smoke-test/ from Step 2, specifically dist-smoke-test/js/user-config.js and dist-smoke-test/index.html

Prompt

Add a timing probe to the smoke test build to verify that PEEP_METADATA is overwritten before any slide initialization runs.

In dist-smoke-test/js/user-config.js, add these two console.log lines immediately after the PEEP_METADATA = {...} assignment:

  console.log('[user-config] PEEP_METADATA set. Keys:', Object.keys(PEEP_METADATA));
  console.log('[user-config] tft.color =', PEEP_METADATA.tft && PEEP_METADATA.tft.color);

Also add this at the very top of dist-smoke-test/js/user-config.js (before the IIFE):
  console.log('[user-config] script loaded');

Then print instructions for the human to follow:
1. Open a terminal: cd dist-smoke-test && npx http-server -p 8080
2. Open http://localhost:8080 in a browser
3. Open browser DevTools → Console
4. Look for:
   - '[user-config] script loaded' appearing in the log
   - '[user-config] PEEP_METADATA set. Keys: [tft, all_d, all_c, grudge, prober, tf2t, pavlov, random]'
   - '[user-config] tft.color = #4089DD'
   - Whether these appear BEFORE or AFTER any Slideshow/PIXI log lines

Do not serve the file automatically — the human must run this step manually and report what the console shows.

Expected output: Instructions printed for the human, probe lines added to user-config.js.

Handoff condition: user-config.js has the probe lines added and is ready for human browser verification.

Dependency: Step 2.


Step 9 · Phase F · Human Task

Labor: Human · [PA] Plausibility Auditing

This is the single check Claude Code cannot perform. It requires opening a browser, reading a console, and making a judgment about log order. If the overwrite happens after PIXI initializes, characters will silently display wrong colors in the live site — no error thrown.

Action

Follow the instructions from Step 8. Serve dist-smoke-test/ and open the browser console. Look for:

PASS: All three probe lines appear before any PIXI/Slideshow initialization.

FAIL (and what to do): If probe lines appear after PIXI lines, the <script src="js/user-config.js"> injection point in generate.js is wrong — the tag must be moved later in index.html. Return to generate.js's patchIndexHtml() function and find a script tag that loads after all PIXI dependencies but before any slide initialization.

Handoff condition: All three probe lines appear in console before PIXI/Slideshow logs. The overwrite executes at the right moment.

Dependency: Step 8.


Step 10 · Phase C · Claude Task

Labor: Claude Code

Context required: lib/html-meta.ts (existing file), trust-template/zebonastic-patches/lib-html-meta-addition.ts (the patch to add), Step 5 bug log (if any keyword trimming or empty-directory issues were found)

Prompt

Add scanArtifactsDir() to lib/html-meta.ts. Source: trust-template/zebonastic-patches/lib-html-meta-addition.ts.

Before adding:
1. Read the existing lib/html-meta.ts — check if there is already an extractMeta or similar helper function for reading title/description/keywords from HTML. If yes, use it instead of duplicating.
2. Check if there is already a slugify() function in lib/html-meta.ts or lib/utils.ts. If yes, use the existing one.
3. Apply the keyword trimming fix if flagged in Step 5: ensure keywords array trims whitespace from each element.
4. Apply the empty-directory guard if flagged in Step 5: directories without index.html are skipped.

Add the function and the ArtifactMeta interface as named exports. Do not modify any existing function.

After adding:
   npx tsc --noEmit

Report the compilation result. If there are type errors, paste them and fix them.

Expected output: lib/html-meta.ts updated with scanArtifactsDir() and ArtifactMeta as exports. npx tsc --noEmit exits with no errors.

Handoff condition: TypeScript compilation clean. scanArtifactsDir and ArtifactMeta are named exports from lib/html-meta.ts.

Dependency: Steps 5 (spike passed), 7 (ToolsBrowser decision made — needed before proceeding to 11).


Step 11 · Phase C · Claude Task

Labor: Claude Code

Context required: app/tools/ToolsBrowser.tsx (existing), Step 6 audit output, Step 7 decision

Prompt

Update ToolsBrowser.tsx to accept ToolCard[] per the decision recorded in [Step 7].

The ToolCard type:
  {
    id: string;
    name: string;
    description: string;
    tags: string[];
    source: 'filesystem' | 'database';
    type: 'artifact' | 'link';
    href: string;
    artifactPath?: string;
    externalUrl?: string;
    openExternal: boolean;
  }

Apply the specific strategy chosen in Step 7 (additive extension, union type, or new component).

In the card rendering:
- Cards with openExternal=true: render as <a href={card.href} target="_blank" rel="noopener noreferrer">
- Cards with openExternal=false: render as <Link href={card.href}>
- Artifact cards (type='artifact'): show 'Artifact' badge
- Link cards (type='link'): show 'Link' badge

Preserve: search input behavior, tag filter bar, card grid layout, all existing visual design.

After the change:
   npx tsc --noEmit
Report any type errors and fix them.

Expected output: ToolsBrowser.tsx updated with ToolCard type support. No type errors.

Handoff condition: TypeScript compilation clean. Both link and artifact card types render with correct navigation behavior.

Dependency: Steps 7, 10.


Step 12 · Phase C · Claude Task

Labor: Claude Code

Context required: app/tools/page.tsx (existing), trust-template/zebonastic-patches/app-tools-page.tsx (patch)

Prompt

Apply the tools/page.tsx patch from trust-template/zebonastic-patches/app-tools-page.tsx.

Before applying:
1. Read the existing app/tools/page.tsx
2. Note any content that differs from the patch:
   - Different page metadata (title, description)
   - Additional database queries beyond the basic tools table fetch
   - Any extra tool types or display logic not in the patch
3. Merge those site-specific elements into the patch before applying

Key behavior to preserve:
- Database link tools must continue to appear alongside filesystem artifact tools
- The page must remain a server component (no 'use client')

Apply the merged file, then:
   npx tsc --noEmit

Report any type errors.

Expected output: app/tools/page.tsx replaced with merged version. No type errors.

Handoff condition: TypeScript compilation clean. The page imports scanArtifactsDir from lib/html-meta and passes ToolCard[] to ToolsBrowser.

Dependency: Steps 10, 11.


Step 13 · Phase C · Claude Task

Labor: Claude Code

Context required: app/tools/[slug]/page.tsx (existing), trust-template/zebonastic-patches/app-tools-slug-page.tsx (patch)

Prompt

Apply the tools/[slug]/page.tsx patch from trust-template/zebonastic-patches/app-tools-slug-page.tsx.

Before applying:
1. Read the existing app/tools/[slug]/page.tsx
2. Note any UI differences in the title bar (different styling, additional buttons, different "Back" link text) or iframe container (different height calculation, sandbox attributes)
3. Merge those into the patch — especially preserve any existing iframe sandbox or allow attributes

The critical behavior change in the patch: resolveFilesystemArtifact() tries both:
  public/artifacts/[slug].html  (flat file — existing behavior)
  public/artifacts/[slug]/index.html  (directory artifact — new)
The flat path is tried first, so existing tools are not affected.

Apply the merged file, then:
   npx tsc --noEmit

Report any type errors.

Expected output: app/tools/[slug]/page.tsx replaced with merged version. No type errors.

Handoff condition: TypeScript compilation clean. resolveFilesystemArtifact() handles both flat and directory paths.

Dependency: Step 10. (This step is independent of Steps 11–12; it can run in parallel if needed.)


Step 14 · Phase C · Human Task

Labor: Human · [TO] Tool Orchestration

Deciding to push to a preview branch rather than main is a tool orchestration decision. The human chooses when to expose the change to Vercel's build system — and chooses a preview branch so a build failure doesn't break the live site.

Action

git checkout -b feat/directory-artifacts
git add lib/html-meta.ts app/tools/ToolsBrowser.tsx app/tools/page.tsx app/tools/[slug]/page.tsx
git commit -m "feat: add directory artifact discovery for trust-template games"
git push origin feat/directory-artifacts

Wait for the Vercel preview deploy to complete. Check the deploy log for build errors — specifically TypeScript compilation errors and any server component errors.

If the build fails: paste the Vercel deploy log error into Claude Code and ask it to diagnose.

Handoff condition: Vercel preview build succeeds (green check in Vercel dashboard). No build errors in the deploy log.

Dependency: Steps 12, 13.


Step 15 · Phase C · Human Task

Labor: Human · [PA] Plausibility Auditing

Regression check before adding any game. The patch should not have changed anything visible on the tools page yet — no directory artifacts exist in the repo. If something broke, it broke because of the code change, not because of new content.

Action

Navigate to the preview deployment's /tools page. Verify:

  1. All existing tools still appear (count them — the number should not have changed)
  2. Tag filter bar still renders and filters correctly
  3. Clicking an existing link tool still opens in a new tab
  4. Clicking an existing artifact tool still navigates to /tools/[slug] and loads the iframe
  5. No JavaScript console errors on page load

PASS: All existing tools work. Page looks identical to production except it's running the patched code.

FAIL: Any existing tool disappears or its behavior changes. This means the merger in Step 12 dropped something from the original page.tsx. Return to Step 12 and fix.

Handoff condition: All existing tools work on the preview deployment. Zero regressions.

Dependency: Step 14.


Step 16 · Phase I · Claude Task

Labor: Claude Code

Context required: trust-template/generate.js, trust-template/example-game.json, ./trust-source/ (trust game source), the Zebonastic project root path

Prompt

Deploy the evolution-of-trust starter template to the Zebonastic site.

1. Create ./example-game/ containing example-game.json from trust-template/

2. Run:
   node trust-template/generate.js ./example-game ./trust-source --nextjs .
   (This writes to ./public/artifacts/evolution-of-trust/)

3. Verify the output:
   ls -la public/artifacts/evolution-of-trust/
   ls -la public/artifacts/evolution-of-trust/js/
   grep -n "description\|keywords\|user-config" public/artifacts/evolution-of-trust/index.html

4. Commit to the preview branch:
   git add public/artifacts/evolution-of-trust/
   git commit -m "feat: add evolution-of-trust starter template (trust-template reskin)"
   git push origin feat/directory-artifacts

Report the generator output, the verification results, and the git output.

Expected output: public/artifacts/evolution-of-trust/ created with full game structure. index.html contains description, keywords, and user-config.js script tag. Committed and pushed to preview branch.

Handoff condition: Directory exists in the repo. index.html passes the grep checks. Commit is on the preview branch.

Dependency: Steps 3 (generator verified), 9 (overwrite timing verified), 15 (site preview stable with no regressions).


Step 17 · Phase I · Human Task

Labor: Human · [PA] Plausibility Auditing

The first moment the full pipeline is visible end-to-end. The card should appear; the fact that it does tells you scanArtifactsDir() found the directory, extracted the metadata, and ToolsBrowser rendered it correctly.

Action

After Vercel rebuilds the preview (from the Step 16 commit), navigate to /tools. Verify:

  1. A card labeled "The Evolution of Trust" appears in the grid
  2. The card shows the description from example-game.json
  3. The card shows the keyword tags (game theory, prisoner's dilemma, ethics, ethical play)
  4. The card is marked as an "Artifact" type (not a "Link")
  5. The card links to /tools/evolution-of-trust (not to an external URL)

PASS: All 5 checks clear.

FAIL on 1–4: scanArtifactsDir() or the metadata extraction failed. Add console.log to scanArtifactsDir() and check Vercel function logs.

FAIL on 5: ToolsBrowser is still routing artifact cards to external URLs. The openExternal field isn't being read correctly.

Handoff condition: Card appears on /tools with correct title, description, tags, and routing.

Dependency: Step 16.


Step 18 · Phase I · Human Task

Labor: Human · [PA] Plausibility Auditing

The highest-stakes handoff in the build. Three independent failure modes (wrong iframe src, WebGL blocked in iframe, PD.js overwrite timing) all manifest here simultaneously. If this fails, the cause must be isolated before anything else proceeds.

Action

Click through to /tools/evolution-of-trust. Verify end-to-end:

  1. Iframe loads: the game appears in the iframe — not a blank frame, not a 404
  2. Characters correct: characters show the colors from example-game.json (blue for Copycat, dark purple for Always Cheat, etc.)
  3. Payoffs correct: play one round of the iterated game — verify the coin payoffs match the defaults (R=2, T=3, S=-1, P=0)
  4. Sound works: confirm audio plays when coins are inserted (may require a user interaction first)
  5. No console errors: open browser DevTools during the game — no uncaught exceptions
Fail triage:

Handoff condition: Game loads in iframe, characters display correct colors, payoffs apply correctly, no console errors.

Dependency: Step 17.


Step 19 · Phase I · Human Task

Labor: Human · [IJ] Interpretive Judgment

This is the gap the course is built on. Claude Code cannot evaluate whether the game works as a teaching tool. That requires playing it, having domain knowledge of how the prisoner's dilemma functions as an ethical frame, and making a judgment about whether a student who has never encountered game theory will encounter moral weight or mere strategy.

Action

Play the Evolution of Trust game end-to-end as a first-time student in Ethical Play Week 7. Ask:

  1. Is the prisoner's dilemma framing legible to someone who hasn't read about it? Does the game's narration explain the ethical stakes, or does it assume prior knowledge?
  2. Does the tournament outcome produce a moment of felt moral weight — or does it feel like a math demonstration?
  3. Would a student building a consequentialist reskin have a clear enough model of what they're changing (payoff structure, character behavior) versus what stays fixed (the dynamics)?

This is not a pass/fail check. It's a content judgment about whether this template will serve the course. Record any observations that should inform how the STUDENT-GUIDE.md (Step 21) frames the template for students.

Handoff condition: Instructor has played the game and has an opinion about whether it serves the pedagogical goal. That opinion feeds Step 20 and Step 21.

Dependency: Step 18.


Step 20 · Phase B · Human Task

Labor: Human · [PF] Problem Formulation

The most irreducibly human step in the entire build. Claude Code can generate a trust-template reskin for any spec. It cannot decide what ethical framework a reskin should embody, which characters would best dramatize that framework, or what words.html should say to produce felt moral weight rather than ethical description. That is the course's subject matter.

Action

For each additional starter template (estimate 2–3 based on course frameworks), write a spec before Step 22 runs:

This spec is the entire input to Step 22. The quality of Step 22's output is bounded by the quality of this spec.

Handoff condition: Written spec for each additional template exists. Each spec names the ethical framework, the payoff reframing, and the 8 characters before Claude Code writes a line.

Dependency: Step 19 (pedagogical assessment informs the spec).


Step 21 · Phase B · Claude Task

Labor: Claude Code

Context required: Step 3 and Step 9 results (verified generator behavior), Step 19 observations (pedagogical notes), trust-template/README.md

Prompt

Write a student-facing guide: "How to reskin a trust template with Claude Code."

Save to trust-template/STUDENT-GUIDE.md.

Target reader: a graduate engineering student in the Ethical Play course, Week 7 (Build I: Core Mechanic). They have a completed GDD and a chosen ethical framework. They have not worked with the trust game codebase before. They use Claude Code.

Cover exactly these topics, in this order:
1. What the template gives you (the prisoner's dilemma mechanics, free — you change who's playing and why, not how the math works)
2. The one constraint they cannot change: each of the 8 characters must embody one of the 8 fixed strategy IDs (tft, tf2t, grudge, all_d, all_c, random, pavlov, prober). Explain this as a design constraint, not a technical limitation: the strategy behavior IS the ethical position.
3. The three files they edit: game.json, words.html, assets/
4. game.json step-by-step: name, color, the strategy ID assignment. One concrete example: "If your consequentialist framework casts Copycat as 'The Proportionalist,' change name to 'Proportionalist' and keep strategy: 'tft'."
5. words.html step-by-step: how to find character name spans (<span class="tft">Copycat</span>), how to replace the display text. Warning: replacing the id attribute breaks the game — replace only the text inside the span.
6. Running the generator — exact command: node generate.js ./my-game ./trust-source --nextjs /path/to/zebonastic
7. What to do when the build fails: paste the error into Claude Code and ask: "The trust-template generator returned this error. What's wrong with my game.json?"

Tone: direct. No condescension. These are graduate engineering students. The ethical architecture decisions are theirs; the technical steps are the generator's job.

Length: one page. No headers beyond the 7 topics above.

Expected output: trust-template/STUDENT-GUIDE.md, approximately 600–800 words, covering all 7 topics, no fluff.

Handoff condition: Guide covers all 7 topics. The <span class="tft"> warning is explicit. The strategy ID constraint is explained as a design constraint, not a technical one.

Dependency: Steps 3, 9 (generator is verified, so the commands in the guide are accurate).


Step 22 · Phase B · Claude Task (one session per additional template)

Labor: Claude Code

Context required: The spec from Step 20 for this specific template, trust-template/example-game.json (as schema reference), ./trust-source/ (trust game source)

Prompt

Generate a trust-template reskin per this spec:

[PASTE SPEC FROM STEP 20 HERE — title, slug, ethical framework, 8 character definitions, payoff reframing]

Steps:
1. Create ./[slug]/ containing game.json with:
   - meta.title, meta.slug, meta.description matching the spec
   - meta.keywords including the ethical framework name and 'ethical play'
   - 8 characters: each with id matching a valid strategy ID (tft/tf2t/grudge/all_d/all_c/random/pavlov/prober), name and color from the spec, frame 0–7 (one unique frame per character)
   - payoffs from the spec (or default 2/3/-1/0 if not specified)

2. Validate the game.json before building:
   node trust-template/generate.js ./[slug] . --validate

3. If validation passes, build:
   node trust-template/generate.js ./[slug] ./trust-source --nextjs .

4. Verify: ls -la public/artifacts/[slug]/

5. Commit:
   git add public/artifacts/[slug]/
   git commit -m "feat: add [slug] starter template ([ethical framework])"

Report: any validation errors encountered, the verification output, the final commit hash.

Expected output: New game directory in public/artifacts/[slug]/, committed to the preview branch.

Handoff condition: --validate passes. Generator completes without errors. Directory exists in the repo.

Dependency: Steps 16 (generator is verified end-to-end), 20 (instructor spec exists).


Step 23 · Phase H · Claude Task

Labor: Claude Code

Context required: trust-template/generate.js, observations from Steps 2 and 16 (any edge cases encountered during actual runs)

Prompt

Improve error handling in trust-template/generate.js. Apply these specific changes:

1. Strip _note fields before processing: after JSON.parse(config), recursively remove any key starting with "_" from all objects. This prevents _note comment fields in game.json from causing unexpected behavior.

2. Specific missing-file error: when trust-source is missing a required engine file (js/sims/PD.js, index.html), fail with: "❌ Missing required file in trust-source: [filename]. Is this the ncase/trust repository?"

3. Keywords as string or array: if meta.keywords is a comma-separated string, split it into an array before validation. If it's already an array, use as-is.

4. Guard against empty alias args: the current arg parsing for output-dir can match '--nextjs' itself if the user forgets the path argument. Add a check: if the output-dir argument starts with '--', it's a flag not a path — fail with a clear error.

5. Add --dry-run flag: when present, print what would be copied/generated without writing any files. Format:
   [dry-run] Would copy: ./trust-source/js → ./dist/js
   [dry-run] Would generate: ./dist/js/user-config.js
   [dry-run] Would write: ./dist/index.html (patched)

After changes:
- Run with example-game.json: node generate.js ./example-game ./trust-source --dry-run
- Run with a broken game.json (remove the 'tft' character): verify the error message is specific
- Report all outputs

Expected output: Updated generate.js with 5 improvements. All three test runs produce expected output.

Handoff condition: --dry-run works. Broken game.json produces specific error naming the missing strategy. _note fields don't cause validation errors.

Dependency: Steps 2, 16 (real runs have surfaced actual edge cases by now).


Step 24 · Phase H · Human Task

Labor: Human · [TO] Tool Orchestration

Deciding how the tool fails is a pedagogical decision, not a technical one. A generator that warns-and-continues with defaults may produce a game that runs but encodes the wrong ethical framing — and the student won't know. A generator that fails loudly may frustrate students who want to iterate quickly. The instructor decides which failure mode serves the course.

Action

Decide the error behavior policy for student-facing generator runs:

For the Ethical Play course, the design decision is the student's core deliverable. A generator that silently patches their mistakes is pedagogically counterproductive.

Handoff condition: Decision is recorded. Claude Code implements it in Step 25.

Dependency: Step 23.


Step 25 · Phase H · Claude Task

Labor: Claude Code

Context required: trust-template/generate.js, decision from Step 24

Prompt

Implement the error behavior policy decided in [Step 24] consistently across generate.js.

If the decision was FAIL LOUD (expected):
- All errors in validate() cause process.exit(1) with a specific message
- Warnings print with ⚠ but the build continues
- Error messages must include: the field path, the invalid value, and what a valid value looks like. Example: "❌ characters[2].strategy: 'tft' is already used by characters[0]. Each strategy must appear exactly once. Valid strategies: tft, tf2t, grudge, all_d, all_c, random, pavlov, prober"

Apply this standard to every error currently in the validate() function. Check that none of the existing error messages are vague (e.g., "invalid strategy" is vague; "unknown strategy 'tft2' — did you mean tf2t?" is specific).

After changes:
- Test with a game.json that has a duplicate strategy: verify the error names both characters
- Test with a game.json that's valid: verify the build completes without printing any errors
- Report both test outputs

Expected output: Updated generate.js with specific, actionable error messages. Both test cases produce expected behavior.

Handoff condition: Error messages name the exact field, the invalid value, and the valid options. Valid game.json produces clean output with no errors.

Dependency: Step 24.


Step 26 · Phase R · Human Task

Labor: Human · [EI] Executive Integration

This is the one step where all four other supervisory capacities are exercised simultaneously. The human must hold the generator, the site patches, the student workflow, and the course taxonomy together and confirm they form a coherent whole before merging to main.

Action

git checkout main
git merge feat/directory-artifacts
git push origin main

After Vercel deploys main:

  1. /tools — all starter templates appear with correct tags. Tag filter "ethical play" returns all course templates.
  2. /tools/evolution-of-trust (and each additional template from Step 22) — iframe loads, game plays correctly.
  3. /sitemap.xml — the new tool slugs appear in the sitemap.
  4. Taxonomy check: the keywords in each game.json align with how the Ethical Play course syllabus describes those frameworks. A student searching by "consequentialism" or "prisoner's dilemma" on /tools would find the right template.
  5. Student workflow check: hand the STUDENT-GUIDE.md to one student or TA and ask them to follow it. Do they hit any step where the instructions don't match what they see?

Handoff condition: All templates visible on /tools with correct tags. All iframes load. Sitemap updated. Taxonomy terms in keywords match course vocabulary. STUDENT-GUIDE.md survives a first reader.

Dependency: All prior steps.


Score Summary

Count%
Total steps26
Claude tasks1350%
Human tasks1350%

Critical Path

The longest dependency chain — any delay cascades:

Step 1 → 2 → 3 → 8 → 9 → 16 → 17 → 18 → 19 → 26

Ten steps. Steps 3, 9, 18, and 19 are all human tasks on this path. The build cannot be fully automated — four browser/play checks are on the critical path and each one gates the next.

Highest-Risk Handoffs

Step 18 — PA: Full game playthrough on preview. Three independent failure modes manifest simultaneously: wrong iframe src (routing bug), WebGL blocked in iframe (Vercel CSP headers), PEEP_METADATA overwrite timing (script load order). If the game fails here, diagnosing which of the three failed requires systematic isolation. The risk is that all three look the same from outside the browser console: a broken or blank game.
Step 9 — PA: PD.js overwrite timing. If PEEP_METADATA is consumed by any PIXI initialization that runs before user-config.js finishes parsing, characters will display original colors silently. No error is thrown. The only evidence is the wrong color on screen. This spike exists specifically to catch this failure mode before it reaches the live site.
Step 7 — IJ: ToolsBrowser props decision. ToolsBrowser.tsx was written without seeing its full context in the codebase. If the component is used in 3+ places with different prop shapes, the Step 11 change could cascade into multiple type errors not visible until the Vercel build runs. The Step 6 audit exists to surface this risk; Step 7 is where the human decides how to handle it.

Supervisory Capacity Distribution

CapacityStepsCount
[PA] Plausibility Auditing3, 5, 9, 15, 17, 186
[PF] Problem Formulation1, 202
[TO] Tool Orchestration14, 242
[IJ] Interpretive Judgment7, 192
[EI] Executive Integration261
FLAG — [EI] appears only once. A build where executive integration happens only at the release step is fragile. There is no mid-build moment where the human has explicitly held all the threads together. Recommend: treat Step 19 (pedagogical judgment) as a lightweight EI checkpoint — add an explicit check at that step for whether the generator output, the site patches, and the student workflow are coherent as a system, not just individually correct.

What Is Missing from This Score

The SDD is the music. This score is who plays what, in what order, and when to listen for the wrong note.