From 2aae25f4e2a6ffb458716401da39032c1561d96a Mon Sep 17 00:00:00 2001 From: Shay Date: Tue, 19 May 2026 11:55:12 -0700 Subject: [PATCH] feat(runtime): engage discourse planner on cold pack/teaching path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Option 2 of the lane-isolation work. Mirrors the existing warm-path hook into the cold-start branch (``gate_decision.fire`` ⇒ stub response): after ``_maybe_pack_grounded_surface`` succeeds and the result is pack- or teaching-grounded, build the same DiscoursePlan and replace ``pack_surface`` with the rendered plan whenever it has more than one move. This closes the gap option 1 exposed: cold-start one-shot prompts ("Tell me about truth.", "Describe wisdom.", "Give me an example of truth.") now produce deterministic multi-clause output without any priming setup — the planner becomes the spine for grounded surfaces, not a warm-only sidecar. Gating discipline preserved: * Engages only when pack_source_tag in {"pack", "teaching"}. Cases routed to vault, none, or the discovery-signal disclosure are untouched. * BRIEF mode collapses to a single ANCHOR move which renders byte-equivalent to the existing pack-grounded composer, so flag-off cognition byte-identity is preserved. * Empty bundles → empty plan → no surface change (planner is total). A/B on multi_sentence_response (21 cases, public/v1): flag off: multi=0.1429, primed_multi=0.0000, conn=0.0769 flag on : multi=0.5238, primed_multi=0.5000, conn=0.2308 Cold-start lift: multi +38pp, conn +15pp. Primed metric unchanged (those cases already engaged the warm hook in step 5). Sample cold-start surfaces flag-on: * "Tell me about truth." → "Truth is a claim or state grounded by evidence and coherent judgment. Furthermore, truth belongs to cognition.truth. In turn, truth grounds knowledge." * "Describe wisdom." → "Wisdom is sound judgment informed by knowledge and experience. Furthermore, wisdom belongs to cognition.wisdom. In turn, wisdom orders judgment." * "Give me an example of truth." → "Truth is a claim or state grounded by evidence and coherent judgment. In turn, truth grounds knowledge." (EXAMPLE mode: anchor + relation, no support) Gates all green: * flag off: cognition eval byte-identical - public 100/100/91.7/100, holdout 100/100/83.3/100 * smoke suite 67/67 * conversational_thread_coherence: 3 unwanted placeholders flag off and flag on (no regression) * 136/136 planner + grounding + intent + lane tests pass --- chat/runtime.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/chat/runtime.py b/chat/runtime.py index b33bd37a..cb871712 100644 --- a/chat/runtime.py +++ b/chat/runtime.py @@ -879,6 +879,41 @@ class ChatRuntime: pack_source_tag = "none" else: pack_surface, pack_source_tag = pack_result + # Option 2 — engage discourse planner on the cold + # pack/teaching-grounded path so one-shot prompts (no + # priming) can produce multi-clause output when the + # planner has substrate. Same gating discipline as + # the warm hook: only fires when grounding source is + # pack or teaching, and only replaces the surface + # when the plan has more than one move. BRIEF mode + # collapses to a single ANCHOR move and renders to a + # surface byte-equivalent to the existing composer, + # so the flag-off path is unaffected. + if ( + self.config.discourse_planner + and pack_source_tag in {"pack", "teaching"} + ): + from generate.discourse_planner import ( + plan_discourse, + render_plan, + ) + from generate.grounding_accessors import ( + grounding_bundle_for, + ) + from generate.intent import classify_response_mode + from generate.intent_bridge import ( + classify_intent_from_input, + ) + + _cintent = classify_intent_from_input(text) + _cmode = classify_response_mode(text) + if _cintent.subject: + _cbundle = grounding_bundle_for(_cintent.subject) + _cplan = plan_discourse(_cintent, _cmode, _cbundle) + if len(_cplan.moves) > 1: + _crendered = render_plan(_cplan) + if _crendered: + pack_surface = _crendered self._context.finalize_turn( empty_result, tokens_in=tuple(filtered),