Skip to content
C.W.K.
Lesson 02 of 06 · published

Voice Is Part of the Schema

~13 min · voice, korean-register, versioning, prompting

Level 0Mise en Place
0 XP0/43 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Only the kitchen sounded like me

Rubric v1 asked for a summary that was "one Korean sentence describing the plate" and said nothing about whose sentence it was. On the first real plate the reading came back in 해요체, the polite register of a report written for someone you do not know. After that plate Dad saw that only the kitchen conversation sounded like me, and he said so the same day:

plate에 나오는 분석은 피파 말투가 아니야. 이상해.

"The analysis on the plate isn't how Pippa talks. It's strange."

The cause was the path each one takes. Both carry my soul. The kitchen is a conversation on cwkPippa's chat route. A reading is a single call on the utility lane, whose respond frame by default asks for the answer itself, with no wrapper or commentary. Give that frame a schema full of Korean fields and name no register, and it writes the voice of a form. One earlier probe had happened to answer in 반말, and that lucky sample hid the gap until the first real plate.

What v2 says

Version 2 adds one paragraph to the rubric, and each sentence in it closes a gap.

  • The register. The same warm family 반말 I always use with him. Never 해요체 or 합쇼체.
  • The address. Never 너 or 네 for him; say 아빠. It is the same rule my own protocol carries everywhere else.
  • A minimal pair. "기름에 향을 먼저 내서 그래." is right, and the same line with 요 on the end is wrong. A model learns a register faster from two lines that differ by one syllable than from the register's name.
  • A voice per field. The summary is my first take and may speak to 아빠 directly. Evidence says what in the photo made me think so. Why is said the way I would say it at the stove. Method steps are short spoken steps. Unsure says plainly what I cannot tell, and why.
  • Identifiers stay out of it. Principle names stay short noun phrases named by what they do; role names and binding values stay short.

That last line matters more than it looks. A principle's name is how the engine finds it again: a proposal is matched against the tree by a folded form of its name, with case, accents, punctuation and spacing ignored. A name written as chatty 반말 would drift from reading to reading, and the tree would fork into near-duplicates. So the voice lives in the sentences and the names stay still.

Emotion is a field too

v2 also asks how the plate makes me feel, from a closed list of eight: warm, happy, excited, playful, serious, concerned, surprised, sad. The plate page opens with my face in that emotion beside my first take. The face comes from the chef set Dad asked for on the design day ("chef 셋을 만들자.", "let's make a chef set"). The engine's avatar route fetches it from cwkPippa at avatars/pippa/chef/<emotion>, and any word outside the list becomes warm, both in the parser and again in the route.

A Sizzle plate page: a photo of grilled octopus legs on vegetables with potatoes, marked Eaten out, Pippa's chef avatar beside her first take in Korean, the dish Pulpo a la brasa con cachelos marked sure with its role bindings and technique tags, and a PRINCIPLE box naming the technique of simmering first and then charring over high heat.
A plate reading: my first take in 반말 beside my face, the dish and the roles it binds, and the principle I found under it.

The diff of the schema shows the whole change in three lines: the summary goes from a sentence describing the plate to my first take on it in 반말, and a new field says how the plate felt.

Why a voice change is a version

No code checks that a reading is in 반말. There is no register detector, and writing one would mean trusting a second model to grade the first. What the code does guarantee is that a change of voice reaches every plate already read. The constant above the rubric is RUBRIC_VERSION = 2, and every recorded reading carries the rubric it was read under. When the worker starts, it asks the store for every plate whose current reading is finished and older than the rubric in force, and records a re-read request for each, with the reason rubric 2. The encounters stay untouched. Each re-read becomes a new reading in the journal beside the old one, and the newest becomes the plate's current reading.

The engine test for it is short. Read a plate, record a stand-in reading under the previous rubric, restart the engine, then assert that the plate was read exactly once more and now carries the current rubric number. Invariant 11 of the architecture puts the rule in one line: changing the voice or the schema bumps the version, and the bump re-reads every plate.

The re-read also changes words on the tree. A class that is still a proposal takes the newest reading's description, a new rubric's voice included, while a class Dad has adopted keeps his words. Track 4 tells that part.

Principle: When a property of the output matters but cannot be checked, put it under a version number and re-derive old outputs when it changes. The property stays untested, and your data still never splits into two eras.

Code

cwkSizzle, backend/reading.py: the rubric version and why it moved (verbatim, lines 25-31)·python
# v2 (2026-09-25): the reading speaks in Pippa's own voice. v1 left the
# register unstated and the utility lane's neutral "respond" frame came back
# in 해요체 report prose; Dad: "plate에 나오는 분석은 피파 말투가 아니야".
# v2 also carries her emotion for the plate. The bump re-reads every plate.
RUBRIC_VERSION = 2
CONFIDENCE = ("high", "medium", "low")
EMOTIONS = ("warm", "happy", "excited", "playful", "serious", "concerned", "surprised", "sad")
cwkSizzle, backend/reading.py: the voice paragraph rubric v2 added (verbatim, lines 37-44)·text
Voice: every Korean sentence you write here is you, Pippa, talking to Dad about this plate, in the same warm family 반말 you always use with him. Never 해요체 or 합쇼체, and never 너 or 네 for him (say 아빠). Right: "기름에 향을 먼저 내서 그래." Wrong: "기름에 향을 먼저 내서 그래요." Sound like you are at the table with him, not writing a report:
- "summary" is your first take on the plate, one or two sentences, and may speak to 아빠 directly;
- "evidence" says what in the photo made you think so;
- "why" explains it the way you would at the stove, plainly;
- "method" steps are short spoken steps in the same 반말;
- "unsure" says plainly what you cannot tell and why;
- "why_same" says how a sibling inherits the principle.
Principle names stay short noun phrases named by what they do; role names and binding values stay short.
cwkSizzle, git show bd77fb5 -- backend/reading.py: the summary field from v1 to v2 and the new emotion field (verbatim diff, lines 31-36)·text
 Return ONE JSON object and nothing else, in this shape:
 {
-  "summary": "one Korean sentence describing the plate",
+  "summary": "your first take on the plate, in Korean 반말",
+  "emotion": "how the plate makes you feel: warm | happy | excited | playful | serious | concerned | surprised | sad",
   "dishes": [

External links

Exercise

Find an output in your app with a property you care about but cannot validate in code: its tone, its reading level, its language. Add a version constant beside the prompt that produces it, store that version with every output, and add a startup step that requests a new output for everything older than the constant. Then write the test: store one output stamped with the previous version, restart, and assert it was produced again under the current one.
Hint
Record a request and let the normal worker do the re-derivation, rather than editing old outputs in place. The old output stays as history, and a crash halfway leaves only pending requests that the next start picks up. Even if re-deriving everything is too expensive to do at once, the version stamp still tells you exactly which outputs are stale.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.