Skip to content

docs: 013 phase 3 — handling poison messages - #154

Merged
iancooper merged 1 commit into
masterfrom
docs/013-phase3-poison-messages
Sep 9, 2026
Merged

docs: 013 phase 3 — handling poison messages#154
iancooper merged 1 commit into
masterfrom
docs/013-phase3-poison-messages

Conversation

@iancooper

Copy link
Copy Markdown
Member

Spec 013 phase 3 (P0-3): one new nested page, contents/HandlingPoisonMessages.md, 294 lines against a ~300 target.

Per design §2.2 this page repairs nothing — 012's phase 10 had already fixed HandlerFailure.md's nack table at 05ab80c. The guide's contribution is the route: the order to do things in, and the two decisions that are easy to get wrong. Both existing tables are linked by anchor, never copied (requirements §8), so there is one copy of each to keep right.

Gates — all on prediction

Gate Before After
linkcheck 161 162
pagelint 159 pages, 772 warnings 160 pages, 0 errors, 772
--check-shape 158, widest 12 of 20 159, widest unmoved
--check-redirects 77 / 7858 unmoved
versioncheck 18 pins / 5 pages unmoved
optioncheck 59 tables / 519 rows unmoved

URL is using-an-external-bus/handlerfailure/handlingpoisonmessages — task 3.7's prediction character for character. --changed read 1 documentation page(s), 8 code block(s) strict, so the strict pass covers the whole page rather than passing vacuously.

All six C# blocks were extracted from the page and compiled against the released 10.7.0 packages rather than ProjectReferences into src/ — phase 2's finding F is why.

Four findings the task list did not predict

A. Subscription<T>'s Proactor default does not survive contact with a transport — and it decides which backstop attribute compiles. Task 3.3 said the async attribute is what the default reader needs. Measured across all eleven generic subscriptions at 10.7.0: seven default Proactor, two default Reactor (KafkaSubscription, RmqSubscription in RMQ.Sync), three default Unknown. On Kafka the default reader gets a Reactor and needs the sync attribute. Getting it wrong is a ConfigurationException at pipeline build. RmqSubscription is two types with one name, and the package you referenced picks the default.

B. Unknown is not a third pump — the base constructor rejects it. Subscription.cs:213 throws, so new PostgresSubscription<T>(…) without naming a pump throws at construction. Phase 2's page passes one and never says why.

C. Two APIs the design lists as "verified live" are live but not reachable as a guide would print them. DontAckDelay is on MessagePump, and ConsumerFactory copies six subscription properties onto the pump without it — so it stays at its 1-second default and printing it in a subscription initialiser is CS0117. DeadLetterNamingConvention and InvalidMessageNamingConvention have no production call site at 10.7.0 (control: 59 files reference DeadLetterRoutingKey). ErrorHandlingOptions.md already had both right — this constrains the new page rather than indicting the corpus. "Verified live" was checking existence; a guide needs reachability.

D. AwsSqsSubscription does not exist — it is SqsSubscription. I wrote the wrong name into finding A's own table and caught it by grepping every type name with a control.

Deliberately not done

  • ReplayOnSeen.md is linked but not offered as the route — it ships after 10.7.0, so step 7 points a V10 reader at an Inbox or their own idempotency.
  • No optioncheck marker on the pump-default table — it would move a gate design §9 predicts unmoved.

🤖 Generated with Claude Code

https://claude.ai/code/session_0146UueHL6H3zGBGTYwz7GtL

`contents/HandlingPoisonMessages.md`, 294 lines against a ~300 target, nested under
`HandlerFailure.md`. Per design §2.2 this page repairs nothing: 012's phase 10 had already
fixed the nack table at `05ab80c`. Its contribution is the route, which was on no page —
the two existing pages carry semantics and options and never have the reader do it.

Every gate landed on task 3.7's prediction: link 161 → 162, pagelint 159 → 160 pages with
0 errors, shape 158 → 159 with the widest section unmoved at 12 of 20, redirects unmoved
at 77/7858, versioncheck and optioncheck unmoved. Warnings unmoved at 772 — every block
carries its `using` directives. The URL is
`using-an-external-bus/handlerfailure/handlingpoisonmessages`, character for character.

`--changed` read `1 documentation page(s), 8 code block(s) strict`, so the strict pass
covers the whole page rather than passing vacuously. All six C# blocks were extracted from
the page and compiled against the RELEASED 10.7.0 packages, not `ProjectReference`s into
`src/` — phase 2's finding F is why.

Four findings the task list did not predict, and the first changes what the page says:

A. `Subscription<T>` defaults to `Proactor`, but the transports mostly override it.
   Measured across all eleven generic subscriptions at 10.7.0: seven are `Proactor`, two
   are `Reactor` (Kafka, RMQ.Sync), three are `Unknown`. So on Kafka the default reader
   gets a Reactor and needs the SYNC attribute — the opposite of task 3.3's note. Getting
   it wrong is a `ConfigurationException` at pipeline build. `RmqSubscription` is two
   types with one name, and the package you referenced picks the default.

B. `Unknown` is not a third pump: `Subscription.cs:213` throws on it, so
   `new PostgresSubscription<T>(…)` without naming a pump throws at construction. Phase
   2's page passes one and never says why.

C. Two APIs the design lists as "verified live" are live but not reachable as a guide
   would print them — `DontAckDelay` is on `MessagePump` and `ConsumerFactory` does not
   copy it, and the two naming-convention types have no production call site at all
   (control: 59 files reference `DeadLetterRoutingKey`). `ErrorHandlingOptions.md` already
   had both right, so this constrains the new page rather than indicting the corpus.
   Verified live was checking existence; a guide needs reachability.

D. `AwsSqsSubscription` does not exist — it is `SqsSubscription`. I wrote the wrong name
   into finding A's own table and caught it by grepping every type name with a control.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0146UueHL6H3zGBGTYwz7GtL
@iancooper
iancooper merged commit 31e565f into master Sep 9, 2026
8 checks passed
@iancooper
iancooper deleted the docs/013-phase3-poison-messages branch September 9, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant