[{"data":1,"prerenderedAt":836},["ShallowReactive",2],{"cycle-doc-design-c133-review-3.md":3},{"cycle":4,"project":7,"path":10,"title":11,"toc":12,"ast":19},{"id":5,"title":6},"c133","Remediation Training",{"id":8,"label":9},"design","Design","review-3.md","c133 · Phase 3 review note: the authoring pipeline (2026-11-11)",[13,14,15,16,17,18],"Where to look","What was decided, and why","What was checked","An incident to own","The calls for you","What is not done",{"type":20,"children":21},"root",[22,60,66,278,291,296,610,615,659,669,674,710,715,803,808],{"type":23,"tag":24,"props":25,"children":26},"element","p",{},[27,34,36,41,43,50,52,58],{"type":23,"tag":28,"props":29,"children":30},"strong",{},[31],{"type":32,"value":33},"text","For:",{"type":32,"value":35}," Mark. ",{"type":23,"tag":28,"props":37,"children":38},{},[39],{"type":32,"value":40},"What exists:",{"type":32,"value":42}," 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 ",{"type":23,"tag":44,"props":45,"children":47},"code",{"className":46},[],[48],{"type":32,"value":49},"\u002Fapi\u002Ftrainings",{"type":32,"value":51}," (D21), the scene and asset conventions written down, and a ",{"type":23,"tag":44,"props":53,"children":55},{"className":54},[],[56],{"type":32,"value":57},"\u002Ftraining",{"type":32,"value":59}," 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.",{"type":23,"tag":61,"props":62,"children":64},"h2",{"id":63},"where-to-look",[65],{"type":32,"value":13},{"type":23,"tag":67,"props":68,"children":69},"table",{},[70,94],{"type":23,"tag":71,"props":72,"children":73},"thead",{},[74],{"type":23,"tag":75,"props":76,"children":77},"tr",{},[78,84,89],{"type":23,"tag":79,"props":80,"children":81},"th",{},[82],{"type":32,"value":83},"What",{"type":23,"tag":79,"props":85,"children":86},{},[87],{"type":32,"value":88},"Where",{"type":23,"tag":79,"props":90,"children":91},{},[92],{"type":32,"value":93},"Why",{"type":23,"tag":95,"props":96,"children":97},"tbody",{},[98,121,164,186,228,256],{"type":23,"tag":75,"props":99,"children":100},{},[101,107,116],{"type":23,"tag":102,"props":103,"children":104},"td",{},[105],{"type":32,"value":106},"The collection, previewed",{"type":23,"tag":102,"props":108,"children":109},{},[110],{"type":23,"tag":111,"props":112,"children":114},"a",{"href":113},"\u002Fpages\u002Fphase4\u002Ftrainings",[115],{"type":32,"value":113},{"type":23,"tag":102,"props":117,"children":118},{},[119],{"type":32,"value":120},"per 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",{"type":23,"tag":75,"props":122,"children":123},{},[124,129,138],{"type":23,"tag":102,"props":125,"children":126},{},[127],{"type":32,"value":128},"The file",{"type":23,"tag":102,"props":130,"children":131},{},[132],{"type":23,"tag":44,"props":133,"children":135},{"className":134},[],[136],{"type":32,"value":137},"content\u002Ftrainings\u002Fen\u002Funapproved-mcp-servers.md",{"type":23,"tag":102,"props":139,"children":140},{},[141,143,149,151,157,158],{"type":32,"value":142},"how a training reads to an author: frontmatter for its fields, then ",{"type":23,"tag":44,"props":144,"children":146},{"className":145},[],[147],{"type":32,"value":148},"# Assignment",{"type":32,"value":150},", ",{"type":23,"tag":44,"props":152,"children":154},{"className":153},[],[155],{"type":32,"value":156},"# Lesson",{"type":32,"value":150},{"type":23,"tag":44,"props":159,"children":161},{"className":160},[],[162],{"type":32,"value":163},"# Check",{"type":23,"tag":75,"props":165,"children":166},{},[167,172,181],{"type":23,"tag":102,"props":168,"children":169},{},[170],{"type":32,"value":171},"The format",{"type":23,"tag":102,"props":173,"children":174},{},[175],{"type":23,"tag":111,"props":176,"children":178},{"href":177},"\u002Fcycles\u002Fdesign\u002Fc133\u002Fdoc\u002Fauthoring",[179],{"type":32,"value":180},"authoring.md",{"type":23,"tag":102,"props":182,"children":183},{},[184],{"type":32,"value":185},"the file, the slots, the scenes decision, the voice rule, what the parser refuses",{"type":23,"tag":75,"props":187,"children":188},{},[189,194,215],{"type":23,"tag":102,"props":190,"children":191},{},[192],{"type":32,"value":193},"What the apps read",{"type":23,"tag":102,"props":195,"children":196},{},[197,203,205,209,210],{"type":23,"tag":111,"props":198,"children":200},{"href":199},"\u002Fcycles\u002Fdesign\u002Fc133\u002Fdoc\u002Fpublish",[201],{"type":32,"value":202},"publish.md",{"type":32,"value":204}," and ",{"type":23,"tag":111,"props":206,"children":207},{"href":49},[208],{"type":32,"value":49},{"type":32,"value":150},{"type":23,"tag":111,"props":211,"children":213},{"href":212},"\u002Fapi\u002Ftrainings\u002FT-MCP-1",[214],{"type":32,"value":212},{"type":23,"tag":102,"props":216,"children":217},{},[218,220,226],{"type":32,"value":219},"the two routes, the shape (the ",{"type":23,"tag":44,"props":221,"children":223},{"className":222},[],[224],{"type":32,"value":225},"Training",{"type":32,"value":227}," type field for field), the slots an app fills, version and hash (D26), languages (D11)",{"type":23,"tag":75,"props":229,"children":230},{},[231,236,245],{"type":23,"tag":102,"props":232,"children":233},{},[234],{"type":32,"value":235},"The record, after Phase 3",{"type":23,"tag":102,"props":237,"children":238},{},[239],{"type":23,"tag":111,"props":240,"children":242},{"href":241},"\u002Fpages\u002Fphase4\u002Fmock\u002Ftraining?findingId=F-A&at=recorded",[243],{"type":32,"value":244},"training?findingId=F-A&at=recorded",{"type":23,"tag":102,"props":246,"children":247},{},[248,254],{"type":23,"tag":44,"props":249,"children":251},{"className":250},[],[252],{"type":32,"value":253},"training.completed.policy",{"type":32,"value":255}," (D27); T-MCP-1 v1 and the hash's first twelve characters (D26); the Reports line now links the Corrections section",{"type":23,"tag":75,"props":257,"children":258},{},[259,264,273],{"type":23,"tag":102,"props":260,"children":261},{},[262],{"type":32,"value":263},"The loop",{"type":23,"tag":102,"props":265,"children":266},{},[267],{"type":23,"tag":44,"props":268,"children":270},{"className":269},[],[271],{"type":32,"value":272},".claude\u002Fskills\u002Ftraining\u002FSKILL.md",{"type":23,"tag":102,"props":274,"children":275},{},[276],{"type":32,"value":277},"the policy and a real finding, the file with slots, the kind's slots and scenes, the voice check, preview, capture, record",{"type":23,"tag":24,"props":279,"children":280},{},[281,283,289],{"type":32,"value":282},"The captures are in the cycle's Visual record under the thread \"Phase 3 · the authoring pipeline\" (",{"type":23,"tag":44,"props":284,"children":286},{"className":285},[],[287],{"type":32,"value":288},"scripts\u002Fshot-programs\u002Fc133-pipeline.json",{"type":32,"value":290},": the collection page, the record).",{"type":23,"tag":61,"props":292,"children":294},{"id":293},"what-was-decided-and-why",[295],{"type":32,"value":14},{"type":23,"tag":297,"props":298,"children":299},"ol",{},[300,409,442,460,477,517,559,577],{"type":23,"tag":301,"props":302,"children":303},"li",{},[304,309,311,317,319,325,327,333,334,340,342,347,349,354,355,361,362,368,370,376,378,384,386,392,394,399,401,407],{"type":23,"tag":28,"props":305,"children":306},{},[307],{"type":32,"value":308},"The format: frontmatter for the fields, the body for the words.",{"type":32,"value":310}," 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 ",{"type":23,"tag":44,"props":312,"children":314},{"className":313},[],[315],{"type":32,"value":316},"##",{"type":32,"value":318}," heading, a short block of ",{"type":23,"tag":44,"props":320,"children":322},{"className":321},[],[323],{"type":32,"value":324},"id:",{"type":32,"value":326}," ",{"type":23,"tag":44,"props":328,"children":330},{"className":329},[],[331],{"type":32,"value":332},"scene:",{"type":32,"value":326},{"type":23,"tag":44,"props":335,"children":337},{"className":336},[],[338],{"type":32,"value":339},"alt:",{"type":32,"value":341}," lines, then its paragraphs; a question is a ",{"type":23,"tag":44,"props":343,"children":345},{"className":344},[],[346],{"type":32,"value":316},{"type":32,"value":348}," heading, ",{"type":23,"tag":44,"props":350,"children":352},{"className":351},[],[353],{"type":32,"value":324},{"type":32,"value":326},{"type":23,"tag":44,"props":356,"children":358},{"className":357},[],[359],{"type":32,"value":360},"step:",{"type":32,"value":326},{"type":23,"tag":44,"props":363,"children":365},{"className":364},[],[366],{"type":32,"value":367},"explain:",{"type":32,"value":369},", then its choices as a task list with ",{"type":23,"tag":44,"props":371,"children":373},{"className":372},[],[374],{"type":32,"value":375},"[x]",{"type":32,"value":377}," on the right one. Paragraphs read as paragraphs, and YAML's traps (a value that starts with ",{"type":23,"tag":44,"props":379,"children":381},{"className":380},[],[382],{"type":32,"value":383},"{",{"type":32,"value":385},", a ",{"type":23,"tag":44,"props":387,"children":389},{"className":388},[],[390],{"type":32,"value":391},": ",{"type":32,"value":393}," inside a sentence) stay out of the prose. It maps one-to-one onto ",{"type":23,"tag":44,"props":395,"children":397},{"className":396},[],[398],{"type":32,"value":225},{"type":32,"value":400}," in ",{"type":23,"tag":44,"props":402,"children":404},{"className":403},[],[405],{"type":32,"value":406},"types.ts",{"type":32,"value":408},"; the parsed file of the first pilot equals Phase 1's TypeScript field for field.",{"type":23,"tag":301,"props":410,"children":411},{},[412,417,418,424,426,432,434,440],{"type":23,"tag":28,"props":413,"children":414},{},[415],{"type":32,"value":416},"One parser, two readers.",{"type":32,"value":326},{"type":23,"tag":44,"props":419,"children":421},{"className":420},[],[422],{"type":32,"value":423},"app\u002Fdata\u002Ftrainings\u002Fparse.ts",{"type":32,"value":425}," reads a file. The lab reads the files at build time (",{"type":23,"tag":44,"props":427,"children":429},{"className":428},[],[430],{"type":32,"value":431},"index.ts",{"type":32,"value":433},", so an edit reloads the mock); the API reads the content collection ",{"type":23,"tag":44,"props":435,"children":437},{"className":436},[],[438],{"type":32,"value":439},"trainings",{"type":32,"value":441}," (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.",{"type":23,"tag":301,"props":443,"children":444},{},[445,450,452,458],{"type":23,"tag":28,"props":446,"children":447},{},[448],{"type":32,"value":449},"One file per language, in a folder per language",{"type":32,"value":451}," (D11): ",{"type":23,"tag":44,"props":453,"children":455},{"className":454},[],[456],{"type":32,"value":457},"content\u002Ftrainings\u002F\u003Clang>\u002F\u003Cslug>.md",{"type":32,"value":459},"; the parser checks the folder and the name against the frontmatter.",{"type":23,"tag":301,"props":461,"children":462},{},[463,468,470,475],{"type":23,"tag":28,"props":464,"children":465},{},[466],{"type":32,"value":467},"The assignment's words moved into the training.",{"type":32,"value":469}," Phase 1 built the message's first two sentences in code, about MCP servers; now each training writes its own (",{"type":23,"tag":44,"props":471,"children":473},{"className":472},[],[474],{"type":32,"value":148},{"type":32,"value":476},"), and the third sentence stays every training's.",{"type":23,"tag":301,"props":478,"children":479},{},[480,485,486,492,494,500,502,508,509,515],{"type":23,"tag":28,"props":481,"children":482},{},[483],{"type":32,"value":484},"Slots per finding kind.",{"type":32,"value":326},{"type":23,"tag":44,"props":487,"children":489},{"className":488},[],[490],{"type":32,"value":491},"slots.ts",{"type":32,"value":493}," holds the common slots and one function per kind of thing a finding touches (",{"type":23,"tag":44,"props":495,"children":497},{"className":496},[],[498],{"type":32,"value":499},"mcpServer",{"type":32,"value":501}," today; Phase 4 adds ",{"type":23,"tag":44,"props":503,"children":505},{"className":504},[],[506],{"type":32,"value":507},"account",{"type":32,"value":204},{"type":23,"tag":44,"props":510,"children":512},{"className":511},[],[513],{"type":32,"value":514},"dataClass",{"type":32,"value":516},"), each reading only the world.",{"type":23,"tag":301,"props":518,"children":519},{},[520,525,527,533,535,541,543,549,551,557],{"type":23,"tag":28,"props":521,"children":522},{},[523],{"type":32,"value":524},"Scenes stay components, in a catalogue.",{"type":32,"value":526}," One file per scene in ",{"type":23,"tag":44,"props":528,"children":530},{"className":529},[],[531],{"type":32,"value":532},"components\u002Ftraining\u002Fscenes\u002F",{"type":32,"value":534},", catalogued in ",{"type":23,"tag":44,"props":536,"children":538},{"className":537},[],[539],{"type":32,"value":540},"data\u002Ftrainings\u002Fscenes.ts",{"type":32,"value":542}," with what it shows, who drew it, the slots it reads and whether it moves; ",{"type":23,"tag":44,"props":544,"children":546},{"className":545},[],[547],{"type":32,"value":548},"Scene.vue",{"type":32,"value":550}," 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 (",{"type":23,"tag":44,"props":552,"children":554},{"className":553},[],[555],{"type":32,"value":556},"public\u002Ftrainings\u002F\u003Cslug>\u002F",{"type":32,"value":558},", shown by a scene component) but none exists. The only motion is the flow arrow, still under reduced motion.",{"type":23,"tag":301,"props":560,"children":561},{},[562,567,569,575],{"type":23,"tag":28,"props":563,"children":564},{},[565],{"type":32,"value":566},"The voice check runs on the preview page too",{"type":32,"value":568},", with the brand MCP's rules mirrored (",{"type":23,"tag":44,"props":570,"children":572},{"className":571},[],[573],{"type":32,"value":574},"voice.ts",{"type":32,"value":576},"), 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.",{"type":23,"tag":301,"props":578,"children":579},{},[580,585,587,593,595,601,603,608],{"type":23,"tag":28,"props":581,"children":582},{},[583],{"type":32,"value":584},"D26 as built:",{"type":32,"value":586}," the content hash is SHA-256 over the ",{"type":23,"tag":44,"props":588,"children":590},{"className":589},[],[591],{"type":32,"value":592},"training",{"type":32,"value":594}," object as the API serves it, from one implementation (",{"type":23,"tag":44,"props":596,"children":598},{"className":597},[],[599],{"type":32,"value":600},"hash.ts",{"type":32,"value":602},") 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 ",{"type":23,"tag":44,"props":604,"children":606},{"className":605},[],[607],{"type":32,"value":253},{"type":32,"value":609}," (Tyler's to rename).",{"type":23,"tag":61,"props":611,"children":613},{"id":612},"what-was-checked",[614],{"type":32,"value":15},{"type":23,"tag":616,"props":617,"children":618},"ul",{},[619,632,637,654],{"type":23,"tag":301,"props":620,"children":621},{},[622,624,630],{"type":32,"value":623},"The parsed first pilot equals Phase 1's ",{"type":23,"tag":44,"props":625,"children":627},{"className":626},[],[628],{"type":32,"value":629},"unapproved-mcp-servers.ts",{"type":32,"value":631}," field for field; the old file is gone.",{"type":23,"tag":301,"props":633,"children":634},{},[635],{"type":32,"value":636},"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.",{"type":23,"tag":301,"props":638,"children":639},{},[640,645,647,652],{"type":23,"tag":44,"props":641,"children":643},{"className":642},[],[644],{"type":32,"value":49},{"type":32,"value":646}," lists the training with its hash; ",{"type":23,"tag":44,"props":648,"children":650},{"className":649},[],[651],{"type":32,"value":212},{"type":32,"value":653}," returns it whole; the hash equals the one the lab's record names. The SHA-256 matches Node's on test strings.",{"type":23,"tag":301,"props":655,"children":656},{},[657],{"type":32,"value":658},"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.",{"type":23,"tag":24,"props":660,"children":661},{},[662,667],{"type":23,"tag":28,"props":663,"children":664},{},[665],{"type":32,"value":666},"What changed on screen:",{"type":32,"value":668}," 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.",{"type":23,"tag":61,"props":670,"children":672},{"id":671},"an-incident-to-own",[673],{"type":32,"value":16},{"type":23,"tag":24,"props":675,"children":676},{},[677,679,685,687,693,695,700,702,708],{"type":32,"value":678},"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 ",{"type":23,"tag":44,"props":680,"children":682},{"className":681},[],[683],{"type":32,"value":684},"}}",{"type":32,"value":686}," inside a ",{"type":23,"tag":44,"props":688,"children":690},{"className":689},[],[691],{"type":32,"value":692},"{{ … }}",{"type":32,"value":694}," 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 (",{"type":23,"tag":44,"props":696,"children":698},{"className":697},[],[699],{"type":32,"value":8},{"type":32,"value":701},"), found the file with ",{"type":23,"tag":44,"props":703,"children":705},{"className":704},[],[706],{"type":32,"value":707},"@vue\u002Fcompiler-sfc",{"type":32,"value":709},", fixed it, and restarted again; every page answers 200 since. Another session's captures in that window would have failed.",{"type":23,"tag":61,"props":711,"children":713},{"id":712},"the-calls-for-you",[714],{"type":32,"value":17},{"type":23,"tag":297,"props":716,"children":717},{},[718,744,762,778],{"type":23,"tag":301,"props":719,"children":720},{},[721,726,728,734,736,742],{"type":23,"tag":28,"props":722,"children":723},{},[724],{"type":32,"value":725},"The right answers ship in the published data.",{"type":32,"value":727}," The web app grades the check (D3), so ",{"type":23,"tag":44,"props":729,"children":731},{"className":730},[],[732],{"type":32,"value":733},"\u002Fapi\u002Ftrainings\u002F\u003Cid>",{"type":32,"value":735}," 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 ",{"type":23,"tag":44,"props":737,"children":739},{"className":738},[],[740],{"type":32,"value":741},"right",{"type":32,"value":743},", and a grading route returns the result. Proposed: keep it as built.",{"type":23,"tag":301,"props":745,"children":746},{},[747,752,754,760],{"type":23,"tag":28,"props":748,"children":749},{},[750],{"type":32,"value":751},"How the apps reach the API.",{"type":32,"value":753}," The design site sits behind Cloudflare Access, so the plane cannot read ",{"type":23,"tag":44,"props":755,"children":757},{"className":756},[],[758],{"type":32,"value":759},"design.internal.qpoint.io",{"type":32,"value":761}," 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.",{"type":23,"tag":301,"props":763,"children":764},{},[765,770,771,776],{"type":23,"tag":28,"props":766,"children":767},{},[768],{"type":32,"value":769},"A language with no file.",{"type":32,"value":326},{"type":23,"tag":44,"props":772,"children":774},{"className":773},[],[775],{"type":32,"value":202},{"type":32,"value":777}," 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.",{"type":23,"tag":301,"props":779,"children":780},{},[781,786,788,794,796,801],{"type":23,"tag":28,"props":782,"children":783},{},[784],{"type":32,"value":785},"When the version moves.",{"type":32,"value":787}," A change of meaning (a step, a question, a right answer) bumps ",{"type":23,"tag":44,"props":789,"children":791},{"className":790},[],[792],{"type":32,"value":793},"version",{"type":32,"value":795},"; a typo fix does not, though the hash moves with any change to the served text. Proposed as written in ",{"type":23,"tag":44,"props":797,"children":799},{"className":798},[],[800],{"type":32,"value":180},{"type":32,"value":802},".",{"type":23,"tag":61,"props":804,"children":806},{"id":805},"what-is-not-done",[807],{"type":32,"value":18},{"type":23,"tag":24,"props":809,"children":810},{},[811,813,818,820,826,828,834],{"type":32,"value":812},"Phase 4 (the two other pilots) runs next in this session. The static deploy of ",{"type":23,"tag":44,"props":814,"children":816},{"className":815},[],[817],{"type":32,"value":49},{"type":32,"value":819}," (prerendered through the preview page's links) is not checked: nothing was deployed. Tyler's answers on D22–D27 are outstanding. ",{"type":23,"tag":44,"props":821,"children":823},{"className":822},[],[824],{"type":32,"value":825},"event-shape.md",{"type":32,"value":827}," still names ",{"type":23,"tag":44,"props":829,"children":831},{"className":830},[],[832],{"type":32,"value":833},"training.completed",{"type":32,"value":835}," in §2 and §3 and is amended by its §8; the lab now follows §8.",1794599382891]