practice: the between-problems pause — conclude ends the turn, the learner's go-ahead paces the stream (round 16)

Owner ruling (2026-10-06): every concluded problem opens a pause. The
agent may speak its closing words about the learner's last thinking
after the conclude result, then ENDS ITS TURN — a system-prompt law
deliberately, per owner correction, NOT tool-level terminate. The next
problem is never posed until the learner explicitly moves on; the pause
is the session's teaching space (repairs, clarifications, follow-ups —
still surgical, never re-teaching).

The move-on signal is a first-class input: { type: "next" } appends a
practice-next marker (content = single-sourced NEXT_PROBLEM_TEXT — the
model's unambiguous go-ahead: pose per the selection rules or wrap if
the arc is complete). Honest 400s: practice sessions only, nothing
active (mid-problem input rides the dock), riding after any pending
dismissal synthesis exactly like text.

The fast path (owner approved: composer-band chip + Enter-on-empty):
- Composer.enterAction gains "next" — Enter on an EMPTY composer in
  the pause fires the signal; typing anything makes Enter a send again;
  busy (steer/stop) outranks the pause.
- The Next chip hovers at the composer band's top-right (pick-pill
  chrome register) whenever the pause is live and a problem has ever
  been posed; the placeholder becomes the hint ("Ask about this
  problem — or press Enter for the next one…", exact);
- the transcript renders the signal as a compact centered NEXT PROBLEM
  line (mono-caps chrome); session-core appends it optimistically.

CONCLUDE_ACK_TEXT rewritten to carry the law; doctrine §VIII gains the
pause law (owner-sanctioned edit #3); 00-base's conclude/dismissal
bullets rewritten + the between-problems section added.
This commit is contained in:
amosblomqvist
2026-10-06 03:47:05 +03:00
parent a2db80b72d
commit 573d89ae66
12 changed files with 246 additions and 36 deletions
+3 -1
View File
@@ -152,7 +152,9 @@ describe("practice flow (scripted model)", () => {
(m) => (m as ToolResultMessage).role === "toolResult" && (m as ToolResultMessage).toolName === "conclude",
) as LhMessage & ToolResultMessage;
assert.ok(concludeAck, "the conclude ack persisted");
assert.ok((concludeAck.content[0] as { text: string }).text.includes("composer is free"));
// Owner round 16: the ack carries the turn-ends law (no more tools,
// the learner's go-ahead paces the next problem).
assert.ok((concludeAck.content[0] as { text: string }).text.includes("END YOUR TURN"));
// The turn continued past conclude to the reveal text.
assert.ok(afterConclude.some((m) => (m as { role?: string }).role === "assistant" && JSON.stringify((m as { content?: unknown }).content).includes("Clean proof.")));
assert.equal(activeProblemOf(afterConclude), null);