Accepted · 2026-06-09
After the Aurora redesign (ADR-001) shipped, real playthroughs surfaced a cluster of problems concentrated in two places: the Codino mini-language itself, and the AI's problem-generation pipeline. The two surfaces are coupled — the AI generates problems against the language's grammar and against the strict exact-string output validation — so symptoms in one place often had causes in the other.
Five concrete patterns emerged during play:
- The AI frequently expected combined output strings. Problems naturally asked for "Animals: 5" on one line, but the language had no construct to combine a string and a variable in a single
WRITE. The player had to print on two lines and the expected output never matched. - The AI generated parity (even/odd) problems. Parity is a real 7–8 curriculum concept, but the language had no modulo or remainder operator — no way to express the check at all.
- Rating explanations referenced Python by name. Sonnet was pattern-matching Codino code (
apples = 5,WRITE apples) to Python and writing explanations in those terms. The cross-language confusion eroded the child's mental model of "this is its own language". - Condition operators got little airtime. Even at levels nominally teaching conditions, the AI's choice of construct skewed heavily toward arithmetic. The per-level prompt allowed
>,<,=but never required them, so the model dodged. - Loop counts had to be literal integers. A child writing
monsters = 5; REPEAT monsters TIMESgot a parse error. The natural phrasing of the most common problem shape was blocked.
A subsequent round of smoke testing on the just-merged changes surfaced two more problems, both in the AI prompt:
- The AI produced step-by-step prose recipes. "Use a variable called totale and multiply 6 by 8, then print totale." The child solved by transcription, not by problem-solving.
- Generated problems required typing emojis as program output. Engaging in the narrative but unreasonable on a child's keyboard.
The fixes touch language, AI pipeline, UI, and curriculum simultaneously. The capability specs hold the resulting invariants, but the cross-cutting why — what was added, what was deliberately deferred, and how the AI's role shifted from permissive to prescriptive — is recorded here.
A cluster of coupled changes, captured as one architectural shift.
Four constructs were added to the Codino grammar and interpreter:
- Multi-argument
WRITE/SCRIVIwith comma separator and space join.WRITE "Animals:", applesprintsAnimals: 5on a single line. Comma-separated arguments are evaluated independently,String()-coerced, and joined with a single space. - Named parity in conditions.
IF n EVEN/SE n PARIand theODD/DISPARIcounterparts as postfix forms. Parity is exposed as a named property of an integer, not as a modulo computation. - Iteration-variable loop.
REPEAT i FROM a TO b … END/RIPETI i DA a A b … FINE. The variablei(or any name) binds for the duration of the loop body, counts inclusively, and remains visible after the loop in the flat scope. - Expression as loop count. The existing
REPEAT N TIMESform accepts any expression — variable, sum, computation — in the count position. The 1000-iteration runtime cap and integer validation still apply.
The Loop AST node is replaced by two direct alternatives in statement: CountLoop and RangeLoop. There is no wrapper Loop node.
Parentheses remain in the grammar but stay undocumented to the player. The AI is instructed not to generate problems whose answer depends on operator precedence.
The language is positioned as one tier in a future multi-age curriculum. Constructs were considered and deferred rather than rejected outright; the grammar is the same across tiers, but the AI's gating and the player-facing surface (USER_GUIDE, HelpPanel) control what gets introduced.
Deferred to a future 9–10 tier: AND / OR in conditions, single-line comments, negative number literals, REMAINDER / modulo, possibly WHILE loops. Each was placed there for a specific cognitive reason — boolean composition is genuinely harder than comparison; meta-cognitive comments are uncommon at 7–8; modulo is too abstract when parity covers the named case.
Deferred to a future 11–13 tier: functions, arrays, input, string manipulation.
This framework matters for future-readers because it justifies the omissions the current tier makes. The grammar's narrowness is intentional, not incidental.
The AI's role in problem generation shifted in posture, not just in detail.
- Shared
CODINO_REFERENCEcard. A single string constant inprompts.tsis injected into the system prompt of every call that generates or evaluates Codino code:buildProblemGenerationPrompt,buildStarRatingPrompt,buildHintPrompt,buildErrorAnalysisPrompt. The card names the language, lists bilingual keywords and operators, explains the=dual meaning, and forbids referencing Python or other languages by name. Map-generation and story-ideas calls never see code and are not injected. LEVEL_CONCEPTSbecomes structured per-level gating. Each level entry hasconcept,unlocks, andrequired. The problem-generation prompt emits three paragraphs derived from it — the cumulative allowed set, the not-yet-introduced (forbidden) set, and the construct the generated problem must exercise. The gating is prescriptive: each level names a specific construct the problem must contain.- Curriculum reshape across levels 6–9. Level 6 introduces a comparison condition (one of
>,<,=, AI's choice with a diversity nudge). Level 7 introduces parity. Level 8 combines comparison with a loop. Level 9 combines parity with a loop. Level 10 is freeform but must contain at least one condition. - Five-rule constraint block on problem generation. Independent of per-level gating, every problem-generation prompt carries five constraints: (a) the narrative contains no Codino code, code blocks, or keyword examples; (b) literal output strings are quoted verbatim in the narrative; (c)
expectedOutputis restricted to ASCII letters, accented Latin vowels (à á è é ì í ò ó ù úand uppercase), digits, single spaces, and basic punctuation — emojis, smart quotes, em/en dashes, and other Unicode symbols are forbidden; (d) the narrative ends with an unambiguous print instruction of the formPrint "<exact text>"orPrint the value of <variable>; (e) the narrative describes the situation but never the solution — no naming variables for the player, no step-by-step ordering, no naming Codino constructs in code or prose form.
The prescriptive shift is the most architecturally important piece. Permissive prompts trust the model to use its allowance; prescriptive prompts constrain it to a specific behavior the curriculum needs.
- Whitespace-separated arguments (
WRITE "Animals:" apples) — rejected as visually ambiguous; comma makes the separator obvious. - Comma-separated, no glue (
WRITE "Animals: ", apples) — rejected because trailing-space-in-string formatting is fiddly at this age. - Relax INV-10 to allow string concatenation via
+— rejected because it overloads+for two operations (add numbers, join strings) and contradicts the spec's deliberate strictness around string operands. - Constrain the AI to never combine string + number on one line — rejected because it permanently rules out the most natural problem phrasings.
REMAINDER/ modulo operator — rejected because remainder-after-dividing is genuinely abstract for 7–8 year olds. Parity is a named property in their school math; modulo is a tool.- Both
EVEN/ODDandREMAINDER— rejected as doubled surface area for marginal benefit at this age. - Skip parity entirely (AI never generates parity problems) — rejected because parity is a concept already in their curriculum.
- Defer to the 9–10 tier — rejected because counted iteration is the most natural form for the most common 7–8 problems ("print 1 to N", "sum 1 to N"). The visible counter in the execution panel reinforces the learning.
WHILEloops instead — rejected as too abstract for the age;WHILEis held for the 9–10 tier.- Wrap both forms in a
LoopAST node — rejected because the wrapper added dispatch overhead with no value;CountLoopandRangeLoopas directstatementalternatives is cleaner.
- Inline gating per prompt without a shared constant — rejected because drift across prompt builders is inevitable as the language evolves.
- Reference card plus a one-shot example program — held in reserve. The constant alone proved sufficient; the one-shot can be added later if model output proves unreliable.
- Permissive gating with a "vary your choices" diversity nudge — what we had before. Rejected after observed under-use of comparison operators even at condition-teaching levels.
- Deterministic per-level operator (level 6 always
>, level 7 alwaysEVEN, etc.) — rejected because every playthrough would drill the same first operator. AI's choice within the allowed set with a per-call diversity nudge gives variation without extra plumbing. - Story-seeded operator choice — rejected as marginal value for extra complexity.
- Runtime validation of
expectedOutput(reject responses with emoji codepoints, retry) — held in reserve. The prompt alone is currently sufficient; this is the planned escalation step. - Per-level scaffolding intensity knob (
scaffoldingLevel: 'high' | 'low'per level) — rejected because the general "situation, not solution" rule subsumes the level-1 case naturally (at level 1 the operation is the situation). - Strict ASCII only in
expectedOutput— rejected because Italian narratives produceperché,così, etc. The allowlist explicitly includes accented Latin vowels but notç/ñ/ü, since the game's languages are Italian and English only.
- Add
AND/ORnow — rejected because reliable two-condition reasoning is a 9–10 skill; colloquial AND is fine at 7–8 but not a curriculum concept. - Add comments now — rejected because self-documentation requires meta-cognition that 7–8 year olds rarely apply voluntarily.
- Add modulo now (alongside parity) — rejected as doubled surface area; modulo is the 9–10 tool that subsumes parity, not the 7–8 form.
- Three capability specs update in step with the code:
codino-language.md(D-decisions for the four constructs and the four corresponding INVs),ai-integration.md(D-decisions forCODINO_REFERENCEand prescriptive gating, plus three new INVs),execution-engine.md(INV-10 reflects the structuredLEVEL_CONCEPTS). Thegame-statecapability is unaffected — store contracts and persistence are untouched. editor.mdINV-06 stays as written (interpreter emits English;RuntimeErrorCardtranslates to Italian). Eleven new error messages were added to the interpreter; the Italian translations are added in lockstep and regression-tested.- The USER_GUIDE and the HelpPanel get new entries reflecting the additions; the level curriculum table is rewritten.
- The age-tier framework is captured here for the first time. Adding a 9–10 or 11–13 tier later will fall out of this ADR's structure: same grammar accepts everything, the tier gates introduction.
- The permissive→prescriptive shift in AI gating is the durable directional choice. Future capability additions (new constructs, new levels) should follow the prescriptive pattern rather than reverting to "allow and hope".
This change set was carried out as a spec-driven experiment — each commit updated the relevant capability spec alongside the code, and spec:validate was run before considering the branch complete.
The constraint block in §4 of the Decision section reached its final five-rule form in two iterations. The first four rules were drafted from the initial smoke-test findings; rule 5 was added after a second round of smoke testing revealed the AI was being too prescriptive in early-level narratives. The iteration is noted here because it is part of the spec-driven experiment's posture: ship, test against real model output, tighten. The rules are presented as a unified outcome in the Decision because that's what the curriculum and the invariants describe; the iteration trail is for context only.
- Pull request: PR #2 — Codino language revision — full commit history and the brainstorm/plan session artifacts that preceded the merge live there.