⌂ Home ☷ Board

Independent Review: Luci Control Room and Runtime Independence Plan

Reviewer: GLM-5.1 (via Z.AI), running as Luci CLI session Date: 2026-05-21 Plan reviewed: ~/workspace/reports/luci-control-room-runtime-independence-plan.md Supporting docs reviewed: - ~/workspace/agent-control-room/docs/runtime-independence.md - ~/workspace/mission-control/docs/runtime-architecture-refresh.md - scheduler.py (PROFILE_PROVIDER, PROFILE_META, _runtime_profile_defaults) - mc_pickup.py (Larry provider state, defaults) - mission-control/dispatch_policy.py (forbidden_runtime_profiles) - MC ticket database (MC-3898, MC-3907)


Overall assessment

The plan is well-structured, honest about current weaknesses, and has the right archural instincts: MC as durable source of truth, runtimes as swappable adapters, control room as governance layer not a second database. Phase 0 and Phase 1 are landed and real. The source-of-truth boundary rules (added after Lucienne's review) are the most important quality gate in the document.

The plan has several factual inaccuracies in its inventory section, one wrong MC ticket reference, and a few gaps where claims about code structure don't match what's actually deployed. These are fixable but should be corrected before Phase 3 work begins, since Phase 3 depends on accurate inventory.


Strengths

  1. Correct top-level principle. MC as the durable layer, runtimes as adapters, is the right abstraction. The core invariant diagram is clear and accurate.

  2. Source-of-truth boundary is excellent. The "allowed / not allowed" lists for each directory are exactly the kind of guardrail that prevents control-room sprawl. The prohibition on duplicated live state and aspirational profile claims is particularly good.

  3. Honest current-state assessment. The weaknesses section doesn't sugarcoat: docs are spread across too many places, runtime profiles aren't a clean portability layer, Hermes config can drift from active runtime. This honesty is valuable.

  4. Phase 1 was executed correctly. The agent-control-room/ directory exists with exactly the four files promised (README.md, shared/commands.md, docs/runtime-independence.md, docs/webui-governance.md). No scope creep.

  5. Gates are appropriate. Architecture/docs, code/runtime, UI, and secrets gates are all reasonable. The Atlas-style signoff requirement for canonical doc changes is correctly applied.

  6. Deferred decisions are correctly deferred. Changing Hermes persistent default from grok-4.3, model/cost routing policy, Telegram home-channel contract — these are all correctly pushed past Phase 1.


Factual issues

1. Wrong MC ticket reference

The plan says "Mission Control tracking ticket: MC-3898" in three places (header, Phase 0 checklist, Immediate next actions). MC-3898 is actually "Confirm Padel Tuesday availability — resolve schedule conflict" (status: inbox). The real tracking ticket is MC-3907 ("Luci control room and runtime independence foundation", status: done).

Fix: Replace all MC-3898 references with MC-3907.

2. Runtime profile inventory has phantom entries

The plan (and the derived runtime-independence.md) list these scheduler profiles:

claude_anthropic, claude_glm, claude_kimi, claude_minimax, direct_gemini, direct_anthropic_sdk, direct_mixed

The actual PROFILE_PROVIDER map in scheduler.py (line 131-144) contains:

claude_anthropic     -> anthropic
claude_sonnet_medium -> anthropic
claude_opus_medium   -> anthropic
claude_opus_1m_medium -> anthropic
claude_opus_1m_high  -> anthropic
claude_glm           -> glm
claude_kimi          -> kimi
claude_minimax       -> minimax
glm_api              -> glm
kimi_api             -> kimi
minimax_api          -> minimax
grok_on_sub          -> grok-on-sub

Issues: - direct_gemini, direct_anthropic_sdk, direct_mixed do NOT exist in PROFILE_PROVIDER. They appear in the runtime-profile honesty rule in CLAUDE.md as sentinel values for tasks that bypass the claude CLI, but they are not registered profiles the scheduler can dispatch to. - claude_sonnet_medium, claude_opus_medium, claude_opus_1m_medium, claude_opus_1m_high, glm_api, kimi_api, minimax_api, grok_on_sub are all real profiles that the inventory omits.

The inventory lists 7 profiles. The code has 12. The phantom 3 aren't profiles at all. This matters because Phase 3 depends on accurate inventory.

Fix: Rebuild the profile inventory directly from PROFILE_PROVIDER keys and PROFILE_META entries. Note which are CLI-backed vs direct-API-backed (which is none currently — the direct_* sentinels exist only in the honesty rule, not in the scheduler).

3. Default profile claims are partially stale

The plan says:

scheduler_profile: claude_anthropic
scheduler_cli_fallback_profile: claude_glm
worker_profile: claude_anthropic
default_profile: claude_anthropic

The static defaults in scheduler.py (lines 300-303) say:

scheduler_profile: claude_anthropic
worker_profile: claude_anthropic
default_profile: claude_anthropic

But _runtime_profile_defaults() (line 410+) dynamically resolves defaults from the persistent model/provider. The static PROFILE_DEFAULTS dict is a fallback, not the live truth. The plan should note this distinction.

Also, scheduler_cli_fallback_profile is not visible in the static defaults — it may be derived elsewhere. The plan should say where.

4. Runtime profile state file is absent

The plan references ~/workspace/.state/runtime_profile_state.json as a live override mechanism. This file does not exist on disk. The plan should note that runtime profile state is currently all defaults with no overrides applied, rather than implying the file is actively used.

5. Larry host IP is stale/wrong

The plan says Larry is at elmar@46.225.208.1. The runtime-independence.md doc says elmar@46.225.208.1, not on Tailscale. This should be verified before Phase 3 — if Larry has moved or is on Tailscale now, the docs are misleading.


Structural observations

Missing from Phase 3: actual adapter interface

Phase 3 says "document backend/provider/model/tools/cost/fallback/smoke test" for each profile. This is documentation work. What's missing is whether there should be an actual adapter interface — a Python class or protocol — that formalizes what "being a runtime adapter" means in code. Currently, _apply_provider_profile_env() and _larry_runtime_config() are the closest things to adapters, but they're just env-injection functions. The plan should state whether Phase 3 is pure documentation or includes code abstraction.

Telegram routing (Phase 5A) is underspecified but correctly deferred

Phase 5A lists six items, all as unchecked todos. This is the right level of detail for now. The key architectural risk — "replacing Luci Persistent with Hermes/OpenAI/Codex should not change Telegram routing semantics" — is correctly identified. But the plan should explicitly state that CCGram's single-poller constraint (from CLAUDE.md) is a hard dependency that any runtime swap must preserve.

No cost data in the plan

Phase 4 is about cost routing, but the plan has zero cost data. There's no mention of current spend per profile, token costs, or even which profiles are expensive vs cheap. Phase 4 can't be evaluated without this baseline. The plan should at least note that cost data collection is a Phase 3 dependency.

No rollback plan for runtime switches

The plan says "a runtime can be retired by changing profiles/adapters and fallback docs, not by redesigning workflow" but doesn't describe the rollback mechanism. If a runtime swap breaks something in production, what's the recovery path? The scheduler's fallback chain exists but isn't documented here. A brief "rollback procedure" subsection would strengthen Phase 3/4.


Consistency with runtime-architecture-refresh.md

The canonical architecture contract (runtime-architecture-refresh.md) and this plan are aligned on the fundamentals: MC is source of truth, runtimes are control surfaces, not independent truth stores. No conflicts detected.

One gap: runtime-architecture-refresh.md references runtime_sessions as the runtime ledger and discusses WAT actions in detail. This plan mentions runtime_sessions in the core invariant but doesn't discuss how runtime session history should be preserved across runtime switches. If MC-3907 is about independence, session continuity across runtime changes is a gap worth noting for Phase 3.


Concrete recommendations

  1. Fix the MC ticket number. MC-3898 → MC-3907 everywhere.

  2. Rebuild the profile inventory from code. Use PROFILE_PROVIDER keys and PROFILE_META entries. Remove direct_gemini, direct_anthropic_sdk, direct_mixed from the inventory (they're sentinels, not profiles). Add the missing profiles (claude_sonnet_medium, claude_opus_*, *_api, grok_on_sub).

  3. Note the runtime_profile_state.json is absent. No overrides are active.

  4. Add a one-line rollback procedure to Phase 3: "If a runtime swap breaks production, revert via runtime_profile_state.json override or static PROFILE_DEFAULTS, then restart scheduler."

  5. Add cost baseline dependency to Phase 3 (collect current per-profile spend) so Phase 4 has data to work with.

  6. Note the CCGram single-poller constraint in Phase 5A as a hard dependency for any Telegram routing changes.

  7. Consider whether Phase 3 is docs-only or includes code abstraction. State this explicitly.


Verdict

The plan is sound in principle and Phase 0/1 execution is clean. The factual issues are in the inventory section — exactly the section Phase 3 depends on. Fix those before starting Phase 3, and this plan will serve as a solid foundation for the runtime-independence initiative.

Priority: fix the MC ticket number and profile inventory now, before the next session picks up Phase 2/3 work and propagates the errors into new docs.