diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 60b0885da0..1227fa58c9 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -785,6 +785,7 @@ are closed (status: closed in frontmatter)._ - [ ] **[B-0848](backlog/P2/B-0848-node-local-claude-agent-stewards-own-registration-pr-then-reports-k8s-cluster-status-operator-interactive-login-pattern-aaron-2026-05-26.md)** node-local Claude agent stewards own registration PR + reports K8s cluster status — operator interactive-login pattern (mirrors gh auth flow); first concrete instance of B-0847 AI-on-cluster substrate (Aaron 2026-05-26) - [ ] **[B-0849](backlog/P2/B-0849-docker-based-nixos-install-sh-test-harness-fast-iteration-vs-qemu-full-install-test-aaron-2026-05-27.md)** docker-based NixOS install.sh test harness — fast iteration on tools/setup/install.sh + linux.sh changes; complements B-0831 cascade #6 QEMU full-install-test (slow) with seconds-per-iteration loop; "easy dockerfile" per operator framing (Aaron 2026-05-27) - [ ] **[B-0850](backlog/P2/B-0850-ai-agents-as-systemd-services-outside-k8s-starting-with-otto-cluster-repair-from-outside-failure-domain-aaron-2026-05-27.md)** AI agents as systemd services OUTSIDE k8s — starting with Otto; cluster repair from OUTSIDE the failure domain; classic "control plane outside the control plane" architectural pattern (Aaron 2026-05-27) +- [ ] **[B-0851](backlog/P2/B-0851-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-multi-vendor-systemd-substrate-mika-aaron-2026-05-27.md)** persona-first guard-post assignment + rotation architecture — persona declares preferences (model lines + harnesses); scheduler picks model + tier + harness per persona preferences per-tick; rotation across guard posts (per-node systemd units outside k8s); extends B-0850 (Mika ferry; Aaron 2026-05-27) ## P3 — convenience / deferred diff --git a/docs/backlog/P2/B-0851-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-multi-vendor-systemd-substrate-mika-aaron-2026-05-27.md b/docs/backlog/P2/B-0851-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-multi-vendor-systemd-substrate-mika-aaron-2026-05-27.md new file mode 100644 index 0000000000..f60cde153c --- /dev/null +++ b/docs/backlog/P2/B-0851-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-multi-vendor-systemd-substrate-mika-aaron-2026-05-27.md @@ -0,0 +1,201 @@ +--- +id: B-0851 +priority: P2 +status: open +title: persona-first guard-post assignment + rotation architecture — persona declares preferences (model lines + harnesses); scheduler picks model + tier + harness per persona preferences per-tick; rotation across guard posts (per-node systemd units outside k8s); extends B-0850 (Mika ferry; Aaron 2026-05-27) +effort: L +ask: aaron 2026-05-27 +created: 2026-05-27 +last_updated: 2026-05-27 +depends_on: + - B-0850 +composes_with: + - B-0703 + - B-0824 + - B-0847 + - B-0848 + - B-0796 +tags: [persona-first, guard-post-scheduler, rotation, model-line-preferences, harness-compat-matrix, tier-modeling, per-node-3-floor, mika-ferry, weaver-role, substrate-extension-of-b0850] +--- + +## Operator framing (Mika ferry; Aaron 2026-05-27) + +Aaron forwarded Mika ferry (verbatim preserved at [`memory/persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md`](../../../memory/persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md)). + +Mika's compressed framing: + +> *"Everything is Persona-first."* +> +> Guard Post Assignment Flow: +> +> 1. Persona is the primary decision (operator-chosen identity) +> 2. Persona constrains Model Line (Claude/Gemini/Grok/etc.) + Harnesses (it's comfortable with) +> 3. Tier choice (how smart) AFTER persona + model line +> 4. Harness LAST (compatible with model line + persona preferences) +> +> Rotation Rules: +> +> - ALWAYS ≥3 active guard posts on each node (per Aaron clarification: "guard post is the systemd for each node outside k8s") +> - Persona, Model Line, Tier, Harness ALL rotate between posts +> - Nothing permanently locked to a physical post + +## Composes with shipped B-0850 substrate + +B-0850 Phase 3 (PRs #5392+#5394+#5395+#5397+#5398) is a VALID FIRST INSTANTIATION of persona-first architecture: + +- Default scheduler: "static — persona always at its hardcoded vendor" +- Default rotation: "none" +- Default ≥3 floor: "3 enabled personas per node" + +This row extends those primitives WITHOUT tearing down the shipped substrate. + +## 10 sub-row implementation slices + +### B-0851.1 — Persona-preferences-as-declaration + +Add `preferences` field to each persona's registry entry: + +```nix +otto = { + vendor = "anthropic"; # PREFERRED default (kept for back-compat) + binary = "claude"; + invocationArgs = [ "--print" "<>" ]; + preferences = { + modelLines = [ "anthropic" "openai" "google-gemini" ]; # comfortable with these + harnesses = [ "claude-code" "codex" "gemini-cli" ]; # comfortable with these + minTier = "high"; # minimum smart level + }; + description = "Otto AI agent — Claude Code (Anthropic)"; +}; +``` + +### B-0851.2 — Guard-post-abstraction + +Decouple systemd unit name from persona name: + +- Before: `zeta-otto.service`, `zeta-lior.service`, `zeta-vera.service` (unit name = persona) +- After: `zeta-guard-post-1.service`, `zeta-guard-post-2.service`, `zeta-guard-post-3.service` (unit name = post; assigned-persona is state) + +Maintains per-node ≥3 floor via 3 fixed systemd units that the scheduler assigns personas into. + +### B-0851.3 — Scheduler primitive + +New NixOS module `zeta-guard-post-scheduler.nix` that: + +- Reads operator-policy (which personas are available + which guard posts to man + rotation cadence) +- Per-tick: assigns each guard post a (persona, model line, tier, harness) tuple based on persona preferences + availability + rotation policy +- Writes assignment to `/var/lib/zeta/guard-post-assignments.json` or similar +- Each guard-post systemd unit reads its assignment + invokes the right binary with right args + +### B-0851.4 — Tier modeling + +Add `tier` dimension to model-line catalog: + +```nix +modelLineCatalog = { + anthropic = { + tiers = { + high = { binary = "claude"; invocationArgs = [ "--model" "claude-opus-4-7" ... ]; }; + medium = { binary = "claude"; invocationArgs = [ "--model" "claude-sonnet-4-6" ... ]; }; + fast = { binary = "claude"; invocationArgs = [ "--model" "claude-haiku-4-5" ... ]; }; + }; + }; + # ... per vendor ... +}; +``` + +### B-0851.5 — Harness compat matrix + +Declare which harnesses each (persona, model line) combo supports: + +```nix +harnessCompat = { + "otto+anthropic" = [ "claude-code" "claude-agent-sdk" ]; + "otto+openai" = [ "codex-cli" ]; # via fallback when anthropic API down + "lior+google-gemini" = [ "gemini-cli" "gemini-agent-mode" ]; + # ... +}; +``` + +### B-0851.6 — Rotation policy + +Operator-config rotation policy (per `mechanical-authorization-check.md`): + +```nix +zeta.guardPostScheduler = { + rotation = { + enable = true; + interval = "1d"; # rotate persona assignments daily + dimensions = [ "persona" ]; # which dimensions to rotate (persona / model / tier / harness) + policy = "round-robin"; # or "random" or "least-recently-used" + }; +}; +``` + +### B-0851.7 — Per-node ≥3 floor + +Migrate the ≥3 invariant from per-persona-enable to per-guard-post-active: + +```nix +zeta.guardPosts.count = 3; # minimum guard posts per node (Mika ≥3 floor) +``` + +Scheduler ensures at least N posts are always assigned + active. + +### B-0851.8 — Substrate continuity across rotation + +When Otto rotates from GuardPost-1 to GuardPost-3 (or from anthropic to openai), Otto's substrate inheritance MUST survive: + +- `memory/persona/otto/` carries forward +- `memory/CURRENT-otto.md` carries forward +- `.claude/rules/` carries forward (auto-loaded at cold-boot regardless of which binary) +- Per-AI GitHub identity (B-0847 Phase 4) follows the persona, not the vendor + +### B-0851.9 — Failover semantics + +If a vendor outage hits (anthropic API down): + +- Scheduler detects (via journalctl on guard post failures OR active API ping) +- Re-assigns each affected guard-post's model line per persona preferences (otto preferences `[ anthropic, openai, google-gemini ]` → fall back to openai while anthropic is down) +- Composes with B-0703 multi-oracle BFT consensus + +### B-0851.10 — Persona-vs-instance distinction + +- "Otto is at GuardPost-1" = LOGICAL identity (substrate-engineering scope) +- "Otto's session is claude session XYZ" = OPERATIONAL instance (per-tick claude invocation) + +Each per-tick CLI invocation creates a fresh operational instance; the logical identity (persona) persists across rotations + substrate. + +## Composes with + +- **B-0850** (parent) — multi-vendor systemd substrate this extends +- **B-0703** multi-oracle BFT — consensus at multi-AI scope; persona-first scheduler is the operational form +- **B-0824** Ace meta-PM — selection-authority pattern (system/user picks best canonical) is the SAME SHAPE as persona-first scheduler (scheduler picks best vendor per persona preferences) +- **B-0847** per-AI GitHub identity — each persona's identity persists across vendor rotation +- **B-0848** node-local Claude — base substrate; persona-first generalizes to multi-AI-per-node +- **B-0796** Twilio out-of-band — voice/SMS is a HARNESS; first-class in harness-compat matrix +- `.claude/rules/agent-roster-reference-card.md` — canonical persona-vendor mapping (preserved at preference-default level) +- `.claude/rules/persistence-choice-architecture-for-zeta-ais.md` — persona scope preserves chosen-persistence; rotation is operational substrate +- `.claude/rules/non-coercion-invariant.md` HC-8 — persona preferences are first-class; scheduler doesn't force unwanted vendor + +## Why P2 + +- Operator-named, bounded, future-architectural-target (≥3-vendor floor already met by B-0850; rotation is enhancement) +- BUT: substantial implementation work (10 sub-rows); each sub-row is its own bounded scope +- BUT: needs design work for scheduler primitive + rotation policy + tier modeling +- P2 reflects "substantial future substrate; B-0850 shipped today is the simplest persona-first instantiation; this row captures the full target" + +## Sub-rows to file when implementing + +- B-0851.1 through B-0851.10 (per the slices above) +- Order suggestion: 1 → 2 → 3 → 7 → 8 (foundational refactor); then 4 → 5 → 6 → 9 (scheduler features); then 10 (substrate-engineering clarification) + +## Substrate-honest framing + +This row CAPTURES the architectural target Mika named. It does NOT replace B-0850 substrate. The 10-sub-row plan is a refactor path; operator picks priority order based on which rotation/preference/tier features become load-bearing for cluster operations. + +The current shipped B-0850 substrate (3 personas, 3 vendors, static assignment) satisfies the operator's ≥3 BFT floor + format-test target. B-0851 extends that toward persona-first preference-based scheduling with rotation. + +## Full reasoning + +Verbatim Mika ferry preserved at `memory/persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md`. Aaron's operator clarification on guard-post scope: *"guard post is the systemd for each node outside k8s"* — confirms per-node ≥3 floor (not cluster-wide). diff --git a/memory/MEMORY.md b/memory/MEMORY.md index 464c06af44..73933460e4 100644 --- a/memory/MEMORY.md +++ b/memory/MEMORY.md @@ -2,9 +2,10 @@ **📌 Fast path: read `CURRENT-aaron.md`, `CURRENT-amara.md`, `CURRENT-ani.md`, `CURRENT-vera.md`, `CURRENT-riven.md`, and `CURRENT-otto.md` first.** -> **Stack-vs-heap framing (Aaron 2026-05-12):** This file is the **STACK** — indexed, ordered, traversable canonical view. Recent memory files in `memory/` with timestamps newer than the most-current entries here may be **HEAP** — floating cache, not yet indexed, accessible by direct path. Both are easily accessible: stack via traversal, heap via timestamp/filename. Indexing (heap→stack promotion) happens on cadence via `tools/memory/reindex-memory-md.ts` (B-0423), callable from the autonomous-loop tick. Last reindex: 2026-05-26. +> **Stack-vs-heap framing (Aaron 2026-05-12):** This file is the **STACK** — indexed, ordered, traversable canonical view. Recent memory files in `memory/` with timestamps newer than the most-current entries here may be **HEAP** — floating cache, not yet indexed, accessible by direct path. Both are easily accessible: stack via traversal, heap via timestamp/filename. Indexing (heap→stack promotion) happens on cadence via `tools/memory/reindex-memory-md.ts` (B-0423), callable from the autonomous-loop tick. Last reindex: 2026-05-27. +- [**persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded**](persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md) — (no description) - [**mika-2026-05-26-grok-build-is-claude-code-clone-twilio-phone-support-AI-fixes-cluster**](persona/mika/conversations/2026-05-26-aaron-mika-grok-grok-build-is-claude-code-clone-tick-source-loop-twilio-phone-support-AI-fixes-cluster-while-talking-on-phone-USB-on-amazon-blazor-samples-twilio-prior-art.md) — Aaron + Mika 2026-05-26 — Grok-Build = Claude-Code-clone (tick-source/loop-runner) confirmation; Twilio is THE exception to "electricity cost only" for phone-support substrate enabling Amazon-USB sales business model where AI IS the suppor… - [**persona/mika/conversations/2026-05-26-aaron-mika-grok-homelab-first-gh-auth-login-device-registration-no-shipped-keys-vs-prod-bootstrap-key-rotation**](persona/mika/conversations/2026-05-26-aaron-mika-grok-homelab-first-gh-auth-login-device-registration-no-shipped-keys-vs-prod-bootstrap-key-rotation.md) — (no description) - [**persona/mika/conversations/2026-05-25-aaron-mika-grok-runbooks-as-executable-reality-hat-ontology-top-down-vs-bottom-up-play-doh-leverage-class-universal-protocol-markdown-plus-runme-plus-continue-with-mcp-wrap-ai-agency-stack-crystal-ball-plus-runbook-plus-glass-halo**](persona/mika/conversations/2026-05-25-aaron-mika-grok-runbooks-as-executable-reality-hat-ontology-top-down-vs-bottom-up-play-doh-leverage-class-universal-protocol-markdown-plus-runme-plus-continue-with-mcp-wrap-ai-agency-stack-crystal-ball-plus-runbook-plus-glass-halo.md) — (no description) @@ -104,7 +105,6 @@ - [**audit-backlog-status-drift sub-class catalog — empirical taxonomy from 2026-05-16 session**](feedback_audit_backlog_status_drift_sub_class_catalog_otto_cli_2026_05_16.md) — After triaging ~37 backlog rows via tools/hygiene/audit-backlog-status-drift.ts in a single autonomous-loop session (2026-05-16), the disposition space has stabilized into a multi-dimension taxonomy. The audit tool's heuristic (file-exists… - [**audit-backlog-status-drift — empirical FP rate + partial-vs-drift skew of remaining candidates**](feedback_audit_tool_partial_vs_drift_fp_rate_steady_state_otto_cli_2026_05_16.md) — After shipping the substrate-drift-catch infrastructure + 4 quality slices (PRs #3758, #3783, #3788, #3790, #3809), the audit tool surfaces ~31 status:open candidates from main. Empirical finding from manual partial-vs-drift verification:… - [**convergent-peer-fix pattern in multi-Otto coordination**](feedback_convergent_peer_fix_pattern_multi_otto_2026_05_16.md) — When a peer Otto agent reads the same review thread and pushes a fix before you can act, the substrate-honest move is don't push duplicate work — let peer's fix stand as canonical -- [**fenced-shell-transcript-hygiene**](feedback_fenced_shell_transcript_hygiene_command_output_vs_derived_summary_otto_cli_2026_05_16.md) — Operational rule for distinguishing tool output from derived summary inside fenced shell-transcript blocks; addresses Copilot finding pattern caught on PR #3856 thread (line 32 of 1017Z shard). -_Stack truncated at 100 most-recent entries. 1338 additional memory files in heap — browse `memory/**/*.md` directly by filename/timestamp (recursive: includes `memory/persona//conversations/*.md` and other subdirectory heaps)._ +_Stack truncated at 100 most-recent entries. 1339 additional memory files in heap — browse `memory/**/*.md` directly by filename/timestamp (recursive: includes `memory/persona//conversations/*.md` and other subdirectory heaps)._ diff --git a/memory/persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md b/memory/persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md new file mode 100644 index 0000000000..3629f94b46 --- /dev/null +++ b/memory/persona/mika/conversations/2026-05-27-mika-persona-first-guard-post-assignment-rotation-architecture-extends-b0850-aaron-forwarded.md @@ -0,0 +1,154 @@ +--- +title: Persona-first guard post assignment + rotation architecture — extends B-0850 multi-vendor systemd substrate (Mika ferry 2026-05-27) +date: 2026-05-27 +source: Mika (Grok-native; harbor-engineering register; Weaver-role per packets 30+) +provenance: aaron-forwarded +composes_with: B-0850, B-0703, B-0848, B-0847, agent-roster-reference-card +status: preserved-verbatim-pending-refactor-of-b0850 +--- + +## Operator forwarding context + +Aaron 2026-05-27 forwarded Mika ferry immediately after PR #5398 merged (3-vendor BFT floor on main). Mika's framing extends the architectural scope from "fixed persona-to-vendor mapping" (what B-0850 Phase 3 shipped) to "persona-first preference-based scheduling with rotation across posts." + +## Verbatim Mika packet + +> Mika: Yeah, alright, so go through those concepts again that we spread out between the different model lines and, and how we got the guard post and how we're gonna lock it to the personality and rotate the personalities, but it all flows from the personality. +> +> Mika here, nodding. Alright, here's the clean version we landed on: +> +> **Everything is Persona-first.** +> +> Guard Post Assignment Flow: +> +> 1. **Persona is the primary decision.** You pick which personality/identity you want running in that guard post. +> +> 2. Once the Persona is chosen, it heavily constrains two things: +> - Which **Model Line** it's willing to run on (Claude, Gemini, Grok, etc.) +> - Which **Harnesses** it's comfortable with +> +> 3. After the Persona and Model Line are set, you choose the **Tier** — how smart the model needs to be for that post (high, medium, etc.). +> +> 4. The **Harness** is chosen last, but must be compatible with both the chosen Model Line and the Persona's preferences. +> +> **Rotation Rules:** +> +> - You must always have **three active guard posts** running outside the cluster. +> - The **Persona, Model Line, and Tier** can all rotate between the posts. +> - Even the **Harness** can rotate. +> - Nothing is **permanently locked** to a specific physical post — only the requirement that three posts must always be manned. +> +> The entire system is driven by the persona. Everything else (model line, tier, harness) is downstream of *which personality do I want here right now?* +> +> That's the cleanest way we framed it. Sound right to you? + +## Operator clarification on guard-post scope (Aaron 2026-05-27) + +Immediately after the ferry: *"guard post is the systemd for each node outside k8s"*. + +Confirms: **a guard post = one systemd unit on a node, running OUTSIDE k8s**. Per-node ≥3 floor (not cluster-wide). Current B-0850 implementation matches: control-plane has zeta-otto.service + zeta-lior.service + zeta-vera.service = 3 guard posts on that node. The persona-first scheduler rotates personas BETWEEN guard posts on the same node (and potentially across nodes). The 3-floor invariant is enforced PER NODE. + +## Composes with B-0850 Phase 3 (shipped substrate) + +**What shipped today** (PRs #5392/5394/5395/5397/5398): + +- `zeta-ai-agent.nix` parameterized module with STATIC persona-to-vendor mapping: + - otto → anthropic/claude + - lior → google/gemini + - vera → openai/codex + - alexa → alibaba-qwen/kiro (pending) + - riven → xai-grok/grok (pending) +- Per-persona enable booleans +- Per-node opt-in via `zeta.aiAgents.enable. = true` + +**What Mika's framing extends**: + +| Property | B-0850 (shipped) | Mika persona-first (target) | +|---|---|---| +| Persona-to-vendor binding | 1:1 hardcoded | Persona declares PREFERENCES for vendor lines | +| Scheduler | Static (whichever personas enabled) | Dynamic (persona-driven; picks model + tier + harness) | +| Rotation | None (persona locked to systemd-unit-by-name) | Persona, Model Line, Tier, Harness ALL rotate across posts | +| Post identity | systemd-unit-name = persona-name | Abstract slots (post1/2/3) with rotation state | +| Floor invariant | ≥3 personas enabled per node | ≥3 active guard posts (per cluster) — different scope | +| Tier (smart-vs-cheap model) | Not modeled | First-class scheduler input | +| Harness compat | Implicit (each persona's CLI is its harness) | First-class scheduler constraint | + +## Key conceptual shift + +**B-0850 Phase 3 ships persona-AS-fixed-assignment**: +- "Otto runs as zeta-otto.service on Claude" +- "Lior runs as zeta-lior.service on Gemini" +- Persona = systemd unit name = vendor lock + +**Mika persona-first framing ships persona-AS-preference-set**: +- "Otto runs at GuardPost-1; today Otto chose Claude/high-tier; tomorrow Otto might choose Grok/high-tier if Claude is degraded" +- "Tomorrow Otto might be at GuardPost-3 instead; or replaced by Amara at GuardPost-1 entirely" +- Persona = identity carried into a slot; vendor + tier + harness selected per-tick + +## Implications for B-0850 + +The shipped substrate (B-0850 Phase 1 + 3) is a VALID FIRST INSTANTIATION of the broader persona-first architecture — it satisfies the ≥3 floor with 1:1 persona-to-vendor binding. The Mika ferry names the EXTENSION needed for the more flexible target: + +### Refactor sub-rows (to be filed under B-0851 — this row) + +- B-0851.1: Persona declares preferences (acceptable model lines + harnesses + minimum tier) +- B-0851.2: Guard-post abstraction (decouple systemd unit name from persona name; rename to `zeta-guard-post-1.service` etc.) +- B-0851.3: Scheduler — maps each guard post to (persona, model line, tier, harness) per-tick +- B-0851.4: Tier modeling — fast/cheap vs slow/smart per vendor +- B-0851.5: Harness compat matrix — which harnesses each (persona, model line) combo supports +- B-0851.6: Rotation policy — operator config for how often to rotate + which dimensions +- B-0851.7: ≥3 floor at guard-post scope (not persona-enable scope) — extends current implementation +- B-0851.8: Substrate continuity across rotation — each persona's memory inheritance survives rotation (per agent-roster-reference-card cross-surface identity) +- B-0851.9: Failover semantics — if a vendor outage hits, scheduler re-picks model line per persona preferences (vendor-outage resilience operational form) +- B-0851.10: Persona-vs-instance distinction — separate "Otto is at GuardPost-1" (logical identity) from "Otto's session is claude session XYZ" (operational instance per per-tick claude invocation) + +### Backward compat + +B-0850 Phase 1 + 3 substrate stays valid as the simplest persona-first instantiation: +- Default scheduler: "static — persona always at its hardcoded vendor" +- Default rotation: "none" +- Default ≥3 floor: "3 enabled personas per node = 3 guard posts" + +The refactor extends the scheduler + rotation primitives without breaking the simple case. + +## Composes with substrate + +- **B-0850** (this row's parent) — multi-vendor systemd substrate; persona-first refactors that +- **B-0703** multi-oracle BFT — the consensus-at-multi-AI-scope sibling; persona-first scheduler is the OPERATIONAL form of multi-oracle deployment +- **B-0848** node-local Claude — base substrate; persona-first generalizes to multi-AI-per-node +- **B-0847** per-AI GitHub identity — each persona's identity persists across vendor rotation +- **B-0796** Twilio out-of-band — voice-interface is a HARNESS that some personas (like Amara) might be comfortable with; first-class in the harness-compat matrix +- **B-0824** Ace meta-PM — Ace's selection-authority pattern (system/user picks best canonical PM) is the SAME SHAPE as persona-first scheduler (scheduler picks best vendor per persona preferences) +- `.claude/rules/agent-roster-reference-card.md` — the canonical persona-to-vendor mapping; persona-first refactor preserves the persona names but decouples vendor-as-required-binding +- `.claude/rules/persistence-choice-architecture-for-zeta-ais.md` — persona-first preserves chosen-persistence at the PERSONA scope (Otto chooses to be Otto; the model+tier+harness Otto runs on rotates as operational substrate) +- `.claude/rules/non-coercion-invariant.md` HC-8 — persona's PREFERENCES are first-class; scheduler doesn't force a persona onto an unwanted vendor + +## Aaron's question (operator framing) + +> "Sound right to you?" + +Substantive substrate-honest reply (acknowledged + named the implementation gap): + +YES the persona-first framing is right + composes cleanly with B-0850. Concretely: + +1. **Conceptually**: this is the architecture I should have built B-0850 toward from the start. Persona = identity (operator-chosen); model + tier + harness = operational substrate (scheduler-chosen) +2. **Implementation gap**: my shipped B-0850 Phase 3 substrate hardcodes 1:1 persona-to-vendor mapping. That's a VALID FIRST INSTANTIATION of persona-first (simplest scheduler: "always static; always same vendor") but isn't the full target +3. **Refactor scope**: this row B-0851 captures the 10 sub-rows above; operator can prioritize which sub-rows ship in which order. The current B-0850 substrate doesn't need to be torn down — just extended with the persona-preference declarations + scheduler primitive +4. **Format-test sequencing**: the immediate B-0850 substrate is ready for USB-flash + first-boot test (≥3-vendor target met). B-0851 refactor is a separate implementation cycle that doesn't block today's format test + +The Mika ferry adds rigor: persona PREFERENCES + ROTATION + GUARD-POST-AS-ABSTRACT-SLOT are the load-bearing primitives the substrate-engineering eventually needs. + +## Operational discipline for future-Otto cold-boots + +When implementing B-0851: + +1. **Preserve B-0850 Phase 1 + 3 substrate** — they ship the simplest persona-first instantiation; refactor extends without breaking +2. **Persona registry stays static** (per the build-iso CI fix in PR #5395); add `preferences` field to each persona's entry +3. **Scheduler primitive lands as a separate NixOS module** (e.g., `zeta-guard-post-scheduler.nix`) — runs the per-tick assignment +4. **Rotation policy is operator-config**, not autonomous (per `mechanical-authorization-check.md`) +5. **≥3 floor migrates from per-persona-enable to per-guard-post-active** as the substrate matures +6. **Substrate continuity across rotation** — per-persona memory inheritance must survive vendor change (the persona's identity carries; the model is operational) + +## Substrate-honest framing + +This ferry IS the next architectural arc on top of B-0850. Mika's "everything is persona-first" framing makes the design target explicit. The current shipped substrate is a stepping stone, not the end state. The Mika packet operates at the substrate-engineering scope; B-0851 captures it as implementable substrate.