Selaa lähdekoodia

docs(agents): prompt-card threading note and a research-notes section

The prompt-card entry records the two behavioural promises (cards thread
via _resolve_outbound_thread, emoji matching normalizes both comparison
sides) and the constant-set rule that stops a fourth hand-copied emoji
list from rejecting valid reactions again.

The research-notes section is the general lesson from this bug's
diagnosis: the session-key fact lived in Hermes, the codepoint facts
lived nowhere, and the report's plausible reading (clarify prompt) was
the wrong prompt. A diff carries none of that, so a diagnosis that took
real digging gets its findings recorded here.
Paul Klumpp 6 päivää sitten
vanhempi
commit
40162cb8e8
1 muutettua tiedostoa jossa 56 lisäystä ja 0 poistoa
  1. 56 0
      AGENTS.md

+ 56 - 0
AGENTS.md

@@ -350,6 +350,26 @@ changes must keep them, or consciously renegotiate the docs.**
 - **Processing reactions.** 👀 while working, then ✅, ❌, or 🚫 (cancelled) —
   driven by `on_processing_start`/`on_processing_complete` and the `reactions`
   setting, never applied to the bot's own events.
+- **Interactive prompt cards thread into their conversation, and their emoji
+  match by normalized key.** `send_clarify` and `_send_exec_approval_prompt`
+  resolve the thread through the same `_resolve_outbound_thread` call as
+  `send()` — an answer to a card is routed by session key, and that key
+  includes the thread ID, so a card at the room root is answered into a
+  session nobody is waiting in (the "Question-Loop" bug: the card worked, the
+  answer never arrived). Emoji matching compares `_normalize_reaction_emoji`
+  of the incoming reaction against keys the card builders also store
+  normalized: it strips variation selectors (U+FE0E/U+FE0F) and folds
+  check-mark variants (✔, ✔️, ☑️, ✓) onto ✅, because the card seeds ✅
+  (U+2705) while clients send whatever the emoji picker offers and may add or
+  strip a selector in transit. Keycap digits (1️⃣…9️⃣) keep their combining
+  keycap (U+20E3) — only the VS16 goes. Display forms (card text, seeded
+  reactions, the reply emoji in `_forward_reaction`) stay raw; only
+  *comparison* keys are normalized, on both sides at once. The prompt emoji
+  sets live once as module constants (`_PROMPT_NUMBER_EMOJIS`,
+  `_PROMPT_OTHER_EMOJI`, `_PROMPT_APPROVAL_EMOJIS` and their derived
+  normalized key lists) — a fourth hand-copied list is the bug waiting to
+  happen, since a list that forgets normalization rejects valid reactions
+  again.
 - **Reconnects resume, restarts resume inside a window.** The realtime loop hands
   `stream_events` the cursor of the last event it finished handling, and advances
   it only after the handler returns: a raising handler leaves the old cursor so
@@ -870,3 +890,39 @@ Why this earns a rule of its own: the script deletes things (`rm -rf
 "$VENDOR_DIR"`, the build-dir trap), so a quoting or word-splitting bug is
 destructive rather than merely wrong output — and both are exactly the
 mistakes review tends to skim past.
+
+## Research notes
+
+**A bug whose diagnosis took real digging gets its findings written down here,
+in its own kind of note — not just the fix in code.**
+
+Most bugs in this repo are legible from the diff: the test that fails names the
+behavior, the fix names the cause. The ones worth recording are the other kind —
+where the expensive part was *finding out how the system actually works*, and
+the fix alone does not carry that knowledge:
+
+- **The knowledge lives across repo boundaries.** The emoji bug needed three
+  sources read together to diagnose: the adapter's own matching code, the
+  Hermes gateway code that keys answers to sessions (`build_session_key`
+  includes the thread ID — a fact visible only in Hermes, not here), and the
+  Unicode facts themselves (✔️ U+2714 vs ✅ U+2705 are different codepoints;
+  variation selectors U+FE0E/U+FE0F are added or stripped by clients in
+  transit; keycap sequences keep their combining U+20E3). None of these is
+  discoverable from this repo alone.
+- **The wrong fix looks right.** Normalizing only the incoming emoji, or
+  normalizing on only one of the two comparison sides, fixes the reported
+  ✔️ case and silently breaks others (1️⃣ losing its keycap, a stored key
+  still carrying its selector). What made the fix correct was deriving both
+  sides from one function — a decision a diff does not explain.
+- **The diagnosis inverted a plausible reading of the report.** The
+  "reactions to questions are broken" report read as a clarify-prompt bug,
+  but ✅ is not a clarify option at all — the failing case was the
+  exec-approval card. Writing that down stops the next reader from
+  re-testing the wrong prompt.
+
+So when a diagnosis required that kind of work, add a note here (or extend the
+relevant *Behavioural contract* entry) recording: what the wrong plausible
+reading was, which cross-repo sources had to be read together, and what makes
+the naive fix incorrect. The measure is not thoroughness — it is whether the
+next agent facing a similar report can skip the digging. The first reader of
+such a note is the agent that meets the sibling bug in another code path.