Repository navigation
docs(e2e): correct five stale procedures found by the first full E4 run - #1862
Conversation
Executing E4 end-to-end against the new fixture surfaced five documented procedures that are stale or wrong. Two are silent-failure traps: they do not error, they produce a confident wrong answer. E4 Phase 2 -- short path 5 -> 8 commands. The bold "do not continue to `plan validate` / `plan accept ...`; those verify nothing additional" was false. `plan activate` hard-blocks without an `impl-accepted` artifact while reporting all six jobs `success`, so it looks clean and does nothing. On the old path Phases 3b/3c/3e had no artifact to read and only 3a scored. Added the two newly-required accept steps and the `plan validate` first-pass-FAIL cycle. E4 Phase 0b -- compare content, not byte size. Three provisioning artifacts each produce a false STALE: the `source:` line `gh aw add` injects into the top-level workflow, CRLF vs LF, and `gh aw add` stripping the trailing newline. With only the first two handled the main workflow still read 1391 vs 1390. Normalizing all three takes all four surfaces to MATCH; verified live against the fixture. E4 3b -- the contamination table and its "guaranteed false FAIL" warning described the fixture that was deleted before this one existed. The new fixture started with 12 labels and zero `squad:*`, which inverts the guidance. Missed when #1856 repointed the runbooks. E4 3a -- warn against substituting `Out-File` for `Set-Content`. `Out-File` wraps at console width and splits markdown table rows mid-cell; it split the roster name `Keaton` into `Ke`/`aton` and silently corrupted a roster check. E1 -- worker PRs are not parked in `action_required`. GitHub suppresses workflow triggers entirely for `GITHUB_TOKEN`-authored PRs, so no run is created. The documented `runs/<ID>/approve` override cannot apply to a run that does not exist. Same consequence, different cause; the PAT/App-token fix stands. Also records the 2026-08-24 amended-procedure verdict at the head of E4: 3a and 3c PASS, 3b/3e PARTIAL -> #1859, #1860. Verified: `test/e2e-runbook-hygiene.test.ts` (3/3), `npm run lint`. Phase 0b's replacement block was executed against the live fixture, not just reviewed. Docs only; no changeset. Closes #1861 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20afe6d2-444e-414e-8a39-e67ab67ca6df
|
🛫 PR Readiness Check
PR Scope: 🔧 Infrastructure
|
| Status | Check | Details |
|---|---|---|
| ✅ | Single commit | 1 commit — clean history |
| ✅ | Not in draft | Ready for review |
| ✅ | Branch up to date | Up to date with dev |
| ❌ | Copilot review | No Copilot review yet — it may still be processing |
| ✅ | Changeset present | No source files changed — changeset not required |
| ✅ | Scope clean | |
| ✅ | No merge conflicts | No merge conflicts |
| ✅ | Copilot threads resolved | No Copilot review threads |
| ❌ | CI passing | 1 check(s) still running |
Files Changed (2 files, +178 −71)
| File | +/− |
|---|---|
.squad/e2e/E1-merge-continuation-relay.md |
+9 −5 |
.squad/e2e/E4-agent-binding-verification.md |
+169 −66 |
Total: +178 −71
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
🟢 Impact Analysis — PR #1862Risk tier: 🟢 LOW 📊 Summary
🎯 Risk Factors
📦 Modules Affectedsquad-state (2 files)
This report is generated automatically for every PR. See #733 for details. |
There was a problem hiding this comment.
🟡 Changes recommended
One moderate procedural issue and additional unresolved documentation corrections remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This docs-only PR updates E1/E4 E2E runbooks based on live execution findings.
Changes:
- Corrects E4 lifecycle and content-comparison procedures.
- Updates fixture, PowerShell, and evidence guidance.
- Corrects
GITHUB_TOKENworkflow-trigger explanations.
File summaries
| File | Review summary |
|---|---|
.squad/e2e/E4-agent-binding-verification.md |
E4 procedure, status, formatting, and freshness guidance updates remain needed. |
.squad/e2e/E1-merge-continuation-relay.md |
Follow-on approval guidance remains inconsistent with the corrected workflow behavior. |
Review details
Suppressed comments (9)
.squad/e2e/E1-merge-continuation-relay.md:65
- The corrected observation identifies only “fixture PR #4,” while this evidence file’s header is explicitly for the deleted
bradygaster/...repo and the replacement reuses the same repo name underoctodemo. Without namingoctodemo/aspiregregator-squad-e2e(or using a declared$FIXTURE), the new measurement cannot be tied unambiguously to the current fixture.
> ⚠️ **Corrected 2026-08-24.** This section previously said such PRs are *parked* in `action_required` pending manual approval. **Measured false on fixture PR #4:** no `pull_request` run was created at all. The check rollup carried only `dynamic`-event checks (CodeQL, dependency submission) — there was nothing queued, nothing pending, and nothing to approve. The practical consequence is the same (the loop cannot close unattended), but the cause is different, and the distinction matters operationally: **you will search for a run ID that was never created.**
.squad/e2e/E4-agent-binding-verification.md:663
- With this path, the Phase 3a extractor at lines 740–742 still selects
.comments[-1].body.plan activateis the final command, and the workflow specifies its activation record as the LAST action, so this selects the activation summary rather than thesquad_artifact=implementationcomment. Phase 3a can therefore inspect the wrong table and miss the taskAgentcolumn; select and validate the implementation artifact by its structured envelope instead of taking the latest comment.
/squad plan implementation ← the #1784 leak site (Phase 3a evidence)
.squad/e2e/E4-agent-binding-verification.md:511
- PowerShell's
-eqcomparison is case-insensitive by default. This makes the gate reportMATCHwhen the source and fixture differ only by letter case, allowing a real prompt change to be missed. Use a case-sensitive comparison after the intentional newline and provenance normalization.
elseif ($s -eq $d) { "MATCH" }
.squad/e2e/E4-agent-binding-verification.md:775
- The new fixture guidance says to re-derive the roster, but the actual 3a/3b criteria still hardcode the retired names (
Keaton,McManus,Fenster,Hockney,Kint, plus their lowercase forms). The document itself says casting the replacement fixture will not reproduce those names, so a fresh run can reject valid bindings or accept stale names. Derive the accepted set from.squad/team.mdfor each run instead of retaining these literals.
> **On a freshly copied fixture the opposite is true.** Measured 2026-08-24 on
> `octodemo/aspiregregator-squad-e2e` immediately after provisioning: **12 labels, none of
> them `squad:*`** — `bug`, `documentation`, `duplicate`, `enhancement`, `good first issue`,
> `help wanted`, `invalid`, `question`, `wontfix`, `.NET`, `dependencies`, `squad`. There is
> no pre-existing contamination to filter, and repo-global absence *is* real evidence.
.squad/e2e/E4-agent-binding-verification.md:451
- This new baseline still directs operators to the
0crefresh when content is stale, but0c's fenced block (lines 543–553) contains comments only—there are no fetch/write/commit/compile commands. Once this comparison correctly reportsSTALE, following the runbook has no executable recovery path and cannot reach the requiredMATCHpost-condition. Restore the refresh commands or link to an executable refresh procedure.
> 🛑 **Compare CONTENT, not byte size.** Three artifacts of provisioning make a byte-size
> comparison report `STALE` **forever** on a healthy fixture, so the 0c refresh below can
> never clear it:
>
> 1. `gh aw add` injects a provenance line into the **top-level workflow only**:
.squad/e2e/E4-agent-binding-verification.md:667
- The command list now adds
plan validateand both acceptance steps, but the Budget section still says~31 minutesbased on the old four-command measurement and later says “All five commands.” The newly required validation/acceptance cycle was the previously omitted work, so the runbook now gives a materially understated duration and contradictory command count. Update the budget and safety text with the measured eight-command path.
/squad plan implementation ← the #1784 leak site (Phase 3a evidence)
/squad plan validate
/squad plan accept scope
/squad plan accept implementation
/squad plan activate ← the #1812 provenance site (3b/3c/3e); STOP HERE
.squad/e2e/E4-agent-binding-verification.md:846
- This new note says every run’s minted labels must be appended before the next run, then records four labels minted by the 2026-08-24 run while leaving the table above as
_(none)_and providing no issue mappings. The next operator will therefore inherit exactly the stale contamination table this warning says invalidates the filter. Populate it with the current run’s issue IDs or derive the contamination data instead of requiring manual maintenance.
> ⚠️ **This table grows.** Every E4 run mints labels at `plan activate`. **After running E4,
> append the newly-minted labels to this table before the next run** — otherwise the next
> run's contamination filter is stale and either passes labels it should catch or catches
> labels it should ignore. If unsure, re-derive it from the fixture:
> `gh label list --repo $FIXTURE` gives repo-global presence; scope by issue via the same
.squad/e2e/E4-agent-binding-verification.md:674
- The E1 correction does not update the identical autonomy-blocker guidance in this E4 file’s follow-on at lines 1077–1082, which still says worker PR runs are parked in
action_requiredand recommends approving a run ID. Since the new E1 text establishes that this mechanism creates no run, operators following the follow-on will still get the wrong procedure; update that section too.
> ⚠️ **This path was five commands until 2026-08-24.** It previously told you to skip
> `plan validate` and `plan accept …` on the grounds that they "verify nothing additional
> for E4". **That is false, and skipping them makes E4 unscoreable.** `plan activate` now
> refuses to act without an accepted implementation plan:
>
.squad/e2e/E4-agent-binding-verification.md:496
Get-AwNormalizedremoves every line matching a genericsource: … .md@…pattern from both sides, then usesTrimEnd()for the trailing-newline artifact. That can hide a legitimate source line or meaningful trailing Markdown spaces and reportMATCHfor substantive drift. Limit the exception to the exact injected line on the top-level fixture workflow and trim only terminal CR/LF.
function Get-AwNormalized($text) {
if ($null -eq $text) { return $null }
$lines = ($text -replace "`r`n", "`n") -split "`n" |
Where-Object { $_ -notmatch '^\s*source:\s*\S+/\S+\.md@' }
return ($lines -join "`n").TrimEnd()
- Files reviewed: 2/2 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| git commit --allow-empty -m "trigger CI" && git push | ||
| ``` | ||
|
|
||
| > The `actions/runs/<RUN_ID>/approve` API this section used to recommend **cannot apply here**: approval acts on an existing queued run, and in this failure mode no run exists. Keep it in mind only for the genuinely distinct `action_required` case (first-time outside contributors), which is not what worker PRs hit. |
| ## Phase 2 — Run the short path | ||
|
|
||
| **Run exactly these five commands, in this order, and stop.** | ||
| **Run exactly these eight commands, in this order, and stop.** |
| > **The amended procedure has now been executed: 2026-08-24, n=1, against | ||
| > `octodemo/aspiregregator-squad-e2e`.** Twelve `/squad` runs, all six jobs green on every one, | ||
| > zero secrets and zero repository variables configured. Result: **3a PASS** (12/12 tasks bound | ||
| > to roster Names, zero forbidden tokens including the dispositive `devrel`), **3c PASS**, and |
| > 🛑 **Compare CONTENT, not byte size.** Three artifacts of provisioning make a byte-size | ||
| > comparison report `STALE` **forever** on a healthy fixture, so the 0c refresh below can | ||
| > never clear it: |
| > roster-provenance gate) has **not yet been executed**. Any claim about #1812 requires a fresh | ||
| > live run against the amended procedure — do not cite the n=1 record as evidence of the | ||
| > provenance gate's behaviour. | ||
| | 2026-08-24 (post-run corrections, #1861) | **Five procedures were stale or wrong, found by executing E4 end-to-end on the new fixture.** (1) **Phase 2 short path 5 → 8 commands** — the bold "do not continue to `plan validate` / `plan accept …`" instruction was false: `plan activate` hard-blocks without an `impl-accepted` artifact while reporting all six jobs `success`, so 3b/3c/3e were unreachable and only 3a scored. (2) **Phase 0b compared byte size** — `gh aw add` injects a `source:` provenance line into the top-level workflow only (+48 bytes, identical 1391-line counts), so a correctly-provisioned fixture read `STALE` forever and 0c could never clear it; now compares content modulo that line. (3) **§3b contamination table and its 🛑 "guaranteed false FAIL" warning described the deleted fixture** — the new one started with 12 labels and zero `squad:*`, inverting the guidance; missed when #1856 repointed the runbooks. (4) **§3a gained an explicit `Out-File` warning** — `Out-File` wraps at console width and split the roster name `Keaton` into `Ke`/`aton` mid-table, silently corrupting a roster check with no error. (5) E1's `action_required` section corrected (see that file). | #1861 — first full E4 execution against `octodemo/aspiregregator-squad-e2e`. Every correction is a measurement, not a review comment: runs `32772695400` (activate blocked), `32776872385` (accept blocked), `32776202217` (validate passed after `plan program revise`) | |
Closes #1861
Corrections to the E2E runbooks found by executing E4 end-to-end against the new fixture (
octodemo/aspiregregator-squad-e2e). Every item below is a measurement from that run, not a review observation.Two of the five are silent-failure traps of exactly the class
test/e2e-runbook-hygiene.test.tsexists to prevent: they do not error, they hand you a confident wrong answer.1. E4 Phase 2 — short path 5 → 8 commands
The runbook said in bold: "Do not continue to
plan validate/plan accept …. Those add ~27 min and verify nothing additional for E4."False.
/squad plan activate(run32772695400) completed with all six jobssuccessand created nothing:A second halt then appeared at
accept implementation, which requiresaccept scopefirst (run32776872385). On the old five-command path, Phases 3b/3c/3e have no artifact to read and only 3a scores — the runbook could not reach its own verification targets.Both halts are correct Squad behaviour: clean lifecycle tables, precise remediation, no partial writes. L615-619 already anticipated this ("refuses to run without
plan acceptin later revisions"); that future arrived and the prescription above it hadn't caught up.Also documented:
plan validatelegitimately FAILs on first pass when the program plan carries unresolved decisions — a real finding, cleared with/squad plan program revise. Budget a cycle for it.2. E4 Phase 0b — compare content, not byte size
Three provisioning artifacts each produce a false
STALE, and 0c's required post-condition ("all four MATCH") could never be satisfied:gh aw addinjectssource: bradygaster/squad/workflows/squad.md@devinto the top-level workflow only (+48 bytes)gh aw addstrips the source file's trailing newlineWorth noting (3) was found by running the replacement block, not by writing it — with only (1) and (2) handled the main workflow still read
src=1391 / fixture=1390.Compare-Objectisolated it to a single empty trailing line. With all three normalized,Compare-Objectreturns nothing and all four surfaces readMATCH, verified live.3. E4 §3b — contamination table describes a fixture that no longer exists
The 🛑 warning claimed repo-global label checks are a "guaranteed false FAIL" because
squad:lead/squad:devrel/squad:reviewer"already exist in the fixture", and tabulated contamination on issues #6-9 / #17-20.All of that described the deleted fixture.
octodemo/aspiregregator-squad-e2estarted with 12 labels and zerosquad:*; those issue numbers don't exist here. The guidance was inverted — on a fresh fixture, repo-global absence is real evidence. Missed when #1856 repointed the runbooks.Rewritten to explain why timestamp-scoping is right (labels persist across repeat runs on the same fixture) rather than asserting a fixture-specific fact that expires. Also records that the fixture is now dirty (20 issues, 4 minted labels) so the next operator knows a clean re-test needs a fresh copy.
4. E4 §3a — warn against substituting
Out-FileOut-Filewraps at console width and splits markdown table rows mid-cell. It split the roster nameKeatonintoKe/aton, silently corrupting a roster-membership check — no error, just a plausible-looking extract with one entry truncated.Set-Content(already used, now with a warning) and[IO.File]::WriteAllTextdon't wrap.5. E1 — wrong mechanism for the autonomy blocker
The runbook said worker PRs are parked in
action_requiredpending approval, and offeredgh api -X POST repos/…/actions/runs/<RUN_ID>/approve.Observed on fixture PR #4:
pull_requestworkflows never triggered at all — GitHub suppresses triggers entirely forGITHUB_TOKEN-authored PRs. The rollup carried onlydynamic-event checks. Same consequence, different cause, and the distinction is operational: you will hunt for a run ID that was never created. The PAT/App-token recommendation stands and is now explained.Also
Records the 2026-08-24 amended-procedure verdict at the head of E4 — 3a PASS (12/12 tasks bound to roster Names, zero forbidden tokens including the dispositive
devrel), 3c PASS, 3b/3e PARTIAL → #1859, #1860 — and notes why both defects survived every guard: TG-2 and validation Check 10 verify membership (eachAgentis a roster Name); nothing verifies correspondence (the label on task N equals the plan'sAgentfor task N). A label can be simultaneously certified and wrong. That gap is the spec for #1801.Verification
npx vitest run test/e2e-runbook-hygiene.test.ts— 3/3 pass (the--argand stderr-suppression rules constrain every edit here)npm run lint— clean