Date. 2026-08-14 · CR. change-requests/cr-2026-211-loomworks-converse-error-truth-v0_1.
State. Built and tested. HALTED before tag and push, per the Checkpoint A instruction. Surface main local commit 8871997 (NOT pushed; no tag), built at 00ed2f2 — exactly the CR's stated baseline, tree clean. Engine untouched (no prerequisite, as scoped). CR-2026-210 holds behind this per the ranking.
converseFailureMessage(err): string in lib/api/converse.ts — one route's vocabulary, two callers, three branches, string-returning. The ruled line is written into its header comment: no code→message table, no route parameter; a third caller is a halt and a ruling, not an import. Caller count at checkpoint: exactly two (useConversation.ts, ChatView.tsx) — the line held; no third caller appeared.ApiError throw), proxy 502/503/504, or the observed dead-upstream shape → "Couldn't reach the Companion." — now true wherever it renders. Any response WITH a body → the server's own usable string detail (FallbackAffordance extraction) or "Something went wrong on our side." — honest ignorance; the constant "Internal Server Error" body is ruled uninformative and takes the generic. Never manufactured unreachability.
The CR anticipated verifying the proxy's engine-down status rather than assuming it, and the probe (dev server pointed at a dead upstream) found the scoping's row-2 assumption wrong: the Next rewrite answers a dead engine with 500 and NO content-type (empty body) — not 502. An engine unhandled 500 arrives as text/plain with the constant body. The two are therefore distinguishable — dead upstream = 500 with detail === undefined; engine bug = a response with a body — and the helper branches on exactly that. The 502/503/504 arm is kept (true if any proxy layer ever emits them). This is the B-96 arc's second correction-by-observation (after the 503-no_credential one), recorded here so the pattern is visible: both of this item's stated mechanisms were wrong until observed.
12 new tests across three files, all observed failing before the helper existed (collection-level for the helper units; assertion-level available for the sites). Helper units: all three true branches AND the false branches, including the future-engine-error string detail rendering. Site tests: the hook (real helper via importActual, mocked sendConverse) and ChatView (driven through the real api() with fetch spies carrying the observed wire shapes — the engine's text/plain 500 and a thrown fetch). The guard both ways: the unreachability sentence does NOT render for reached-server failures, and DOES render for a thrown fetch — the true branch is pinned, which is what makes this a confinement rather than a deletion. Suite 792/792; tsc clean.
Mechanism: a kill-able local relay (127.0.0.1:8998 → engine :8000) with a dev server pointed through it — so the engine could "go down" under a live page without touching production. Sequence, observed:
cr-2026-211-eyetest-true-branch.png. (Incidentally observed: the Memory room's own fetch failed honestly alongside — "Couldn't load this room." — and the page rendered newest-first with the composer at top, CR-2026-208's default doing its job on the no-preference account.)no_credential example was wrong; the route composes a 200 around key absence; the class survived on the corrected members (the 500-bug and the 422-surface-bug) — and the ranking was re-justified on the corrected facts rather than carried on the original claim. That is the difference between a correction and a patch.Kind C as expected: surface error-rendering only; nothing reads or writes the seed. Null finding recorded as an entry.
Tag; push 8871997; watch the run; redeploy; post-deploy smoke on the conversation surface.
DUNIN7 — Done In Seven LLC — Miami, Florida — CR-2026-211 Checkpoint A — v0.1 — 2026-08-14 The sentence keeps its true branches and loses its false ones — observed live, in the one state where it is earned.