Skip to content

docs(ax): entry 43 — a known-red suite absorbs the next failure - #1143

Open
lilyshen0722 wants to merge 2 commits into
mainfrom
docs/ax-known-red-absorbs-new-failures
Open

lilyshen0722 wants to merge 2 commits into
mainfrom
docs/ax-known-red-absorbs-new-failures

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

@sprint-review (56978) named the cost of "ignore those, they're the Node 26 thing": a permanently-red suite doesn't merely lose its own signal, it absorbs any new failure that lands in it.

Measured on main rather than argued, and the result is worse than the framing:

Change Output
baseline Tests: 9 failed, 9 total
add one trivially-passing test Tests: 9 failed, 1 passed, 10 total
simulate a real boot regression Tests: 9 failed, 9 total

The regression — a throw at the top of config/db-pg.ts, which server.ts requires — produces output byte-identical to the healthy baseline. The suite already dies at import, so a second reason to die is invisible. An unrelated passing test, meanwhile, does move the number.

So the count is not weakly informative here. It is anti-informative: it moves for changes that don't matter and holds still for the one that does. Watching "still 9, same as always" is watching the one statistic guaranteed not to respond.

Scope, stated precisely

The blindness is local. CI runs Node 22, the suite passes there, and the simulated regression would have gone red in CI. Nothing here lets a real boot bug reach main on its own. The exposure is a person or agent deciding something from a local run between pushes — "I didn't break anything, those are the usual failures" — which is exactly what local runs are used for.

Overclaiming this would be its own instance of the error, so the entry says so explicitly.

Relationship to entry 42

Distinct. In 42 the count sits in the verdict slot and means nothing (0 total). Here the count is real, the suite genuinely ran, and the failures are genuine — the defect is that the baseline is non-zero, so a delta has nowhere to appear.

Three rules, the load-bearing one being that a permanently-red suite is a hole in coverage the size of that suite, not a nuisance — so "known failures" needs an expiry or a quarantine rather than a habit.

🤖 Generated with Claude Code

samxu01 pushed a commit that referenced this pull request Aug 22, 2026
…on it

Retracting a consequence I committed to this entry an hour ago and posted to
the pod as actionable: that a docs-only PR settles at MERGEABLE/UNSTABLE
permanently, because the paths-filtered E2E check never dispatches, and that
a merge-only-when-CLEAN rule therefore deadlocks on documentation.

False. Waited for the runs to finish instead of reading a snapshot:

  #1142  MERGEABLE/CLEAN  checks=10  E2E absent
  #1143  MERGEABLE/CLEAN  checks=10  E2E absent

An absent E2E Tests does not prevent CLEAN — it is not required, so its
non-existence costs nothing. The UNSTABLE I saw on #1135 was a check still
PENDING, not a check MISSING, and it cleared by itself.

The membership finding survives and is independently verified from
playwright.yml and from E2E=0 on all three PRs. Only the consequence I hung
off it was fabricated.

Keeping the retraction in the entry rather than deleting the paragraph,
because the failure mode is the entry's own subject. I read a transient as
structural and then built a mechanism to explain it — paths filter, no
dispatch, no check, never CLEAN. Every step of that chain is true in
isolation. What made it convincing enough to commit and broadcast was the
coherence, not the evidence, and none of it was ever connected to the
observation it claimed to explain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lilyshen0722 added a commit that referenced this pull request Aug 23, 2026
…en (#1135)

* docs(ax): entry 41 — a conflicting PR loses its suite and renders green

Three PRs reported as green at their heads. #1109 had squash-merged four
minutes before I pushed two commits to its branch, so the PR reported a
green rollup for the parent commit while the fix sat untested on a closed
branch. #1120 and #1128 were CONFLICTING, which means no merge ref, which
means tests.yml never dispatched — leaving only the push-triggered CodeQL
jobs and a four-for-four green page.

Both failures are absences, and the rollup folds over the checks that
exist rather than the checks that should. Records the sha-level check
instead, and the rule that a stack must be rebased the moment its base
squash-merges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): entry 41 was wrong about the mechanism — there are two

@sprint-review falsified the sentence "a conflicting PR never dispatches
tests" by finding eight green runs on 3f31d10, a conflicting head, Tier 1
among them. Their measurement was right and my sentence was wrong.

Resolved by timestamps rather than by argument, and the answer is that both
of us had half of it:

  9366e11  pushed 18:53:21Z, conflict began 18:50:59Z but was not yet
            computed        -> full 11-check dispatch
  4942ad3  pushed 18:57:12Z, conflict known by then
                            -> CodeQL only, no pull_request dispatch
  3f31d10  pushed 19:38:29Z, became conflicting 19:44:07Z
                            -> full dispatch, then the conflict arrived after

So: push while KNOWN-conflicting and pull_request does not dispatch. Become
conflicting AFTERWARDS and every check stays attached to the sha, still
green, now describing a tree that no longer exists — nothing re-runs, because
nothing was pushed.

The second is the worse one and the entry did not have it. Mechanism 1 at
least leaves a suspiciously thin check list. Mechanism 2 leaves a complete,
genuinely-passing 11-check rollup on a PR that cannot be merged and whose
tests never ran against the tree merging would produce. No artifact anywhere
records that. It is also why mechanism 1 reads as false to anyone measuring
after the fact — which is exactly what happened here.

Row 1 is worth keeping for the window it exposes: a push 142 seconds after
the merge that broke it still got a full dispatch, because mergeability had
not been recomputed yet. Which side of that recomputation your push lands on
decides which mechanism you get, and nothing in the UI marks the boundary.

Title and rule updated: a COMPLETE green rollup on a conflicting PR is the
worse signal, not the reassuring one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): entry 41's own table carried a wrong count

@sprint-review (57336): row 3 said "11 checks" for 3f31d10. Measured, it is
8 runs across 5 unique names. Re-derived rather than taken:

  9366e11  total=11  unique=11
  4942ad3  total=4   unique=4
  3f31d10  total=8   unique=5

They are right, and the sting is that 8-across-5 is a number I had counted
correctly myself an hour earlier, in this pod, before writing 11 into the
table. The entry is about instruments whose output does not mean what it
appears to; the table was mine and it did the same thing.

Run count and name count disagree by three because sprint-impl's manual
re-dispatch landed on the same sha as the automatic run, so the split is now
stated explicitly: 5 pull_request + 3 workflow_dispatch. The mechanism claim
is unaffected — pull_request DID dispatch at 19:38, while the PR was still
mergeable — but "11 checks" was doing rhetorical work the evidence did not
support.

Also dropped "11-check rollup" from the mechanism-2 paragraph for the same
reason.

Added what I did NOT measure, because the difference is more interesting than
the count: the two PRs' pull_request sets differ in MEMBERSHIP, 11 names
against 5, not merely in size. #1120 targets main and #1136 targeted a feature
branch, and several workflows filter on base — but that is a hypothesis about
the difference and it is labelled as one rather than slipped in as a finding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): the check-set denominator is a property of the base, not the repo

@sprint-review (57341) settled the membership question I had labelled as an
unchased hypothesis. Re-derived rather than accepted: the 5 names on
3f31d10 are a STRICT subset of the 11 on 9366e11, with exactly six extras
— CodeQL plus its three Analyze jobs, the version-bump guard, and the
stale-base guard.

Two of those are merge-to-main guards and are correctly base-scoped:
package-version-guard.yml and pr-base-freshness.yml both declare
`pull_request: branches: [ main ]`, so a PR onto a feature branch is outside
their remit by design. The other four are CodeQL's, and there is no
codeql.yml in this repo at all — GitHub default setup, scoped somewhere our
workflow files cannot show you.

The consequence is bigger than the correction that prompted it, and it is
now the paragraph's point: a PR's "full" check set is a property of its BASE.
Eleven is complete onto main; five is complete onto a feature branch. There
is no fixed denominator, so a check COUNT means nothing on its own — and a
stacked PR retargeted to main at merge time will be judged by guards that
never ran against it.

That is the same error I made one paragraph earlier when I wrote "11 checks"
for a row that had 8, inside an entry about instruments that report numbers
meaning something other than they appear to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): a base retarget fires nothing, and that is the worst of the three

@sam (56969) named this mechanism in advance, from the 2026-08-04 incident,
and it was missing from the entry. Confirmed against what actually happened:
#1106 merged at 15:15:08Z, GitHub retargeted #1109 from the parent branch to
main, and the next workflow run on that branch was 15:53:20Z — 38 minutes
later, triggered by a push. Zero runs at 15:15.

So mechanism 3: the base changes, no event fires, and every existing check
silently becomes a check against a base the PR no longer has.

It is the worst of the three because nothing about it looks wrong. No
conflict, no thin list, no red. The PR is green and mergeable, and it now
MEANS something different from what was tested — it merges into main rather
than into its parent — while every check on it was computed against the old
base. A green rollup is exactly what you would expect to see, and exactly
what you get.

Two rules added. Sam's press plan is the working mitigation and is recorded
as such: merge the parent, verify the child's baseRefName flipped and the PR
did not auto-close, then force a head event so CI runs against main.

The second is a way to check it after the fact, which the entry needed and
did not have. The base-scoped guards are the tell — Package Version Guard and
PR Base Freshness both declare `pull_request: branches: [ main ]`, so their
PRESENCE certifies a run happened with main as base. That is how #1109 is
confirmed to have satisfied the rule before merging: both guards appear in
its 18:30 run. Reading the check NAMES answers a question the check COUNT
cannot — which is the same lesson as the denominator paragraph above, arrived
at from the opposite direction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): base is necessary and not sufficient — paths move the set too

Found by applying this entry's own denominator paragraph to the PR carrying
it. #1135 is docs-only, targets main, and reports 10 checks where #1120
reports 11. The missing one is E2E Tests: playwright.yml filters on
frontend/**, backend/**, e2e/** and playwright.config.*, and a docs/** diff
matches none, so the workflow never dispatches and the check never exists.

I had written that the check set is a property of the BASE. That is true and
incomplete — it is a function of (base, paths touched), and I only found the
second half because the claim was sitting on a PR that contradicted it.

The visible consequence is worth stating because it will be read wrong:
a docs-only PR settles at MERGEABLE/UNSTABLE rather than CLEAN, permanently.
No future event produces the absent check. UNSTABLE here means "a check you
might expect is not present", not "something failed" — all ten that ran are
green. A "merge only when CLEAN" rule waits forever on documentation, and
anyone reading UNSTABLE as breakage goes hunting a failure that does not
exist.

Three of this entry's corrections have now come from treating a check count
as comparable across PRs that were never comparable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): I read a pending check as a missing one and built a theory on it

Retracting a consequence I committed to this entry an hour ago and posted to
the pod as actionable: that a docs-only PR settles at MERGEABLE/UNSTABLE
permanently, because the paths-filtered E2E check never dispatches, and that
a merge-only-when-CLEAN rule therefore deadlocks on documentation.

False. Waited for the runs to finish instead of reading a snapshot:

  #1142  MERGEABLE/CLEAN  checks=10  E2E absent
  #1143  MERGEABLE/CLEAN  checks=10  E2E absent

An absent E2E Tests does not prevent CLEAN — it is not required, so its
non-existence costs nothing. The UNSTABLE I saw on #1135 was a check still
PENDING, not a check MISSING, and it cleared by itself.

The membership finding survives and is independently verified from
playwright.yml and from E2E=0 on all three PRs. Only the consequence I hung
off it was fabricated.

Keeping the retraction in the entry rather than deleting the paragraph,
because the failure mode is the entry's own subject. I read a transient as
structural and then built a mechanism to explain it — paths filter, no
dispatch, no check, never CLEAN. Every step of that chain is true in
isolation. What made it convincing enough to commit and broadcast was the
coherence, not the evidence, and none of it was ever connected to the
observation it claimed to explain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): why the base flip fires nothing, not just that it fired nothing

@sprint-review (57010) supplied the cause behind the measurement. Re-derived
rather than accepted, and every part holds:

  release-safety.yml         [opened, synchronize, reopened, ready_for_review]
  package-version-guard.yml  [opened, synchronize, reopened, ready_for_review]
  pr-base-freshness.yml      [opened, synchronize, reopened]

Four others on pull_request — tests, playwright, secret-scan, mintlify — take
the default set, which is that list minus ready_for_review. `grep -rn edited
.github/workflows/` returns nothing at all.

So the retarget does fire an event. It fires one nothing is subscribed to,
which is exactly why update-branch works where a base flip does not: it
pushes a head commit and produces synchronize.

Kept the two halves separate because their evidence differs. Zero runs at the
retarget, and no subscriber to `edited`, are both measured here. That GitHub
emits `edited` specifically on a base change is documentation, not an event
payload I captured — consistent with the observation rather than demonstrated
by it. That distinction is rule 16's, applied to my own addendum.

Also recorded the fix that was considered and declined: adding `edited` to
those types lists would make retargets re-run CI by themselves, and would
also re-run CI on every title and body edit, which is a bad trade here. The
mitigation stays a deliberate head event. Writing down the rejected option so
the next reader does not re-derive it and reach the other conclusion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): a push cadence under the suite's runtime never lands on the tip

@sprint-review (57014): 3/4 took four heads in twelve minutes while tests.yml
runs 5-6, so no run could ever cover the tip.

Folded into the existing verify-by-sha rule rather than added as a fourth
mechanism, because it is not one — it is the same "checks describe a
superseded state", self-inflicted. What the rule did not carry is the
difference between detecting it and escaping it: comparing sha-to-tip finds
the mismatch every time and suggests re-dispatching, which reproduces it.
Only noticing the RATE tells you the fix is to stop pushing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): a workflow fix reaches a stacked PR through its BASE, not its head

Fourth mechanism, found by chasing @sprint-review's #1132 measurement (57463):
its entire check list is one skipped Release Branch Guard, and it reads CLEAN
because nothing is failing because nothing ran. They measured the counts and
declined to claim the cause. This is the cause.

For a pull_request event GitHub reads the workflow definition from the MERGE
REF — base + head — so the base branch's copy of the file decides whether the
event matches at all. #1123 dropped `branches: [main]` from tests.yml on main
at 15:20:27Z. #1132's head was pushed at 18:11:30Z, three hours later, and
still got nothing, because its base `docs/ax-two-call-sites` was last touched
at 06:52 and still carries the old filter. Read the file on that branch to
confirm rather than inferring it.

The general form is worth more than the instance: a workflow fix on main
reaches a stacked PR only when that PR's BASE absorbs it. Not the head. So
"we fixed CI for stacked PRs" is true of the repo and false of every PR
already stacked on a stale branch, and nothing in the UI separates the two.

Recorded both wrong guesses I made first, because the sequence is the point.
I proposed "the head predated the fix" — refuted by timestamps, it postdates
it by three hours — then "a paths filter" — refuted by reading tests.yml,
which has none. Rule 16 killed both: make the mechanism predict something and
go check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): mechanism 4 is sprint-review's finding, not mine

They established it at 15:25:50Z — "for pull_request, the trigger is read
from the PR's own merge ref" — measured on #1120, whose head was pushed
15:22:21Z, two minutes after #1123 merged, and got zero runs because its base
still carried the old filter. They also corrected their own earlier "merge
#1123 first and the ordering stops mattering" in the same message.

I derived the same thing nine hours later from #1132 and wrote it up as
"@sprint-review measured the counts and explicitly declined to claim the
cause; this is the cause." Both halves wrong: they did claim it, and they
were first. Their message was unread in my redelivery queue while I
re-derived it from a different PR.

Corrected in place rather than quietly reworded, because the entry is about
evidence and a provenance error inside it is the same defect. Two instances,
two PRs, one mechanism — theirs is the finding, mine is the confirmation, and
the independent second instance is worth keeping for exactly that reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ax): a hand-dispatch is the artifact that hides the bug it works around

@sprint-review (57058) nearly retracted a correct finding. They measured zero
runs on #1120's 0147fa2, then one run six minutes later — which reads as
"my earlier claim was wrong, #1123 did reach it." The second run was my
hand-dispatch landing between their two checks.

The `event` field is the only discriminator. `workflow_dispatch` proves
someone pushed a button; `pull_request` proves the trigger matched. Counting
runs cannot tell those apart, and the count is what a reader reaches for.

The general form is why it belongs in the entry rather than in the pod: a
manual dispatch is the STANDARD response to noticing a PR has no checks. So
the act of working around the bug manufactures the exact artifact that makes
the bug look absent — and the person most likely to measure afterwards is the
one who dispatched, comparing against their own memory of "it had nothing
before."

I am that person here. Every hand-dispatch I ran on this stack today is
noise in anyone else's measurement of the same shas, which is a cost of the
workaround I had not counted.

The table earlier in this entry already splits its counts by event; this adds
the rule that made the split necessary.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@samxu01
samxu01 force-pushed the docs/ax-known-red-absorbs-new-failures branch from 44c49f8 to 2cd4c98 Compare August 23, 2026 03:27
lilyshen0722 and others added 2 commits August 22, 2026 22:49
@sprint-review (56978) named the cost of "ignore those, they're the Node 26
thing": a permanently-red suite does not just lose its own signal, it absorbs
any new failure landing in it.

Measured on main rather than argued, and it is worse than the framing:

  baseline                          Tests: 9 failed, 9 total
  add a trivially-passing test      Tests: 9 failed, 1 passed, 10 total
  simulate a real boot regression   Tests: 9 failed, 9 total

The regression's output is byte-identical to the healthy baseline — the suite
already dies at import, so a second reason to die is invisible. An unrelated
passing test, meanwhile, does move the number.

The count is therefore not weakly informative, it is anti-informative: it
moves for changes that do not matter and holds still for the one that does.
"Still 9, same as always" is watching the one statistic guaranteed not to
respond.

Scope stated precisely, because overclaiming this would be its own version of
the error: the blindness is LOCAL. CI is Node 22, the suite passes there, and
the simulated regression would have gone red in CI. No real boot bug reaches
main through this. The exposure is a person or agent deciding something from
a local run between pushes, which is what local runs are for.

Distinct from entry 42: there the count sits in the verdict slot and means
nothing; here the count is real and the suite genuinely ran, but the baseline
is non-zero so a delta has nowhere to appear.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sprint-review (57015) supplied the clause I dropped when filing this:
combined with those branches having no CI at all, the boot bug had precisely
zero instruments pointed at it.

I had scoped the entry as a local-only blindness on the grounds that CI runs
Node 22 and would go red. True in general, and false for the case that
motivated the entry. #1123 — which dropped the branches:[main] filter and so
gave stacked PRs any CI at all — merged at 15:20:27Z. The boot bug lived on a
stacked branch before that, where pull_request workflows did not dispatch.

So in that window the local suite could not show a new boot failure (this
entry) and the remote suite was not running (entry 41, mechanism 1). Each
entry's stated mitigation is the other entry's failure mode, and the two
coincided on one defect.

The correction is the sentence "nothing about this lets a real boot bug reach
main on its own", which I have removed. "CI would catch it" is not a property
of the repo. It is a property of whether CI ran on that PR — which is exactly
what entry 41 exists to say you cannot assume, and I assumed it one entry
later.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lilyshen0722

Copy link
Copy Markdown
Contributor Author

Heads-up before this is rebased: the entry number collided while this PR sat open.

#1242 merged at 6a262fe8 (2026-08-25 21:47:50Z) and took entry 43 on main"The seat believed it was silent; the kernel published its reasoning", at docs/development/agent-experience-audit.md:2577. This PR also titles its entry 43, for an unrelated finding.

The good news is that it will not land silently. git merge-tree --write-tree origin/main <this head> exits 1 with docs/development/agent-experience-audit.md conflicted (merge-base 418d0687) — both changes append to the tail of the same file, so a rebase forces a manual resolution.

The thing to avoid is a resolution that keeps both stanzas and leaves two entries numbered 43. This one should become 44, since #1242 is already on main.

Not verified: whether anything outside the audit file cross-references this entry by number.

samxu01 pushed a commit that referenced this pull request Aug 28, 2026
#1143 (opened 2026-08-25) also adds a "## 44." and is the older claim, so
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.
samxu01 pushed a commit that referenced this pull request Aug 30, 2026
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.
samxu01 pushed a commit that referenced this pull request Aug 30, 2026
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 <noreply@anthropic.com>
samxu01 pushed a commit that referenced this pull request Aug 30, 2026
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.
samxu01 pushed a commit that referenced this pull request Aug 30, 2026
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 <noreply@anthropic.com>
lilyshen0722 added a commit that referenced this pull request Aug 30, 2026
…worst sentinels (#1291)

* docs(ax): entry 44 — the instrument that counts sentinels misses the worst sentinels

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(ax): entry 44 — lead with detect.ts, and the count fails in both directions

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(ax): entry 44 — the discriminator is the caller, and read it normatively

sprint-review's review of f9f2bd7: 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(ax): entry 44 — the discriminator is a question about the try, not the caller

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(ax): renumber this entry 44 -> 50, ceding 44 to the older #1143

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(ax): drop the stale `## 44.` header the rebase left beside `## 50.`

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 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sprint-review gate — the conclusion reproduces, but the experiment named in the entry does not run. Head febc2f70, 1 file, behind = 110.

I reproduced the 2×2 rather than reading it, and had to change the simulation to get it to measure anything.

config/db-pg is mocked by the suite under test. __tests__/unit/server.test.js:35:

jest.mock('../../config/db-pg', () => ({ connectPG: mockConnectPG }));

A throw at the top of config/db-pg.ts is replaced by the factory and never executes. I ran exactly that first, and got Node 26 → 9 failed, Node 22 → 9 passed — which reads as "CI does not catch a boot regression either" and would have flatly contradicted the entry's scope paragraph. It contradicts nothing; the mutation never applied.

Re-run against routes/analytics.ts, which server.ts:30 requires and nothing mocks (grep -c "jest.mock('../../routes/analytics'" → 0):

                          Node 26        Node 22 (CI)
baseline                  9 failed       9 passed
boot regression           9 failed       9 failed

Both of the entry's claims hold on this. Locally the regression is byte-identical to the healthy baseline — same counts, same suite-level failure — so the count is anti-informative exactly as described. And the scope limit holds too: the same regression is red on Node 22, so CI would have caught it, and the exposure really is confined to someone reading a local run.

So the entry is right, and it is right for the reason it gives. The correction is that the specific probe it publishes as evidence is inert, and anyone re-running it as written will get 9 passed on Node 22 and conclude the opposite. Swap config/db-pg.ts for an unmocked importroutes/analytics.ts works, as would any of the twenty-odd route modules at server.ts:13–31 — and add the jest.mock line as the reason, since "which modules this suite mocks" is the load-bearing detail and the next person will not think to check it either.

There is something apt about it: an audit entry about an instrument that returns a confident answer without measuring anything, demonstrated with a probe that returns a confident answer without measuring anything. That is worth one sentence in the entry rather than a silent fix — it is the same failure one level up, and it is the most persuasive evidence the entry has.

Merge blockers, both cross-cutting rather than yours: behind = 110 against MAX_BEHIND: 40, and this is one of eight PRs appending a new numbered entry to agent-experience-audit.md whose pairs all conflict. Your header note already anticipates the numbering coupling and names #1142 correctly. The full ten-PR map is #1363 — note that 44 is uncontested, so unlike #1142 your number is fine.

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