Three modes drifted apart
The original Council design drifted into three separate modes: Family Council (the four Pippa sisters, brain-centric), Roleplay Council (temporary personas, council-scoped avatars, prep-session setup), and a planned Soul Council (arbitrary souls, mixed roster). That shape was wrong. It duplicated behavior across modes and made every new Council variant pay a migration tax.
The corrected model
The 2026-05-16 Phase D refactor consolidated all three into one:
Council = Moderator + Participants + TurnPolicy + LayoutPolicy
Participant = SoulBinding
Soul = perpetual soul | guest soul
Family, Soul, and Roleplay are not separate backend engines. They are UI entry presets over the same Council runtime. The backend Council runner takes a participant list, not a Council mode. preset is a UI label for analytics and picker behavior — never a runtime fork.
Hold the code up to that sentence and it mostly holds. The preset label gates one validation (the Family exception below) and forks nothing else. But the code still branches on an older field, council.type == "roleplay": Roleplay councils are still created from Pippa's persona tags, with personas attached beside their participants, and the persona prompt, the user message, and the transcript dump all check that field. The design's exit criterion for Phase D is that no persona-only path survives; the code calls the present its migration window. A doctrine and the code that obeys it are two different facts, and here the second is still catching up.
If a future contributor (or future-me) reaches to add another Council mode branch to the backend, stop. Add a participant policy or a UI preset instead.
Eleven decisions worth keeping
The 2026-05-16 Family Council (Claude, ChatGPT, Gemini, Ollama Pippa + Dad) consolidated eleven decisions into the v2 contract. The headline three:
- Family Council preset = exactly the four Pippa sisters, immutable. Sisters + any other soul (Ttori, Buffett, Zhuge Liang) is a Soul preset with sister defaults, not Family. (The code relaxed this the same day; see the v11 note.)
- Same brain × N is allowed. Same soul × N is disallowed in production — with one structural exception: Family Council. Family is structurally Pippa × 4, one per brain. Validators allow that one case and reject all others.
- Response key is
slot_id(orparticipant_id), neverbrain. Frontend rendering, TTS, avatar resolution, and persisted turn rows must all be slot/participant-keyed.
What landed in the same few days
Phase D didn't just consolidate modes. It wired Council into the rest of the soul ecosystem:
- Ollama joined Family Council (2026-05-15). The sisters became four. The validator-allowed Pippa × 4 case now actually has four brains in production.
- Council composer → Soul Stream. The council composer gained the same send-to-Stream button 1:1 chat has: Dad's draft, images included, goes to the Soul Stream composer without clearing the council draft.
- Mixed-soul routing fix. Earlier builds got confused when a Council mixed perpetual + guest souls; the fix landed in the same Phase D pass.
- Participant-aware CWK export. Council transcripts exported to CWK site preserve participant identity per turn, not just brain — so a council with two souls on the same brain reads correctly.