{"record":{"id":"8421c47e4d5865a4","repo":"Hmbown/CodeWhale","slug":"initial-prompt-deferred-status","errorCode":null,"errorMessage":"{INITIAL_PROMPT_DEFERRED_STATUS}","messagePattern":"\\{INITIAL_PROMPT_DEFERRED_STATUS\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/tui/src/tui/ui/dispatch.rs","lineNumber":577,"sourceCode":"            warning: Some(\n                \"message_submit hook executor did not run; submission continued because no strict gate matched\"\n                    .to_string(),\n            ),\n        }\n    } else {\n        crate::hooks::MessageSubmitOutcome::Blocked {\n            reason: \"message_submit hook executor did not run; a strict gate blocked submission\"\n                .to_string(),\n        }\n    }\n}\n\npub(crate) fn prepare_user_dispatch(\n    app: &mut App,\n    config: &Config,\n    message: QueuedMessage,\n) -> Result<UserDispatchPrepare> {\n    anyhow::ensure!(!app.redaction_gate, \"{INITIAL_PROMPT_DEFERRED_STATUS}\");\n    let _ = app.maybe_nudge_for_planning_prompt(&message.display);\n    let _ = app.maybe_nudge_plugin_for_prompt(&message.display);\n\n    // Plan paused-command changes without touching App or the engine pause\n    // gate. Route selection can await and client preflight can fail; neither\n    // may resume or discard a paused command unless a turn is ready to send.\n    let paused_dispatch = plan_paused_command_message(app, &message.display);\n\n    let cwd = std::env::current_dir().ok();\n    // One cache for this submit: the references pass and the payload pass\n    // otherwise each shell out for `@git`/`@diff`, making git compute a large\n    // working-tree diff twice to attach it once (#4067 review follow-up).\n    let mut git_cache = crate::tui::git_mention::GitMentionCache::default();\n    let completion_index = app.composer.mention_discovery.fuzzy_candidates(\n        &app.workspace,\n        &app.composer.mention_cwd,\n        app.mention_walk_depth,\n        app.workspace_follow_symlinks,","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/tui/ui/dispatch.rs#L559-L595","documentation":"prepare_user_dispatch refuses to send a queued user message while the redaction gate is active (app.redaction_gate == true). The gate blocks dispatch until the user resolves the model-bound masking confirmation (\"confirm\" or \"keep masking\"). The error message is the INITIAL_PROMPT_DEFERRED_STATUS constant: \"Initial prompt ready; complete setup to send it\" — it signals the initial prompt is held, not lost.","triggerScenarios":"Calling prepare_user_dispatch (from dispatch_user_message_with_recovery / start_user_dispatch) when app.redaction_gate is set — i.e. the first prompt was submitted before the user completed the redaction-gate confirmation flow, so the message is intentionally deferred.","commonSituations":"A user launching Codewhale with an initial prompt (CLI arg or restored input) while the model-bound redaction decision prompt is pending; automated tests dispatching prompts without resolving the gate.","solutions":["Resolve the redaction gate prompt in the UI (choose \"confirm\" or \"keep masking\") — the deferred prompt is then sent automatically.","Check app.redaction_gate before dispatch and route the message into the deferred queue instead of calling prepare_user_dispatch.","In tests or scripts, simulate the gate resolution (or set app.redaction_gate = false after handling) before dispatching.","The prompt is not lost: it remains queued and dispatches once setup completes; no user action beyond the gate is needed."],"exampleFix":"// before\nprepare_user_dispatch(app, config, message)?;\n// after\nif app.redaction_gate {\n    app.status_message = Some(INITIAL_PROMPT_DEFERRED_STATUS.to_string());\n    return Ok(UserDispatchPrepare::Deferred(message));\n}\nprepare_user_dispatch(app, config, message)?;","handlingStrategy":"validation","validationCode":"if app.redaction_gate {\n    app.status_message = Some(INITIAL_PROMPT_DEFERRED_STATUS.to_string());\n    return Ok(UserDispatchPrepare::Deferred(message));\n}","typeGuard":"fn dispatch_allowed(app: &App) -> bool { !app.redaction_gate }","tryCatchPattern":"match prepare_user_dispatch(app, config, message) {\n    Err(err) if err.to_string() == INITIAL_PROMPT_DEFERRED_STATUS => {\n        // expected: gate pending — keep the message queued, no user alarm\n    }\n    other => other?,\n}","preventionTips":["Resolve the redaction gate (confirm / keep masking) before expecting the initial prompt to send.","In automated flows/tests, simulate the gate resolution before dispatching prompts.","Treat the message as deferred, not failed: it sends automatically once the gate clears."],"tags":["dispatch","redaction","safety-gate","deferred-input"],"backgroundTag":"invalid-state-transition","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}