# Proposal execution glue — all 8 ProposalKind paths are stubs

`recoil/api/proposal_dispatch.py` defines `_KIND_INFO`, the table mapping each `ProposalKind` to its execution function. Every entry currently has `exec: None`. The proposal lifecycle (originate → review → approve → reject) works end-to-end against this table; the approval path emits a BUS event but does NOT actually call the engine-side dispatcher that would mutate the underlying artifact. This is the third leg of the "wired UI, stubbed engine" stool the audit flagged in Cluster 5C.

The 8 ProposalKinds and their target dispatchers when wired:

| ProposalKind | Engine-side dispatcher | What it mutates |
|---|---|---|
| `PromptRewrite` | `recoil.execution.prompt_compiler.rewrite_prompt(beat_id, new_text)` | Beat's prompt text in the prompt JSON |
| `ParamTweak` | `recoil.pipeline.core.dispatch.update_take_params(take_id, params)` | Take's resolved params (seeds, durations, model overrides) |
| `RefSwap` | `recoil.pipeline.lib.ref_loader.swap_ref(beat_id, ref_id, new_ref_path)` | Reference image binding for one slot |
| `BibleEdit` | `recoil.pipeline.lib.bible_loader.patch_bible(project, key_path, new_value)` | Universe / Project bible YAML at a specific path |
| `ScriptDoctor` | `recoil.skills.script_doctor.fix_episode(project, episode_id, annotation)` | Episode script via the script-doctor skill |
| `RetimeBeat` | `recoil.pipeline.core.workflow.retime_beat(beat_id, new_duration)` | Beat duration on the workflow + propagates to dependent takes |
| `LineageBranch` | `recoil.pipeline.core.take.fork_take(take_id)` | Creates a new Take in the same Beat with a copied workflow |
| `KeeperPromote` | `recoil.execution.feedback.set_keeper(beat_id, take_id)` | Beat's primary_take_id |

PromptRewrite is the named "first one to wire" per BUILD_SPEC.md §19.3 of the parent Console v2 build. The reasoning: it's the most isolated mutation (one text field on disk, no provenance regeneration, no downstream invalidation) and exercises the full proposal lifecycle from a UI surface JT uses every day. Once PromptRewrite is wired and stable, the remaining seven follow the same pattern with progressively wider blast radii (param tweaks invalidate caches; ref swaps trigger thumbnail regeneration; bible edits cascade through the prompt compiler; script-doctor is the heaviest).

Why this isn't part of the Console v2 fix:

1. **The fix targets truth-restoration of always-visible chrome.** Proposals are a visible-on-demand surface (only when a ProposalCard is open). The Cluster 2 / Cluster 4 failure modes — green pill on disconnect, hierarchy unwalkable — do not depend on proposal execution.
2. **Each dispatcher is a separable build.** The 8 dispatchers above have nothing structural in common beyond "they call into the engine." Wiring them piecemeal is the right shape; bundling all 8 into one CP is the wrong shape.
3. **The substrate is correct today.** `_KIND_INFO` is the typed registry; `exec: None` is honest. When a CP wires PromptRewrite, the change is a single line: `_KIND_INFO[ProposalKind.PromptRewrite] = ProposalKindInfo(..., exec=execute_prompt_rewrite)`. No frontend change. No contract change.

ADR-0011 (P3 hierarchy synthesis as minimal fix) is the structural precedent: the audit identified a long-term correct path AND a minimal-fix-now path, and the Console v2 fix shipped only the minimal fix. Proposal execution is the same shape: long-term correct (8 dispatchers, full lifecycle) is documented here; minimal-fix-now (lifecycle works, exec returns honest stub) is what ships.

Cited: console-v2-audit-2026-05-04 Cluster 5C. See `chat-anthropic-sdk.md` and `jt-priority-slash-commands.md` (sibling Cluster 5B deferrals).
