← Design · c133

review-3.md

c133 · Phase 3 review note: the authoring pipeline (2026-11-11)

For: Mark. What exists: the trainings as a content collection (D4), one parser that both the lab and the API read through, a preview page in the lab, the publish step at /api/trainings (D21), the scene and asset conventions written down, and a /training skill for the next one. The first pilot moved into the collection without a word changed. Mark's D25–D27 (ruled the same night while this was built) are in: the record names the training's title, version and content hash, and the completion is its own event per assigner. Phase 4 follows without a stop; the calls below wait for the end of Phase 4.

Where to look

WhatWhereWhy
The collection, previewed/pages/phase4/trainingsper training: policy, minutes, steps, questions, lang, version, the content hash, the voice check run live on every sentence as read on each finding of its policy, the slots it reads, the scenes it draws; links that open it on each of those findings in the mock; files with problems listed as withheld; the scene catalogue
The filecontent/trainings/en/unapproved-mcp-servers.mdhow a training reads to an author: frontmatter for its fields, then # Assignment, # Lesson, # Check
The formatauthoring.mdthe file, the slots, the scenes decision, the voice rule, what the parser refuses
What the apps readpublish.md and /api/trainings, /api/trainings/T-MCP-1the two routes, the shape (the Training type field for field), the slots an app fills, version and hash (D26), languages (D11)
The record, after Phase 3training?findingId=F-A&at=recordedtraining.completed.policy (D27); T-MCP-1 v1 and the hash's first twelve characters (D26); the Reports line now links the Corrections section
The loop.claude/skills/training/SKILL.mdthe policy and a real finding, the file with slots, the kind's slots and scenes, the voice check, preview, capture, record

The captures are in the cycle's Visual record under the thread "Phase 3 · the authoring pipeline" (scripts/shot-programs/c133-pipeline.json: the collection page, the record).

What was decided, and why

  1. The format: frontmatter for the fields, the body for the words. The training's fields (id, slug, title, policyId, minutes, version, lang, contact) are frontmatter; the assignment's two sentences, the lesson and the check are markdown sections. A step is a ## heading, a short block of id: scene: alt: lines, then its paragraphs; a question is a ## heading, id: step: explain:, then its choices as a task list with [x] on the right one. Paragraphs read as paragraphs, and YAML's traps (a value that starts with {, a : inside a sentence) stay out of the prose. It maps one-to-one onto Training in types.ts; the parsed file of the first pilot equals Phase 1's TypeScript field for field.
  2. One parser, two readers. app/data/trainings/parse.ts reads a file. The lab reads the files at build time (index.ts, so an edit reloads the mock); the API reads the content collection trainings (its schema checks the frontmatter) and passes the file's raw text to the same parser. The lab and what the apps read cannot disagree. A file with problems is withheld from both, with the reason on the preview page.
  3. One file per language, in a folder per language (D11): content/trainings/<lang>/<slug>.md; the parser checks the folder and the name against the frontmatter.
  4. The assignment's words moved into the training. Phase 1 built the message's first two sentences in code, about MCP servers; now each training writes its own (# Assignment), and the third sentence stays every training's.
  5. Slots per finding kind. slots.ts holds the common slots and one function per kind of thing a finding touches (mcpServer today; Phase 4 adds account and dataClass), each reading only the world.
  6. Scenes stay components, in a catalogue. One file per scene in components/training/scenes/, catalogued in data/trainings/scenes.ts with what it shows, who drew it, the slots it reads and whether it moves; Scene.vue frames it and maps the name, and a catalogued scene without a drawing is a type error. A scene reads the finding and the theme, which an asset file cannot. Hand-drawn art has a place (public/trainings/<slug>/, shown by a scene component) but none exists. The only motion is the flow arrow, still under reduced motion.
  7. The voice check runs on the preview page too, with the brand MCP's rules mirrored (voice.ts), on the file and on every finding of its policy, so a later edit cannot slip a violation in. The MCP tool stays the check of record when a training is written.
  8. D26 as built: the content hash is SHA-256 over the training object as the API serves it, from one implementation (hash.ts) used by the API and by the lab's record. D25: the record carries the training's title. D27: the lab's audit log mock writes training.completed.policy (Tyler's to rename).

What was checked

  • The parsed first pilot equals Phase 1's unapproved-mcp-servers.ts field for field; the old file is gone.
  • Thirteen rendered pages of the mock compared as text before and after the move (F-A at every stage and step, the finding, the Findings report, F-C's absence): identical.
  • /api/trainings lists the training with its hash; /api/trainings/T-MCP-1 returns it whole; the hash equals the one the lab's record names. The SHA-256 matches Node's on test strings.
  • The preview page: zero voice violations across 77 texts (the file and F-A, F-B, F-E as read); no failed requests in the browser pane.

What changed on screen: the record card and the audit row (D25–D27), the record page's Reports line (now a link; it said "Phase 2"), and the honest-absence copy (it names planned pilots only while any are planned). Phase 1's captures stay as they were, as history; the record is retaken under the Phase 3 thread.

An incident to own

From about 15:14 to 15:40 every page on the shared dev server answered 500 ("IPC connection closed"). The cause was this phase's preview page: a template literal with }} inside a {{ … }} interpolation, which ends the interpolation early, so the page failed to compile and vite-node's SSR worker took every route down with it (the same failure memory records from c122). Restarts could not help until the file was fixed. I stopped the server that had been running since 12:49, restarted it from the launch config (design), found the file with @vue/compiler-sfc, fixed it, and restarted again; every page answers 200 since. Another session's captures in that window would have failed.

The calls for you

  1. The right answers ship in the published data. The web app grades the check (D3), so /api/trainings/<id> marks the right choice. Anyone who reads the API can read the answers; the check is a check of understanding, not an exam (R3). The alternative: the plane grades, the API drops right, and a grading route returns the result. Proposed: keep it as built.
  2. How the apps reach the API. The design site sits behind Cloudflare Access, so the plane cannot read design.internal.qpoint.io without a service token. Options: the plane syncs from the design site with a service token; the publish step writes the JSON into the plane's repository at release; or the trainings move to a public route. Proposed: the publish step's JSON copied into the plane at release, so a training is versioned with the plane that serves it (D5's content modules would then be signed from there). Not built.
  3. A language with no file. publish.md says the app shows the English file and says so. The alternative is to show nothing until a translation exists. Proposed: English with a line saying so.
  4. When the version moves. A change of meaning (a step, a question, a right answer) bumps version; a typo fix does not, though the hash moves with any change to the served text. Proposed as written in authoring.md.

What is not done

Phase 4 (the two other pilots) runs next in this session. The static deploy of /api/trainings (prerendered through the preview page's links) is not checked: nothing was deployed. Tyler's answers on D22–D27 are outstanding. event-shape.md still names training.completed in §2 and §3 and is amended by its §8; the lab now follows §8.

Qpoint Brand Style Guide