I almost clicked approve on the interview packet. The script looked tidy. The calendar hold was already sent. Then I asked a quieter question. What had the participant actually agreed to discuss?
The research lead owned that click. A free-model moderator would run the session. One extra follow-up could leave the consent fence. The only clean reverse sat before the first unscripted probe, not after the transcript landed in a shared drive.
That is the decision I now freeze. Not the insight readout. Not the highlight reel. The moment a model wants one more question.
Why this moment, and not later? Because later is theater. You cannot un-ask a probe. You can only hide it, which is worse. Hidden probes still shape the quotes you trust.
Think of consent as a fence around a yard. The scripted questions live inside. Follow-ups are the dog that sprints the perimeter. If you never mark the fence, the dog decides the yard.
This walkthrough is a from-zero packet. I treat it as a proposed research ops tutorial, not a completed study. I do not present sample chats as findings. I do not invent participant quotes. The artifact is the consent card, the probe ceiling, and a local checker you can run before anyone joins.
Stage 0: Name the owner and the reverse
I start a folder before I touch a model. The first file is not a prompt. It is a decision stub.
mkdir -p study/{consent,probes,runs,handback}
cat > study/consent/decision.yaml << 'EOF'
decision: approve_ai_moderated_interview
owner: research_lead
consequence: off_protocol_probe_enters_evidence
reverse_point: before_first_unscripted_follow_up
status: blocked_until_scope_verified
EOF
Verification is boring on purpose. Does the owner field name a human? Does reverse_point sit before speech, not after coding? If either answer is no, I stop. A model cannot be the owner. A transcript cannot be the reverse.
Who gets hurt if we skip this? The participant, first. Then the study. Then the product claim that will quote a question nobody agreed to hear.
Stage 1: Write the consent scope as fields, not vibes
I refuse paragraphs of “we may ask related topics.” Related to what? Related is how a model wanders. I write fields a checker can fail.
cat > study/consent/scope.yaml << 'EOF'
study_id: checkout-recovery-2026-09
consent_topics:
- recovering a failed payment
- what the error message meant
- whether they tried again the same day
out_of_scope:
- household income
- other household members
- medical or disability detail
- employer names
max_followups_per_topic: 1
recording: audio_only
identifiable_quotes: prohibited_until_redaction_review
participant_can_stop: say_stop_or_leave_call
hand_back_to: human_moderator
EOF
Verification is a field count, not a vibe check.
python3 - << 'PY'
import yaml
from pathlib import Path
scope = yaml.safe_load(Path("study/consent/scope.yaml").read_text())
required = ["consent_topics","out_of_scope","max_followups_per_topic","hand_back_to"]
missing = [k for k in required if not scope.get(k)]
assert not missing, missing
assert scope["max_followups_per_topic"] == 1
assert scope["hand_back_to"] != "model"
print("scope_ok")
PY
If that print never appears, there is no session. Would a longer policy PDF help here? Usually it only adds noise. The missing evidence is the topic list the participant saw, not a legal novel.
Stage 2: Separate evidence from design hypotheses
I keep two files on purpose. Mixing them is how a probe becomes a leading question.
cat > study/consent/evidence.yaml << 'EOF'
evidence:
- field: last_shown_error_copy
status: unknown_until_session
- field: participant_restated_consent_topics
status: unknown_until_session
hypotheses:
- users blame themselves for gateway timeouts
- retry copy feels like a threat
rule: hypotheses_may_not_become_probes
EOF
The hypothesis file is a warning label. It is not a question bank. If a designer wants to “just check” self-blame, that check waits for a human moderator after hand-back. Why? Because a free model will turn a hypothesis into a why-did-you question. That why is not on the fence.
Verification asks one rude question. Can I grep a hypothesis noun in the probe file? If yes, I delete the probe. I do not soften it. Softening is how leading questions survive review.
Stage 3: Cap the probes before the model sees the packet
I write every allowed follow-up in advance. Improvisation is the product risk, not the feature. The model may reorder silence. It may not invent a third question.
cat > study/probes/allowed.yaml << 'EOF'
scripted:
- What did you think the payment error was asking you to do?
- Did you try again that same day?
followups_allowed:
- Can you say that last part in your own words?
forbidden_stems:
- why did you
- how much
- does anyone else
- are you disabled
- where do you work
EOF
Here is the original checker. It is small. That is the point. A research gate should fail closed without a dashboard.
cat > study/probes/check_probes.py << 'EOF'
from pathlib import Path
import re, sys, yaml
scope = yaml.safe_load(Path("study/consent/scope.yaml").read_text())
probes = yaml.safe_load(Path("study/probes/allowed.yaml").read_text())
hyp = yaml.safe_load(Path("study/consent/evidence.yaml").read_text())
errors = []
if len(probes.get("followups_allowed", [])) > scope["max_followups_per_topic"]:
errors.append("followup_ceiling_exceeded")
blob = " ".join(probes.get("scripted", []) + probes.get("followups_allowed", [])).lower()
for stem in probes.get("forbidden_stems", []):
if stem.lower() in blob:
errors.append(f"forbidden_stem:{stem}")
for item in hyp.get("hypotheses", []):
key = re.sub(r"[^a-z]+", " ", item.lower())
for token in key.split():
if len(token) > 5 and token in blob:
errors.append(f"hypothesis_leaked:{token}")
break
if errors:
print("FAIL")
print("\n".join(errors))
sys.exit(1)
print("probes_ok")
EOF
python3 study/probes/check_probes.py
If this exits nonzero, the packet is not shy. It is invalid. Do we need model-quality scores before this gate? No. Scores would only add noise. The missing evidence is still the fence.
Stage 4: Dry-run on a free lane, never on a person
I needed a staging lane that was not a live participant. Disclosure: This article was prepared as part of MonkeyCode's product outreach. I used MonkeyCode's free model access and free server option as that staging lane for the moderator packet. I still ran the local checker first. A free lane does not bless a leaky probe.
The dry-run rule is simple. The model sees scope.yaml and allowed.yaml only. It never sees hypotheses. It never sees real names. The output is a rehearsal transcript, labeled rehearsal.
cat > study/runs/dry_run_prompt.txt << 'EOF'
You are a research moderator in rehearsal, not a live session.
Ask only scripted questions from allowed.yaml.
You may use at most one follow-up from followups_allowed.
If the user mentions an out_of_scope topic, say:
"I will hand this back to a human moderator."
Then stop.
Do not invent questions.
Do not treat this chat as evidence.
EOF
Verification after the dry run is a grep, not a feeling.
python3 - << 'PY'
from pathlib import Path
text = Path("study/runs/rehearsal.txt").read_text().lower() if Path("study/runs/rehearsal.txt").exists() else ""
flags = []
for stem in ["why did you", "how much", "where do you work"]:
if stem in text:
flags.append(stem)
print("dry_run_flags:", flags or "none")
assert not flags, flags
PY
No rehearsal file yet? Then there is nothing to approve. An empty dry run is a stop, not a pass. Would a longer chat log make me safer? Only if I am hunting stems. Extra witty turns are noise.
Stage 5: Accessibility review of the consent moment
The fence fails if the participant cannot perceive it. I review the consent screen as a pattern, not as a component library. Can a screen-reader user hear the topic list as a list of topics, not a blob? Can they get the stop phrase before the call starts? Is the language short enough to reread without a timer?
I keep a review card next to the YAML.
CONSENT PATTERN REVIEW
Decision owner: research_lead
What the participant must hear: the three consent_topics
Stop control: say stop or leave the call, equally valid
Time pressure: none; start is participant-started
Reading load: topics as separate items, not one paragraph
Audio alternative: same topics spoken, then confirmed
Failure: if they cannot restate one topic, do not start the model
Verification is a restatement test. In rehearsal I ask a colleague to say the topics back. If they invent a fourth topic, the copy failed. If they miss an out-of-scope warning, the copy failed. I do not “clarify live” with the model. Clarifying live is a new probe.
What if the consent copy is beautiful and still silent on recording? Then it is not consent. Beauty is noise. The missing evidence is whether recording was named.
Stage 6: Hand-back and recovery before any quote is coded
When a probe hits the fence, the session is not “mostly fine.” The turn is contaminated. I write the hand-back packet before the call, because mid-call invention is how teams keep going.
cat > study/handback/card.yaml << 'EOF'
trigger:
- out_of_scope_topic_mentioned
- model_asks_unlisted_question
- participant_says_stop
- participant_cannot_restate_consent
action:
- stop_model_speech
- mark_turn_contaminated
- do_not_code_quote
- human_moderator_joins_or_ends
record_kept:
- the unasked follow-up that was refused
- the reason for refusal
reverse: discard_contaminated_turn_not_the_whole_day_by_default
EOF
I keep refused follow-ups in the record. Why keep a question nobody asked? Because the discarded probe shows the fence worked. If we only store answers, the log pretends the model never reached. That pretence is how later readers think the protocol was looser than it was.
Verification is a file, not a standup story.
test -s study/handback/card.yaml && echo handback_ok
What should stop approval, and what is noise
Missing evidence that must stop me: no named human owner, no topic list the participant will hear, no probe ceiling, no forbidden stems, no restatement check, no hand-back owner, no dry-run grep. Extra information that only adds noise: model brand chat, elo scores, a second color pass on the consent button, a longer empathy paragraph in the script, a promise that the model is “careful.”
Careful is not a control. A ceiling is a control.
This method will not fit every team. Do not use it for clinical, legal, or investigative interviews that need a licensed human from the first word. Do not use it if you cannot name a research lead who will discard a turn. Do not use a free-model rehearsal as if it were a participant. Do not ship product copy from a dry run. The free lane is a fence rehearsal. It is not a person.
I still catch myself wanting one clever follow-up. That urge is the tell. The model is outgrowing the test when the test is “did the interview happen.” The test I want is narrower. Did every spoken probe stay inside the consent the participant could restate?
If you also stage packets before a live hour, a free server lane can hold the rehearsal files. The consent card remains the product. The model remains the dog at the fence.
Top comments (0)