From 8d5d154c28c21e1aea7912522dff82ad0bcef090 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 3 Sep 2026 03:20:20 +0200 Subject: [PATCH] =?UTF-8?q?chore(memory):=20LRN-149=20=E2=80=94=20backgrou?= =?UTF-8?q?nd=5Ftasks=20gates=20the=20turn-end=20signal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/memory/journal.md | 1 + .claude/memory/learnings.md | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index 104acdf..e7b64d3 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -459,3 +459,4 @@ rules: - BDR-087 + LRN-146 + BLK-020 capitalized. Branch feature/notify-stop-event, merged to develop (f90ee74). - Post-merge regression: toast dead again after re-attach from a RESTORED terminal, bell fine. Root cause [[LRN-147]]: ext hooks only terminals born after its activation; `enablePersistentSessions` restores terminals before it. Fix = disable persistent sessions, or fresh terminal + `dtach -a`. Verified: 3/3 toasts on fresh pty. - Same-day counter-example broke that cause: second session's terminal deaf though created LATER, same window, ext global, shells identical. Trigger unknown; [[LRN-148]] adds the 5s pre-flight test + demotes LRN-147's mechanism claim. +- Attention signal refined: per-event labels (BDR-087 follow-on), silence on non-attention events, and no turn-end signal while `background_tasks` non-empty ([[LRN-149]]). Payload dump beat the docs: `background_tasks` undocumented for Stop but present on the wire. Branch bugfix/notify-subagent-spawn. diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index 102b0dc..dcf98b2 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -1414,3 +1414,10 @@ Rule: when editing a doctrine file under structure locks, grep the test's lock s - **Recovery**: deaf terminal never repairs. Open fresh terminal, pre-flight it, `dtach -a ~/.dtach/`. dtach broadcasts, so old client may stay attached; session never at risk. - **Diagnostic split (holds)**: bell alive + toast dead = terminal instrumentation. Toast alive + bell dead = client audio ([[BLK-020]]). Neither = bytes never arrive. - **Future**: do NOT assert the born-before-activation cause as established — it fits the first incident, not the second. Unknown trigger is the honest state. + +## LRN-149 — Stop hook payload carries background_tasks; use it to skip premature signals +- **Context**: 2026-09-03. User: "notif à la création d'un sous-agent alors qu'il faudrait pas". Instrumented hook, ran probe subagents: NEITHER subagent creation NOR completion calls the hook. Only event = `Stop`, fired when the turn ends right after spawning. Signal was real but LIED ("Finished responding" while work continued). +- **Pattern**: dump the real payload (`printf '%s' "$payload" >> file.jsonl`) instead of trusting docs — docs list Stop fields without `background_tasks`, the wire has it: `[{"id","type":"subagent","status":"running","description","agent_type"}]`. Rule: on Stop, `(.background_tasks // []) | length` > 0 → exit 0 silent. Next turn end signals for real. Interaction events (permission/question) always signal, background or not. +- **Fail-open**: field absent (older client) → still signal. Missed notification worse than extra one. +- **Cross-session gotcha**: hook is user-scope, so EVERY session runs it. A single-file dump (`> file`) gets overwritten by another project's session — append JSONL and filter on `.cwd`. That accident proved `permission_prompt` fires with `message="Claude needs your permission"` (unexercisable in this session under `defaultMode: auto`). +- **Future**: any hook needing turn-completion semantics must check background_tasks; "turn ended" ≠ "work done". Verified live: Stop with 0 tasks signals, Stop with 1 running subagent silent.