Story-3115 Walkthrough

Outcome: Vani now receives one writing instruction beside the existing Surface: line in stable META. WhatsApp receives a short, single-message, table-free contract. The ACP panel receives a markdown-and-tables contract with room for a longer answer.

Surface: whatsapp.
Writing surface: WhatsApp. Keep the answer short and in one message. Do not use tables.

Surface: app.
Writing surface: ACP panel. Markdown and tables render here; use them when helpful,
and take the space the answer needs.
One truth, two presentations. The channel changes only Vani's wording. No tool accepts a channel parameter, no tool returns different facts, and the broker still owns per-rail delivery under pramaan-docs ADR-110 §12 and §9.6.

Why the instruction is conditional

MiraConverseInput.channel_origin already defaults to app. Pydantic records whether the caller actually supplied the field. Story-3115 adds writing guidance only for an explicitly supplied app or whatsapp. An omitted field keeps the exact pre-Story prompt, including the existing Surface: app. line.

Cache receipt

InputPrompt byteso200k tokensDelta
channel omitted9682930 bytes · 0 tokens
explicit ACP/app1,090318+122 bytes · +25 tokens
explicit WhatsApp1,062313+94 bytes · +20 tokens

The omitted full text prompt remains 12,438 UTF-8 bytes with SHA-256 fe20f5573221efda27fdecc28130b32dfc17dcd5be8e6c2a9cd27fe9c55745ad. Explicit ACP and WhatsApp sessions deliberately occupy different stable cache entries; turns on the same channel retain a byte-identical prefix.

Executable proof

RequirementTest
Omitted channel keeps the exact previous prompt test_omitted_channel_prompt_is_byte_identical_to_pre_d16
Distinct guidance reaches the real assembled request and streamed turn path test_explicit_channel_guidance_reaches_the_model_request_and_stream (deterministic model; assembly/wiring proof, not a live-seat quality score)
Raw runtime input preserves omitted versus explicit channel_origin test_runtime_preserves_whether_channel_origin_was_supplied
Each explicit channel remains stable across turns test_explicit_channel_prefix_is_stable_across_turns
The lab declares channel in live stable META test_identity_declares_channel_as_stable_meta
No model-visible tool schema gains a channel field test_converse_registers_the_exact_specced_tools_and_measured_schema_delta
A rejected UNAVAILABLE finding still never reaches a delta test_rejected_unavailable_finding_never_reaches_the_delta_stream

Verification

Focused converse + tools + runtime tests → 43 passed
uv run ruff check .                        → All checks passed
uv run pytest -q                           → 444 passed, 3 dependency warnings