ADR-0012: Resolution Protocol 0.2 — provisional raises, a smaller core, adoption hooks

Why

Three independent reviews of RP 0.1 (simplification, universality, correctness), and one bug Rafa saw in the meeting simulation. The bug: "back on the record" did not return the room, because 0.1 held raises for 30 s.

The correctness review also found genuine safety bugs:

Decision

The details are in protocol/SPEC.md, Appendix C. In short:

  1. Raises for others are provisional. They take effect at once. Within the objection window, an objection, a room lowering or the session ending undoes them, and restamps everything said since. A second raise restarts the window.
  2. The core is smaller.
    • 6 intents: erase became forget without a span, and claim became an extension.
    • Side conversations are an extension, with per-voice caps that survive merges.
    • Who is speaking moved to the indicator binding.
  3. Grammars are dialect-safe:
    • space-normalised text with no \b, \w or \d;
    • {count} and {unit} placeholders;
    • first match wins;
    • self markers count only inside the match.
  4. Adoption hooks:
    • identity sources (diarised, stream, roster, claimed);
    • intent sources (speech, UI, DTMF, SDP, preference, exchange);
    • transient processing rules;
    • session boundaries from bindings;
    • room_raise: disabled for wearables;
    • a lowerings exchange between recorders (minimum wins, raises never exchanged);
    • standing preferences (raises need authentication);
    • versioning and extension rules;
    • regulated recording as a non-goal.
  5. Honest defaults: a default above 0 is the operator's choice, never consent. Level 0 is recommended for telephony, wearables and all-party-consent places.

Second review round (same day)

A fresh adversarial reviewer confirmed most round-1 fixes. It found eight more ways a lowering or forget could silently fail, all fixed with vectors (SPEC Appendix C, "Round-2 fixes"):

  1. Late-filed speech from an undone window.
  2. Speech filed across a session end.
  3. A late filing moving the clock back.
  4. A raise beating a lowering in one sentence.
  5. Missed forget phrasings.
  6. Standing preferences dropped under a ceiling.
  7. Forget-all leaving ids in the log.
  8. Exchange messages faking side conversations.

It also found that unsure raisers could raise the room, and that a room raise lifted ceilings. Both are fixed.

The core simplification from that review: undoing a raise rewrites the level history, there is one clock entry point, and filings from before the session start are refused.

Evidence

Consequences for Goldfish

# ADR-0012: Resolution Protocol 0.2 — provisional raises, a smaller core, adoption hooks

- **Status:** accepted (2026-10-12)
- **Builds on:** ADR-0010, ADR-0011

## Why

Three independent reviews of RP 0.1 (simplification, universality, correctness), and one bug Rafa saw in the meeting simulation. The bug: "back on the record" did not return the room, because 0.1 held raises for 30 s.

The correctness review also found genuine safety bugs:
- a side-conversation lowering could be lifted silently when groups shifted;
- first-person words elsewhere in a sentence turned room lowerings personal;
- the Python and JavaScript grammars differed on non-ASCII text;
- forgets missed speech filed later;
- segments spanning a level change took the later level.

## Decision

The details are in `protocol/SPEC.md`, Appendix C. In short:

1. **Raises for others are provisional.** They take effect at once. Within the objection window, an objection, a room lowering or the session ending undoes them, and restamps everything said since. A second raise restarts the window.
2. **The core is smaller.**
   - 6 intents: `erase` became `forget` without a span, and `claim` became an extension.
   - Side conversations are an extension, with per-voice caps that survive merges.
   - Who is speaking moved to the indicator binding.
3. **Grammars are dialect-safe:**
   - space-normalised text with no `\b`, `\w` or `\d`;
   - `{count}` and `{unit}` placeholders;
   - first match wins;
   - self markers count only inside the match.
4. **Adoption hooks:**
   - identity sources (diarised, stream, roster, claimed);
   - intent sources (speech, UI, DTMF, SDP, preference, exchange);
   - transient processing rules;
   - session boundaries from bindings;
   - `room_raise: disabled` for wearables;
   - a lowerings exchange between recorders (minimum wins, raises never exchanged);
   - standing preferences (raises need authentication);
   - versioning and extension rules;
   - regulated recording as a non-goal.
5. **Honest defaults:** a default above 0 is the operator's choice, never consent. Level 0 is recommended for telephony, wearables and all-party-consent places.

## Second review round (same day)

A fresh adversarial reviewer confirmed most round-1 fixes. It found eight more ways a lowering or forget could silently fail, all fixed with vectors (SPEC Appendix C, "Round-2 fixes"):
1. Late-filed speech from an undone window.
2. Speech filed across a session end.
3. A late filing moving the clock back.
4. A raise beating a lowering in one sentence.
5. Missed forget phrasings.
6. Standing preferences dropped under a ceiling.
7. Forget-all leaving ids in the log.
8. Exchange messages faking side conversations.

It also found that unsure raisers could raise the room, and that a room raise lifted ceilings. Both are fixed.

The core simplification from that review: undoing a raise rewrites the level history, there is one clock entry point, and filings from before the session start are refused.

## Evidence

- 149 conformance vectors pass in both implementations: 40 en phrases, 18 es phrases, 60 session cases, 19 retention checks, 12 profile checks. Python also runs the grammar lint on both locales.
- A differential fuzz agrees over 2,000 random sessions (45,213 steps), including exchange messages, preferences, UI intents and late filing.
- The Goldfish tests pass.

## Consequences for Goldfish

- The profile now uses `objection_window`, `session_gap`, `room_raise` and `extensions: ["side_conversations"]`.
- Claiming stays off until the device can re-identify voices (B-29).
- "Back on the record" is instant on the device and the site, and objectable for 30 s.