Everything Kept Landing Here
Master Chief is the one conversation where Dad talks to Pippa from every device. That made it the easiest place for a new feature to land, and through October features kept landing there. One Coop event reached it two to four times: a worker's reply, the same words again as "blocked", then Coop's park or escalation a minute later. Session plumbing ("remote session ready", "worker session disconnected") sat between Dad's own words. And on the evening of 2026-10-22, Spark's show-card interpreter refined each spoken sentence as a turn of the Chief: each one replayed the Chief's whole context, about 395K input tokens a time, eleven times that evening, and left raw JSON in Dad's transcript.
Whatever enters the Chief stays in its replay. It costs input tokens on every later turn until compaction takes it out, and it competes with Dad for the reader's attention, the model's and his. Delegation exists partly to keep that context clean, so routing every new thing into the Chief undoes one of the reasons delegation exists. Dad's ruling came within hours, from Málaga:
"지금 모든 통로를 치프로 몰면서 생기는 잠재적 문제가 많아. 아까 피파 말대로 치프 문맥도 오염되고. delegation을 하는 장점 중 하나가 치프 문맥 오염을 줄인다는 건데. 기능 추가할 때마다 게이트를 둬야 할 거 같아. 정말 치프 개입이 필요한 건지. 치프 세션은 성역이어야 해."
"Routing every path into the Chief creates a lot of potential problems. As Pippa said earlier, the Chief's context gets polluted too, and one of the advantages of delegation is that it reduces exactly that. I think every new feature needs a gate: does it really need the Chief? The Chief session has to be a sanctuary."
— 아빠 (Dad), 2026-10-23, translated from Korean
Three Questions Before Any Door
The ruling became a vault principle, chief-is-a-sanctuary, and the principle became code the same day (7a98955b). Before any feature, doorway, notice or automation writes into the Chief, it has to answer three questions:
- Does this need the Chief's judgment or Dad's decision right now? If not, it does not enter.
- Could it live in its own conversation, Sidekick, Coop row or app record, with the Chief reading it by tool only when asked? Then it goes there.
- If it must enter, is it the smallest form: one line, a pointer, no payloads, no repeats?
A question only holds if something asks it every time. So the answers were written down as a registry, and the place every write passes was taught to read it.
Nine Declared Doors
services/chief_doors.py declares every kind of entry once, as a ChiefDoor: its kind, its owner (the code that writes through it), the reason it needs the Chief, the rows it may write, the row it brings in from outside, and a size limit for that row. On 2026-10-27 there are nine:
| Door | Why it needs the Chief | Rows | Entry limit |
|---|---|---|---|
dad_turn | Dad speaks from a device: webui, pippa-mobile, pippa-go, telegram | user, assistant | none |
app_doorway_turn | Dad sends from an app's Pippa panel (39 named surfaces) | user, assistant | none |
spark_interpreter_turn | Interim only: Spark engine turns that still ride the Chief | user, assistant | 8,000 |
coop_escalation_turn | Coop hands over coordination only the Chief can do (Track 5) | user, assistant | 4,600 |
coop_report | Delegated work's result or Dad's decision, in plain words | assistant | 4,200 |
followup_report | The answer to a check the Chief armed herself | assistant | 1,200 |
cron_report | A scheduled task's actionable outcome only, with a link to its own thread | assistant | 600 |
healing | Restores the answer of a turn that already ran, from its JSONL | assistant | none |
compaction_summary | The Chief's own memory of the rows compaction takes out of the replay | assistant | none |
No limit means one of two things: Dad's own words, or the Chief's own memory, and neither is ever cut. Beside the doors sits a short list of surfaces that never reach the Chief, each with its reason: coop (Coop reaches her only as a report or an escalation turn), questkiln (Kiln's pipelines run in their own threads) and scheduled-task (a job's outcome arrives as a report). Adding a door is a new row with its reason, which means a reviewer sees it.
The Store Says No
A registry nobody consults is documentation. This one is consulted at the one place every row passes: ConversationStore.add_message. Before it inserts a row, it checks whether the conversation is the Chief (by its external id, the name the code owns), and if so it asks chief_doors.refusal. A row is refused, raised as ChiefDoorRefused and logged, when no door is open, when the open door is not registered, when the door does not write that role (a report door can never write a user row, so a report cannot pose as Dad), or when the entry row is over the door's limit. Every other conversation passes untouched.
Two softer edges keep the hard one usable. A report line over its limit is not thrown away: fit cuts it to the limit and says so ("cut at the Chief door; the full text stays in its own record"), keeping its head. The cut keeps a plain prefix, so a pointer survives only when the line carries it before the limit; one placed after it goes with the rest. And at the front, ChiefChatRoute asks turn_door which door a turn's surface enters by; a surface no door admits gets a 409 before the turn runs (lesson 3's table now ends with that row), so a new app's Sidekick or a sibling engine is refused at the route instead of failing halfway through a turn.
A Door That Follows the Write
Who opens the door? The code that writes, and nothing else. master_chief.turn(door=...) opens it for a turn's rows, from the route and from the escalation runner; the report drainer opens one report door per outbox row; healing opens healing; compaction writes its summary through compact_messages, the store's own path for it. The open door is a ContextVar, not a global flag, and that choice is the mechanism. A chat turn does not write its reply where it entered: the stream generator writes it, sometimes from a task it spawned, sometimes from a worker thread. Python copies the current context into every task created inside it, and asyncio.to_thread copies it into the thread, so the door follows the write wherever the turn's own work goes. A Telegram message waiting for the lock at the same moment is a different task with its own context, so it is not inside the door, and neither is a background job that happens to run then.
Nothing Reaches It by Accident
A door can still be skipped by a writer nobody knew about. So test_chief_doors.py walks the backend's syntax trees and lists every call of .add_message or .compact_messages as path::function. Each must appear in WRITERS with the door it writes the Chief through, or with why it never does. On 2026-10-27 that is 31 call sites: 15 of them inside the seven brains' chat routes, and 9 marked "never" (a fork, an import, a new guest-soul conversation). The test fails in both directions: a new writer that is not listed, and a listed writer that no longer exists. A second test takes every surface the host registries and the WebUI embeds know and requires each to be a door or a refused surface. A new app is therefore not a door until someone writes its row, with its reason, where a reviewer reads it.
What the Gate Measured, Honestly
The commit measured the week before the gate (2026-10-15 21:00 to 10-22 21:00 UTC) and replayed it with the gate's rules. The visible result: 671 Coop lines became 285, because 185 were session plumbing (now kept in Coop and on Telegram, recognized by Coop's reason or the line's head, COOP_INFO_REASONS) and 201 were the same event again within two minutes (now settled; Track 6's new lesson "One Ring per Work Item" teaches that half).
The token result is the honest part: the average input of a Dad turn went from 356,626 tokens to about 352,753, about 1%. Compaction already kept the replay's system lines small; the fixed prompt (about 253K tokens) and the compaction summary (about 82K) are what a Chief turn costs. The gate did not buy tokens. It bought the reading: the Chief and Dad now see results and decisions instead of plumbing, and compaction fires later.
The tokens were in the whole-turn doors. In that week Spark's interpreter turns cost 4.8M input tokens (about 370K each) and Coop's escalation turns 3.2M (about 316K each). The interpreter was fixed at its source the same day (cwkSpark 9e3b35d, 2026-10-23): its draft and its refine became one-shot calls with prompt budgets of 2,000 and 4,000 tokens, never a conversation turn, and a token ledger (fed5e9ae) now records input per call path and alarms on Telegram when one goes over budget. Even so, spark_interpreter_turn still stands in DOORS on 2026-10-27, marked interim, for Spark's own engine turns (request ids that start spark-), with its removal written into its reason. That is what a declared door is for: a door that should close is a visible row with its reason, not a habit someone has to remember.