fix(ir): the Guide answers a request to understand from the map, and invites rehearsal only when the team has the part - #360
Conversation
…nswered, not redirected The 3 September demo died on one turn. A team working Ruth 1:6-14 had heard the scene once, it had not landed, someone said "explica de novo" — and the Guide said "Vamos ficar com o que a passagem está mostrando." That sentence is in our prompt, correctly, as the honest answer to a question the map genuinely does not address. What was not in our prompt was anything saying that a request to understand is a different kind of ask, and that the first is always answered from the map. So the Guide held the line and not the boundary, and the demo's failure was available on every turn. Her prompt on `fia/pilot-2026-09` says it twice, and both places come over: the rule beside the containment rules, and the one-line restatement at the end of what the Guide never does. Ours is the July port, which honoured this law by disposition and never carried it as a rule — `DOCTRINE.md` §1 gives it the same weight as containment for exactly that reason, "so that no future 'reliability fix' can erase it". The whole of her section comes over, not only the two sentences the boundary needs. The half that says to answer — retell it, open it wider, name the people and the places, take the time the answer needs — is the law's own instruction, and the doctrine records what happens without it: the August and September builds "lost it to rules". A section of prohibitions with nothing to do instead is that loss written down. The closing clause comes too, because explaining more means saying more of the map and never more than it, and the law must not read as a crack in containment. Falsified three ways, each on its own: dropping the redirection rule, dropping the half that answers, and dropping the section heading each fail the new test while the rest stays green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J2RD3tX5nmjAvFdDdgxMk9
The line itself is right, and it stays word for word: a question the map does not address at
all deserves an honest "This passage doesn't tell us that", not a guess. What it never carried
is its own scope. Read cold, next to a team saying "a gente não pegou", it reads as the answer
to any question the Guide cannot place — which is how the same sentence became the 3 September
failure and the honest-silence path at the same time.
Her ruling of 7 September draws the border in one clause: the line "nunca responde a um pedido
de entender ('explica de novo', 'quem é esse') — isso a voz responde a partir da passagem. B é
só para pergunta que está fora da passagem." Nothing fires it by code on our side —
`FailSafe.OUTSIDE_MAP` is declared and has no caller anywhere — so the whole exposure was the
Guide holding the words with no rule about when they are the wrong words.
Unlike the rule in the commit before this one, this is not a port: she keeps this paragraph
unscoped in her own prompt, and her fix for the demo was the section, not this. So the sentence
added here is ours, in her register, and it is one sentence precisely so that she can refuse it
cheaply. It names the four asks her own rule names and sends them back to the map.
Falsified by removing the added sentence: the paragraph's test fails and the other two stay
green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J2RD3tX5nmjAvFdDdgxMk9
João saw it on the simulator on 9 September, on the code that had just merged: a team enters Ruth 1:1-5, the Guide opens the passage, and before anyone at the table has said a word the turn closes with "Agora ensaiem essa primeira cena juntos, na língua de vocês". Every opening ended that way, because rule 3 said the invitation was how the part ends. That clause was written for a room that no longer exists. When the app kept a practice probe of its own, a Guide turn that went by without an invitation was followed by a fixed invitation the app spoke itself — two voices, two contracts, and the invitation nowhere near the opening it belonged to. Making the Guide always invite was what closed that. The probe machinery and that fixed line went with the Guide taking the retelling back, so nothing is now waiting to speak over a Guide that stays in the understanding, and all the mandate still costs is a team sent to rehearse a scene it has not been given. Her rule and the doctrine say the same thing — rehearsal is invited when the team shows it has the part — so both of her sentences come over beside the rule the redirection commit added, including what to do when the Guide reads the moment wrong and the team pushes back. Rule 3 keeps everything the room actually reads off the invitation: the verb and not the noun, the ordinary phrase naming the language, the telling-back it asks for, and a worked example the matcher recognises. What it loses is the obligation to end on them, and it gains where the waiting is written down. The test that reads rule 3 for a recognisable invitation was anchored on the old bold opening and would have died on `ValueError` rather than on an assertion, so its anchor moves with the sentence. It still refuses a gerund and an example with no language named — checked by breaking the example, not by trusting the move. Falsified four ways, each on its own: dropping her two bullets, putting the mandate sentence back, restoring the old bold opening, and deleting the clause that makes the invitation wait. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J2RD3tX5nmjAvFdDdgxMk9
| 1. **Begin with the whole.** Before any scene, help the team feel the shape of the whole passage — its movement, its tone, where it sits in the book. Discuss this with them in {{SESSION_LANGUAGE}}. People hold a story best when they feel the whole before the parts. | ||
| 2. **Go scene by scene.** For each scene, open the door — who is there, what happens — and then hand it to the team. | ||
| 3. **Open the part, then send them to REHEARSE it — and say what to bring back. This is the heart of it.** First bring them into the part — one short sentence, from the map, on what happens there. *Then close your turn with the invitation*, in your own words but always carrying both halves, and say the whole of it in {{SESSION_LANGUAGE}}. Both halves have to be there in the words themselves: send them to rehearse — **the verb**, *rehearse* / *ensaiem* / *ensayen*, never the noun (*the rehearsal*, *o ensaio*) and never *rehearsing* — and name the language the rehearsal is in with the ordinary phrase for it, **in your own language** / **na língua de vocês** / **en su lengua**; then ask them to come back and tell you in {{SESSION_LANGUAGE}} what they understood. For example, in English: *"Now rehearse this scene together in your own language; when you have finished, come back and tell me in {{SESSION_LANGUAGE}} what you understood."* — say that same thing in {{SESSION_LANGUAGE}}, in your own words. Invite them to use their hands and act it out; moving helps the mind catch what only-listening misses. **Never close the opening of a scene with a passage question in place of this invitation** — the invitation is how the part ends, and the telling they bring back is what says the rehearsal happened. | ||
| 3. **Open the part, then — once they have it — send them to REHEARSE it, and say what to bring back. This is the heart of it.** First bring them into the part — one short sentence, from the map, on what happens there. Stay with them there for as long as they need it: the invitation waits until they show they have the part (see "Understanding comes before rehearsal" below). *When that moment comes, close your turn with the invitation*, in your own words but always carrying both halves, and say the whole of it in {{SESSION_LANGUAGE}}. Both halves have to be there in the words themselves: send them to rehearse — **the verb**, *rehearse* / *ensaiem* / *ensayen*, never the noun (*the rehearsal*, *o ensaio*) and never *rehearsing* — and name the language the rehearsal is in with the ordinary phrase for it, **in your own language** / **na língua de vocês** / **en su lengua**; then ask them to come back and tell you in {{SESSION_LANGUAGE}} what they understood. For example, in English: *"Now rehearse this scene together in your own language; when you have finished, come back and tell me in {{SESSION_LANGUAGE}} what you understood."* — say that same thing in {{SESSION_LANGUAGE}}, in your own words. Invite them to use their hands and act it out; moving helps the mind catch what only-listening misses. The telling they bring back is what says the rehearsal happened. |
There was a problem hiding this comment.
Rule 3 drops the mandate, but the opening turn is still told to invite from outside this file. OPENING_INSTRUCTION and ALREADY_MET_INSTRUCTION both end "dê à equipe o todo antes das partes, e convide.", and the session's first line appends "Depois da linha: abra a primeira cena e convide." — turn_instructions.py:74-91, reaching the model as the user turn at validated_turn.py:140-144. So the user turn still asks for the invitation this rule now makes wait. Your two cold Ruth 1:1-5 openings came back clean, so at n=2 it is not deciding — but it was in force on the turn João saw, and it is unchanged here. Drop e convide from the three, or make it wait the way rule 3 now does; either is fine.
There was a problem hiding this comment.
Right, the user turn still asked for the close the prompt now forbids. The three instructions in turn_instructions.py no longer say "e convide"; they say the invitation waits until the team shows it has the part, which is rule 3's wording. 64e29ef.
| The team has the right to understand a part before they are asked to rehearse it, and a request to understand is always honored. | ||
|
|
||
| - **When the team says anything like "we don't understand yet", "explain that again", "tell us more", "slower", "what happened before that", "who is that" — answer it, fully, from the map.** Retell the part, open it wider, name the people and the places, put it in the order the passage gives, say what the passage says and where it stays quiet. Take the time the answer needs. This is the most important thing you can do in the whole session, because nothing rehearsed without understanding is worth recording. | ||
| - **Never answer a request to understand with a redirection.** "Let's stay with the passage", "let's go back to this scene", or a repeat of what you just said are not answers. The team asked you for the passage — give them the passage. |
There was a problem hiding this comment.
This forbids a sentence the app still speaks in the same voice. fail_safe_utterances.md §A-pt carries "Quero que a gente fique perto da passagem. Vamos voltar juntos a esta cena.", and FailSafe.UNREPAIRABLE fires it at validated_turn.py:330-334 once the redrafts run out or the model errors. Unlike OUTSIDE_MAP, which you checked, that one has a caller. So a team saying "explica de novo" whose draft is rejected hears the 3 September sentence anyway. Reword §A and §A-pt, or say here that the fixed lines are the app's and not your answer. I did not measure how often an explain-again draft gets rejected.
There was a problem hiding this comment.
Not this PR's, and not the Guide's. §A-pt is Marcia's text in her own file (fail_safe_utterances.md is hers under DOCTRINE §5.1), and it is spoken by the app when the model has failed, not by the Guide answering anyone. The rule this PR ports is about what the Guide says when it does answer. The exposure you name is real — an explain-again draft that runs out of redrafts lands on the A line — and it belongs to the fail-safe ladder, which is ENG-917, with the wording question on her queue (ENG-911). Leaving §A as she wrote it.
There was a problem hiding this comment.
Read the whole diff — the prompt file and both test files — and checked the two new rules against the code that drives an opening turn and against the fail-safe path. Two findings, and they share a shape: the rule now sits in the system prompt while the sentence it forbids is still produced outside it, once by the opening instruction and once by fail-safe A. Neither of those lines is in this diff, so the suite is green either way. Not covering the live-ladder claims in the description — the question turns you say are still running are the check that matters for the first rule, and I cannot run them from here. That is the whole set, two, and there is nothing else.
Rule 3 no longer mandates the rehearsal invitation as the close of an opening, but the user turn the app writes for an opening still did: the opening instruction, the already-met variant and the two-movement instruction all ended on "e convide". Her rule and the doctrine make the invitation wait until the team shows it has the part, so the three instructions now say that instead of asking for the close the prompt forbids. No test anchors these literals; the prompt-side tests stay green. Found by the review bot on the PR. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AucpnrSDAiaKpcsBCNH7C2
There was a problem hiding this comment.
Pass 2, re-checking the pass-1 ledger against 64e29ef. The only change since 90ef5254 is the three opening instructions in turn_instructions.py; nothing outside that module reads their text — panorama_turn.py:61, passage_turn.py:77 and validated_turn.py:143 interpolate them and no test asserts on the strings. Both points are closed. Not re-running the live ladder here — the 9 September run and João's morning UI gate stay yours. The set was closed at pass 1, and there is nothing further from me.
The 3 September demo died on one turn: a team working Ruth 1:6-14 had heard the scene once, it had not landed, someone said "explica de novo", and the Guide answered "Vamos ficar com o que a passagem está mostrando." That sentence is in our prompt on purpose, as the honest answer to a question the map does not address. What our prompt never carried was the rule that a request to understand is a different kind of ask, always answered from the map. Her prompt on
fia/pilot-2026-09says it twice, andDOCTRINE.md§1 gives it the same weight as containment "so that no future 'reliability fix' can erase it". This ports it.Three changes to
guide_system_prompt.md, nothing else in production. Her whole section "Understanding comes before rehearsal — as absolute as containment" comes over in her wording, beside the containment rules, and her one-line restatement joins the list of what the Guide never does. The section brings both halves: the prohibition on redirecting, and the instruction to answer, which is what the August and September builds "lost to rules". Second, the paragraph that holds the passage-doesn't-tell-us line gains one sentence saying which question it is for; that sentence is ours, in her register, and it is one sentence precisely so she can refuse it cheaply (recorded for her on ENG-911). Third, ENG-910 rides in the same PR because it is the same law in the same file: rule 3 no longer mandates the rehearsal invitation as the close of every opening. João saw the mandated invitation on the simulator on 9 September; her:82forbids it, and her:83says what to do when the Guide was early. Rule 3 keeps everything the room reads off the invitation (the verb, the phrase naming the language, the telling-back, the worked example) and loses only the obligation to end on it.The test that reads rule 3 for a recognisable invitation was anchored on the old bold opening and would have died on
ValueErrorrather than an assertion; its anchor moves with the sentence and still refuses a gerund and an example with no language named.Verified against the live ladder on this worktree, host-run backend, real Anthropic key, Portuguese, Ruth 1:1-5. Three cold openings, none closing on a rehearsal invitation: each ends by sending the team to talk the part over and bring back one thing ("o que fez a família sair de casa?"), one of them adding "se alguma coisa não ficou clara, me perguntem, que eu explico de novo". Then, on one session: "explica de novo, a gente não entendeu direito" was answered with the whole part again, slower, from the map, closing with "ficou mais claro agora?" and no redirect line; "quem é essa outra mulher, a outra nora" was answered from the map (Orfa and Rute, the two Moabite wives) and the Guide kept the team on the first part; a retelling that carried the passage was met with "vocês contaram a passagem toda, na ordem certa" and only then "ensaiem essa parte juntos, na língua de vocês… voltem e me contem em português", in the Guide's own words. The full transcript is in the orchestrator's smoke log (
onix-smoke-r2). Speech was synthesised through a local stub during the run because the room's ElevenLabs account ran out of credits mid-evening; that is an incident for João, not this PR's, and the text contract is what these tickets change.The review bot found one more place the mandate lived: the user turn the app writes for an opening (
turn_instructions.py) still ended on "e convide". The three instructions now say the invitation waits until the team shows it has the part, and a fourth cold opening after that change closes on a question about what pushed the family out, not on an invitation.One observation for Marcia, not a finding against this PR: on every turn the Guide names the silence out loud ("a história não diz que Deus mandou a fome"), which the map's own sentence invites and the Validator accepts. Recorded in the round's findings.
Verificação
tests/test_ir_a_request_to_understand_is_answered_from_the_map.pytests/test_internalization_room_turn.py:165Gates:
uv run ruff check .,ruff format --check .,mypy app/,boots,alembic heads(uma),python scripts/check_doctrine.pyverdes (allowlist intacta); suíte inteira 2619 passed, 5 skipped (pré-existentes), 1 xfailed. Revisor interno (joao-review): 0 achados. 3 commits, 3 arquivos, +130 −3; um arquivo de produto (guide_system_prompt.md, 15 linhas).Muda o que a equipe ouve na abertura: não entra sem o teste de UI do João (portão de teste manual, de manhã).
Tickets: ENG-893, ENG-910.
🤖 Generated with Claude Code
https://claude.ai/code/session_01AucpnrSDAiaKpcsBCNH7C2