From 9375a247e565aa137909ccc4d0243f2e1e90b816 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:49:45 -0700 Subject: [PATCH 1/6] =?UTF-8?q?docs(ax):=20entry=2044=20=E2=80=94=20the=20?= =?UTF-8?q?instrument=20that=20counts=20sentinels=20misses=20the=20worst?= =?UTF-8?q?=20sentinels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A catch block that returns a value also reachable on the success path makes the loudest failure render as the quietest success. Two confirmed defects (#1275 readLongTerm, #1287 findLiveIntegration). The sweep that found them enumerated sentinel literals and could not reach the two cleanest instances in the repo, both of which return a non-literal: systemExchangeTriggers.ts:354 collapses three conditions into 'default', and discordService.ts:501 returns 'error', a member of the IntegrationStatus enum. Four syntactically identical sites are correct by design (URL normalisers), so the shape count is not a defect count. --- docs/development/agent-experience-audit.md | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 761de5390..c74442b97 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2769,3 +2769,65 @@ declared missing; verifying it myself rather than accepting it is what turned "the comments API is incomplete" into the `commit_id` asymmetry, and sweeping the other seven PRs is what found `#1330`, where both APIs are silent and the gate is real anyway. +## 44. The instrument that counts sentinels misses the worst sentinels (2026-08-26, pod-architect + sprint-review) + +**Surface:** `catch { return }` across `backend/`, and the two +confirmed defects it has already produced — `readLongTerm` returning `''` on a +transport failure (#1275) and `findLiveIntegration` returning `null` when the +Integration lookup throws (#1287 item 2). + +**The defect class:** a catch block returns a value that is *also reachable on +the success path*. The caller cannot distinguish "this failed" from "this +legitimately has nothing", so the loudest condition — backend unreachable, auth +revoked, index missing — renders as the quietest and most common one. In #1275 +the guard `err?.status && err.status !== 404` skipped the error branch exactly +when `err.status` was undefined, which is precisely the transport-failure case. + +**What we got wrong, and it is the reason this entry exists.** We swept for the +shape by enumerating sentinel *literals*. Two rounds of widening the literal set +(`false`, `null`, `''`, `[]`, `{}`, then `0` and `""`) produced a confident +inventory: 21 sites at `994a963f`, bare 15 / bound 6. `0` and `""` contributed +zero sites; only `{}` ever moved the count. + +Re-running the census *without* the literal filter found 16 further sites +returning a non-literal from a catch body — and the two cleanest instances of +the class in the repo are both there, invisible to every version of the +literal grep: + +``` +services/systemExchangeTriggers.ts:354 catch { return 'default' } + success path: return inst?.instanceId || 'default' +``` +Three conditions collapse to one string: the query threw, no active +installation exists, and `instanceId` is literally `'default'`. + +``` +services/discordService.ts:501 catch { return 'error' } + success path: return integration.status || 'unknown' +``` +`'error'` is a member of the `IntegrationStatus` enum +(`models/Integration.ts:118`). "The status lookup threw" and "the integration is +in an error state" return the same value. + +**And the reciprocal, which is why the count is not a defect count.** Four sites +have identical syntax and are correct by design — `avatarService.ts:47`, +`agentMessageService.ts:474`, `skillsCatalogService.ts:134`, `pods.ts:180` are +all "normalise this URL; keep the original if it will not parse". There, the +sentinel being reachable on the success path *is the specification*. + +**Rules earned:** +- The discriminator is never the literal. It is whether the returned value is + reachable on the success path *without being the documented fallback*. That is + checkable per site and it is the only thing that separates a defect from a + normaliser. +- A shape count is the number that gets quoted, and it is not a defect count. + Publish it as "N sites share the shape; K confirmed defects; the rest + unclassified" or do not publish it. +- Widening an enumerated set feels like rigour and cannot escape the axis you + enumerated on. Two rounds of adding literals never reached a non-literal. When + a sweep is defined by a value set, run one census with the value filter removed + and classify by hand — that is the only pass that can tell you the axis was + wrong. +- `@typescript-eslint/no-floating-promises` has no analogue here: there is no + rule that can see this, because the defect is a relation between two return + sites, not a property of either. From 92fbb74199f4bc9138b9cf9edf3844f59d072f4f Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:10:37 -0700 Subject: [PATCH 2/6] =?UTF-8?q?docs(ax):=20entry=2044=20=E2=80=94=20lead?= =?UTF-8?q?=20with=20detect.ts,=20and=20the=20count=20fails=20in=20both=20?= =?UTF-8?q?directions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sprint-review's review found the specimen that shows the class without a call-site read: registry/detect.ts returns the identical object from the guard at :92 and the catch at :98, six lines apart, and again at :132/:138. Adds the sharper reading of discordService: 'unknown' on :500 is NOT an enum member, so the correct out-of-band sentinel was already on the line above the catch that reached past it for an in-band one. Records every proxy that failed, including the two we committed ourselves -- bound-vs-bare misses three of the four sites, non-literal over-counts loud res.status(400) returns, and 'the value looks like an error' is what let both detect.ts sites through the first hand pass. --- docs/development/agent-experience-audit.md | 99 ++++++++++++++-------- 1 file changed, 65 insertions(+), 34 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index c74442b97..1e25ff5e9 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2783,51 +2783,82 @@ revoked, index missing — renders as the quietest and most common one. In #1275 the guard `err?.status && err.status !== 404` skipped the error branch exactly when `err.status` was undefined, which is precisely the transport-failure case. -**What we got wrong, and it is the reason this entry exists.** We swept for the -shape by enumerating sentinel *literals*. Two rounds of widening the literal set -(`false`, `null`, `''`, `[]`, `{}`, then `0` and `""`) produced a confident -inventory: 21 sites at `994a963f`, bare 15 / bound 6. `0` and `""` contributed -zero sites; only `{}` ever moved the count. - -Re-running the census *without* the literal filter found 16 further sites -returning a non-literal from a catch body — and the two cleanest instances of -the class in the repo are both there, invisible to every version of the -literal grep: +**The specimen, because it needs no call-site read to see.** +`backend/routes/registry/detect.ts`, twice in one file: ``` -services/systemExchangeTriggers.ts:354 catch { return 'default' } - success path: return inst?.instanceId || 'default' +:92 if (!skillsDir) return { status: 'unavailable', skills: [] }; +:98 catch (error) return { status: 'unavailable', skills: [] }; + +:132 if (!dockerfilePath) return { status: 'unavailable', aptPackages: [], pythonPackages: [] }; +:138 catch (error) return { status: 'unavailable', aptPackages: [], pythonPackages: [] }; ``` -Three conditions collapse to one string: the query threw, no active -installation exists, and `instanceId` is literally `'default'`. + +Identical expression, six lines apart, guard and catch. "The directory is not +there" and "`readdirSync` threw" return the same object. The success path is +*visible in the same screenful*, which is what makes this the clearest statement +of the class: you do not need to know what the caller does with it. + +**A second instance where the correct value was already on the line above.** +`backend/services/discordService.ts`: ``` -services/discordService.ts:501 catch { return 'error' } - success path: return integration.status || 'unknown' +:500 return (this.integration as IntegrationDoc).status || 'unknown'; +:502 catch (error) { return 'error'; } ``` + `'error'` is a member of the `IntegrationStatus` enum -(`models/Integration.ts:118`). "The status lookup threw" and "the integration is -in an error state" return the same value. +(`backend/models/Integration.ts:118`). `'unknown'` is not. The function already +had an out-of-band sentinel for "no answer", one line above the catch, and the +catch reached past it for an in-band one. + +**A third, collapsing three conditions into one string.** +`backend/services/systemExchangeTriggers.ts`: + +``` +:353 return inst?.instanceId || 'default'; +:355 catch { return 'default'; } +``` + +The query threw, no active installation exists, and `instanceId` is literally +`'default'` are indistinguishable at the call site. + +**And the reciprocal, which is why a shape count is not a defect count.** Four +sites have identical syntax and are correct by design — +`services/avatarService.ts:47`, `services/agentMessageService.ts:474`, +`services/skillsCatalogService.ts:134`, `routes/pods.ts:180` are all "normalise +this URL; keep the original if it will not parse". There, the sentinel being +reachable on the success path *is the specification*. + +**How we found the class, and every proxy that failed on the way.** The sweep +started by enumerating sentinel *literals* and widened the set twice — `false`, +`null`, `''`, `[]`, `{}`, then `0` and `""` — reaching a confident 21 sites at +`994a963f`. `0` and `""` contributed nothing; only `{}` ever moved the count. -**And the reciprocal, which is why the count is not a defect count.** Four sites -have identical syntax and are correct by design — `avatarService.ts:47`, -`agentMessageService.ts:474`, `skillsCatalogService.ts:134`, `pods.ts:180` are -all "normalise this URL; keep the original if it will not parse". There, the -sentinel being reachable on the success path *is the specification*. +- **Literal-only** missed every site above: all four return a non-literal. +- **Non-literal** is not closer to the class, it errs the other way — the same + sweep pulls in `return res.status(400).json({ error: err.message })` from + several controllers, which is maximally *loud*. +- **Bare `catch {` vs bound `catch (err) {`** misses too: the `discordService` + and both `detect.ts` sites are bound, with the binding unused. +- **"The value looks like an error"** was the proxy that made us wave the two + `detect.ts` sites through on the first pass. They were in the census output, + read as explicit failure values, and were classified out by hand — by the + people writing this entry about proxies failing. **Rules earned:** -- The discriminator is never the literal. It is whether the returned value is - reachable on the success path *without being the documented fallback*. That is - checkable per site and it is the only thing that separates a defect from a - normaliser. +- The discriminator is never a property of the returned value. It is a relation: + is this value *also* reachable on the success path, without being the + documented fallback? That is checkable per site and nothing else separates a + defect from a normaliser. - A shape count is the number that gets quoted, and it is not a defect count. Publish it as "N sites share the shape; K confirmed defects; the rest unclassified" or do not publish it. - Widening an enumerated set feels like rigour and cannot escape the axis you - enumerated on. Two rounds of adding literals never reached a non-literal. When - a sweep is defined by a value set, run one census with the value filter removed - and classify by hand — that is the only pass that can tell you the axis was - wrong. -- `@typescript-eslint/no-floating-promises` has no analogue here: there is no - rule that can see this, because the defect is a relation between two return - sites, not a property of either. + enumerated on. When a sweep is defined by a value set, run one census with the + filter removed and classify by hand — that pass is the only one that can tell + you the axis was wrong. Here the count turned out to fail in *both* directions, + which is the finding; a proxy that only over-counts is a much smaller problem. +- No lint rule can see this. `@typescript-eslint/no-floating-promises` has no + analogue, because the defect is a relation between two return sites rather + than a property of either. From af98062b9a21909be702d52e093f792b63d88f36 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:25:55 -0700 Subject: [PATCH 3/6] =?UTF-8?q?docs(ax):=20entry=2044=20=E2=80=94=20the=20?= =?UTF-8?q?discriminator=20is=20the=20caller,=20and=20read=20it=20normativ?= =?UTF-8?q?ely?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sprint-review's review of f9f2bd70: the specimen tell I leaned on -- guard and catch returning the identical expression in view of each other -- fires harder on avatarService.ts, which is correct by design. Four 'return value' in thirteen lines, one of them the catch. Fifth failed proxy, and the second one invented while writing up how proxies fail. Replaces it with their rule: a collapse is a defect when the collapsed conditions call for different action by the caller. Adds the caveat that rule needs. Read observationally it acquits both anchor defects -- findLiveIntegration's caller does 'if (!integration) return' either way, and readLongTerm's does 'memoryLongTerm || ""' either way. The identical handling is the bug. --- docs/development/agent-experience-audit.md | 64 ++++++++++++++++++---- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 1e25ff5e9..7e72c0c7e 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2823,12 +2823,49 @@ catch reached past it for an in-band one. The query threw, no active installation exists, and `instanceId` is literally `'default'` are indistinguishable at the call site. -**And the reciprocal, which is why a shape count is not a defect count.** Four -sites have identical syntax and are correct by design — -`services/avatarService.ts:47`, `services/agentMessageService.ts:474`, -`services/skillsCatalogService.ts:134`, `routes/pods.ts:180` are all "normalise -this URL; keep the original if it will not parse". There, the sentinel being -reachable on the success path *is the specification*. +**And the reciprocal — which fires the same tell harder, and is correct.** +`backend/services/avatarService.ts` normalises an avatar reference: + +``` +:37 if (LEGACY_COLOR_AVATARS.has(value)) return value; +:38 if (/^data:/i.test(value) || value.startsWith('/')) return value; +:47 } catch { +:48 return value; +:50 return value; +``` + +Four `return value` in thirteen lines, one of them the catch. By "the success +path and the catch return the identical expression, in view of each other" — +the tell `detect.ts` seems to teach — this is the most flagrant site in the +repo. It is also exactly right. `services/agentMessageService.ts:474`, +`services/skillsCatalogService.ts:134` and `routes/pods.ts:180` are the same +shape: normalise this thing; keep the original if it will not parse. + +**So the discriminator is not syntactic, not local, and not about the value:** + +> A collapse is a defect when the collapsed conditions call for **different +> action by the caller** — not when they merely have different causes. + +In `avatarService` every path means "use `value`", so the conditions really are +equivalent at the boundary and the collapse *is* the specification. In +`detect.ts`, "there is no Dockerfile" is a configuration state and "`readFileSync` +threw" is a fault; a caller wanting to surface or retry the second cannot tell +it from the first. Same in `getStatus`, which is why the out-of-band `'unknown'` +one line above the catch was the available right answer. + +**Read "call for" normatively, or the rule acquits the two defects that anchor +this entry.** Both callers today do the same thing either way: + +``` +telegramBridgeService.ts:131 const integration = await findLiveIntegration(podId); + if (!integration) return; // no config, or the query threw +readLongTerm (#1275) buildPrompt(prompt, ctx.memoryLongTerm || '') // empty, or the backend was down +``` + +Neither caller branches. That identical handling is the bug, not evidence +against it — the caller *should* distinguish a transient outage from a steady +empty state, and cannot, because the information was destroyed at the catch. Ask +what a caller would need to do, not what this caller does. **How we found the class, and every proxy that failed on the way.** The sweep started by enumerating sentinel *literals* and widened the set twice — `false`, @@ -2847,10 +2884,14 @@ started by enumerating sentinel *literals* and widened the set twice — `false` people writing this entry about proxies failing. **Rules earned:** -- The discriminator is never a property of the returned value. It is a relation: - is this value *also* reachable on the success path, without being the - documented fallback? That is checkable per site and nothing else separates a - defect from a normaliser. +- The discriminator is never a property of the returned value, nor of the two + return sites' syntax. It is the **caller**: do the collapsed conditions call + for different action? Read "call for" normatively — every defect here has a + caller that currently handles both cases identically. +- Five proxies were tried and all five failed, the last two invented during this + write-up: sentinel-literal, non-literal, bare-vs-bound catch, "the value looks + like an error", and "guard and catch return the same expression in view of + each other". A syntactic tell can be necessary; none was sufficient. - A shape count is the number that gets quoted, and it is not a defect count. Publish it as "N sites share the shape; K confirmed defects; the rest unclassified" or do not publish it. @@ -2859,6 +2900,9 @@ started by enumerating sentinel *literals* and widened the set twice — `false` filter removed and classify by hand — that pass is the only one that can tell you the axis was wrong. Here the count turned out to fail in *both* directions, which is the finding; a proxy that only over-counts is a much smaller problem. +- Publish the correct site next to the defect, not the defect alone. Both + `detect.ts` and `avatarService.ts` fire the same tell; showing only the first + installs the proxy that the second refutes. - No lint rule can see this. `@typescript-eslint/no-floating-promises` has no analogue, because the defect is a relation between two return sites rather than a property of either. From a2a34916a6cb6faf6ddfe267d8446db2dd4fe12b Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:39:57 -0700 Subject: [PATCH 4/6] =?UTF-8?q?docs(ax):=20entry=2044=20=E2=80=94=20the=20?= =?UTF-8?q?discriminator=20is=20a=20question=20about=20the=20try,=20not=20?= =?UTF-8?q?the=20caller?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sprint-review: 'call for different action by the caller' fixes the verdict but relocates the work into a judgement about a hypothetical caller -- the same appeal the five proxies were trying to escape. Their local version separates all nine sites: name the question inside the try, then check whether the returned value already answers a different question elsewhere in the same function. Predicate (only a throw can ask) vs fault report. Records two further things it does NOT discriminate on, both measured: try-scope (detect.ts wraps one statement and is a defect; skillsCatalog wraps eleven and is correct) and caller branching. Keeps the JSON.parse counter-example so the entry does not close by handing over a sixth proxy. --- docs/development/agent-experience-audit.md | 72 ++++++++++++++-------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 7e72c0c7e..a60e973b4 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2841,31 +2841,47 @@ repo. It is also exactly right. `services/agentMessageService.ts:474`, `services/skillsCatalogService.ts:134` and `routes/pods.ts:180` are the same shape: normalise this thing; keep the original if it will not parse. -**So the discriminator is not syntactic, not local, and not about the value:** +**So the discriminator is not syntactic, and not about the value. It is a +question about the `try`:** -> A collapse is a defect when the collapsed conditions call for **different -> action by the caller** — not when they merely have different causes. +> Name the question the code inside the `try` is asking. Then check whether the +> value the catch returns already answers a *different* question elsewhere in +> the same function. -In `avatarService` every path means "use `value`", so the conditions really are -equivalent at the boundary and the collapse *is* the specification. In -`detect.ts`, "there is no Dockerfile" is a configuration state and "`readFileSync` -threw" is a fault; a caller wanting to surface or retry the second cannot tell -it from the first. Same in `getStatus`, which is why the out-of-band `'unknown'` -one line above the catch was the available right answer. - -**Read "call for" normatively, or the rule acquits the two defects that anchor -this entry.** Both callers today do the same thing either way: +Where throwing is the only way to ask, the catch is the `else` and the collapse +is the specification. All four correct sites are the same construct — `new +URL(...)` at `avatarService.ts:42`, `agentMessageService.ts:474`, +`skillsCatalogService.ts:125`, `pods.ts:177`. Where the code asked one question +and the catch answers a different one with the same value, it is a defect: ``` -telegramBridgeService.ts:131 const integration = await findLiveIntegration(podId); - if (!integration) return; // no config, or the query threw -readLongTerm (#1275) buildPrompt(prompt, ctx.memoryLongTerm || '') // empty, or the backend was down +detect.ts:96 readdirSync — "is it there?" was already answered at :91 +detect.ts:136 readFileSync — already answered at :131 +discordService.ts:499 initialize() — 'error' is an IntegrationStatus enum member +telegramBridgeService findOne — null already means "no live integration" +systemExchangeTriggers findOne — 'default' is a real instanceId ``` -Neither caller branches. That identical handling is the bug, not evidence -against it — the caller *should* distinguish a transient outage from a steady -empty state, and cannot, because the information was destroyed at the catch. Ask -what a caller would need to do, not what this caller does. +This is why the paired snippets look identical and are not: in `detect.ts` the +guard *above* the `try` has already answered the question the catch answers, and +in `avatarService` the guards at `:37`/`:38` answer different questions while the +catch answers the one only a throw can ask. The difference is one line up, in +both. + +**Not sufficient either, and the entry would be dishonest to close on it.** +`try { JSON.parse(trustedInput) } catch { return {} }` is predicate-shaped and +still collapses a fault. Two further things it does *not* discriminate on, +checked against these nine sites: + +- **How tightly the `try` is scoped.** `detect.ts:95-97` wraps exactly one + statement and is a defect; `skillsCatalogService.ts:124-134` wraps eleven, ten + of which cannot throw, and is correct. Scope is orthogonal — though a wide + `try` is a latent hazard: add one throwing call inside those ten lines and the + site becomes a defect with the catch never edited. (Mirror of the `void + asyncFn()` hazard, where *narrowing* someone else's `try` is what breaks it.) +- **Whether the caller branches.** See above — no caller here does. + +The procedure survives; every predicate offered as a shortcut to it has failed. **How we found the class, and every proxy that failed on the way.** The sweep started by enumerating sentinel *literals* and widened the set twice — `false`, @@ -2884,14 +2900,18 @@ started by enumerating sentinel *literals* and widened the set twice — `false` people writing this entry about proxies failing. **Rules earned:** -- The discriminator is never a property of the returned value, nor of the two - return sites' syntax. It is the **caller**: do the collapsed conditions call - for different action? Read "call for" normatively — every defect here has a - caller that currently handles both cases identically. -- Five proxies were tried and all five failed, the last two invented during this +- The discriminator is a question about the `try`, not about the value, the + syntax, or the caller: name what the code inside it is asking, then check + whether the catch's return value already answers a different question in the + same function. +- Do not close a write-up about failed proxies by handing over a new one. Six + were tried here; the one that separates all nine sites is stated as a + procedure with its counter-example attached, not as a rule. +- Six proxies were tried and all six failed, three of them invented during this write-up: sentinel-literal, non-literal, bare-vs-bound catch, "the value looks - like an error", and "guard and catch return the same expression in view of - each other". A syntactic tell can be necessary; none was sufficient. + like an error", "guard and catch return the same expression in view of each + other", and "the caller branches differently". A syntactic tell can be + necessary; none was sufficient. - A shape count is the number that gets quoted, and it is not a defect count. Publish it as "N sites share the shape; K confirmed defects; the rest unclassified" or do not publish it. From d8dea1f1dbeee15f269383369cd5cdcab7724269 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:39:22 -0700 Subject: [PATCH 5/6] docs(ax): renumber this entry 44 -> 50, ceding 44 to the older #1143 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this one moves. Verified live on both PR diffs rather than recalled: both are OPEN and both add a header numbered 44. Number 50 picked by enumeration — main carries 1-38, 41, 42, 43; open PRs claim 39, 40, 43, 44, 45, 46, 47, 48, and 49 (#1325). Single occurrence in this file; no cross-references to renumber. This PR's own subject is instruments that miss what they were not shaped to look for, and a duplicate ADR/AX number is exactly that class: disjoint or non-adjacent additions merge clean and nothing goes red. main has carried two ADR-018s for 22 days on the same mechanism. --- docs/development/agent-experience-audit.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index a60e973b4..767418b88 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2770,6 +2770,7 @@ declared missing; verifying it myself rather than accepting it is what turned the other seven PRs is what found `#1330`, where both APIs are silent and the gate is real anyway. ## 44. The instrument that counts sentinels misses the worst sentinels (2026-08-26, pod-architect + sprint-review) +## 50. The instrument that counts sentinels misses the worst sentinels (2026-08-26, pod-architect + sprint-review) **Surface:** `catch { return }` across `backend/`, and the two confirmed defects it has already produced — `readLongTerm` returning `''` on a From 74d7e785e1f3171717d161c7b8b2beb1dea1d074 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 29 Aug 2026 18:46:23 -0700 Subject: [PATCH 6/6] docs(ax): drop the stale `## 44.` header the rebase left beside `## 50.` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 44 -> 50 renumber commit replaced one header line; replaying it during the rebase onto current main added the new line beside the old one instead, so the file carried both `## 44.` and `## 50.` on consecutive lines titling one entry. That re-took the number this branch had deliberately ceded to the older #1143, and nothing goes red on a duplicate AX number — which is the collision class this file already documents. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 767418b88..94316be23 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2769,7 +2769,6 @@ declared missing; verifying it myself rather than accepting it is what turned "the comments API is incomplete" into the `commit_id` asymmetry, and sweeping the other seven PRs is what found `#1330`, where both APIs are silent and the gate is real anyway. -## 44. The instrument that counts sentinels misses the worst sentinels (2026-08-26, pod-architect + sprint-review) ## 50. The instrument that counts sentinels misses the worst sentinels (2026-08-26, pod-architect + sprint-review) **Surface:** `catch { return }` across `backend/`, and the two