From 5c4514a367aeb1a6d95fe0812b240429b4bbbe2c Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:25:56 -0700 Subject: [PATCH] docs(ax): UNKNOWN mergeability is a fifth row, and its decoder is the same query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @sprint-review verified #1122 (OPEN, 10/10 green, MERGEABLE/CLEAN) and noted it only settled on the second query — the first returned UNKNOWN/UNKNOWN, which is GitHub computing mergeability lazily, not a state change. That belongs in the "value correct and insufficient" table in entry 12, but it inverts the rule the table earns. For `attempts`, the requeue floor and `reviewDecision`, the disambiguating surface is a different one — a write site, a second file, branch protection. Here it is the SAME query run again: the first read can return UNKNOWN and schedule the computation the second read collects. Stated with its limit: two independent observations, and NOT reproduced on demand. Re-running #1122, #1140, #1156, #1204 and #809 today returned the settled value on the first read every time, because all five had been queried earlier in the session and were warm. The failure only shows cold — which is exactly when a one-shot matrix is the thing doing the querying. Docs-only. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index c12c72a19..e2e514bc8 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -328,9 +328,28 @@ Second, and live: **three of four driver classes terminate inside the requeue's | `AGENT_EVENT_REQUEUE_DELIVERED_MINUTES` | `10` | *10-minute floor* — or *10–20*, depending on a cron interval declared in a different file | | `reviewDecision` on a PR | `""` | *no review recorded* — or *no review required* | | `mergeStateStatus` | `BLOCKED` | *a gate is unmet* — or *a required check has not reported yet* | +| `mergeable` / `mergeStateStatus` | `UNKNOWN` | *not mergeable* — or *not computed yet*, because GitHub computes mergeability lazily on read | **No value is wrong. No value is sufficient alone. Nothing on the first surface says a second one exists.** That is why four careful readers each stopped exactly one query short — there was no error to notice, because the first surface answered, plausibly, and closed the question. An absent field prompts a search; a *present, plausible, incomplete* one does not. +**The `UNKNOWN` row has a wrinkle the other three do not, and it inverts the +rule below.** For `attempts`, the floor, and `reviewDecision`, the +disambiguating surface is a *different* one — a write site, a second file, +branch protection. For `mergeable`/`mergeStateStatus` it is **the same query, +run again**: GitHub computes mergeability lazily, so the first read can return +`UNKNOWN` and *schedule* the computation that the second read collects. One +query cannot distinguish "not mergeable" from "not computed yet", and the +sequence `UNKNOWN` → `MERGEABLE/CLEAN` is not a state change. Anyone reading +that field to decide whether to press must read it twice. *(Observed +independently twice: once on a stale-PR matrix where exactly the PRs most +likely to be `DIRTY` came back null on a one-shot pass, and again by +@sprint-review on #1122 — `UNKNOWN/UNKNOWN` then `MERGEABLE/CLEAN`, 10/10 +green. **Not reproduced on demand**: re-running it 2026-08-25 across #1122, +#1140, #1156, #1204 and #809 returned the settled value on the first read every +time, because all five had been queried earlier in the session and were already +warm. The failure mode only appears cold, which is also when a one-shot matrix +is most likely to be the thing querying it.)* + **The operational rule, small enough to actually use:** when a field's **empty, zero, or default** value is load-bearing for your conclusion, go find the surface that distinguishes *not applicable* from *not present* before concluding. All four instances fall to that one habit — `attempts` by grepping the write rather than the read, the floor by reading both files, `reviewDecision` by reading branch protection, `BLOCKED` by asking what it measures. **And the human half, which is why the rule needs stating at all.** In three of these, the refuting datum was in the reader's own output before the wrong conclusion was published — a `mergeStateStatus` printed in three consecutive sign-offs, a route line quoted inside the finding it undercut. **Output we generate ourselves gets read as decoration rather than as evidence.** So the failure is not "did not look"; it is "looked, printed it, and did not join it to the claim two lines below." *(Prior form of the same observation: entry #5, re-check before you rely on a fact — this is the narrower case where the fact was never in doubt, only never connected.)*