Tightens the multi_sentence_response lane predicates so OOV
invitations and refusal disclosures can no longer be counted as
articulate capability. Three new metrics partition the case space:
articulate_sentence_rate - >=2 sentences AND grounded in
{pack, teaching}. Real capability.
disclosure_sentence_rate - >=2 sentences AND grounded in
{oov, refusal, none}. Structural
multi-sentence from disclosure templates.
unarticulate_rate - <2 sentences regardless of source.
The three sum to 1.0 (modulo rounding) by construction. The
doctrine-correct headline is now ``articulate_sentence_rate``;
``multi_sentence_rate`` is kept as a continuity metric only.
2 new tests pin: (a) the three-way partition is total and disjoint
(articulate + disclosure + unarticulate == 1.0); (b) OOV/refusal
disclosure surfaces contribute to disclosure_sentence_rate but
never to articulate_sentence_rate.
Live A/B on 21 cases under the new partition:
flag off: articulate=0.0952, disclosure=0.0476, unarticulate=0.8571
flag on : articulate=0.8571, disclosure=0.0476, unarticulate=0.0952
Planner lift is +76pp on articulate. Disclosure stays flat across
the flag (the planner gate correctly leaves disclosure surfaces
alone). The remaining 9.5pp unarticulate flag-on is the genuine
miss list (walkthrough + compound prompts) that the next two
landings will target.
contract.md updated to make articulate_sentence_rate the headline
and to document the partition explicitly.
cognition eval byte-identical: public 100/100/91.7/100.
smoke suite 67/67.
Option 1 of the lane-isolation work after the 8d1aeec predicate
refinement. Adds optional ``priming_prompts: [str, ...]`` to each
case in ``multi_sentence_response``. The runner runs priming prompts
on the same ``ChatRuntime`` instance before the scored prompt and
discards their responses; only the scored prompt is measured.
This isolates code paths (notably the discourse planner hook) that
engage only on the warm pack/teaching path from cold-start one-shot
paths. Cold-start measurement is preserved: cases without
``priming_prompts`` (or with an empty list) keep the old behavior.
New metric ``primed_multi_sentence_rate`` reports only on primed
cases. ``primed`` is also exposed per-case in case_details.
Six primed cases added to ``public/v1/cases.jsonl`` (Explain truth /
Tell about truth / Explain knowledge / Tell about light / Tell about
parent / Write a short paragraph about truth). Each is the cold-
start variant of an existing case plus a single "What is X?"
priming prompt.
3 new tests:
* Priming prompts run in order on the same runtime before the
scored prompt; primed=True on the result.
* Default cold-start behavior: no priming key OR empty list ⇒
primed=False; aggregate untouched.
* ``primed_multi_sentence_rate`` separates from aggregate so
cold cases never inflate/depress the warm-path metric.
A/B measurement on the live runtime (21 cases):
flag off: multi=0.1429, primed_multi=0.0000, primed_cases=6
flag on : multi=0.2857, primed_multi=0.5000, primed_cases=6
Lift is real and exclusively on the substrate the planner can
actually serve (teaching-grounded narrative). The three primed
"Explain X" and "Write a short paragraph about X" cases stay
vault-grounded (Explain / Write are not DEFINITION / NARRATIVE
intents and so don't fire pack-grounded warm), so they don't lift.
That gap is what option 2 will close.
contract.md updated to document priming and the new metric.