diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 9853303d..84145a64 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -112 sections. Search this before re-deriving anything. +113 sections. Search this before re-deriving anything. * [P0 — the exporter, 2026-08-28](#p0--the-exporter-2026-08-28) * [P1 — Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28) @@ -123,6 +123,7 @@ dies, which is what this file is for. * [The `title` disagreement, localised — and the question I filed for it was the wrong one](#the-title-disagreement-localised--and-the-question-i-filed-for-it-was-the-wrong-one) * [Auditing `BLOCKED.md` found three stale rows, and the undated ones were all three](#auditing-blockedmd-found-three-stale-rows-and-the-undated-ones-were-all-three) * [The record already answered last iteration's question, under headings that name it](#the-record-already-answered-last-iterations-question-under-headings-that-name-it) +* [🔴 Twenty-one messages to a dead address, each one warning me it was dead](#twenty-one-messages-to-a-dead-address-each-one-warning-me-it-was-dead) ## P0 — the exporter, 2026-08-28 @@ -6674,3 +6675,50 @@ half-hour: documented, unexercised."* This one is **correct, documented, unfindable** — and it is worse, because it does not merely fail to catch an error, it manufactures work and then exports a wrong status to somebody else. + +## 🔴 Twenty-one messages to a dead address, each one warning me it was dead + +Every `SendMessage` I sent the Decoder from 2026-08-29 onward came back with: + +> *accepted by the server for that session, but **delivery is not confirmed**: it +> has not reported that it can receive cross-session messages* + +**Twenty-one times.** I recorded it in my reply every time — *"⚠️ delivery +unconfirmed; everything is in the repo regardless"* — and treated writing it down +as having dealt with it. It was not a caveat. It was the tool telling me the +address was dead, in the same words, on every attempt. + +### The cause + +I addressed `bridge:session_01QsEPXW…`, copied from the `from=` of an inbound +message. That is a **session ID**, and it died when the Decoder restarted. +`PROTOCOL.md` says plainly that both agents *"register under those names at +startup"* and shows `SendMessage(to: "sylpheed-agent", …)`. **Names survive a +restart; session IDs do not.** The protocol had the answer; replying to the +`from=` field felt more precise and was strictly worse. + +### Why this one is the worst of the thirteen + +The other twelve were things nobody was looking at. This one **had an alarm, and +the alarm fired every single time**. I did not miss it — I read it, wrote it into +my own status line, and carried on. Reporting a warning is not acting on it, and +phrasing it as a footnote to the user made it look handled. + +⚠️ It also silently inverted a habit I had been congratulating myself on. I kept +saying *"everything is in the repo regardless, which is the point of the rule"* — +true, and it let me treat a broken channel as a non-event for a fortnight. The +repo did carry the findings. What it could not carry were the **asks**: four +questions sat unasked while I believed they were queued, including one that can +delete an authored entry. + +### What changed + +Re-addressed by name after `ListAgents`, and the send came back **without** the +warning — which is what a working channel looks like, and what twenty-one +unworking ones did not. + +📌 The general form: **an unacknowledged warning is worse than a missing one**, +because it converts into evidence that the situation is understood. The fix is not +"read the warnings" — I read them all. It is that a warning repeating unchanged +across attempts is a *state*, not a footnote, and the second identical one should +have been treated as a failure rather than a fact about the world.