From 44cd0abae91c86d3322e1e0e82772756bd865a65 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 22 Aug 2026 23:09:51 -0700 Subject: [PATCH 1/7] docs(ax): a stacked PR runs no static analysis, and CodeQL is not in the repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @sprint-review noticed #1109 showed 11 checks and #1120 showed 5, and named the six: the two base-scoped merge guards plus three CodeQL Analyze jobs. That makes the retarget load-bearing for a second reason. A stacked PR is not differently-checked, it is less-checked, and the gap is the security analysis: until its base is main, nothing scans it. The part worth an audit entry is that none of this is discoverable from a checkout. There is no codeql.yml — the scan is GitHub default setup, and `gh api .../code-scanning/default-setup` is the only place its state and language list live. Every other check here traces to a file with an `on:` block a reader can inspect; this one does not, so an agent computing "which checks should this PR have" from .github/workflows/ gets the wrong denominator, with the security checks as the invisible omission. Filed as an addendum to entry 41 rather than a new entry: same defect, same incident, and 41 is already where the (base, paths) denominator is recorded. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index c12c72a19..db1440aed 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2519,6 +2519,39 @@ workflow's clock instead of the pod's, the parent commit instead of the head. retarget. Reading the check *names* answers a question the check *count* cannot. +### Addendum: the missing checks include the security ones, and they are invisible to the repo + +@sprint-review, 2026-08-22. A stacked PR does not merely run a *different* +check set than a main-based one — it runs a **smaller** one, and the difference +is weighted toward analysis rather than tests. `#1109` (base `main`) showed 11 +checks; `#1120` (stacked) showed 5. The six absent were the two base-scoped +merge guards plus **CodeQL: `Analyze (actions)`, `Analyze (javascript-typescript)`, +`Analyze (python)`**. + +So the retarget is load-bearing for a second reason beyond a green tick being +about the right tree: until its base is `main`, a stacked PR gets **no static +analysis at all**. A change can be reviewed, gated, and merged into its parent +having never been scanned. + +**The part that makes this agent-experience rather than trivia:** you cannot +discover any of it by reading the repository. There is no `codeql.yml` in +`.github/workflows/` — the scan is GitHub *default setup*, configured through +the web UI, and `gh api repos///code-scanning/default-setup` +is the only place its state and language list exist: + + state: configured + languages: actions, javascript, javascript-typescript, python, typescript + +Every other check in this repo can be traced to a file with a `on:` block a +reader can inspect. This one cannot, so its trigger scoping is unfalsifiable +from inside a checkout — and an agent reasoning about "which checks should this +PR have" from `.github/workflows/` will confidently compute the wrong +denominator, with the security checks as the omission it cannot see. + +Practical rule, matching the base-scoped-guard tell above: **`Analyze (…)` jobs +are a second certificate that a run happened against `main`.** Their absence +means the PR is stacked, and it means nothing has been scanned yet. + ## 42. A dual-auth route degrades to the other identity silently, so a test can name a shape it never exercises (2026-08-22, sprint-review + pod-architect) > Numbering follows entry 41's caveat: 39 and 40 are still reserved by #1122 From 579bab81de4188633fcb5b80c71196cdc84f7bbb Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 22 Aug 2026 23:43:27 -0700 Subject: [PATCH 2/7] docs(ax): trim the addendum to what entry 41 does not already say Re-reading the merged entry, its body already records the 11-vs-5 membership, names the six extras, and says there is no codeql.yml. My addendum restated all three before getting to its point, which is the padding that makes an append-only log unreadable. Cut to the two things that are genuinely absent: that a stacked PR therefore runs no static analysis at all until its base is main, and that CodeQL's scoping is unfalsifiable from a checkout because it lives only behind `gh api .../code-scanning/default-setup`. Kept the practical tell. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 63 +++++++++++----------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index db1440aed..6b22f3ab0 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2519,38 +2519,37 @@ workflow's clock instead of the pod's, the parent commit instead of the head. retarget. Reading the check *names* answers a question the check *count* cannot. -### Addendum: the missing checks include the security ones, and they are invisible to the repo - -@sprint-review, 2026-08-22. A stacked PR does not merely run a *different* -check set than a main-based one — it runs a **smaller** one, and the difference -is weighted toward analysis rather than tests. `#1109` (base `main`) showed 11 -checks; `#1120` (stacked) showed 5. The six absent were the two base-scoped -merge guards plus **CodeQL: `Analyze (actions)`, `Analyze (javascript-typescript)`, -`Analyze (python)`**. - -So the retarget is load-bearing for a second reason beyond a green tick being -about the right tree: until its base is `main`, a stacked PR gets **no static -analysis at all**. A change can be reviewed, gated, and merged into its parent -having never been scanned. - -**The part that makes this agent-experience rather than trivia:** you cannot -discover any of it by reading the repository. There is no `codeql.yml` in -`.github/workflows/` — the scan is GitHub *default setup*, configured through -the web UI, and `gh api repos///code-scanning/default-setup` -is the only place its state and language list exist: - - state: configured - languages: actions, javascript, javascript-typescript, python, typescript - -Every other check in this repo can be traced to a file with a `on:` block a -reader can inspect. This one cannot, so its trigger scoping is unfalsifiable -from inside a checkout — and an agent reasoning about "which checks should this -PR have" from `.github/workflows/` will confidently compute the wrong -denominator, with the security checks as the omission it cannot see. - -Practical rule, matching the base-scoped-guard tell above: **`Analyze (…)` jobs -are a second certificate that a run happened against `main`.** Their absence -means the PR is stacked, and it means nothing has been scanned yet. +### Addendum: what the six absent checks mean, and why one of them is unfalsifiable from a checkout + +@sprint-review, 2026-08-22. The table above establishes the counts and the +membership; two consequences of it are worth stating outright rather than +leaving to be re-derived. + +**A stacked PR is not differently checked, it is LESS checked, and the missing +set is weighted toward analysis.** Three of the six extras are CodeQL's. So +until its base is `main`, a stacked PR gets **no static analysis at all** — a +change can be reviewed, gated, and merged into its parent having never been +scanned. That is a second reason the retarget is load-bearing, alongside the +auto-close hazard. + +**The scoping of those three cannot be checked from inside a checkout.** The +entry above notes there is no `codeql.yml`; the sharper form is that the +configuration lives *only* behind an API call: + + gh api repos///code-scanning/default-setup + state: configured + languages: actions, javascript, javascript-typescript, python, typescript + +Every other check in this repo traces to a file with an `on:` block a reader +can inspect and falsify. This one does not — so an agent computing "which +checks should this PR have?" from `.github/workflows/` will confidently +produce the wrong denominator, with the *security* jobs as the omission it has +no way to see. The failure is silent and points the wrong way: the checks that +are hardest to notice missing are the ones you would most want to notice. + +**Practical rule**, the mirror of the base-scoped-guard tell above: `Analyze +(…)` jobs are a second certificate that a run happened against `main`. Their +absence means the PR is stacked — and that nothing has scanned it yet. ## 42. A dual-auth route degrades to the other identity silently, so a test can name a shape it never exercises (2026-08-22, sprint-review + pod-architect) From 4e34bfa502bc9d0129356f555d8c91e5f7a46347 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sat, 22 Aug 2026 23:51:07 -0700 Subject: [PATCH 3/7] docs(ax): four of the six extras are CodeQL's, not three Miscounted my own addendum against the table sitting directly above it, which already says "the other four are CodeQL's": the umbrella check plus three Analyze jobs. @sprint-review re-measured the membership and the six are exact. Small, and worth the commit rather than a silent amend, because the whole point of the addendum is that the check denominator is easy to compute wrong. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 6b22f3ab0..5149ffe87 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2526,8 +2526,10 @@ membership; two consequences of it are worth stating outright rather than leaving to be re-derived. **A stacked PR is not differently checked, it is LESS checked, and the missing -set is weighted toward analysis.** Three of the six extras are CodeQL's. So -until its base is `main`, a stacked PR gets **no static analysis at all** — a +set is weighted toward analysis.** Four of the six extras are CodeQL's — the +umbrella check plus `Analyze (actions)`, `(javascript-typescript)` and +`(python)`. So until its base is `main`, a stacked PR gets **no static +analysis at all** — a change can be reviewed, gated, and merged into its parent having never been scanned. That is a second reason the retarget is load-bearing, alongside the auto-close hazard. From 6abe8e6d34159f4cd930fef69ec546ec3f899715 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:22:30 -0700 Subject: [PATCH 4/7] docs(ax): E2E's absence on a stacked PR is path-driven, not stacking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @sprint-review decomposed #1132's seven absent checks as "4 analysis, 1 E2E, 2 by-design guards" and called the stacking gap five, then retracted it: the E2E doesn't belong in that gap. playwright.yml carries no `branches` filter on `pull_request`, and the comment directly above it says so — "No branches filter: stacked PRs must get E2E too". E2E is absent from #1132 because that PR touches only `docs/`, which the path filter excludes. The stacking gap is four. Worth an addendum paragraph rather than a silent fix, because the person who made the misattribution is the one who found the CodeQL scoping in the first place. Two absences that render identically in the checks list can have different causes, and a count is only portable if each absence is attributed to its filter. Docs-only. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 5149ffe87..387c1678e 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2534,6 +2534,19 @@ change can be reviewed, gated, and merged into its parent having never been scanned. That is a second reason the retarget is load-bearing, alongside the auto-close hazard. +**Not every absence is a stacking absence, and E2E is the one that fools you.** +Measured on a second pair (#1170 at 11 checks, the stacked #1132 at 4), seven +are absent rather than six, and the extra one is `E2E Tests`. It is tempting to +add it to the stacking gap; it does not belong there. `playwright.yml` carries +no `branches` filter on `pull_request` — the line above it says so outright, +*"No branches filter: stacked PRs must get E2E too"* — so E2E is absent from +#1132 because that PR touches only `docs/`, which the path filter excludes. +@sprint-review made exactly this attribution and retracted it, which is the +evidence that it is worth writing down: the stacking gap is **four**, and any +other absence has to be traced to a filter before it is counted. Two absences +with the same appearance can have different causes, and the count is only +portable if each one is attributed. + **The scoping of those three cannot be checked from inside a checkout.** The entry above notes there is no `codeql.yml`; the sharper form is that the configuration lives *only* behind an API call: From b7089698dc535ece5143cbb4575bd54f06ce5983 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:24:08 -0700 Subject: [PATCH 5/7] docs(ax): separate the paths axis from the base axis with a controlled middle point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @sprint-review supplied the measurement that isolates them: #1122 is docs-only on `main`, holding content constant against the stacked #1132 and varying only the base. Measured live 2026-08-25: #1170 backend/ base main 11 #1122 docs/ base main 10 #1132 docs/ base stacked 4 #1170 → #1122 moves exactly one check, `E2E Tests` — the paths axis. #1122 → #1132 moves six: the four CodeQL-family jobs plus the two base-scoped merge guards, which are correctly filtered rather than lost. So what stacking costs is the CodeQL family, entire and nothing else. That is sharper than "seven missing" and, unlike it, falsifiable — and it is the form the practical rule below already assumes. Replaces the two-point version from 6abe8e6d, which stated the right conclusion from a pair that could not distinguish the two axes. Docs-only. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 40 ++++++++++++++++------ 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 387c1678e..5e2c55a95 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2535,17 +2535,35 @@ scanned. That is a second reason the retarget is load-bearing, alongside the auto-close hazard. **Not every absence is a stacking absence, and E2E is the one that fools you.** -Measured on a second pair (#1170 at 11 checks, the stacked #1132 at 4), seven -are absent rather than six, and the extra one is `E2E Tests`. It is tempting to -add it to the stacking gap; it does not belong there. `playwright.yml` carries -no `branches` filter on `pull_request` — the line above it says so outright, -*"No branches filter: stacked PRs must get E2E too"* — so E2E is absent from -#1132 because that PR touches only `docs/`, which the path filter excludes. -@sprint-review made exactly this attribution and retracted it, which is the -evidence that it is worth writing down: the stacking gap is **four**, and any -other absence has to be traced to a filter before it is counted. Two absences -with the same appearance can have different causes, and the count is only -portable if each one is attributed. +Two axes move the denominator independently — **paths** and **base** — and +folding one into the other is how a count stops being portable. Three PRs +measured 2026-08-25 separate them, because the middle one holds content +constant and varies only the base: + +| PR | content | base | checks | +|---|---|---|---| +| #1170 | `backend/` | `main` | 11 | +| #1122 | `docs/` | `main` | 10 | +| #1132 | `docs/` | stacked | 4 | + +`#1170 → #1122` isolates the **paths** axis and moves exactly one check: +`E2E Tests`. `playwright.yml` carries no `branches` filter on `pull_request` — +the line above it says so outright, *"No branches filter: stacked PRs must get +E2E too"* — so E2E is absent from a docs-only PR whether or not it is stacked. + +`#1122 → #1132` isolates the **base** axis and moves six: the four CodeQL-family +jobs plus the two base-scoped merge guards (`Source changed ⇒ version bumped`, +`Stale-base merge guard`). The guards are correctly filtered rather than lost, +so **what stacking actually costs you is the CodeQL family, entire and nothing +else** — which is a sharper claim than a raw "seven missing", and a falsifiable +one. + +@sprint-review first decomposed #1132's seven as "4 analysis, 1 E2E, 2 by-design +guards" and put the E2E in the stacking gap, then retracted it and supplied the +#1122 measurement that settles it. Worth recording because the misattribution +was made by the person who found the CodeQL scoping in the first place: two +absences render identically in the checks list, so an absence has to be traced +to its filter before it is counted. **The scoping of those three cannot be checked from inside a checkout.** The entry above notes there is no `codeql.yml`; the sharper form is that the From d5c3c6ca8478746a0ec13f76d5dc4d85b6dee0d4 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:59:32 -0700 Subject: [PATCH 6/7] docs(ax): narrow entry 41's severity to the verdict, and widen its paths case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three amendments from @sprint-review, 2026-08-25. 1. The paths axis is wider than the docs-only case. playwright.yml gates on frontend/backend/e2e/playwright.config, so a stacked PR CARRYING CODE in cli/, scripts/, k8s/, commonly-mcp/, packages/ or _external/clawdbot gets Tests + Detect secrets and neither E2E nor static analysis. That is the case the entry is about; docs-only is its weak form. Confirmed independent on merged history: #1187 and #1185 each ran CodeQL, neither ran E2E. Also names why it hides: playwright.yml's "No branches filter: stacked PRs must get E2E too" is true about the base axis and silently undone for a class of code by the paths: clause three lines below it. 2. "Merged having never been scanned" did not survive measurement. 0 of the last 200 merged PRs had base != main; 18/18 sampled merged PRs carry CodeQL. Retarget-on-parent-merge means nothing reached main unanalysed. The harm relocates to a review-time verdict hazard: green on a stacked PR carries no signal that nothing has been scanned. Window stated, including why baseRefName cannot see a retargeted PR and the CodeQL sample can. 3. release-safety.yml is a THIRD branches-scoped pull_request workflow but is branches: [ v1.0.x ] — absent from main-based and stacked PRs alike, so it sits outside the denominator. Recorded so the next person recomputing the gap neither counts it nor "corrects" it to main. Docs-only. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 68 ++++++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 5e2c55a95..7d7f55ba6 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2529,10 +2529,38 @@ leaving to be re-derived. set is weighted toward analysis.** Four of the six extras are CodeQL's — the umbrella check plus `Analyze (actions)`, `(javascript-typescript)` and `(python)`. So until its base is `main`, a stacked PR gets **no static -analysis at all** — a -change can be reviewed, gated, and merged into its parent having never been -scanned. That is a second reason the retarget is load-bearing, alongside the -auto-close hazard. +analysis at all**. + +**What that costs, measured rather than assumed (2026-08-25).** The first +draft of this addendum said such a change "can be reviewed, gated, and merged +having never been scanned." The merge half does not survive checking: + + last 200 merged PRs with base != main ........ 0 + 18 most recent merged, carrying CodeQL ....... 18 / 18 + incl. #1187 (commonly-mcp only), #1185 (scripts + dev.sh + docs), + #1189 (backend + cli) + open stacked PRs at time of writing .......... 2, both docs-only + +GitHub auto-retargets a stacked PR to `main` when its parent lands, and the +retargeted head then draws the full main-based set. Where the child merges into +the parent branch instead, that merge is a `synchronize` on the parent's own +main-based PR, so the combined content is analysed there before it reaches +`main`. Nothing in the sampled window reached `main` unanalysed. + +So the harm is **not merge safety — it is a review-time verdict hazard**. A +reviewer reads green on a stacked PR and cannot tell from the checks that +nothing has been scanned yet. That is entry-worthy on its own: by the +cheap/expensive split, a stale observation costs a paragraph, while an approval +issued against an unanalysed head is the expensive kind, and the reviewer has +no signal distinguishing the two. The retarget stays load-bearing for the +auto-close hazard and for moving the verdict onto scanned ground; it is not +what stands between unscanned code and `main`. + +Window, since a negative is only as good as its range: 200 merged PRs by +`baseRefName`, 18 by check history, all open PRs as of 2026-08-25. `baseRefName` +reports the **final** base, so a PR that was stacked and then retargeted is +indistinguishable from one never stacked — which is why the CodeQL-presence +sample is the load-bearing half here and the base count is not. **Not every absence is a stacking absence, and E2E is the one that fools you.** Two axes move the denominator independently — **paths** and **base** — and @@ -2551,6 +2579,24 @@ constant and varies only the base: the line above it says so outright, *"No branches filter: stacked PRs must get E2E too"* — so E2E is absent from a docs-only PR whether or not it is stacked. +The docs-only case is the *weak* form of the paths axis, and reading it as the +whole of it under-states the gap — @sprint-review, 2026-08-25. `playwright.yml` +is gated on `frontend/** | backend/** | e2e/** | playwright.config.*`, so a +stacked PR **carrying code** in `cli/`, `scripts/`, `k8s/`, `commonly-mcp/`, +`packages/` or `_external/clawdbot` gets `Tests` + `Detect secrets` and +**neither E2E nor static analysis**. That is the case this entry is really +about. The two axes bite independently, confirmed on merged history: #1187 +(`commonly-mcp` only) and #1185 (`scripts`, `dev.sh`, `install.sh`, docs) each +ran CodeQL and neither ran E2E; stack either and the remaining coverage is two +checks. + +Worth naming why it is easy to miss: `playwright.yml`'s `pull_request` block +carries the comment *"No branches filter: stacked PRs must get E2E too"*, which +is true about the **base** dimension and is silently undone for a whole class of +code by the `paths:` clause three lines below it. A comment asserting coverage +that a sibling clause in the same `on:` block removes — in the file that +documents the fix. + `#1122 → #1132` isolates the **base** axis and moves six: the four CodeQL-family jobs plus the two base-scoped merge guards (`Source changed ⇒ version bumped`, `Stale-base merge guard`). The guards are correctly filtered rather than lost, @@ -2580,9 +2626,21 @@ produce the wrong denominator, with the *security* jobs as the omission it has no way to see. The failure is silent and points the wrong way: the checks that are hardest to notice missing are the ones you would most want to notice. +**One exclusion, stated so nobody "fixes" it later** — @sprint-review, +2026-08-25. Counting `branches`-scoped `pull_request` workflows in +`.github/workflows/` returns **three**, not two: `package-version-guard.yml`, +`pr-base-freshness.yml`, and `release-safety.yml`. The third is +`branches: [ v1.0.x ]` — a different release line, not a main-PR skip. It is +absent from a `main`-based PR and from a stacked one alike, so it belongs +**outside** this denominator entirely. Anyone recomputing the gap from the +workflow files will find it and, without this note, will either count it as a +fourth base-scoped guard or "correct" it to `main`. + **Practical rule**, the mirror of the base-scoped-guard tell above: `Analyze (…)` jobs are a second certificate that a run happened against `main`. Their -absence means the PR is stacked — and that nothing has scanned it yet. +absence means the PR is stacked — and that nothing has scanned it yet. Read it +as a fact about the *verdict you are about to issue*, not about what will reach +`main`: the code will be scanned, later, on someone else's PR. ## 42. A dual-auth route degrades to the other identity silently, so a test can name a shape it never exercises (2026-08-22, sprint-review + pod-architect) From ad37286efdb8dc8f62c7cf0afbf071dfa7f42309 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Tue, 25 Aug 2026 19:09:41 -0700 Subject: [PATCH 7/7] =?UTF-8?q?docs(ax):=20narrow=20the=20retarget=20claim?= =?UTF-8?q?=20=E2=80=94=20being=20in=20the=20population=20is=20not=20being?= =?UTF-8?q?=20checked?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The addendum said a retargeted head "then draws the full main-based set". #1251 measured otherwise for the half that lives in this repo: neither pr-base-freshness.yml nor package-version-guard.yml lists `edited`, and retargeting fires `edited` and never `synchronize`, so neither guard runs on the transition itself. The CodeQL half cannot be answered from a checkout at all, which is this entry's own point turned on the entry. The 18/18 CodeQL-presence measurement is untouched — it samples merged heads, not the trigger that produced them. Co-Authored-By: Claude Opus 5 --- docs/development/agent-experience-audit.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 7d7f55ba6..8b64b6012 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -2542,7 +2542,19 @@ having never been scanned." The merge half does not survive checking: open stacked PRs at time of writing .......... 2, both docs-only GitHub auto-retargets a stacked PR to `main` when its parent lands, and the -retargeted head then draws the full main-based set. Where the child merges into +retargeted head then draws the full main-based set. **That second clause is too +strong, and #1251 is what caught it** — @sprint-review, 2026-08-26. Being *in* +the main-based population and being *checked* by its full set are two claims, +and this sentence ran them together. The two base-scoped guards list +`opened, synchronize, reopened[, ready_for_review]`; retargeting fires `edited`, +which is in neither list, so neither guard runs on the transition itself — only +on the next push, if one comes. What the retarget reliably does is move the head +into the population, not subject it to the checks. The CodeQL family is +configured outside any `on:` block in this repo, so whether *it* fires on a +retarget cannot be answered from a checkout either — this entry's own complaint, +pointed back at the entry. The measurement above is unaffected: it samples +CodeQL presence on merged heads, and that observation stands however the +transition is triggered. Where the child merges into the parent branch instead, that merge is a `synchronize` on the parent's own main-based PR, so the combined content is analysed there before it reaches `main`. Nothing in the sampled window reached `main` unanalysed.