From e02a64c83fbce38e2488a3d0a97abe3cad928c19 Mon Sep 17 00:00:00 2001 From: brady gaster Date: Sat, 22 Aug 2026 18:31:53 -0700 Subject: [PATCH 1/6] chore(squad): record #1793 session state, decisions and logs Merges both decision inbox records from the #1793/PR #1831 work (EECOM's CRLF working-tree repair, FIDO's independent review) and elevates the gate-instructions principle as its own entry: a correct check paired with a remediation hint that cannot observe the failure is still a broken gate. Also captures the gh-aw Tier 1/2/3 triage decisions and the .squad-must-not-be-gitignored decision, plus orchestration and session logs from both waves. Log files are force-added: .squad/ is hidden by the shared .git/info/exclude that #1826 re-creates, which makes new files under .squad/ silently unstageable while git status reads clean. Tracked files are unaffected. Refs #1793 #1826 #1830 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0e20e987-a753-41c4-a6f8-992d863a32cd --- .squad/agents/booster/history.md | 4 + .squad/agents/eecom/history.md | 8 + ...y-archive-2026-08-19T13-11-34.130-07-00.md | 118 ++++++++ .squad/agents/fido/history.md | 108 +------- .squad/agents/flight/history.md | 4 + .squad/agents/procedures/history.md | 4 + .squad/agents/sims/history.md | 5 + .squad/agents/surgeon/history.md | 4 + .squad/decisions-archive.md | 96 +++++++ .squad/decisions.md | 260 +++++++++++------- .../2026-08-22T17-10-52-07-00-gh-aw-triage.md | 23 ++ ...6-08-22T18-25-00-07-00-1793-crlf-merged.md | 15 + .../2026-08-22T17-10-52-07-00-booster.md | 16 ++ .../2026-08-22T17-10-52-07-00-eecom.md | 16 ++ .../2026-08-22T17-10-52-07-00-flight.md | 16 ++ .../2026-08-22T17-10-52-07-00-procedures.md | 16 ++ .../2026-08-22T18-25-00-07-00-EECOM.md | 15 + .../2026-08-22T18-25-00-07-00-FIDO.md | 12 + 18 files changed, 551 insertions(+), 189 deletions(-) create mode 100644 .squad/agents/sims/history.md create mode 100644 .squad/log/2026-08-22T17-10-52-07-00-gh-aw-triage.md create mode 100644 .squad/log/2026-08-22T18-25-00-07-00-1793-crlf-merged.md create mode 100644 .squad/orchestration-log/2026-08-22T17-10-52-07-00-booster.md create mode 100644 .squad/orchestration-log/2026-08-22T17-10-52-07-00-eecom.md create mode 100644 .squad/orchestration-log/2026-08-22T17-10-52-07-00-flight.md create mode 100644 .squad/orchestration-log/2026-08-22T17-10-52-07-00-procedures.md create mode 100644 .squad/orchestration-log/2026-08-22T18-25-00-07-00-EECOM.md create mode 100644 .squad/orchestration-log/2026-08-22T18-25-00-07-00-FIDO.md diff --git a/.squad/agents/booster/history.md b/.squad/agents/booster/history.md index e052a5a1d..827e2eb9a 100644 --- a/.squad/agents/booster/history.md +++ b/.squad/agents/booster/history.md @@ -144,3 +144,7 @@ gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: C - πŸ“Œ **Team update (2026-08-21 β€” Agentic-Workflows Audit):** Authored PR #1815 chore(gh-aw): ignore downloaded workflow logs under .github/aw/logs. Created .github/aw/logs/.gitignore (* + !.gitignore). LF-only blob verified via hex inspection. Correctly requested reviewer pass; Flight approved and squash-merged at 2026-08-21T16:23:46Z. PR #1815 MERGED βœ…. + +## 2026-08-22 β€” gh-aw triage team update + +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): Booster completed Tier 2 gh-aw CI/release-surface triage: #1556 and #1493 are p1/wave:1-next/spec-ready, #1502 is p2/wave:2-soon/needs-research. PR #1709 only partially addresses #1493; #1827 and #1556 are separate generated-YAML code paths. diff --git a/.squad/agents/eecom/history.md b/.squad/agents/eecom/history.md index d47a54ae2..09ac5fdb6 100644 --- a/.squad/agents/eecom/history.md +++ b/.squad/agents/eecom/history.md @@ -49,3 +49,11 @@ gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: C Batch 2 complete. Fixed #1772 (P0): `max: 1` β†’ `max: 2` in squad-implement-worker.md + `checkDispatchWorkflowSchemas()` static gate + 6 tests. All tests verified to fail against pre-fix state. CI run 32410579973 confirms gate active. PR #1777 green, awaiting Flight gate. `max: 2` is the worker's outbound budget; Procedures' guard is squad.md's inbound validation β€” complementary layers. + +## 2026-08-22 β€” gh-aw triage team update + +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): EECOM is in flight on #1793 phantom CRLF diffs causing stuck sessions in sub-session 5cba11df-facd-44c9-a1d9-437259728019. Related context: coordinator must avoid broad staging while the CRLF issue exists. + +## πŸ“Œ Team update β€” 2026-08-22T18:25:00-07:00 + +PR #1831 merged as `9378a379` for #1793. EECOM shipped local CRLF working-tree detection/repair, resolved three Copilot review threads, and captured the follow-on principle that gate remediation/verification instructions must cover the same artifact set as the check itself. \ No newline at end of file diff --git a/.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md b/.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md index 9c88ff7c0..f3a333a97 100644 --- a/.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md +++ b/.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md @@ -249,3 +249,121 @@ Reviewed 9 community PRs (8 from tamirdresher, 1 from eric-vanartsdalen). Key fi **Learning:** Community contributors consistently struggle with two things: (a) scoped npm package names in changesets, and (b) monorepo file placement. Both are preventable with better contributor docs. + + +--- + + + +# Fido history + +Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. +Full pre-summary history archived at `.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md`. + +## 2026-08-20 β€” #1732 compile gate shipped + +- **Defect confirmed:** `gh aw compile` was never a real CI gate. `test/gh-aw-quality.test.ts:978` uses `it.skipIf(!ghAwAvailable)` and `squad-ci.yml` never installed `gh-aw`, so the test always skipped in CI. +- **Fix:** Added `gh extension install github/gh-aw` step to the `test` job in `.github/workflows/squad-ci.yml`, immediately before Build. Reason: the test lives in `npm test` β€” wiring it into `squad-workflow-lint.yml` (which never runs `npm test`) would accomplish nothing. +- **Non-skippability verified locally:** (1) passing case: `gh aw compile --strict` on intact workflows exits 0; (2) break test: removed `squad-implement-worker.md` from temp workspace β†’ compile exited 1 with "dispatch-workflow validation failed: workflow 'squad-implement-worker' not found" β†’ gate fails as expected. +- **Issue split noted:** Prompt-budget gate already shipped (test:637-669). String-assertion replacement too vague β€” both closed without implementing. +- **Rule 5:** This gate fails if `gh aw compile --strict` exits non-zero β€” e.g., missing dispatch target, invalid frontmatter, or any `gh-aw` strict validation error. + +## Condensed signals + +- Quality gate authority for all PRs. Test assertion arrays (EXPECTED_GUIDES, EXPECTED_FEATURES, EXPECTED_SCENARIOS, etc.) MUST stay in sync with files on disk. When reviewing PRs with CI failures, always check if dev branch has the same failures β€” don't block PRs for pre-existing issues. 3,931 tests passing, 149 test files, ~89s runtime. +- πŸ“Œ **Team update (2026-03-26T06:41:00Z β€” Crash Recovery Execution & Community PR Review):** Post-CLI crash recovery completed: Round 1 baseline verified (5,038 tests βœ… green), Round 2 executed duplicate closures (#605/#604/#602) and 9-PR community batch review. FIDO approved 3 PRs (#625 notification-routing, #603 Challenger agent, #608 security policyβ€”merged via Coordinator) and issued change requests on 6 PRs identifying systemic issues: changeset package naming (4 PRs used unscoped `squad-cli` instead of `@bradygaster/squad-cli`); file paths (2 PRs placed files at root instead of correct package structure). Quality gate result: high-bar community acceptanceβ€”approved 3/9 (33%), change-request 6/9 (67%), 0 rejections. PR #592 (legacy, high-quality) also merged. All actions complete; dev branch remains green. +- πŸ“Œ **Team update (2026-03-25T15:23Z β€” Triage Session & PR Review Batch):** FIDO reviewed 10 open PRs for quality and merge readiness. Identified 3 duplicate/overlap pairs consolidating 6 PRs into 4: #607 (retro enforcement, comprehensive) approved for merge, #605 closed as duplicate. #603 (Challenger agent, correct paths) approved, #604 closed as duplicate. #606 (tiered memory superset) approved, #602 closed as duplicate. Merge-ready: #611 (blocked on #610), #592 (joniba wiring guide, high-quality). Decisions merged. +- ### Test Assertion Sync Discipline +- EXPECTED_* arrays in docs-build.test.ts must match filesystem reality. When PRs add new content files, verify the corresponding test arrays are updated. Consider dynamic discovery pattern (used for blog posts) for resilience against content additions. Stale assertions that block CI are FIDO's responsibility. **Fixed PR #331:** EXPECTED_SCENARIOS expanded to 25 entries, EXPECTED_FEATURES array created with 32 entries (commit 6599db6). +- πŸ“Œ **Team update (2026-03-26T06:41:00Z β€” Crash Recovery Execution & Community PR Review):** Post-CLI crash recovery completed: Round 1 baseline verified (5,038 tests βœ… green), Round 2 executed duplicate closures (#605/#604/#602) and 9-PR community batch review. FIDO approved 3 PRs (#625 notification-routing, #603 Challenger agent, #608 security policyβ€”merged via Coordinator) and issued change requests on 6 PRs identifying systemic issues: changeset package naming (4 PRs used unscoped `squad-cli` instead of `@bradygaster/squad-cli`); file paths (2 PRs placed files at root instead of correct package structure). Quality gate result: high-bar community acceptanceβ€”approved 3/9 (33%), change-request 6/9 (67%), 0 rejections. PR #592 (legacy, high-quality) also merged. All actions complete; dev branch remains green. Decision inbox merged and deleted. Next: Monitor 6 change-request PRs for author responses. +- πŸ“Œ **Team update (2026-03-25T15:23Z β€” Triage Session & PR Review Batch):** FIDO reviewed 10 open PRs for quality and merge readiness. Identified 3 duplicate/overlap pairs consolidating 6 PRs into 4: #607 (retro enforcement, comprehensive) approved for merge, #605 closed as duplicate (less comprehensive). #603 (Challenger agent, correct paths) approved for merge, #604 closed as duplicate (wrong file paths). #606 (tiered memory superset, 3-tier model) approved for merge, #602 closed as duplicate (narrower 2-tier scope). Merge-ready PRs identified: #611 (blocked on #610), #592 (joniba wiring guide, high-quality). Draft #567 not ready. Impact: reduces PR count from 10 to 7, eliminates file conflicts, preserves unique value. All other PRs (#611, #608, #592, #567) can proceed independently. Decisions merged to decisions.md and decisions inbox deleted. +- EXPECTED_* arrays in docs-build.test.ts must match filesystem reality. When PRs add new content files, verify the corresponding test arrays are updated. Consider dynamic discovery pattern (used for blog posts) for resilience against content additions. Stale assertions that block CI are FIDO's responsibility. +- Verdict scale: GO (merge), FAIL (block until fixed), NO-GO (reject). Always verify: test discipline (assertions synced), CI status (distinguish pre-existing vs new failures), content accuracy, cross-reference validity. When detecting CI failures, run baseline comparison (dev branch vs PR branch) to isolate regressions. +- Tests reading live .squad/ files must assert structure/behavior, not specific agent names. Names change during team rebirths. Two test classes: live-file tests (survive rebirths, property checks) and inline-fixture tests (self-contained, can hardcode). +- cli-command-wiring.test.ts prevents "unwired command" bug: verifies every .ts file in commands/ is imported in cli-entry.ts. Bidirectional validation. +- `test/init-scaffolding.test.ts` β€” 15 tests: casting directory scaffolding (verifies .squad/casting/ + all 3 JSON files), no-remote resilience (init succeeds without git remote), doctor validation after init (zero failures). Follows existing test conventions β€” vitest, randomBytes temp dirs in cwd, compiled dist imports. + +## 2026-08-20: #1732 triage + E2E readiness gate analysis + +- Audited #1732 ("Make gh aw compile non-skippable, add prompt-budget gate, replace string-assertion workflow tests") as part of gh-aw wave cleanup before E2E day. +- **Compile gate gap confirmed:** `gh aw compile` is completely absent from CI. The test at `test/gh-aw-quality.test.ts:978` uses `it.skipIf(!ghAwAvailable)` β€” `gh aw` is not installed in the CI `test` job, so this test always skips in CI. Zero lock.yml files exist in the repo. +- **Prompt-budget gate already done:** `test/gh-aw-quality.test.ts:637-669` enforces 100 KB ceiling + >5 KB headroom guard via `npm test`. +- **String-assertion concern is mostly resolved:** Tests use parser helpers (extractFrontmatter, extractSafeOutputs, extractModeTable, extractInlineSkills) throughout. Some `.toContain()` calls exist but target specific contract values, not fragile substrings. +- **`gh aw compile --no-emit --dir workflows` exits 1** (expected: dispatch-workflow cross-references require `.github/workflows/` layout; the test correctly mirrors that in a temp workspace). +- Verdict: Split #1732. Ship only the CI install step. Close prompt-budget item. Defer/close string-assertion item. +- Decision record filed: `.squad/decisions/inbox/fido-1732-compile-gate-triage.md` + +## 2026-08-20 (second follow-up): Runbook corrected for post-#1777 dispatch semantics + +- EECOM landed PR #1777 fixing #1772 via `dispatch-workflow: max: 2` in `squad-implement-worker.md`. +- Post-fix, **2 dispatch_workflow entries is the EXPECTED healthy state** β€” empty probe + real dispatch. + Previous runbook said "2 entries = bug". That was inverted. Fixed. +- Verified empirically against real runs: + - run 32394811753 (post-#1777): `{ "type": "dispatch_workflow" }` (empty probe) + `{ ..., "workflow_name": "squad", "inputs": { "command": "implement", "issue_number": "5" } }` β†’ 1 well-formed, 1 malformed β†’ βœ… PASS + - run 32316227601 (wrong-schema failure): `{ "type": "dispatch_workflow", "command": "implement", "issue_number": "5" }` (fields at top level, no `inputs` wrapper, no `workflow_name`) β†’ 0 well-formed, 1 malformed β†’ ❌ FAIL +- Three empirically observed malformed shapes: empty probe (no fields besides `type`), wrong schema (top-level fields), 0 entries. +- Updated `e2e-capture-runbook.md` Step 3 to use well-formed/malformed classification instead of raw count. +- Conditional note added: if Procedures ships a guard in squad.md that rejects empty dispatches, a "dispatch rejected" comment will appear on the triggering issue β€” Brady should check for it, but it may not exist yet. +- All PowerShell one-liners smoke-tested against real downloaded artifacts; both verdicts printed correctly. + +- Verified `gh aw logs` artifact sets: activation, agent, all, detection, evals, experiment, firewall, github-api, mcp, usage. Default (`usage`) is compact summary only β€” `--artifacts all` needed for full diagnostic. +- `gh aw audit --parse` generates Markdown reports from agent logs. Key command for post-run diagnosis. +- `safe_output.jsonl` is the canonical artifact for verifying gh-aw structured data contracts. It's uploaded as a GH Actions artifact with default 90-day retention β€” survives but requires `gh run download` to persist locally. +- Confirmed: `gh run list` JSON fields are `databaseId`, `conclusion`, `url`, `startedAt`, `workflowName`. Flag is `--json fields` not `--json`. +- Wrote Part 2 (evidence capture protocol), Part 1 (what survives vs evaporates), Part 3 (measurability rubric + #1606 rewrite). +- Rubric: 5 rules for measurable criteria in this system. Anti-patterns named: floor-without-semantics, vibe assertions, non-binary criteria, tautological criteria, missing "compared to what." + +## Recent preserved tail + +- **PRs #607 / #605** overlap on retrospective ceremony β€” both add weekly retro ceremony with Ralph enforcement. #607 adds ceremony + enforcement skill + guide (444 lines), #605 modifies existing templates/ceremonies.md + ralph-reference.md (217 lines). Both solve the same problem (retro enforcement) with different file structures. #607 is more comprehensive (includes enforcement guide + pseudocode), #605 is more concise (inline in existing templates). **Verdict: Pick one** β€” recommend #607 (standalone ceremony file is more discoverable). +- **PRs #604 / #603** are complete duplicates β€” both add Challenger agent template + fact-checking skill. #604 has `templates/challenger.md` (153 lines), #603 has `.squad/templates/agents/challenger.md` + `.squad/skills/fact-checking/SKILL.md` (133 lines). File locations differ but content is nearly identical. **Verdict: Close one as duplicate** β€” recommend #603 (file locations match project conventions). +- **PRs #606 / #602** overlap on tiered memory/history β€” #606 adds tiered-memory skill (hot/cold/wiki tiers, 370 lines), #602 adds tiered-history skill (hot/cold split, 158 lines). #606 is broader (3 tiers, scribe integration, spawn templates), #602 is narrower (2 tiers, history.md only). Both cite same production data source. **Verdict: #606 supersedes #602** β€” recommend closing #602 as subset. + +**Quality assessment:** +- **PR #611 (TypeDoc API):** CI passing, large well-scoped PR (1569 additions), includes tests (Playwright), screenshots provided, PAO reviewed. Ready to merge pending PAO's requested fixes (crosslink banner, nav URL simplification). Quality: HIGH. +- **PR #608 (Security policy):** Trivial (28 lines), no tests needed, no CI configured. Adds SECURITY.md with standard vulnerability reporting text. Quality: ACCEPTABLE (minor typo: "timely manor" β†’ "timely manner"). +- **PR #592 (Enforcement wiring):** Well-documented (549 additions), adds missing step to hiring process + 3 appendices. CI passing, no code changes, docs-only. Quality: HIGH. +- **PR #567 (StorageProvider):** DRAFT status, clean implementation (321 additions), 18 tests passing, Wave 1 foundation PR (no call-site migration yet). Quality: HIGH, but keep as DRAFT until Wave 2 ready. + +**CI status:** 9/10 PRs have CI passing. #608 (security policy) has no CI configured on branch "patch-1" (external contributor branch). + +**Test coverage:** +- #611: Playwright tests included (8 tests) +- #607, #605, #604, #603, #606, #602: All docs-only, no tests needed +- #592: Docs-only, no tests needed +- #567: 18 tests included, all passing + +**Overlap resolution needed:** tamirdresher has 6 PRs, 3 pairs have significant overlap. Recommend: merge #607 (not #605), merge #603 (close #604), merge #606 (close #602). + +**Blocking issues:** +- None for mergeability β€” all non-overlapping PRs are technically ready +- Deduplication decision needed for tamirdresher's PRs before merging any of them + +### Community PR Batch Review β€” Post-Crash Recovery (2026-03-26) + +Reviewed 9 community PRs (8 from tamirdresher, 1 from eric-vanartsdalen). Key findings: + +1. **Changeset package name pattern:** 4 of 8 Tamir PRs (#623, #622, #621, #614) use unscoped `"squad-cli"` / `"squad-sdk"` instead of `"@bradygaster/squad-cli"` / `"@bradygaster/squad-sdk"`. Only #625 got this right. This is a recurring community contributor mistake β€” consider adding guidance to CONTRIBUTING.md or PR template. + +2. **File path pattern:** PRs #607 and #606 place files at root `ceremonies/`, `skills/`, `docs/`, `templates/` directories that don't exist. Skills belong in `packages/squad-cli/templates/skills/` and SDK equivalent. Community contributors don't know the monorepo layout. + +3. **Verdicts:** βœ… MERGE: #625 (notification-routing), #603 (Challenger agent), #608 (SECURITY.md). ⚠️ NEEDS CHANGES: #623, #622, #621, #614 (changeset fix), #607, #606 (path restructuring). + +**Learning:** Community contributors consistently struggle with two things: (a) scoped npm package names in changesets, and (b) monorepo file placement. Both are preventable with better contributor docs. + +## πŸ“Œ Team update β€” 2026-08-20T11:59:44-07:00 + +gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: CLOSE 7 issues (#1738,#1762,#1764,#1768,#1763,#1604,#1609); SHIP-NOW 5 (#1772,#1758,#1759,#1732-compile,#1761); 2 contested (#1730,#1756); 12 deferred. Both P0s (#1772,#1758) still real β€” structural defects unresolved. Wave:1 cap=6. Tomorrow is a full-day E2E series against aspiregregator-squad-e2e. E2E will break at S3 if #1772 is not fixed first. + + +## πŸ“Œ Team update β€” 2026-08-20T13:20:20-07:00 + +Batch 2 complete. (1) PR #1775: added `gh extension install github/gh-aw` to squad-ci.yml test job. CI run 32410579973 confirmed compile test ran 894ms, not skipped. (2) Runbook corrections: OneDrive path fixed, 9 `\` paths converted to Join-Path, `>` redirects replaced with Set-Content. Test bar principle applied: tests must fail against the pre-fix state β€” derived from #1766 incident. + + +## πŸ“Œ Team update β€” 2026-08-22T18:25:00-07:00 + +FIDO independently reviewed and reproduced PR #1831 for #1793, approving with nits. Reusable quality techniques preserved: + +- Mutation testing found that a truncating filename parser still returned `fail` and still counted `1 of 1` β€” so a status-only assertion would have passed it clean while reporting a filename that does not exist. Assert that a check *names* the offending artifact, not merely that it fails. +- CI structurally cannot verify a working-tree condition, because CI always starts from a fresh checkout. Such proofs require a local adversarial repro. diff --git a/.squad/agents/fido/history.md b/.squad/agents/fido/history.md index f697a87b6..c566a3061 100644 --- a/.squad/agents/fido/history.md +++ b/.squad/agents/fido/history.md @@ -1,105 +1,19 @@ # Fido history -Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. -Full pre-summary history archived at `.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md`. - -## 2026-08-20 β€” #1732 compile gate shipped - -- **Defect confirmed:** `gh aw compile` was never a real CI gate. `test/gh-aw-quality.test.ts:978` uses `it.skipIf(!ghAwAvailable)` and `squad-ci.yml` never installed `gh-aw`, so the test always skipped in CI. -- **Fix:** Added `gh extension install github/gh-aw` step to the `test` job in `.github/workflows/squad-ci.yml`, immediately before Build. Reason: the test lives in `npm test` β€” wiring it into `squad-workflow-lint.yml` (which never runs `npm test`) would accomplish nothing. -- **Non-skippability verified locally:** (1) passing case: `gh aw compile --strict` on intact workflows exits 0; (2) break test: removed `squad-implement-worker.md` from temp workspace β†’ compile exited 1 with "dispatch-workflow validation failed: workflow 'squad-implement-worker' not found" β†’ gate fails as expected. -- **Issue split noted:** Prompt-budget gate already shipped (test:637-669). String-assertion replacement too vague β€” both closed without implementing. -- **Rule 5:** This gate fails if `gh aw compile --strict` exits non-zero β€” e.g., missing dispatch target, invalid frontmatter, or any `gh-aw` strict validation error. +Summarized by Scribe on 2026-08-22T18:25:00-07:00 because this history exceeded 15KB. +Full pre-summary history appended to `.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md`. ## Condensed signals -- Quality gate authority for all PRs. Test assertion arrays (EXPECTED_GUIDES, EXPECTED_FEATURES, EXPECTED_SCENARIOS, etc.) MUST stay in sync with files on disk. When reviewing PRs with CI failures, always check if dev branch has the same failures β€” don't block PRs for pre-existing issues. 3,931 tests passing, 149 test files, ~89s runtime. -- πŸ“Œ **Team update (2026-03-26T06:41:00Z β€” Crash Recovery Execution & Community PR Review):** Post-CLI crash recovery completed: Round 1 baseline verified (5,038 tests βœ… green), Round 2 executed duplicate closures (#605/#604/#602) and 9-PR community batch review. FIDO approved 3 PRs (#625 notification-routing, #603 Challenger agent, #608 security policyβ€”merged via Coordinator) and issued change requests on 6 PRs identifying systemic issues: changeset package naming (4 PRs used unscoped `squad-cli` instead of `@bradygaster/squad-cli`); file paths (2 PRs placed files at root instead of correct package structure). Quality gate result: high-bar community acceptanceβ€”approved 3/9 (33%), change-request 6/9 (67%), 0 rejections. PR #592 (legacy, high-quality) also merged. All actions complete; dev branch remains green. -- πŸ“Œ **Team update (2026-03-25T15:23Z β€” Triage Session & PR Review Batch):** FIDO reviewed 10 open PRs for quality and merge readiness. Identified 3 duplicate/overlap pairs consolidating 6 PRs into 4: #607 (retro enforcement, comprehensive) approved for merge, #605 closed as duplicate. #603 (Challenger agent, correct paths) approved, #604 closed as duplicate. #606 (tiered memory superset) approved, #602 closed as duplicate. Merge-ready: #611 (blocked on #610), #592 (joniba wiring guide, high-quality). Decisions merged. -- ### Test Assertion Sync Discipline -- EXPECTED_* arrays in docs-build.test.ts must match filesystem reality. When PRs add new content files, verify the corresponding test arrays are updated. Consider dynamic discovery pattern (used for blog posts) for resilience against content additions. Stale assertions that block CI are FIDO's responsibility. **Fixed PR #331:** EXPECTED_SCENARIOS expanded to 25 entries, EXPECTED_FEATURES array created with 32 entries (commit 6599db6). -- πŸ“Œ **Team update (2026-03-26T06:41:00Z β€” Crash Recovery Execution & Community PR Review):** Post-CLI crash recovery completed: Round 1 baseline verified (5,038 tests βœ… green), Round 2 executed duplicate closures (#605/#604/#602) and 9-PR community batch review. FIDO approved 3 PRs (#625 notification-routing, #603 Challenger agent, #608 security policyβ€”merged via Coordinator) and issued change requests on 6 PRs identifying systemic issues: changeset package naming (4 PRs used unscoped `squad-cli` instead of `@bradygaster/squad-cli`); file paths (2 PRs placed files at root instead of correct package structure). Quality gate result: high-bar community acceptanceβ€”approved 3/9 (33%), change-request 6/9 (67%), 0 rejections. PR #592 (legacy, high-quality) also merged. All actions complete; dev branch remains green. Decision inbox merged and deleted. Next: Monitor 6 change-request PRs for author responses. -- πŸ“Œ **Team update (2026-03-25T15:23Z β€” Triage Session & PR Review Batch):** FIDO reviewed 10 open PRs for quality and merge readiness. Identified 3 duplicate/overlap pairs consolidating 6 PRs into 4: #607 (retro enforcement, comprehensive) approved for merge, #605 closed as duplicate (less comprehensive). #603 (Challenger agent, correct paths) approved for merge, #604 closed as duplicate (wrong file paths). #606 (tiered memory superset, 3-tier model) approved for merge, #602 closed as duplicate (narrower 2-tier scope). Merge-ready PRs identified: #611 (blocked on #610), #592 (joniba wiring guide, high-quality). Draft #567 not ready. Impact: reduces PR count from 10 to 7, eliminates file conflicts, preserves unique value. All other PRs (#611, #608, #592, #567) can proceed independently. Decisions merged to decisions.md and decisions inbox deleted. -- EXPECTED_* arrays in docs-build.test.ts must match filesystem reality. When PRs add new content files, verify the corresponding test arrays are updated. Consider dynamic discovery pattern (used for blog posts) for resilience against content additions. Stale assertions that block CI are FIDO's responsibility. -- Verdict scale: GO (merge), FAIL (block until fixed), NO-GO (reject). Always verify: test discipline (assertions synced), CI status (distinguish pre-existing vs new failures), content accuracy, cross-reference validity. When detecting CI failures, run baseline comparison (dev branch vs PR branch) to isolate regressions. -- Tests reading live .squad/ files must assert structure/behavior, not specific agent names. Names change during team rebirths. Two test classes: live-file tests (survive rebirths, property checks) and inline-fixture tests (self-contained, can hardcode). -- cli-command-wiring.test.ts prevents "unwired command" bug: verifies every .ts file in commands/ is imported in cli-entry.ts. Bidirectional validation. -- `test/init-scaffolding.test.ts` β€” 15 tests: casting directory scaffolding (verifies .squad/casting/ + all 3 JSON files), no-remote resilience (init succeeds without git remote), doctor validation after init (zero failures). Follows existing test conventions β€” vitest, randomBytes temp dirs in cwd, compiled dist imports. - -## 2026-08-20: #1732 triage + E2E readiness gate analysis - -- Audited #1732 ("Make gh aw compile non-skippable, add prompt-budget gate, replace string-assertion workflow tests") as part of gh-aw wave cleanup before E2E day. -- **Compile gate gap confirmed:** `gh aw compile` is completely absent from CI. The test at `test/gh-aw-quality.test.ts:978` uses `it.skipIf(!ghAwAvailable)` β€” `gh aw` is not installed in the CI `test` job, so this test always skips in CI. Zero lock.yml files exist in the repo. -- **Prompt-budget gate already done:** `test/gh-aw-quality.test.ts:637-669` enforces 100 KB ceiling + >5 KB headroom guard via `npm test`. -- **String-assertion concern is mostly resolved:** Tests use parser helpers (extractFrontmatter, extractSafeOutputs, extractModeTable, extractInlineSkills) throughout. Some `.toContain()` calls exist but target specific contract values, not fragile substrings. -- **`gh aw compile --no-emit --dir workflows` exits 1** (expected: dispatch-workflow cross-references require `.github/workflows/` layout; the test correctly mirrors that in a temp workspace). -- Verdict: Split #1732. Ship only the CI install step. Close prompt-budget item. Defer/close string-assertion item. -- Decision record filed: `.squad/decisions/inbox/fido-1732-compile-gate-triage.md` - -## 2026-08-20 (second follow-up): Runbook corrected for post-#1777 dispatch semantics - -- EECOM landed PR #1777 fixing #1772 via `dispatch-workflow: max: 2` in `squad-implement-worker.md`. -- Post-fix, **2 dispatch_workflow entries is the EXPECTED healthy state** β€” empty probe + real dispatch. - Previous runbook said "2 entries = bug". That was inverted. Fixed. -- Verified empirically against real runs: - - run 32394811753 (post-#1777): `{ "type": "dispatch_workflow" }` (empty probe) + `{ ..., "workflow_name": "squad", "inputs": { "command": "implement", "issue_number": "5" } }` β†’ 1 well-formed, 1 malformed β†’ βœ… PASS - - run 32316227601 (wrong-schema failure): `{ "type": "dispatch_workflow", "command": "implement", "issue_number": "5" }` (fields at top level, no `inputs` wrapper, no `workflow_name`) β†’ 0 well-formed, 1 malformed β†’ ❌ FAIL -- Three empirically observed malformed shapes: empty probe (no fields besides `type`), wrong schema (top-level fields), 0 entries. -- Updated `e2e-capture-runbook.md` Step 3 to use well-formed/malformed classification instead of raw count. -- Conditional note added: if Procedures ships a guard in squad.md that rejects empty dispatches, a "dispatch rejected" comment will appear on the triggering issue β€” Brady should check for it, but it may not exist yet. -- All PowerShell one-liners smoke-tested against real downloaded artifacts; both verdicts printed correctly. - -- Verified `gh aw logs` artifact sets: activation, agent, all, detection, evals, experiment, firewall, github-api, mcp, usage. Default (`usage`) is compact summary only β€” `--artifacts all` needed for full diagnostic. -- `gh aw audit --parse` generates Markdown reports from agent logs. Key command for post-run diagnosis. -- `safe_output.jsonl` is the canonical artifact for verifying gh-aw structured data contracts. It's uploaded as a GH Actions artifact with default 90-day retention β€” survives but requires `gh run download` to persist locally. -- Confirmed: `gh run list` JSON fields are `databaseId`, `conclusion`, `url`, `startedAt`, `workflowName`. Flag is `--json fields` not `--json`. -- Wrote Part 2 (evidence capture protocol), Part 1 (what survives vs evaporates), Part 3 (measurability rubric + #1606 rewrite). -- Rubric: 5 rules for measurable criteria in this system. Anti-patterns named: floor-without-semantics, vibe assertions, non-binary criteria, tautological criteria, missing "compared to what." - -## Recent preserved tail - -- **PRs #607 / #605** overlap on retrospective ceremony β€” both add weekly retro ceremony with Ralph enforcement. #607 adds ceremony + enforcement skill + guide (444 lines), #605 modifies existing templates/ceremonies.md + ralph-reference.md (217 lines). Both solve the same problem (retro enforcement) with different file structures. #607 is more comprehensive (includes enforcement guide + pseudocode), #605 is more concise (inline in existing templates). **Verdict: Pick one** β€” recommend #607 (standalone ceremony file is more discoverable). -- **PRs #604 / #603** are complete duplicates β€” both add Challenger agent template + fact-checking skill. #604 has `templates/challenger.md` (153 lines), #603 has `.squad/templates/agents/challenger.md` + `.squad/skills/fact-checking/SKILL.md` (133 lines). File locations differ but content is nearly identical. **Verdict: Close one as duplicate** β€” recommend #603 (file locations match project conventions). -- **PRs #606 / #602** overlap on tiered memory/history β€” #606 adds tiered-memory skill (hot/cold/wiki tiers, 370 lines), #602 adds tiered-history skill (hot/cold split, 158 lines). #606 is broader (3 tiers, scribe integration, spawn templates), #602 is narrower (2 tiers, history.md only). Both cite same production data source. **Verdict: #606 supersedes #602** β€” recommend closing #602 as subset. - -**Quality assessment:** -- **PR #611 (TypeDoc API):** CI passing, large well-scoped PR (1569 additions), includes tests (Playwright), screenshots provided, PAO reviewed. Ready to merge pending PAO's requested fixes (crosslink banner, nav URL simplification). Quality: HIGH. -- **PR #608 (Security policy):** Trivial (28 lines), no tests needed, no CI configured. Adds SECURITY.md with standard vulnerability reporting text. Quality: ACCEPTABLE (minor typo: "timely manor" β†’ "timely manner"). -- **PR #592 (Enforcement wiring):** Well-documented (549 additions), adds missing step to hiring process + 3 appendices. CI passing, no code changes, docs-only. Quality: HIGH. -- **PR #567 (StorageProvider):** DRAFT status, clean implementation (321 additions), 18 tests passing, Wave 1 foundation PR (no call-site migration yet). Quality: HIGH, but keep as DRAFT until Wave 2 ready. - -**CI status:** 9/10 PRs have CI passing. #608 (security policy) has no CI configured on branch "patch-1" (external contributor branch). - -**Test coverage:** -- #611: Playwright tests included (8 tests) -- #607, #605, #604, #603, #606, #602: All docs-only, no tests needed -- #592: Docs-only, no tests needed -- #567: 18 tests included, all passing - -**Overlap resolution needed:** tamirdresher has 6 PRs, 3 pairs have significant overlap. Recommend: merge #607 (not #605), merge #603 (close #604), merge #606 (close #602). - -**Blocking issues:** -- None for mergeability β€” all non-overlapping PRs are technically ready -- Deduplication decision needed for tamirdresher's PRs before merging any of them - -### Community PR Batch Review β€” Post-Crash Recovery (2026-03-26) - -Reviewed 9 community PRs (8 from tamirdresher, 1 from eric-vanartsdalen). Key findings: - -1. **Changeset package name pattern:** 4 of 8 Tamir PRs (#623, #622, #621, #614) use unscoped `"squad-cli"` / `"squad-sdk"` instead of `"@bradygaster/squad-cli"` / `"@bradygaster/squad-sdk"`. Only #625 got this right. This is a recurring community contributor mistake β€” consider adding guidance to CONTRIBUTING.md or PR template. - -2. **File path pattern:** PRs #607 and #606 place files at root `ceremonies/`, `skills/`, `docs/`, `templates/` directories that don't exist. Skills belong in `packages/squad-cli/templates/skills/` and SDK equivalent. Community contributors don't know the monorepo layout. - -3. **Verdicts:** βœ… MERGE: #625 (notification-routing), #603 (Challenger agent), #608 (SECURITY.md). ⚠️ NEEDS CHANGES: #623, #622, #621, #614 (changeset fix), #607, #606 (path restructuring). - -**Learning:** Community contributors consistently struggle with two things: (a) scoped npm package names in changesets, and (b) monorepo file placement. Both are preventable with better contributor docs. - -## πŸ“Œ Team update β€” 2026-08-20T11:59:44-07:00 - -gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: CLOSE 7 issues (#1738,#1762,#1764,#1768,#1763,#1604,#1609); SHIP-NOW 5 (#1772,#1758,#1759,#1732-compile,#1761); 2 contested (#1730,#1756); 12 deferred. Both P0s (#1772,#1758) still real β€” structural defects unresolved. Wave:1 cap=6. Tomorrow is a full-day E2E series against aspiregregator-squad-e2e. E2E will break at S3 if #1772 is not fixed first. - +- FIDO owns quality gate authority: distinguish regressions from pre-existing failures, verify assertions cover the actual artifact set, and keep EXPECTED_* arrays synchronized with filesystem reality unless tests dynamically discover content. +- `gh aw compile --strict` became a real CI gate for #1732 only after CI installed `github/gh-aw`; skipped tool-dependent tests are not gates. +- Post-#1777 dispatch health is structural: two dispatch_workflow entries can be expected when one is an empty probe and one is well-formed; classify well-formed vs malformed rather than asserting raw count. +- Community PR reviews repeatedly found scoped package-name mistakes in changesets and monorepo file-placement mistakes; treat both as common contributor risks. +- For docs/live `.squad/` tests, assert behavior and structure rather than specific agent names; rosters change. -## πŸ“Œ Team update β€” 2026-08-20T13:20:20-07:00 +## 2026-08-22 β€” #1831 review reusable techniques -Batch 2 complete. (1) PR #1775: added `gh extension install github/gh-aw` to squad-ci.yml test job. CI run 32410579973 confirmed compile test ran 894ms, not skipped. (2) Runbook corrections: OneDrive path fixed, 9 `\` paths converted to Join-Path, `>` redirects replaced with Set-Content. Test bar principle applied: tests must fail against the pre-fix state β€” derived from #1766 incident. +FIDO independently reviewed and reproduced PR #1831 for #1793, approving with nits. Reusable quality techniques preserved: +- Mutation testing found that a truncating filename parser still returned `fail` and still counted `1 of 1` β€” so a status-only assertion would have passed it clean while reporting a filename that does not exist. Assert that a check *names* the offending artifact, not merely that it fails. +- CI structurally cannot verify a working-tree condition, because CI always starts from a fresh checkout. Such proofs require a local adversarial repro. \ No newline at end of file diff --git a/.squad/agents/flight/history.md b/.squad/agents/flight/history.md index f84b9270e..6ec979d2e 100644 --- a/.squad/agents/flight/history.md +++ b/.squad/agents/flight/history.md @@ -75,3 +75,7 @@ Batch 2: pre-merge gate review of PRs #1775/#1776/#1777/#1778 in progress. All f - πŸ“Œ **Team update (2026-08-21 β€” Agentic-Workflows Audit):** Reviewed PR #1815. Independently re-verified all five of Booster's claims. Resolved git-negation-semantics question (* + !.gitignore correct for flat-file dirs). Judged .github/aw/logs/.gitignore correct placement over root .gitignore rule (colocation beats surviving directory deletion). Squash-merged at 2026-08-21T16:23:46Z. Decision captured in decisions.md: gitignore-colocation. PR #1815 APPROVED + MERGED βœ…. + +## 2026-08-22 β€” gh-aw triage team update + +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): Flight completed Tier 1 gh-aw false-green triage: #1824 #1812 #1801 #1822 #1827 #1825 labeled. Architectural ruling: keep #1801/#1812 independent; do not absorb #1801 into #1757; re-scope #1757 after #1801 lands. diff --git a/.squad/agents/procedures/history.md b/.squad/agents/procedures/history.md index e218a5e74..75b55c78c 100644 --- a/.squad/agents/procedures/history.md +++ b/.squad/agents/procedures/history.md @@ -119,3 +119,7 @@ Tests: `test/gh-aw-plan-lifecycle.test.ts` (23 assertions), incl. a role-leak de **Files modified:** `.github/copilot-instructions.md`, `.copilot/skills/protected-files/SKILL.md` (new). **Pattern:** When trimming agent instructions, extract domain-specific reference content to skills (lazy-loaded on demand) and keep the main instructions file as a routing/workflow document. Skills are the right abstraction for "read this when you touch X" β€” they don't consume tokens until needed. + +## 2026-08-22 β€” gh-aw triage team update + +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): Procedures completed Tier 3 #1729 prompt-architecture triage: sequence #1730+#1731 β†’ #1733 β†’ #1734 β†’ #1736, with #1735 optional. Tier 1 false-green work blocks #1734 and enforcement-facing #1736. Prompt budget remains under the 100 KB ceiling. diff --git a/.squad/agents/sims/history.md b/.squad/agents/sims/history.md new file mode 100644 index 000000000..aeed47047 --- /dev/null +++ b/.squad/agents/sims/history.md @@ -0,0 +1,5 @@ +# Sims history + +## 2026-08-22 β€” gh-aw triage team update + +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): Heads-up for Sims: Flight assigned #1822 in the Tier 1 false-green cluster. Treat it as part of the success/no-op ambiguity repair stream; coordinate with #1801/#1812 outcomes before E2E/runbook assumptions harden. diff --git a/.squad/agents/surgeon/history.md b/.squad/agents/surgeon/history.md index c8794286b..5cce80ed9 100644 --- a/.squad/agents/surgeon/history.md +++ b/.squad/agents/surgeon/history.md @@ -137,3 +137,7 @@ Prepared comprehensive release playbook and CI improvement plan for Brady's revi - Documentation must be user-first (Brady's perspective, not technical jargon) πŸ“Œ **Team update (2026-07-29T17:11:56+10:00 β€” Issue #1556 / PR #1557):** A changeset `.changeset/fix-workflow-shellcheck-quoting.md` (patch, squad-cli + squad-sdk) landed in PR #1557. Separately, a new `squad-workflow-lint` job (`.github/workflows/squad-workflow-lint.yml`) runs actionlint 1.7.12 + shellcheck 0.10.0 on workflow templates β€” this is a distinct check, entirely independent of `changelog-gate`, which only enforces changeset/CHANGELOG requirements and has no role in linting. For future releases, be aware that PRs touching `.github/workflows/`, `.squad-templates/workflows/`, `templates/workflows/`, or either package's `templates/workflows/` will trigger this lint check. Whether `squad-workflow-lint` is configured as a required branch-protection gate has not been verified β€” confirm before treating it as a hard release blocker. + +## 2026-08-22 β€” gh-aw triage team update + +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): Heads-up for Surgeon: Flight assigned #1825 in the Tier 1 false-green cluster. Treat it as release/user-facing safety work connected to silent CLI pin drift; coordinate with Booster on workflow/CI release surfaces. diff --git a/.squad/decisions-archive.md b/.squad/decisions-archive.md index 91815f696..031c88caf 100644 --- a/.squad/decisions-archive.md +++ b/.squad/decisions-archive.md @@ -8171,3 +8171,99 @@ To disable enforcement: commit `dispatchEnforcement: "off"` in `.squad/config.js **By:** RETRO (Security) **What:** Added mandatory Git Safety section to copilot-instructions.md: prohibits staging the entire working tree with a bare-dot `git add` (i.e. `git add` followed by just `.`), requires feature branches and PRs, adds pre-push checklist, defines red-flag stop conditions. **Why:** Incident #631 β€” @copilot used destructive staging on an incomplete working tree, deleting 361 files. + + +--- + + + +### 2026-08-13: Restore shared ancestry between dev and main via merge, dev-wins conflict policy + +#### Context + +`dev` and `main` had unrelated git histories. `dev`'s root commit (`4c5772c5`, a +dependabot bump dated 2026-07-13) shares no ancestor with `main`'s root +(`f4830e48`, 1722 commits). `dev` itself has 196 commits. `git merge-base +upstream/dev upstream/main` returned nothing and `git merge-tree` refused +outright. This made the v0.12.0 promotion PR (#1698, `dev` -> `main`) flatly +unmergeable, with no way to review a normal diff. The v0.11.0 promotion +(2026-06-29) predates the July 13 reset, which is why it worked and why +#1698 was the first to hit this wall. + +#### Decision + +Merge `upstream/main` into `dev` with `--allow-unrelated-histories`, resolving +every one of the 275 conflicts in `dev`'s favor, on a new branch +`squad/restore-main-ancestry`, landed via PR #1699 into `dev`. + +Rejected alternative: rebasing `dev` onto `main`. `dev` carries a +`non_fast_forward` ruleset that blocks the force-push a rebase requires, and a +rebase would rewrite all 196 commits on `dev`, invalidating every PR currently +open against it. A merge is additive only and needs no force-push. + +#### Why dev-wins conflict resolution is safe + +All 275 conflicts were `add/add` (identical path on both branches, no common +base to 3-way merge from). Resolved every one with `git checkout --ours` (dev's +content). This is safe because the only `main`-only code fix that mattered, +#1415 (`tools: ['*']` in `.github/agents/squad.agent.md`), was verified already +present on `dev` before starting the merge, so dev-wins loses zero code. +Verified the resolution was a true no-op against dev's pre-merge tree: diffing +all 275 resolved files plus the 48 removed changesets plus the 6 auto-merged +files against dev's HEAD showed only 18 real changes total, exactly the +files deliberately kept (see below). Confirmed unchanged post-merge: +`package.json` / `packages/squad-cli/package.json` / `packages/squad-sdk/package.json` +(all `0.12.0`), `CHANGELOG.md` (`## [0.12.0] - 2026-08-12` intact), +`test/gh-aw-quality.test.ts` (#1697 fix intact), `workflows/squad.md` and +`workflows/squad-implement-worker.md` (#1682 feature intact). + +#### What was restored (kept from main, lost in the July 13 reset) + +7 docs pages: +- docs/src/content/blog/015-wave-2-the-repl-moment.md +- docs/src/content/blog/032-v010-stabilisation-insider.md +- docs/src/content/blog/033-swe-bench-lite-results.md +- docs/src/content/docs/features/remote-control.md +- docs/src/content/docs/get-started/choosing-your-path.md +- docs/src/content/docs/guide/personal-squad.md +- docs/src/content/docs/guide/shell.md + +5 decision records: +- .squad/decisions/inbox/booster-ci-deletion-guard.md +- .squad/decisions/inbox/booster-release-skill-v094.md +- .squad/decisions/inbox/flight-versioning-policy.md +- .squad/decisions/inbox/procedures-fix-coordinator-inline-dispatch-gate.md +- .squad/decisions/inbox/retro-copilot-git-safety.md + +Plus 6 files that auto-merged cleanly via a genuine 3-way merge (not a +conflict), appending older history from main onto dev's existing content with +no loss on either side: `.squad/agents/{eecom,fido,flight,pao,procedures}/history.md` +and `.squad/decisions.md`. + +#### What was dropped + +48 `.changeset/*.md` files that arrived from `main`. These are spent: their +content is already consumed into `CHANGELOG.md`'s `[0.12.0]` entry, and +re-adding them risked tripping the Changeset Drift check. `.changeset/` after +this merge contains exactly what `dev` had before: `README.md`, +`config.json`, `max-reasoning-effort.md`. + +#### Validation + +Static/diff verification was thorough (see above). Dynamic validation +(`npm run build`, `npx vitest run`) could **not** be executed in this sandbox: +the corporate npm proxy does not mirror `eslint-plugin-n@18.3.0` (its cache +tops out at 18.2.2) and there is no direct route to the public npm registry +from this environment. Confirmed unrelated to the merge: +`package-lock.json`'s staged content is byte-identical to dev's pre-merge +HEAD, and this exact dependency/version was already in dev's lockfile before +any of this work. CI (which has full registry access) is the source of truth +for build/test validation on PR #1699. + +#### Outcome + +`git merge-base upstream/main` now succeeds, confirming `dev` +has a real common ancestor with `main` again. This unblocks PR #1698 and +prevents the same failure on future promotions, provided the new release-process +skill gate (verify `git merge-base dev main` before starting release-prep) is +followed going forward. diff --git a/.squad/decisions.md b/.squad/decisions.md index 2ece6a429..423f6bf5e 100644 --- a/.squad/decisions.md +++ b/.squad/decisions.md @@ -367,98 +367,6 @@ The recommendation does not weaken the no-write zones covered by `excluded-files These are high-impact, recurring failure modes. Documenting them in the skill files ensures every agent (human or AI) working on releases has the knowledge to avoid repeating the v0.9.4 delays. The GITHUB_TOKEN limitation in particular is non-obvious and would catch any future release. - -### 2026-08-13: Restore shared ancestry between dev and main via merge, dev-wins conflict policy - -#### Context - -`dev` and `main` had unrelated git histories. `dev`'s root commit (`4c5772c5`, a -dependabot bump dated 2026-07-13) shares no ancestor with `main`'s root -(`f4830e48`, 1722 commits). `dev` itself has 196 commits. `git merge-base -upstream/dev upstream/main` returned nothing and `git merge-tree` refused -outright. This made the v0.12.0 promotion PR (#1698, `dev` -> `main`) flatly -unmergeable, with no way to review a normal diff. The v0.11.0 promotion -(2026-06-29) predates the July 13 reset, which is why it worked and why -#1698 was the first to hit this wall. - -#### Decision - -Merge `upstream/main` into `dev` with `--allow-unrelated-histories`, resolving -every one of the 275 conflicts in `dev`'s favor, on a new branch -`squad/restore-main-ancestry`, landed via PR #1699 into `dev`. - -Rejected alternative: rebasing `dev` onto `main`. `dev` carries a -`non_fast_forward` ruleset that blocks the force-push a rebase requires, and a -rebase would rewrite all 196 commits on `dev`, invalidating every PR currently -open against it. A merge is additive only and needs no force-push. - -#### Why dev-wins conflict resolution is safe - -All 275 conflicts were `add/add` (identical path on both branches, no common -base to 3-way merge from). Resolved every one with `git checkout --ours` (dev's -content). This is safe because the only `main`-only code fix that mattered, -#1415 (`tools: ['*']` in `.github/agents/squad.agent.md`), was verified already -present on `dev` before starting the merge, so dev-wins loses zero code. -Verified the resolution was a true no-op against dev's pre-merge tree: diffing -all 275 resolved files plus the 48 removed changesets plus the 6 auto-merged -files against dev's HEAD showed only 18 real changes total, exactly the -files deliberately kept (see below). Confirmed unchanged post-merge: -`package.json` / `packages/squad-cli/package.json` / `packages/squad-sdk/package.json` -(all `0.12.0`), `CHANGELOG.md` (`## [0.12.0] - 2026-08-12` intact), -`test/gh-aw-quality.test.ts` (#1697 fix intact), `workflows/squad.md` and -`workflows/squad-implement-worker.md` (#1682 feature intact). - -#### What was restored (kept from main, lost in the July 13 reset) - -7 docs pages: -- docs/src/content/blog/015-wave-2-the-repl-moment.md -- docs/src/content/blog/032-v010-stabilisation-insider.md -- docs/src/content/blog/033-swe-bench-lite-results.md -- docs/src/content/docs/features/remote-control.md -- docs/src/content/docs/get-started/choosing-your-path.md -- docs/src/content/docs/guide/personal-squad.md -- docs/src/content/docs/guide/shell.md - -5 decision records: -- .squad/decisions/inbox/booster-ci-deletion-guard.md -- .squad/decisions/inbox/booster-release-skill-v094.md -- .squad/decisions/inbox/flight-versioning-policy.md -- .squad/decisions/inbox/procedures-fix-coordinator-inline-dispatch-gate.md -- .squad/decisions/inbox/retro-copilot-git-safety.md - -Plus 6 files that auto-merged cleanly via a genuine 3-way merge (not a -conflict), appending older history from main onto dev's existing content with -no loss on either side: `.squad/agents/{eecom,fido,flight,pao,procedures}/history.md` -and `.squad/decisions.md`. - -#### What was dropped - -48 `.changeset/*.md` files that arrived from `main`. These are spent: their -content is already consumed into `CHANGELOG.md`'s `[0.12.0]` entry, and -re-adding them risked tripping the Changeset Drift check. `.changeset/` after -this merge contains exactly what `dev` had before: `README.md`, -`config.json`, `max-reasoning-effort.md`. - -#### Validation - -Static/diff verification was thorough (see above). Dynamic validation -(`npm run build`, `npx vitest run`) could **not** be executed in this sandbox: -the corporate npm proxy does not mirror `eslint-plugin-n@18.3.0` (its cache -tops out at 18.2.2) and there is no direct route to the public npm registry -from this environment. Confirmed unrelated to the merge: -`package-lock.json`'s staged content is byte-identical to dev's pre-merge -HEAD, and this exact dependency/version was already in dev's lockfile before -any of this work. CI (which has full registry access) is the source of truth -for build/test validation on PR #1699. - -#### Outcome - -`git merge-base upstream/main` now succeeds, confirming `dev` -has a real common ancestor with `main` again. This unblocks PR #1698 and -prevents the same failure on future promotions, provided the new release-process -skill gate (verify `git merge-base dev main` before starting release-prep) is -followed going forward. - ### 2026-08-19: Squad protected-files policy **Date:** 2026-08-19T13:11:34.130-07:00 **By:** Flight @@ -603,3 +511,171 @@ When implementation happens, update the workflow source and recompile the instal **By:** Flight + FIDO (batch 2) **What:** A test that passes while the system is broken is decoration, not a gate. Derived from #1766, which shipped prompt-wording-only with a test that passed throughout the broken period. Applied to #1777 and #1778: each test was verified to fail against the pre-fix state. Also applies to pinning tests: a pin that reads one side as ground truth and regenerates from it is decoration, not a gate. **Why:** Establishes a reusable quality bar for this workstream going forward. + +--- + +### 2026-08-22: gh-aw Tier 2 triage β€” workflow generation +**By:** Booster (CI/CD), requested by bradygaster +**What:** Labeled #1556 as `workflows`, `type:bug`, `priority:p1`, `wave:1-next`, `squad:booster`, `triaged`, `go:spec-ready`; labeled #1493 as `workflows`, `type:bug`, `priority:p1`, `wave:1-next`, `squad:booster`, `triaged`, `go:spec-ready`; labeled #1502 as `workflows`, `type:rfc`, `priority:p2`, `wave:2-soon`, `squad:booster`, `triaged`, `go:needs-research`. Posted crash-proof triage briefs on all three. PR #1709 partially addresses #1493 with a `.local-backup` preservation path and green-but-stale checks; recommendation is request changes for user-facing docs and a rebase/rerun before merge. #1827 is genuinely separate from #1556: #1827 is gh-aw `.lock.yml` compiler/actionlint schema output from `workflows/*.md`, while #1556 is conventional YAML templates copied by `squad upgrade`; they share only the generated-YAML linting theme. +**Why:** The implementation surfaces are easy to confuse. `workflows/*.md` and `workflows/shared/*.md` are gh-aw source files that compile to lock files, while #1493/#1556/#1502 primarily target CLI/SDK conventional workflow templates under `packages/squad-cli/templates/workflows/`, `packages/squad-sdk/templates/workflows/`, and the upgrade/generator code that writes `.github/workflows/*.yml`. #1502 spans configuration design, SDK parity, and checkout security validation, so it needs an RFC/design pass before implementation. #1493 already has PR #1709, but the issue acceptance includes docs; stale CI should be refreshed rather than treated as a genuine failure. + +--- + +### 2026-08-22: `.squad/` must not be gitignored + +**By:** bradygaster (via Copilot) + +**What:** The `.squad/` folder must not be hidden from git. Team state β€” decisions, +history, logs, orchestration records, casting, archives β€” is authoritative project data +and belongs in version control. + +**Standing rule:** No Squad command may write `.squad/` into any git ignore surface +(`.gitignore`, `.git/info/exclude`, or global excludes). + +**Why:** Two independent mechanisms were hiding it, and the second caused real data loss. + +1. **`.git/info/exclude` pollution (#1826, #1817).** `squad consult` writes `.squad/` and + `.github/agents/squad.agent.md` to the exclude file + (`packages/squad-sdk/src/sharing/consult.ts:447`). It resolves the path with + `git rev-parse --git-path info/exclude`, which from *any* worktree returns the shared + common dir β€” verified as `C:/src/squad/.git/info/exclude`. One consult run therefore + poisons the main checkout and every sibling worktree simultaneously. + + The failure is silent and progressive: files already tracked stay tracked, so the repo + looks healthy, while every *new* `.squad/` file becomes invisible. + +2. **`.gitignore` entries (#1823).** `.squad/log/`, `.squad/orchestration-log/`, + `.squad/decisions/inbox/`, and `.squad/sessions/` are ignored repo-wide, which is why + Scribe logging has never worked in a clean clone. + +**Data loss recovered:** Removing the exclude entries surfaced +`.squad/archive/2026-08-20-decisions-archive.md` (7,513 bytes, 6 decision entries) and +`.squad/agents/sims/history.md`, both untracked since 2026-08-20. Spot-checking three +archived entries β€” "Copilot git safety rules", "Dispatch Enforcement β€” Stop Coordinator +From Doing Domain Work Inline", and "Workflow templates linted via explicit actionlint +file paths" β€” confirmed none are present in the tracked `.squad/decisions.md`. They +existed only on one machine and would not have survived a clean clone. + +This is precisely the failure the Scribe ARCHIVAL SAFETY RULES describe: moving content +into an untracked destination is a deletion, not an archive (#1774, #1783, #1760). + +**Standing corollary:** Scribe must verify an archival destination is tracked +(`git ls-files --error-unmatch `) before moving any content into it. + +**Follow-on risk:** `.squad/decisions.md` is 51,819 bytes, over the 51,200-byte hard gate. +The next Scribe run will attempt archival again and will repeat the loss unless the ignore +surfaces are fixed first. + +--- + +### 2026-08-22: gh-aw Tier 1 triage β€” false-green cluster +**By:** Flight (Lead), requested by bradygaster +**What:** Keep #1801 and #1812 independent: #1801 owns the validation/template false-green and deterministic artifact checks; #1812 owns `plan activate` reading/reporting the wrong roster. Do not absorb #1801 into #1757. Re-scope #1757 to the later adversarial-quality pass after #1801's deterministic gate repair lands. +**Why:** The shared thesis is "success and no-op are indistinguishable without independent verification," but the repair surfaces differ. E4 showed `plan validate` can read `.squad/team.md` correctly while `plan activate` reports the default `lead/reviewer/devrel/security/docs` roster, so #1812 is stage-local and not blocked by #1801. #1801 is a concrete bug with a red-today check: literal pre-filled verdict cells and fail-open parsing. #1757 remains valuable, but it is broader product behavior; mixing it with #1801 would let subjective adversarial prompting mask a deterministic gate that must fail against recorded bad artifacts. + +--- + +### 2026-08-22: gh-aw Tier 3 triage β€” /squad review epic sequencing +**By:** Procedures (Prompt Engineer), requested by bradygaster +**What:** Sequenced the /squad review chain as #1730 + #1731 β†’ #1733 β†’ #1734 β†’ #1736, with #1735 optional after #1733. Kept the epic and phase issues in wave:3-later because none of the Tier 1 false-green work depends on /squad review landing first. Marked #1734, and enforcement-facing #1736 work, as blocked on #1824, #1812, #1801, #1822, #1827, and #1825. Prompt-budget projection: only #1730 should add router text to workflows/squad.md, estimated +1–2 KB over the current 62,398 B, leaving roughly 35.6–36.6 KB under the 100 KB ceiling. +**Why:** A required review check would be unsafe while gh-aw still has known success/no-op ambiguity: green no-op cast, false provenance, pre-filled validation βœ…, dead runbook queries, invalid generated .lock.yml, and silent CLI pin drift. Keeping review advisory until those land avoids creating a permanently red or blind gate, which would be equivalent to no gate. The prompt budget stays viable only if review and remediation remain separate workflows rather than being folded into the monolithic router prompt. + +--- + +### 2026-08-22: CRLF working-tree repair (#1793) +**By:** EECOM (Core Dev), requested by bradygaster + +**What:** Two additions plus one shared detector. + +- **Remediation command:** `npm run fix:crlf` (`node scripts/fix-crlf-worktree.mjs`). It finds every path pinned `eol=lf` whose working file is `w/crlf`, excludes any path with a real content difference from the index, rewrites the rest with `git checkout-index -f`, then **re-measures** and reports anything that survived. +- **Doctor rule:** `working tree line endings` in `squad doctor` β€” fails when any `eol=lf`-pinned file is CRLF on disk, names the files, and prints the repair command. Returns `undefined` (not applicable) outside a git repo or when nothing is pinned. +- **Shared detector:** `listWorktreeCrlf` / `listContentModified` exported from the existing `scripts/check-shebang-eol.mjs`, which already owns this invariant family, rather than a third parallel implementation. + +**Why this shape over a repo-wide renormalize:** + +- `git add --renormalize .` rewrites the **index**, which is the opposite side of the defect β€” the files on disk are the problem, and their blobs are already correct. It would also sweep 95 CRLF-storing `.ts` blobs into one line-ending churn commit, which `.gitattributes` documents as a deliberate exclusion. The repair must produce **no commit at all**; it is something a developer runs locally. +- `git checkout -- ` is not sufficient. In this state the file is content-clean: git's checkin filter normalizes the CRLF away, so the cleaned blob equals the index blob exactly (verified β€” identical SHAs, empty `git diff`). Git therefore has nothing to restore and can no-op, which is precisely why the condition is so durable. `git checkout-index -f` writes from the index unconditionally and is the primitive that actually repairs it. It is safe here only because it is gated on "no content difference". +- The working-tree invariant is **deliberately not wired into `scripts/check-shebang-eol.mjs`'s CI gate.** CI always has a fresh checkout, so a working-tree assertion there could never observe the failure it exists to catch β€” a permanently green gate is equivalent to no gate (per the 2026-08-20 test bar). The condition is local-only by nature, so it belongs in `squad doctor`, which runs on the developer's actual disk. + +**Verification (the check was proven capable of failing):** with the three files from #1793 forced to CRLF, `squad doctor` reported `❌ 3 of 173 LF-pinned file(s) still have CRLF on disk` and the three suites collapsed from 29 tests to 6 (5 failed). After `npm run fix:crlf`: `w/crlf` count 0 of 41, doctor `βœ… 173 LF-pinned file(s) all LF on disk`, and 29/29 tests passing. + +**Incidental finding, not fixed here:** `npm run build` dirties the tree as a side effect β€” `scripts/bump-build.mjs` bumps all three `package.json` versions (suppress with `SKIP_BUILD_BUMP=1`) and `scripts/sync-skill-templates.mjs` rewrites two `templates/skills/release-process/SKILL.md` files. Both are real content diffs, not CRLF phantoms, so `git diff --ignore-cr-at-eol` does not filter them and they are easy to stage by accident. + +#### Addendum, 2026-08-22 (post-review, FIDO on #1831) + +Approved with nits; one changed the reasoning enough to record. + +**A verification hint can be under-scoped relative to the check it accompanies β€” and that is the same failure mode as a gate that cannot fail.** The doctor check covers every `eol=lf`-pinned path (174 here), but both remediation messages told the developer to verify with `git ls-files --eol "*.mjs"` (42 paths). A pinned non-`.mjs` file left CRLF would have reported all-clear. The check was correct; the sentence telling you how to confirm it was not, and the sentence is what a developer actually acts on. The 2026-08-20 test bar says a gate that cannot observe failure is equivalent to no gate β€” this extends it: **the instructions a gate prints are part of the gate.** Both hints now point at the check's real scope, and a test asserts the message does not silently re-narrow. + +Two smaller carry-overs, both about claiming only what is true: +- Hardcoded counts drift. The CRLF-storing `.ts` blob figure measured **94** at review time; `.gitattributes:38` still says 95, and my own docs said 173/41 where the tree now reads 174/42 (this PR adds one `.mjs`). Prefer describing a quantity over pinning it unless the exact number is load-bearing. `.gitattributes` left alone deliberately β€” correcting its comment is unrelated churn. +- `fix-crlf-worktree.mjs` batches by **file count**, which bounds argv length only indirectly. Measured rather than assumed: longest tracked path is 80 chars, so a full 200-file batch is ~16K against the 32767 Windows limit, and overflow would need a ~164-character mean path. Explicit length accounting declined, and the comment now says so instead of implying a guarantee. + +Both deliberate non-actions stand: no `git add --renormalize`, no CI gate. + +--- + +### 2026-08-22: FIDO review β€” PR #1831 +**Date:** 2026-08-22 +**Reviewer:** FIDO +**PR:** https://github.com/bradygaster/squad/pull/1831 +**Verdict:** APPROVE WITH NITS + +#### Verification performed + +- Built the PR worktree successfully with `npm run build`. +- Baseline `squad doctor` on the PR worktree reported: + - `working tree line endings β€” 174 LF-pinned file(s) all LF on disk` + - `Summary: 13 passed, 0 failed, 0 warnings, 0 info` +- Forced these three LF-pinned `.mjs` files to CRLF on disk without changing the index: + - `packages/squad-cli/scripts/patch-esm-imports.mjs` + - `scripts/check-changeset-drift.mjs` + - `scripts/promote-insider-tag.mjs` +- Confirmed `git diff --name-only -- ` showed no content diff while `git ls-files --eol` showed `i/lf w/crlf attr/text eol=lf`. +- Poisoned-tree `squad doctor` reported: + - `3 of 174 LF-pinned file(s) still have CRLF on disk` + - named all three files + - `Summary: 12 passed, 1 failed, 0 warnings, 0 info` +- `npm run fix:crlf` repaired all three files and exited 0. +- After repair, `git ls-files --eol -- "*.mjs"` reported `0 of 42` `.mjs` files with `w/crlf`. +- After repair, `squad doctor` returned to `Summary: 13 passed, 0 failed, 0 warnings, 0 info`. +- Guard verification: I added a real content edit plus CRLF to `scripts/promote-insider-tag.mjs`; `npm run fix:crlf` skipped it, exited 1, and preserved the `FIDO_PRECIOUS_GUARD` marker. +- Targeted Vitest run: + - `test/scripts/check-changeset-drift.test.ts`: 8 tests + - `test/promote-insider-tag.test.ts`: 15 tests + - `test/cli/patch-esm-imports.test.ts`: 6 tests + - `test/scripts/crlf-worktree-repair.test.ts`: 13 tests + - total: 42 passed +- `node scripts/check-shebang-eol.mjs` passed: 46 shebanged files pinned to LF, 174 LF-pinned files storing LF blobs. + +#### Judgment + +The primary verification gap is closed: the doctor check observes the dirty working-tree-only state that CI cannot produce, reports it as a failed check, names the stale files, and the remediation repairs them. + +The repair safety guard holds. A content-modified file is detected by `git diff --name-only`, skipped, and not clobbered by `git checkout-index -f`. + +The `check-shebang-eol.mjs` refactor does not weaken the original CI check. Its existing index-based invariants still pass, and the new working-tree detection remains deliberately exported for local doctor/repair rather than wired into CI. + +The new tests assert real behavior, not parser decoration: they first establish the poisoned state, assert the repair result, inspect `git ls-files --eol`, and verify preserved user content for the destructive path. + +Both deliberate non-actions are sound: + +1. No `git add --renormalize .`: correct. This defect is a stale working tree, not bad index blobs. I measured 94 CRLF-storing `.ts` blobs in this PR worktree, so the exact documented 95 count appears stale by one, but the churn argument still holds. +2. No CI gate for the working-tree check: correct. Fresh CI checkout is exactly the condition that masks this class of defect, making such a gate permanently green. + +#### Nits / discrepancies + +- My measured counts differ slightly from EECOM's transcript: 174 LF-pinned files instead of 173, and `0 of 42` `.mjs` files after repair instead of `0 of 41`. This appears explained by the newly added `scripts/fix-crlf-worktree.mjs`, and is not a blocker. +- The `.gitattributes` / CONTRIBUTING rationale says 95 CRLF-storing `.ts` blobs; I measured 94. The rationale remains valid, but the literal count is stale. + +--- + +### 2026-08-22: Gate instructions are part of the gate +**By:** Scribe, from EECOM/FIDO #1793/#1831 +**Extends:** 2026-08-20: Test bar for the gh-aw workstream β€” a test must fail against the pre-fix state + +**What:** The instructions a gate prints are part of the gate. A correct check paired with a remediation or verification command that cannot observe the failure is still a broken gate, because the printed command is what a developer actually runs. + +**Concrete instance:** `squad doctor`'s working-tree check counted all 174 `eol=lf`-pinned paths, but printed `git ls-files --eol "*.mjs"` β€” which covers only 42 of them. A pinned non-`.mjs` file left CRLF would have verified all-clear. + +**Why:** Verification and remediation hints must cover the same artifact set as the check. Otherwise the team has built a check that can fail while teaching developers to run a narrower command that proves nothing. diff --git a/.squad/log/2026-08-22T17-10-52-07-00-gh-aw-triage.md b/.squad/log/2026-08-22T17-10-52-07-00-gh-aw-triage.md new file mode 100644 index 000000000..cfe7f47ff --- /dev/null +++ b/.squad/log/2026-08-22T17-10-52-07-00-gh-aw-triage.md @@ -0,0 +1,23 @@ +# gh-aw triage session + +**Timestamp:** 2026-08-22T17:10:52-07:00 +**Requested by:** bradygaster + +## Summary + +Flight, Booster, and Procedures completed Tiers 1–3 gh-aw defect triage. EECOM is still in flight on #1793 phantom CRLF diffs / stuck sessions in sub-session `5cba11df-facd-44c9-a1d9-437259728019`. + +## Outcomes + +- Flight: labeled #1824, #1812, #1801, #1822, #1827, #1825; ruled #1801 and #1812 independent; #1757 should be re-scoped after #1801 lands. +- Booster: labeled #1556, #1493, #1502; found PR #1709 partially addresses #1493; separated #1827 from #1556 implementation surfaces. +- Procedures: labeled #1729 and #1730/#1731/#1733/#1734/#1735/#1736; sequenced #1730+#1731 β†’ #1733 β†’ #1734 β†’ #1736, #1735 optional; Tier 1 blocks #1734/enforcement-facing #1736. +- EECOM: #1793 fix remains in progress. + +## Scribe health report + +- Pre-check: `.squad/decisions.md` measured 43,426 bytes; inbox count was 4 files: `booster-gh-aw-tier2-triage.md`, `copilot-squad-not-gitignored.md`, `flight-gh-aw-tier1-triage.md`, `procedures-gh-aw-tier3-triage.md`. +- Decision archival: measured under the 51,200-byte 7-day gate; Tier 1 (>20KB) check found 0 entries older than 30 days. No archive move was performed. Move count: 0 removed from source / 0 added to destination. No tracked `.squad/archive/*.md` destination currently exists for future eligible archives. +- Decision inbox merge: 4 removed from inbox / 4 added to decisions.md. No expected inbox files were absent. +- History summarization: not required by measured sizes. Move count for every history file: 0 removed from source / 0 added to destination. +- Recovered files: `.squad/archive/2026-08-20-decisions-archive.md` is missing; `.squad/agents/sims/history.md` was missing before this run and now exists as an untracked new history file. \ No newline at end of file diff --git a/.squad/log/2026-08-22T18-25-00-07-00-1793-crlf-merged.md b/.squad/log/2026-08-22T18-25-00-07-00-1793-crlf-merged.md new file mode 100644 index 000000000..9bb8a7050 --- /dev/null +++ b/.squad/log/2026-08-22T18-25-00-07-00-1793-crlf-merged.md @@ -0,0 +1,15 @@ +# Session log β€” #1793 CRLF merged + +**Timestamp:** 2026-08-22T18:25:00-07:00 +**Requested by:** bradygaster + +- EECOM fixed #1793; PR #1831 merged as `9378a379` after resolving 3 Copilot review threads. +- FIDO independently reviewed and reproduced PR #1831, approving with nits. +- Scribe archived decisions if eligible, merged two decision inbox files, elevated the gate-instructions principle, logged orchestration, and propagated EECOM/FIDO history updates. + +## Health report + +- Decisions archival: 0 removed from source / 0 added to destination. +- Decision inbox: 2 processed. +- History summarization: fido history: 8 removed from source / 8 added to destination +- Decisions archival tier 2: 1 removed from source / 1 added to destination. diff --git a/.squad/orchestration-log/2026-08-22T17-10-52-07-00-booster.md b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-booster.md new file mode 100644 index 000000000..364d70095 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-booster.md @@ -0,0 +1,16 @@ +# Orchestration Log Entry + +--- + +### 2026-08-22T17:10:52-07:00 β€” gh-aw triage / booster + +| Field | Value | +|-------|-------| +| **Agent routed** | Booster (CI/CD) | +| **Why chosen** | Tier 2 CI/release-surface gh-aw defects | +| **Mode** | `background` | +| **Why this mode** | Independent workflow-generation triage thread | +| **Files authorized to read** | GitHub issue/PR metadata for assigned triage scope; repository context as needed | +| **File(s) agent must produce** | GitHub labels/comments only; Scribe records outcomes locally | +| **Outcome** | Completed β€” labeled #1556 #1493 #1502; PR #1709 partially addresses #1493; #1827 and #1556 are separate code paths. | +| **Token usage** | Not reported by coordinator | diff --git a/.squad/orchestration-log/2026-08-22T17-10-52-07-00-eecom.md b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-eecom.md new file mode 100644 index 000000000..aa0b4c020 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-eecom.md @@ -0,0 +1,16 @@ +# Orchestration Log Entry + +--- + +### 2026-08-22T17:10:52-07:00 β€” gh-aw triage / eecom + +| Field | Value | +|-------|-------| +| **Agent routed** | Eecom (Core Dev) | +| **Why chosen** | Isolated fix for #1793 phantom CRLF diffs causing stuck sessions | +| **Mode** | `sub-session` | +| **Why this mode** | Code fix isolated in child session | +| **Files authorized to read** | GitHub issue/PR metadata for assigned triage scope; repository context as needed | +| **File(s) agent must produce** | GitHub labels/comments only; Scribe records outcomes locally | +| **Outcome** | In flight β€” sub-session 5cba11df-facd-44c9-a1d9-437259728019; no result yet. | +| **Token usage** | Not reported by coordinator | diff --git a/.squad/orchestration-log/2026-08-22T17-10-52-07-00-flight.md b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-flight.md new file mode 100644 index 000000000..6f1a727f9 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-flight.md @@ -0,0 +1,16 @@ +# Orchestration Log Entry + +--- + +### 2026-08-22T17:10:52-07:00 β€” gh-aw triage / flight + +| Field | Value | +|-------|-------| +| **Agent routed** | Flight (Lead) | +| **Why chosen** | Tier 1 false-green defects needed architectural rulings on issue merges | +| **Mode** | `background` | +| **Why this mode** | Independent triage thread with no hard data dependency | +| **Files authorized to read** | GitHub issue/PR metadata for assigned triage scope; repository context as needed | +| **File(s) agent must produce** | GitHub labels/comments only; Scribe records outcomes locally | +| **Outcome** | Completed β€” labeled #1824 #1812 #1801 #1822 #1827 #1825; kept #1801/#1812 independent; re-scope #1757 after #1801 lands. | +| **Token usage** | Not reported by coordinator | diff --git a/.squad/orchestration-log/2026-08-22T17-10-52-07-00-procedures.md b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-procedures.md new file mode 100644 index 000000000..75630ce04 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T17-10-52-07-00-procedures.md @@ -0,0 +1,16 @@ +# Orchestration Log Entry + +--- + +### 2026-08-22T17:10:52-07:00 β€” gh-aw triage / procedures + +| Field | Value | +|-------|-------| +| **Agent routed** | Procedures (Prompt Engineer) | +| **Why chosen** | Tier 3 #1729 prompt-architecture epic sequencing | +| **Mode** | `background` | +| **Why this mode** | Independent prompt architecture triage thread | +| **Files authorized to read** | GitHub issue/PR metadata for assigned triage scope; repository context as needed | +| **File(s) agent must produce** | GitHub labels/comments only; Scribe records outcomes locally | +| **Outcome** | Completed β€” labeled #1729 and #1730/#1731/#1733/#1734/#1735/#1736; sequenced review work and flagged Tier 1 blockers. | +| **Token usage** | Not reported by coordinator | diff --git a/.squad/orchestration-log/2026-08-22T18-25-00-07-00-EECOM.md b/.squad/orchestration-log/2026-08-22T18-25-00-07-00-EECOM.md new file mode 100644 index 000000000..104b037a1 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T18-25-00-07-00-EECOM.md @@ -0,0 +1,15 @@ +# Orchestration log β€” EECOM + +**Timestamp:** 2026-08-22T18:25:00-07:00 +**Requested by:** bradygaster + +## Work + +1. Fix #1793 (CRLF working-tree repair) β€” sub-session. + - Outcome: PR #1831 merged as `9378a379`. +2. Address 3 Copilot review threads β€” sub-session. + - Outcome: all resolved; PR merged. + +## Notes + +EECOM's addendum elevated the reusable gate-instructions principle into decisions.md. \ No newline at end of file diff --git a/.squad/orchestration-log/2026-08-22T18-25-00-07-00-FIDO.md b/.squad/orchestration-log/2026-08-22T18-25-00-07-00-FIDO.md new file mode 100644 index 000000000..0b6fe7ef5 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T18-25-00-07-00-FIDO.md @@ -0,0 +1,12 @@ +# Orchestration log β€” FIDO + +**Timestamp:** 2026-08-22T18:25:00-07:00 +**Requested by:** bradygaster + +## Work + +Independent review and repro of PR #1831 β€” background. + +## Outcome + +APPROVE WITH NITS; all reproduced. Reusable findings recorded in FIDO history. \ No newline at end of file From 76e4181afaa4ed7725e020843cb8972bc2c23a5f Mon Sep 17 00:00:00 2001 From: brady gaster Date: Sat, 22 Aug 2026 20:01:39 -0700 Subject: [PATCH 2/6] chore(squad): merge 3 gh-aw decision records, log #1824 wave Merges FIDO's #1832 review, RETRO's shell-input security contract, and Procedures' fail-loud command-parse record into decisions.md (48 -> 56 entries). Adds orchestration + session logs for the wave. Archival correctly skipped: all entries within a 4-day window, none older than the 7-day threshold. eecom/history.md held back pending repair of a dangling archive pointer. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0e20e987-a753-41c4-a6f8-992d863a32cd --- .squad/agents/fido/history.md | 17 +- .squad/agents/procedures/history.md | 12 +- .squad/agents/retro/history.md | 12 +- .squad/decisions.md | 533 +++++++++++++++++- .../2026-08-22T19-42-25-0700-gh-aw-wave-1.md | 56 ++ .../2026-08-22T19-42-25-0700-eecom.md | 56 ++ .../2026-08-22T19-42-25-0700-fido.md | 49 ++ .../2026-08-22T19-42-25-0700-procedures.md | 35 ++ .../2026-08-22T19-42-25-0700-retro.md | 40 ++ 9 files changed, 805 insertions(+), 5 deletions(-) create mode 100644 .squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md create mode 100644 .squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md create mode 100644 .squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md create mode 100644 .squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md create mode 100644 .squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md diff --git a/.squad/agents/fido/history.md b/.squad/agents/fido/history.md index c566a3061..664623a6b 100644 --- a/.squad/agents/fido/history.md +++ b/.squad/agents/fido/history.md @@ -1,4 +1,4 @@ -# Fido history +ο»Ώ# Fido history Summarized by Scribe on 2026-08-22T18:25:00-07:00 because this history exceeded 15KB. Full pre-summary history appended to `.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md`. @@ -16,4 +16,17 @@ Full pre-summary history appended to `.squad/agents/fido/history-archive-2026-08 FIDO independently reviewed and reproduced PR #1831 for #1793, approving with nits. Reusable quality techniques preserved: - Mutation testing found that a truncating filename parser still returned `fail` and still counted `1 of 1` β€” so a status-only assertion would have passed it clean while reporting a filename that does not exist. Assert that a check *names* the offending artifact, not merely that it fails. -- CI structurally cannot verify a working-tree condition, because CI always starts from a fresh checkout. Such proofs require a local adversarial repro. \ No newline at end of file +- CI structurally cannot verify a working-tree condition, because CI always starts from a fresh checkout. Such proofs require a local adversarial repro. +## πŸ“Œ Team update β€” 2026-08-22T19:42:25-07:00 + +Three-turn review of PR #1832 (issue #1824). + +**Pass 1 β€” APPROVE WITH NITS:** Reproduced all claims (mutation 1 & 2 load-bearing, injection-safe via env, acceptance test holds). Nits: HTML comment parsing, greedy last-token, 102 skip figure. + +**Pass 2 β€” MERGE AFTER FIXES:** Adjudicated automated reviewer findings. Finding 2 BLOCKING: bare workflow_dispatch commands regress to loud failure (untested path). Finding 1 NON-BLOCKING but security-critical: assignment step left to LLM discretion. Finding 3 NON-BLOCKING real defect. + +**Pass 3 β€” APPROVE:** Re-reviewed EECOM rework (commit 6e7628c5). PC-0 normalization fixes BLOCKING regression; all 6 dispatch modes resolve; mutations red-and-naming; CI green. PC-0 NR==1 leading-newline latent nit (unreachable via real producers, noted for follow-up). + +**Pattern:** Test incomplete in isolation (dispatch path missed). Reviewer's domain context caught it. New coverage added in revision. + +PR merged; issue closed. \ No newline at end of file diff --git a/.squad/agents/procedures/history.md b/.squad/agents/procedures/history.md index 75b55c78c..3ae20bc4d 100644 --- a/.squad/agents/procedures/history.md +++ b/.squad/agents/procedures/history.md @@ -1,4 +1,4 @@ -# Procedures history +ο»Ώ# Procedures history Summarized by Scribe on 2026-08-20T11:59:44-07:00 because this history exceeded 15KB. Full pre-summary history archived at `.squad/agents/procedures/history-archive-2026-08-20T11-59-44-0700.md`. @@ -123,3 +123,13 @@ Tests: `test/gh-aw-plan-lifecycle.test.ts` (23 assertions), incl. a role-leak de ## 2026-08-22 β€” gh-aw triage team update πŸ“Œ Team update (2026-08-22T17:10:52-07:00): Procedures completed Tier 3 #1729 prompt-architecture triage: sequence #1730+#1731 β†’ #1733 β†’ #1734 β†’ #1736, with #1735 optional. Tier 1 false-green work blocks #1734 and enforcement-facing #1736. Prompt budget remains under the 100 KB ceiling. + +## πŸ“Œ Team update β€” 2026-08-22T19:42:25-07:00 + +Issue #1824 closed. Authored /squad parser hardening (PR #1832) with explicit NO_COMMAND β†’ fail contract. Mutation tests proved load-bearing cases (indented command, mid-sentence). Mutation 2 proved status-only gates miss bad diagnostics. + +FIDO's Pass 2 found BLOCKING dispatch regression (bare command:"implement" β†’ NO_COMMAND β†’ fail; pre-fix worked). Reviewer Rejection Protocol applied: Procedures locked out, EECOM revised. Commit 6e7628c5 added PC-0 normalization layer before PC-1. FIDO Pass 3 verified all mutations green. + +**Lesson:** Mutation testing in isolation can miss callers. FIDO's first pass shared the same frame; the blind spot was enumeration of all parser call paths (command-dispatch path was unexercised in new suite). + +PR #1832 merged; issue #1824 closed. Decision records merged to .squad/decisions.md. \ No newline at end of file diff --git a/.squad/agents/retro/history.md b/.squad/agents/retro/history.md index 6b751355f..f3b75cb7f 100644 --- a/.squad/agents/retro/history.md +++ b/.squad/agents/retro/history.md @@ -1,4 +1,4 @@ -# RETRO +ο»Ώ# RETRO > Retrofire Officer @@ -51,3 +51,13 @@ Fixed a false-positive regression in PR #1559 (`squad/fix-security-scanner-prose - PR #1558 diff (`squad/state-sync-2026-07-29`) β€” scanner returned no findings after fix. **Known follow-up (not fixed here):** `/git\s+add\s+\./` also matches safe scoped dot-prefixed add commands. Separate issue documented in PR body. + +## πŸ“Œ Team update β€” 2026-08-22T19:42:25-07:00 + +Authored normative security contract for PR #1832 (/squad shell input channel). Threat model: GitHub event text fully attacker-controlled. Mandatory channel: env variables + quoted parameter expansion. + +Measured 8 hostile payloads through environment channel (result: injection-safe). Demonstrated direct-interpolation anti-pattern (RCE). Documented forbidden patterns: untrusted command strings, printf format-slot usage, awk program interpolation, awk -v mutation. + +Hop-1 (GitHub Actions template β†’ shell) implementation is LLM discretion; no compiled gh-aw output exists in this repo to verify. Gate verification deferred to #1834. + +Decision record merged to .squad/decisions.md. \ No newline at end of file diff --git a/.squad/decisions.md b/.squad/decisions.md index 423f6bf5e..071184caf 100644 --- a/.squad/decisions.md +++ b/.squad/decisions.md @@ -1,4 +1,4 @@ -# Decisions +ο»Ώ# Decisions > Team decisions that all agents must respect. Managed by Scribe. @@ -679,3 +679,534 @@ Both deliberate non-actions are sound: **Concrete instance:** `squad doctor`'s working-tree check counted all 174 `eol=lf`-pinned paths, but printed `git ls-files --eol "*.mjs"` β€” which covers only 42 of them. A pinned non-`.mjs` file left CRLF would have verified all-clear. **Why:** Verification and remediation hints must cover the same artifact set as the check. Otherwise the team has built a check that can fail while teaching developers to run a narrower command that proves nothing. + + +--- + +### 2026-08-22: FIDO review β€” PR #1832 (closes #1824): fail loudly when /squad parses no command + +### FIDO review β€” PR #1832 (closes #1824): fail loudly when `/squad` parses no command + +**Reviewer:** FIDO (Quality Owner) Β· **Author:** Procedures Β· **Date:** 2026-08-22 +**Verdict:** βœ… **APPROVE WITH NITS** (posted as `COMMENTED` β€” GitHub blocks a formal Approve on an own-account PR) + +This was an adversarial re-derivation, not a read-through. I reproduced every claim independently in the PR worktree +(`bradygaster-silver-engine`) and record measured-vs-assumed below. + +--- + +#### Measured + +##### Baseline +- New suite `test/gh-aw-command-parse.test.ts`: **15/15 pass** on clean branch (Git Bash resolved). +- `gh pr checks 1832`: **all gates green**, including the CI `test` job (5m39s) and `Diff Size Guard`. + +##### Claim 1 β€” Mutation 1 (reintroduce position-0 line anchoring: `/^\/squad/`) β€” VERIFIED, load-bearing +- Applied the mutation (awk regex only). Result: **2 failed / 13 passed.** +- **Headline #1824 case ("prose, blank line, then command") PASSED under the reintroduced bug** β€” confirms the + diagnosis: awk `^` anchors per *record*; `printf` feeds awk line-by-line, so a line-anchored parser still handles a + command on its own line after prose. **The obvious test for #1824 is structurally blind to #1824's own bug.** +- The only catchers were the **indented** and **mid-sentence** cases (2 failures, each naming its specific input). +- **Inverse check:** removed those two cases, kept the mutation β†’ **13/13 GREEN, mutation escapes entirely.** + So the two cases are the *sole* catchers. (I measured **0** catch without them β€” marginally stronger than the + PR body's "1 of 14"; the exact scalar is bookkeeping, the substance is that they are singularly load-bearing.) + +##### Claim 2 β€” Mutation 2 (generic diagnostic: `echo 'unrecognized command'`) β€” VERIFIED (#1793 shape) +- Applied. Result: **3 failed / 12 passed.** +- The three catchers all require the diagnostic to **contain the offending text** / match the sentinel. +- Crucially, the **status-shaped assertions stayed GREEN** β€” "sends NO_COMMAND to PC-3 and forbids fallback" and + "PC-3 fails the run" both passed against the gutted diagnostic. That is exactly the #1793 failure mode: a status-only + gate cannot observe a diagnostic that reports nothing. Content-requiring assertions are what close it. + +##### Claim 3 β€” Independence β€” VERIFIED, not circular +- The test extracts the fenced `bash` block after each PC heading (`bashBlockAfter`) and **executes** it via + `execFileSync(shell, ['-c', cmd])` with the body in env. Mutations 1 & 2 prove it: altering the *declared parser* in + the markdown flipped behavioral verdicts. A broken declared parser makes behavioral cases fail. The test does not + re-read prose to confirm prose. + +##### Claim 4 β€” the `/bin/sh` false-green and the new suite's hard-assert +- `HAS_POSIX_SHELL = existsSync('/bin/sh')` is false on Windows; the two `describe.skipIf(!HAS_POSIX_SHELL)` blocks in + `gh-aw-quality.test.ts` skip. Measured on this host: **13 skipped tests / 28 literal `expect()` / 22 `it` decls** in + those blocks (`it.each` expands further on a POSIX host). **Mechanism confirmed real** β€” a permanently-green gate on + Windows. I could not reproduce the exact figure **102**; that is an expansion/counting convention, not a substantive + disagreement. +- **The important half β€” forced red:** I hard-forced `resolvePosixShell()` to return `null`. New suite went + **13 FAILED / 2 passed**, with the guard test failing loudly ("No POSIX shell found…"). It reports **RED, not a + green skip**, when no shell resolves. Verified by force, not inferred. (The 2 still-green are pure static-markdown + PC-2 checks that need no shell β€” expected.) + +##### Claim 5b β€” #1812 separation β€” spot-checked +- The diff touches only the Parse Command routing section. The `plan activate` hardcoded roster lives in a separate + skill, downstream of routing. No shared code path. This PR does not modify #1812's surface. + +##### My own acceptance test for #1824 β€” could I construct a silent no-op / green-with-no-cast? +Ran the **exact PC-1 and PC-3 commands** from the markdown against hostile bodies (empty, only-fenced-block, HTML +comment, `/squad` in a URL, Cyrillic look-alike, two-per-line, `squadify` near-miss, leading tab, CRLF, quoted, +bare-with-trailing-space, zero-width space, no-slash): +- **Every zero-action body β†’ `NO_COMMAND` β†’ PC-3 loud fail.** No silent no-op, no green-with-no-cast constructible. +- The acceptance bar ("a run that cast no agents must not report success") **holds at the parser layer.** + +--- + +#### Nits (non-blocking) +1. **HTML comment `` parses `cast` and would cast.** Documented "deliberate widening" (surface, + don't silently skip). Defensible, but invisible-in-render comment text triggering a real cast is worth a follow-up + thought. Not a #1824 defect β€” it acts loudly, the opposite of the bug. +2. **Two `/squad` tokens on one line β†’ greedy `sub(/^.*\/squad/,"")` picks the LAST** (`/squad cast … /squad plan` + yields `plan`). An ordering surprise, still a loud action, not a no-op. Rare. Low severity. +3. The `102` skip figure in the PR body isn't reproducible as-stated (I measure 13 skipped tests / 28 expects). Cosmetic. + +#### Residual I cannot close (stated plainly) +PC-2/PC-3's "exit non-zero / never `noop` / comment on the issue" are **prose instructions to an LLM**, not executed +code. The suite verifies (a) the diagnostic *command* emits correct verbatim text and (b) the markdown *declares* the +fail contract. It cannot verify the runtime LLM actually exits non-zero. This is inherent to gh-aw (the parser is a +prompt) and Procedures acknowledged it. The mitigation is that the *observable* diagnostic is now content-bearing and +mutation-sensitive, which is the strongest guarantee available at this layer. + +#### Why APPROVE WITH NITS +Every load-bearing claim reproduced. The suite is mutation-sensitive where it matters (content, not status), fails red +when it cannot run, and is independent of the prose it guards. I tried to build a bypass and could not. The nits are +observations under a documented design decision, not regressions. Ship it; consider a follow-up issue for nit #1/#2 and +for the real `/bin/sh` 102-skip cleanup (out of scope here per Diff Size Guard). + +*β€” FIDO. If it can break, I'll find how. This time I mostly couldn't, and I said so.* + +--- + +### ADDENDUM β€” 2026-08-22 (adjudicating the automated reviewer's findings) + +Coordinator asked me to adjudicate two findings my first pass did not cover (injection; a +`workflow_dispatch` regression) plus confirm one convergence. Measured, not reasoned. Where I could not +measure, I say so. + +#### FINDING 1 β€” shell injection ("verbatim issue text interpolated unsafely") β†’ **NON-BLOCKING as stated; real hardening gap** + +I ran 8 hostile payloads through the EXACT PC-1 and PC-3 pipelines with the body delivered via the +environment (the channel the tests use and the natural reading of `"$SQUAD_TRIGGER_BODY"`): +`$(touch)`, `` `touch` ``, `"; touch x; echo "`, `/squad cast; touch x`, `%s%s%s%n`, `/squad %n%n%n`, +`-e /squad`, `--version`. + +- **Measured: zero side effects. No marker file ever created.** The pipeline is injection-safe. + - `printf '%s\n' "$VAR"` β€” `%s` is a fixed literal in the *script*; the body is an **argument** to + printf, never a **format** slot. Body `%n`/`%s` is inert data (payload `%s%s%s%n` β†’ `NO_COMMAND`; + `/squad %n%n%n` β†’ extracted literally as `%n%n%n`, no crash, no write). + - `grep -n -i -m 3 -F -- '/squad'` β€” `-F` fixed-string, `--` terminates options, `/squad` is the + literal pattern; the body is **stdin**, so `-e`/`--version` in the body are data, not grep args. + - Every hop is double-quoted; no word-splitting, no glob, no substitution. +- The reviewer's specific mechanism β€” *"verbatim issue text is interpolated into shell commands"* β€” is + **not reproducible against the code in the diff.** The body is *referenced* (`"$VAR"`), not + interpolated, and I could not turn it into an RCE. +- **The real residual, stated plainly:** line 240 says *"Assign the resolved trigger body ... to + `SQUAD_TRIGGER_BODY`"* without specifying HOW. If a runtime agent implements that by pasting the body + into a bash assignment (`SQUAD_TRIGGER_BODY=""`), that channel IS an RCE β€” I demonstrated it: + body `hello"; touch pwned; echo "` created the marker. Whether the gh-aw runtime uses the safe channel + (pre-set env var) or the unsafe one (interpolation) is **decided by the gh-aw compiler + LLM, and there + is no compiled `squad.lock.yml` in this repo to inspect. I cannot measure the runtime channel from + here, and I will not infer it.** +- **Adjudication: NON-BLOCKING** β€” the demonstrated, reviewable pipeline is safe. But this must not stay + at LLM discretion. **Required hardening (own follow-up):** pin the assignment to a named + gh-aw-provided env var and add one line forbidding interpolation of body text into any script. Also + note a one-hop-later exposure: PC-2 extracts `cast; touch pwned_env` as the *argument string*; harmless + in PC-1/PC-3, but any downstream step that ever interpolates parsed args into a shell reopens it. + +#### FINDING 2 β€” `workflow_dispatch` bare command regresses to a loud failure β†’ **BLOCKING** + +- **Measured (deterministic):** `PC1("implement")` = `NO_COMMAND`; `PC1("research")` = `NO_COMMAND`. + Bare mode names carry no `/squad` token, and PC-1 returns the sentinel for anything lacking one. +- **This is exactly what dispatch sends.** `workflows/squad-implement-worker.md:259`: + `"command": "implement"` (bare, nested under `inputs`). The activation guard (`squad.md:158-160`) itself + lists `research`, `triage`, `plan*`, `implement` as valid bare dispatched commands. +- **Does it flow through PC-1?** `squad.md:240` names *"the dispatched command"* as a `SQUAD_TRIGGER_BODY` + source, and PC-1 is `[MANDATORY]`. Literal reading: `implement` β†’ PC-1 β†’ `NO_COMMAND` β†’ PC-2 β†’ + PC-3 β†’ **exit non-zero.** The pre-fix flow ("strip `/squad` prefix, match longest-prefix-first, default + to cast") matched `implement` and **worked** β€” so the PR converts a working relay into a guaranteed + false failure. +- **The contradiction is the defect.** `squad.md:176-177` ("use this value as the command, skip remaining + sources") treats the dispatched command as a pre-resolved mode; PC-1 requires a `/squad` token none of + them carry. Either the agent obeys `[MANDATORY]` PC-1 and hard-fails the core autonomous path, or it + ignores a `[MANDATORY]` step and behavior is undefined. Both are bad. +- **Untested:** the new suite never feeds a bare dispatched command; it only exercises `/squad`-bearing + bodies and prose. Dispatch resolution has zero coverage. Confirmed by grep. +- **Adjudication: BLOCKING.** The implement relay is the highest-traffic non-interactive path. + **Fix shape:** normalize dispatch input *before* PC-1 β€” when `event_name == workflow_dispatch` and + `inputs.command` is a non-empty bare mode, treat it as already-resolved (bypass the `/squad` scan) or + synthesize `SQUAD_TRIGGER_BODY="/squad ${command}"` ahead of PC-1. Normalize the input; do not loosen + PC-1's scan (loosening reopens #1824). + +#### FINDING 3 β€” greedy `sub(/^.*\/squad/,"")` picks the LAST token β†’ **NON-BLOCKING, but a real defect (confirmed)** + +- **Measured:** `PC1("Please run /squad cast, then /squad status")` = `status`. Declared contract + (`squad.md:247`, "takes the **first** `/squad` token") says `cast`. **Contract violated.** +- Cause: `!f` stops at the first matching *line*, but within it the greedy `.*` strips through the LAST + `/squad`, so the second command's argument wins. +- Two independent reviewers (me, then `copilot-pull-request-reviewer`) landed on the same line β€” promotes + it from nit to real defect. **On its own: NON-BLOCKING** (needs two `/squad` on one line; still yields a + loud valid action, not the silent-no-op #1824 class). But it lives on the same awk line as no other + defect, so it should be fixed in this PR, not deferred. Fix shape: extract only up to the FIRST bounded + `/squad` on the matched line (awk has no non-greedy; use `index()`/`match()` from the token position). + +#### FINDING 4 (their 4th item) β€” PC-3 emission/exit untested: closable or inherent? + +- **Partly closable, mostly inherent β€” and the two framings are the same residual.** + - The PC-3 **diagnostic command** (the `grep` one-liner) IS extracted and executed by the suite, and + Mutation 2 proved it content-sensitive. That half is closed. + - The **`echo "::error::…"` emission** is prose with a `` placeholder the agent fills, + not a standalone command β€” only its *declaration* is assertable (the test already does + `expect(pc3).toContain('::error::')`). Making the interpolated annotation itself executable/tested is + marginally possible but low-value. + - **"Post one comment"** (safe-output tool call) and **"fail the run β€” exit non-zero"** (the agent's + control-flow choice) are gh-aw *runtime* behaviors. **Not reachable from a Vitest unit test.** + Genuinely inherent. +- So the reviewer ("test gap") and my first pass ("inherent LLM-prompt limit") describe the same boundary. + **This needs to be written down as a known limitation** so every future reviewer doesn't re-discover it: + *the PC-3 contract is verified as declared and its diagnostic is verified behaviorally; the actual + non-zero exit and issue comment are gh-aw runtime actions and are not unit-testable at this layer.* + +--- + +#### VERDICT BLOCK + +| # | Finding | Adjudication | Basis (measured) | +|---|---------|-------------|------------------| +| 1 | Shell injection | **NON-BLOCKING** (as stated) + required hardening | 8 payloads through the real pipeline via env β†’ 0 side effects; interpolation channel is RCE but is the unspecified assignment step, and no lock exists here to confirm the runtime channel | +| 2 | Dispatch bare-command regression | **BLOCKING** | `PC1("implement")`/`PC1("research")` = `NO_COMMAND`; dispatch sends bare `command:"implement"` (worker:259); line 240 routes it through `[MANDATORY]` PC-1 β†’ PC-3 hard fail; pre-fix worked; untested | +| 3 | Greedy last-token | **NON-BLOCKING** (real defect, fix in-PR) | `PC1("…/squad cast, then /squad status")` = `status`, contract says `cast` | +| 4 | PC-3 emission/exit test gap | Inherent (record as known limit); diagnostic half already closed | Suite executes the grep diagnostic; comment + non-zero exit are gh-aw runtime, not unit-testable | + +**Overall: MERGE AFTER FIXES (rework the dispatch path).** Finding 2 is a net regression on the core +autonomous relay and blocks. Finding 3 rides the same awk line and should be fixed here. Finding 1 is not +a demonstrated exploit in the diff but leaves a security-critical step to LLM discretion β€” pin a safe +channel. My original #1824 assessment is unchanged and still stands: the issue-path fix is sound; the +dispatch-path handling introduced alongside it is not. + +*β€” FIDO. Measured what I could; named what I couldn't.* + +--- + +#### Addendum 3 β€” Pass 3 re-review of rework commit `6e7628c5` (2026-08-22T19:20-07:00, FIDO) + +Re-reviewed EECOM's rework "fix(gh-aw): normalize bare workflow_dispatch commands before PC-1". +All measurements run in `bradygaster-animated-guacamole` (on branch, HEAD `6e7628c5`, `node_modules` present). +Method: extract the **declared** bash from `workflows/squad.md`, execute it, mutate the markdown, observe. + +##### Claims β€” verified by measurement + +1. **PC-0 fixes the BLOCKING dispatch regression (my Finding 2) β€” VERIFIED / resolved.** + `PC0("implement")β†’"/squad implement"`; idempotent on `"/squad implement"`; `" implement "β†’"/squad implement"`; + `""β†’"EMPTY_DISPATCH"`. Full relay `PC1(PC0(x))` resolves all six documented dispatch modes + (`implement, research, cast, status, connect org/repo, plan accept implementation phase 2`) to their mode. + The prior BLOCKING regression is closed. + +2. **PC-1 deliberately NOT loosened; guard fires under mutation β€” VERIFIED.** + Mutation (c) below fires the dedicated guard `PC-1 is NOT loosened …` naming the input, AND reopens the + #1824 headline `no command anywhere`. The guard is load-bearing, not decorative. + +3. **Greedy last-token fix (my Finding 3) β€” VERIFIED.** + `PC1("Please /squad cast, then /squad status")β†’"cast, then /squad status"` (first `/squad` wins, remainder starts + with `cast`); `PC1("/squad research and later /squad implement")β†’"research and later /squad implement"`. + No longer returns the last token (`status`/`implement`). + +4. **Text contradiction resolved β€” VERIFIED.** + Only `squad.md:177` retains "skip the remaining sources", now scoped to *source selection*; `:184-187` state + "Choosing a source never skips parsing: every source is parsed by **Parse Command** below … MUST be normalized by + **Step PC-0** before PC-1 sees it." End-to-end unambiguous; PC-1 stays `[MANDATORY]`. + +5. **Three mutations red-AND-naming β€” VERIFIED (standing bar met on all three).** + - (a) PC-0 pass-through (`else print $0`): 7 red. Names input: + `A workflow_dispatch of "implement" must resolve to that command … expected 'NO_COMMAND' to be 'implement'`. + - (b) greedy `sub(/^.*\/squad/,"")` restored: 2 red. Names input: + `PC-1 must extract "cast, then /squad status" from "Please /squad cast, then /squad status" … expected 'status'`. + - (c) PC-1 loosened (accept first non-empty line): 9 red incl. the guard + `PC-1 must still reject "implement" … expected 'implement' to be 'NO_COMMAND'` and the #1824 headline + `We should improve the docs.` returned as prose. + File restored via `git checkout --` after each; final tree clean. + +6. **Tests 15 β†’ 27 β€” VERIFIED.** `27 passed (27)`, clean. + +7. **RETRO security contract, hop-1 UNMEASURED, gate deferred to #1834 β€” VERIFIED (by reading).** + Text: "That gate is **not implemented**; it is tracked in #1834. This contract is normative today but reviewed by + hand, not enforced by CI … hop 1 is unverifiable here, since this repository ships no compiled gh-aw output." + Cannot be read as claiming enforcement that does not exist. + +8. **PC-3 exit-non-zero recorded as a known limitation (my Finding 4) β€” VERIFIED (by reading).** + "Known limitation β€” step 4 is an instruction, not an enforced exit code … That gap is inherent to gh-aw, not an + oversight." Written down; no longer needs re-discovery. + +##### The two probes the coordinator raised + +- **Probe A β€” PC-0 `NR==1` leading-newline: MEASURED, mechanism REAL, NON-BLOCKING (nit).** + `PC0($'\nimplement')β†’"EMPTY_DISPATCH"` and `PC0($' \nimplement')β†’"EMPTY_DISPATCH"` β€” a value that *carries* + `implement` silent-halts. `PC0($'implement\nfoo')β†’"/squad implement"` (line 2 silently dropped); + `PC0($'implement\r')β†’"/squad implement"` (CRLF handled). So the concern is real: `NR==1` + empty-first-line β†’ + `EMPTY_DISPATCH` β†’ activation-guard silent halt, the exact defect class this PR closes. + **Reachability (measured against the schema):** `command` is a `workflow_dispatch` string input + (`squad.md:17-19`, `required:false`). Producers are (1) `squad-implement-worker.md:259` literal + `"command": "implement"` β€” no newline; (2) the "Run workflow" UI β€” single-line field, cannot enter a newline; + (3) a crafted REST/`gh api` dispatch with an embedded `\n` β€” possible but requires `actions:write` (a privileged + actor). **Not reachable via either real producer or the UI; only via a hand-crafted privileged API payload.** + **Untested** (no leading-newline fixture among the 27). Verdict: NON-BLOCKING (low severity, privileged + malformed + surface), but a genuine latent silent-halt. Recommend closing cheaply: pin the behavior with a leading-newline test + and/or have PC-0 scan the first *non-empty* line rather than hard-binding `NR==1`, so the halt is a deliberate choice. + +- **Probe B β€” enumerate every caller: MEASURED, clean.** + `grep` across `workflows/*.md` for JSON `"command":` producers β†’ exactly **one**: `squad-implement-worker.md:259` + (`"command": "implement"`). The only consumers of `inputs.command` are `squad.md:3` (run-name display) and + `squad.md:139` (the value fed to PC-0). `squad-implement-worker.md`'s own `workflow_dispatch` inputs are + `issue_number`/`aw_context` only β€” no `command`. **No third bare-command caller exists**; the "hardened in + isolation" bug class has no other instance. + +##### CI +All green: Diff Size Guard, Architectural Review, Security Review β€” Permissions & Secrets, test (4m51s), Policy Gates, +Changeset Drift, etc. `docs-quality` and `Scope Boundary` skipping. `MERGEABLE`/`CLEAN`. + +##### Pass-3 verdict β€” APPROVE (merge as-is) +The pass-2 BLOCKING regression (Finding 2) is fixed **and** regression-guarded by input-naming tests; Finding 3 fixed; +the text contradiction resolved; all three mutations go red and name the offending input; the two inherent limits +(PC-3 exit; compiler-channel hop-1, #1834) are now written down rather than re-discovered. One NON-BLOCKING nit +remains: the PC-0 `NR==1` leading-newline silent-halt (Probe A) β€” latent, unreachable via known producers, untested; +worth a follow-up test + first-non-empty-line scan, not a merge blocker. +(Posted as `COMMENTED` β€” GitHub blocks a formal Approve from the PR-owning account.) + + +--- + +### 2026-08-22: RETRO security contract β€” /squad shell input channel + +### RETRO security contract β€” `/squad` shell input channel + +**Scope:** PR #1832 / issue #1824, the `/squad` command parser in `workflows/squad.md`, and the gh-aw compiled workflow YAML produced from it. + +**Threat model:** issue bodies, issue-comment bodies, issue titles, PR titles/bodies, and any other event field influenced by an external GitHub user are fully attacker-controlled. They may contain command substitutions, quotes, newlines, options, printf formats, awk escape sequences, and delimiter-looking text. + +#### Normative text for `workflows/squad.md` + +Paste the following block into `workflows/squad.md` as normative parser requirements. + +````markdown +### Shell input security contract [MANDATORY] + +The `/squad` parser treats issue bodies, issue-comment bodies, issue titles, PR titles/bodies, and any other GitHub event text as attacker-controlled. + +**Mandatory channel:** attacker-controlled GitHub event text MUST cross from the GitHub Actions expression layer into shell only through named step/job environment variables. The shell MUST read those values only through quoted shell parameter expansion, for example: + +```yaml +env: + SQUAD_TRIGGER_BODY: ${{ github.event.comment.body || github.event.issue.body || '' }} + SQUAD_TRIGGER_TITLE: ${{ github.event.issue.title || '' }} +run: | + body="${SQUAD_TRIGGER_BODY-}" + printf '%s\n' "$body" | awk '...' | grep -F -- '/squad' +``` + +**Forbidden anti-patterns:** + +- `UNTRUSTED_TEMPLATE_IN_RUN`: never place `${{ github.event.comment.body }}`, `${{ github.event.issue.body }}`, `${{ github.event.issue.title }}`, PR title/body expressions, or expressions derived from them directly inside a `run:` block. This is unsafe even inside shell quotes because GitHub Actions template expansion happens before the shell starts. +- `UNTRUSTED_COMMAND_STRING`: never build shell syntax from attacker-controlled text. No `eval`, no `source`, no generated script text containing the body, and no `bash -c`/`sh -c` command string containing the body. +- `UNTRUSTED_PRINTF_FORMAT`: never pass attacker-controlled text as the first argument to `printf`. The first argument is the format slot and must be a literal such as `'%s\n'`; the body belongs only in an argument slot such as `printf '%s\n' "$body"`. +- `UNTRUSTED_AWK_PROGRAM_OR_VAR`: never interpolate attacker-controlled text into an `awk` program string. Do not pass the raw body through `awk -v`; `awk -v` performs escape-sequence processing on values and can mutate parser input. The raw body must reach `awk` on stdin, with a static single-quoted awk program. + +**Per-hop requirements:** + +1. **Actions assignment:** event text is assigned in YAML `env:` only. The compiled gh-aw workflow must not contain attacker-controlled `${{ github.event... }}` expressions in any `run:` block. +2. **Shell local variable:** if copied to a local variable, use ordinary assignment only, e.g. `body="${SQUAD_TRIGGER_BODY-}"`. Do not use `eval`, command substitution, here-doc script generation, or `bash -c` with the body. +3. **`printf`:** use `printf '%s\n' "$body"` or equivalent literal format. The body must be an argument slot, never the format slot. +4. **Pipe:** move the body between parser stages as stdin bytes. Do not re-materialize it into shell syntax between stages. +5. **`awk`:** keep the awk program static and single-quoted; receive the body from stdin. Use `awk` variables only for trusted parser constants, not the raw body. +6. **`grep`:** when matching attacker-controlled or user-derived literal text, use `grep -F -- "$pattern"` with the pattern quoted. `-F` makes the pattern fixed-string, not regex; `--` terminates grep option parsing so values like `-e` and `--version` are data, not flags. + +**Verification requirement:** the repository gate must inspect the compiled gh-aw workflow output, not just this markdown. It must fail if any compiled `run:` block contains attacker-controlled GitHub event expressions, or if parser code passes a body variable as a `printf` format, into `eval`/`bash -c`, or into an awk program/`awk -v`. A gate that cannot turn red on a fixture containing `run: printf '%s\n' "${{ github.event.issue.body }}"` is not a valid gate. +```` + +End of pasteable block. + +#### Evidence measured locally + +Measurements were run with Git Bash in a scratch directory outside the repository and the scratch directory was deleted afterward. + +##### Safe environment-variable channel + +Payloads containing `$(touch owned)`, backticks, `"; touch owned #`, `%s%n`, `-e`, `--version`, and a no-command body were passed through: + +```bash +cmd=$(printf "%s\n" "$SQUAD_TRIGGER_BODY" | + awk '/\/squad/ { sub(/^.*\/squad[[:space:]]*/, "", $0); print; found=1; exit } + END { if (!found) print "NO_COMMAND" }') +printf "%s\n" "$SQUAD_TRIGGER_BODY" | grep -F -- "/squad" >/dev/null +``` + +Measured result: `SAFE_PIPELINE_SIDE_EFFECT=NO`. No `owned` file was created. + +##### Direct `run:` interpolation channel + +A generated shell script equivalent to Actions template interpolation into `run:` was executed: + +```bash +printf '%s\n' "/squad $(touch owned)" >/dev/null +``` + +Measured result: `DIRECT_INTERPOLATION_SIDE_EFFECT=YES`. The command substitution executed before `printf` received an argument. Shell quoting around the already-interpolated text did not protect it. + +##### `printf` format slot + +Measured: + +```bash +BODY='literal\n%s%n' +printf '%s\n' "$BODY" +printf "$BODY" + +BODY='prefix%n suffix' +target=before +printf "$BODY" target >/dev/null +printf '%s\n' "$target" +``` + +Results: argument-slot printing preserved the body literally; format-slot printing interpreted backslash and percent sequences. Bash `printf` `%n` assigned `target=6`. This is not the same as command execution, but it is a real parser-integrity bug and proves the body must never occupy the format slot. + +##### `grep -F --` + +Measured: + +```bash +printf '%s\n' 'needle --version' | grep -F -- '--version' +printf '%s\n' 'needle -e' | grep -F -- '-e' +printf '%s\n' 'literal .* [abc]' | grep -F -- '.* [abc]' +``` + +Results: all patterns matched as literal text. `--version` and `-e` were not treated as options, and `.* [abc]` was not treated as a regex. FIDO's claim is confirmed for the measured grep invocation shape: quoted pattern, `-F`, and `--` before the pattern. + +##### `awk -v` and awk program interpolation + +Measured: + +```bash +awk -v body='line1\nline2' 'BEGIN { print body }' +printf '%s\n' 'line1\nline2' | awk '{ print }' +``` + +Result: `awk -v` converted `\n` into a newline; stdin preserved the literal backslash-n bytes. This is input mutation, distinct from shell injection. + +Measured awk program injection with a generated program containing attacker syntax: + +```bash +printf '%s\n' 'input' | awk '{ print ""; system("touch owned"); "" }' +``` + +Result: `AWK_PROGRAM_INTERPOLATION_SIDE_EFFECT=YES`. If attacker text is allowed to become awk program text, awk can execute commands through `system(...)`. + +#### Verification shape + +A compliant gate should run against the compiled gh-aw YAML. Source markdown checks are useful, but not sufficient. + +Minimum static assertions: + +1. Extract every compiled YAML `run:` block and fail on: + - `\$\{\{[^}]*github\.event\.(comment\.body|issue\.body|issue\.title|pull_request\.body|pull_request\.title)[^}]*\}\}` + - `printf[[:space:]]+["']?\$[{]?(SQUAD_TRIGGER_BODY|SQUAD_TRIGGER_TITLE|body|title)\b` + - `\b(eval|source)\b.*\$(SQUAD_TRIGGER_BODY|SQUAD_TRIGGER_TITLE|body|title)\b` + - `\b(bash|sh)[[:space:]]+-c\b.*\$(SQUAD_TRIGGER_BODY|SQUAD_TRIGGER_TITLE|body|title)\b` + - `awk[^\n]*-v[^\n]*(SQUAD_TRIGGER_BODY|SQUAD_TRIGGER_TITLE|body|title)` +2. Include a positive-control fixture that must fail the gate: + + ```yaml + run: | + printf '%s\n' "${{ github.event.issue.body }}" + ``` + +3. Include a dynamic parser test that executes the compiled parser path with payloads `$(touch owned)`, backticks, `"; touch owned #`, `%s%n`, `-e`, and `--version`, then asserts: + - no sentinel side-effect file exists; + - no `NO_COMMAND` path falls back to `cast`; + - diagnostics do not cause additional command execution. + +The instructions printed by the gate must identify the exact rule name above, for example `UNTRUSTED_TEMPLATE_IN_RUN`, so the failure is searchable and actionable. + +#### Residual risk + +I could measure POSIX shell behavior for the command shapes above. I could not determine whether the real gh-aw compiler currently emits a safe `env:` channel because no compiled gh-aw workflow lock/output for PR #1832 exists in this repository. The compiled output is where GitHub Actions template interpolation becomes executable shell text, so compliance remains unmeasured until a gate inspects that compiled artifact. + + +--- + +### 2026-08-22: Decision β€” /squad command parsing must fail loudly (#1824) + +### Decision β€” `/squad` command parsing must fail loudly (#1824) + +**By:** Procedures (Prompt Architecture) +**Date:** 2026-08-22 +**Issue:** #1824 +**Files:** `workflows/squad.md` (Parse Command), `test/gh-aw-command-parse.test.ts` + +#### Context + +`/squad cast` silently no-opped with a green check unless the command started the +issue body. The `## Parse Command` section said *"Strip `/squad` prefix, trim +whitespace"* β€” a position-0 assumption β€” and had **no failure branch at all**. +There was no state in which the router reported "I did not understand this." +Success and no-op were byte-identical to a first-run user. + +#### Decision + +Two changes, in priority order. + +1. **A no-op run must fail.** `Parse Command` now has an explicit `NO_COMMAND` + outcome routed to a mandatory `Step PC-3` that emits `::error::`, posts a + comment quoting the offending text, and exits non-zero. Defaulting to `cast` + on an unparsed body is now explicitly forbidden. This is the load-bearing + half: it converts every future variant of the bug from silent to visible. +2. **The scan reads the whole body.** The command is found wherever it sits. + +#### Method β€” an executable contract, not prose + +The parser is an LLM prompt, so there is no function to unit-test. Instead the +parse is expressed as two concrete shell commands embedded in the markdown, and +the test **extracts those exact commands from `workflows/squad.md` and executes +them** against real issue bodies. The two sources compared are the declared +contract and its observed behavior β€” neither re-reads the other. This follows the +existing TG-1 precedent in `test/gh-aw-quality.test.ts`. + +#### What the mutation tests actually proved + +**Mutation 1 β€” reintroduce position-0 anchoring, headings and prose untouched.** +Only **1 of 14** assertions caught it. The headline case β€” prose, blank line, +then the command, i.e. the literal #1824 scenario β€” **passed under the +reintroduced bug**. Cause: `^` in awk anchors per *record*, so a line-anchored +parser still handles a command sitting on its own line further down the body. The +blank-line case cannot distinguish a body-wide scan from a line-anchored one. + +Two cases were added whose only job is to carry that weight: an **indented** +command and a **mid-sentence** command. Both are invisible to a line-anchored +scan. Re-running the mutation then produced 2 failures naming the specific input. +These cases look redundant with the blank-line case and are not; there is a +comment in the test saying so. + +**Mutation 2 β€” replace PC-3's diagnostic with `echo 'unrecognized command'`.** +Every status-shaped signal stayed intact: `::error::` still present, PC-2 still +forbids the cast fallback, the run still fails. A status-only assertion passes +this clean β€” the exact shape that let a truncating parser through on #1793. It +was caught by 3 assertions, because they assert the diagnostic **contains the +offending text** rather than merely that a diagnostic exists. + +#### Generalizable lessons + +- **A red transcript is not automatically a good one.** Against pre-fix state the + suite went 13/14 red, but on *"heading missing"* β€” structural, not behavioral. + That proves coupling to the new contract, not sensitivity to a wrong parser. + Only the mutations tested sensitivity, and they found the blind spot. +- **Test the anchor semantics you actually rely on.** A per-line `^` and a + per-body scan agree on most realistic inputs. Pick cases where they disagree. +- **A skipped test is a permanently-green gate.** `HAS_POSIX_SHELL = + existsSync('/bin/sh')` silently skips 102 behavioral assertions in + `gh-aw-quality.test.ts` on every Windows machine. The new suite resolves Git + Bash instead of skipping, and asserts that it found a shell β€” so a suite that + could not run reports red rather than green. + +#### Deliberate non-actions + +- **The scan matches `/squad` inside quoted lines and fenced code blocks.** + Excluding them would reintroduce a silent-skip path, which is the bug class + being removed. gh-aw's `slash_command` trigger has already decided the run is a + squad command by the time this prompt sees the body. Documented in-file. +- **The 102 `/bin/sh` skips in `gh-aw-quality.test.ts` were not fixed.** Real and + worth a separate issue; out of scope for #1824 and would blow the diff budget. +- **#1812 not touched.** Confirmed separate: #1812 is in `plan activate`'s roster + source, downstream of routing. It shares no code path with Parse Command. diff --git a/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md b/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md new file mode 100644 index 000000000..e2a959707 --- /dev/null +++ b/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md @@ -0,0 +1,56 @@ +# Session Log β€” gh-aw Wave 1 + +**Timestamp:** 2026-08-22T19:42:25-07:00 +**Wave:** #1 β€” `/squad` parser hardening (issue #1824) + +## Overview + +Autonomous spawn wave closed. Four agents worked the `/squad` command parser, reaching **PR #1832 merged** and **issue #1824 closed** under conditional lockout and revision protocol. + +## Manifest + +| Agent | Task | Mode | Outcome | +|-------|------|------|---------| +| Procedures | Author parser hardening (issue #1824) | isolated | PR #1832 authored; blocked on Pass 2 | +| FIDO | Adversarial review, 3-turn adjudication | background | Found BLOCKING dispatch regression; rework required | +| RETRO | Shell input security contract | background | Delivered normative contract | +| EECOM | Rework under lockout | isolated | Commit `6e7628c5`; PR merged; issue closed | + +## Decision Records Merged + +Three new entries added to `.squad/decisions.md`: + +1. **Procedures decision** β€” `/squad` command parsing must fail loudly (#1824) + - Parser now rejects position-0 assumption, scans whole body + - Explicit `NO_COMMAND` β†’ Step PC-3 β†’ mandatory fail + - Mutation tests proven load-bearing + +2. **RETRO security contract** β€” `/squad` shell input channel + - Threat model: GitHub event text fully attacker-controlled + - Mandatory channel: env variables + quoted parameter expansion + - Forbidden patterns: direct interpolation, untrusted command strings, format-slot printf, awk program mutation + - Verification scope: compiled gh-aw YAML inspection deferred to #1834 + +3. **FIDO review findings** β€” Passes 1, 2, and 3 documented + - Pass 1: APPROVE WITH NITS (mutation-sensitive, injection-safe via env) + - Pass 2: MERGE AFTER FIXES (Finding 2: BLOCKING dispatch regression) + - Pass 3: APPROVE (EECOM rework verified; regression fixed; mutations green) + +## Key Insights + +- **Reviewer Rejection Protocol applied:** When domain author (Procedures) produced regression in isolation, blind spot shared by first reviewer (FIDO Pass 1). Lockout triggered; alternative agent (EECOM) revised. Factually recorded without demerit. + +- **Dispatch path was untested:** Mutation suite exercised `/squad`-bearing bodies and prose but not bare `workflow_dispatch` commands. New test coverage added in revision. + +- **Known limitations documented:** PC-3 exit-non-zero is inherent to gh-aw prompt layer (not unit-testable); hop-1 channel verification deferred to #1834. + +## References + +- PR: github.com/bradygaster/friendly-guide/pull/1832 +- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- Commit (EECOM revision): `6e7628c5` +- Follow-up gate: #1834 + +## Status + +βœ“ Wave closed. All agents idle. diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md new file mode 100644 index 000000000..7fd201fed --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md @@ -0,0 +1,56 @@ +# Orchestration Log β€” EECOM + +**Agent:** EECOM (Core Runtime & Orchestration) +**Timestamp:** 2026-08-22T19:42:25-07:00 +**Task:** Rework PR #1832 under reviewer lockout +**Mode:** isolated session + +## Context + +**Reviewer Lockout Applied:** Procedures locked out after FIDO's Pass 2 found BLOCKING dispatch regression. + +**Blocking Issue:** `workflow_dispatch` bare commands regress to loud failure: +- PC-1 requires `/squad` token; dispatch sends bare `command:"implement"` +- Pre-fix worked; post-fix: `implement` β†’ NO_COMMAND β†’ hard fail +- Core autonomous relay broken + +## Solution + +**Commit:** `6e7628c5` β€” fix(gh-aw): normalize bare workflow_dispatch commands before PC-1 + +**Step PC-0 added** (normalization layer before mandatory PC-1): +- `workflow_dispatch` bare `command` β†’ synthesize `/squad ${command}` prefix +- Examples: `implement` β†’ `/squad implement`; empty β†’ `EMPTY_DISPATCH` +- Idempotent: `/squad implement` stays `/squad implement` +- All 6 documented dispatch modes resolve correctly + +**PC-1 NOT loosened** β€” guard fires on mutation, proving guard is load-bearing + +**Greedy last-token fix (Finding 3):** Extract only up to FIRST `/squad` token on matched line (FIDO's nit in Pass 2) + +## Verification + +**FIDO Pass 3 measurements:** +- PC-0 fixes BLOCKING regression (dispatch now works) +- PC-1 deliberately not loosened (mutation catches it) +- Greedy last-token fixed +- All mutations red-and-naming (tests 15 β†’ 27, all pass) +- CI green (Diff Size Guard, Architectural Review, Security Review, tests) +- Mergeable + +## Known Limitations Documented + +1. PC-0 `NR==1` leading-newline edge case (latent, unreachable via real producers, noted for follow-up) +2. PC-3 exit-non-zero recorded as known limitation (inherent to gh-aw prompt layer) +3. Hop-1 (GitHub Actions β†’ shell) channel verification deferred to #1834 + +## Status + +PR #1832 merged; issue #1824 closed. + +## Reference + +- Charter: `.squad/agents/eecom/charter.md` +- PR: github.com/bradygaster/friendly-guide/pull/1832 +- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- Commit: `6e7628c5` diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md new file mode 100644 index 000000000..563d45a30 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md @@ -0,0 +1,49 @@ +# Orchestration Log β€” FIDO + +**Agent:** FIDO (Quality Owner) +**Timestamp:** 2026-08-22T19:42:25-07:00 +**Task:** Adversarial review of PR #1832 +**Mode:** background, 3 turns + +## Turn 1 β€” APPROVE WITH NITS + +**Verdict:** COMMENTED (GitHub blocks formal Approve on own-account PR) + +- Reproduced every claim independently in `bradygaster-silver-engine` worktree +- Mutation 1 (reintroduce position-0 line anchoring): 2 failures, load-bearing +- Mutation 2 (generic diagnostic): 3 failures, mutation-sensitive +- Acceptance test: every hostile body β†’ `NO_COMMAND` β†’ loud fail (no silent no-op constructible) +- Nits: HTML comment parsing, greedy last-token, 102 skip figure + +## Turn 2 β€” MERGE AFTER FIXES (1 BLOCKING) + +**Verdict:** Adjudication of automated reviewer's findings + +- **FINDING 1 (injection):** NON-BLOCKING; pipeline is injection-safe via env channel; but assignment step is unspecified (LLM discretion) +- **FINDING 2 (dispatch regression):** **BLOCKING** β€” bare `command:"implement"` β†’ PC-1 β†’ `NO_COMMAND` β†’ fail; pre-fix worked +- **FINDING 3 (greedy last-token):** NON-BLOCKING real defect, fix in-PR +- **FINDING 4 (PC-3 exit):** Inherent to gh-aw; record as known limitation + +## Turn 3 β€” APPROVE (pass-3 re-review of EECOM rework) + +**Verdict:** COMMENTED +**Commit audited:** `6e7628c5` (EECOM's dispatch normalization fix) + +- **Verified:** PC-0 fixes BLOCKING regression (Finding 2), all 6 dispatch modes resolve +- **Verified:** PC-1 not loosened; mutations red-and-naming +- **Verified:** Greedy last-token fixed (Finding 3) +- **Verified:** Text contradiction resolved +- **Nit:** PC-0 `NR==1` leading-newline edge case (latent, unreachable via real producers) + +All mutations pass; CI green; mergeable. + +## Status + +PR #1832 merged; issue #1824 closed. + +## Reference + +- Charter: `.squad/agents/fido/charter.md` +- PR: github.com/bradygaster/friendly-guide/pull/1832 +- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- Commit (EECOM revision): `6e7628c5` diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md new file mode 100644 index 000000000..e18bf05c6 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md @@ -0,0 +1,35 @@ +# Orchestration Log β€” Procedures + +**Agent:** Procedures (Prompt Architecture) +**Timestamp:** 2026-08-22T19:42:25-07:00 +**Task:** #1824 β€” `/squad` parser returns NO_COMMAND silently; make it fail loud +**Mode:** isolated session + +## Outcome + +**Status:** BLOCKED on review (FIDO Pass 2), then REVISION SHIPPED (EECOM, commit `6e7628c5`) + +- Authored PR #1832 with two changes: + 1. Parse Command now has explicit `NO_COMMAND` outcome routed to Step PC-3 (mandatory fail) + 2. The scan reads the whole body, not just position-0 + +## Findings + +- Mutation testing proved load-bearing cases (indented command, mid-sentence command) +- Suite is mutation-sensitive on content, not just status +- Draft PR passed all CI checks and Diff Size Guard + +## Reviewer Lockout Applied + +FIDO's Pass 2 found a **BLOCKING regression** β€” `workflow_dispatch` bare commands regress to loud failure: +- Pre-fix: `implement` β†’ routed β†’ worked +- Post-fix: `implement` β†’ PC-1 β†’ `NO_COMMAND` β†’ PC-3 β†’ fail + +Under Reviewer Rejection Protocol: **Procedures locked out**, EECOM did the revision (Step PC-0 added to normalize dispatch input before PC-1). + +## Reference + +- Charter: `.squad/agents/procedures/charter.md` +- PR: github.com/bradygaster/friendly-guide/pull/1832 +- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- Commit (EECOM revision): `6e7628c5` diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md new file mode 100644 index 000000000..a3c334475 --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md @@ -0,0 +1,40 @@ +# Orchestration Log β€” RETRO + +**Agent:** RETRO (Security & Threat Modeling) +**Timestamp:** 2026-08-22T19:42:25-07:00 +**Task:** Author the gh-aw shell input security contract +**Mode:** background + +## Outcome + +**Status:** DELIVERED + +Authored normative contract for `workflows/squad.md` security requirements. + +## Content + +The security contract (`.squad/decisions/inbox/retro-1832-shell-input-contract.md`, lines 11–44) specifies: + +- **Threat model:** Issue bodies, comments, titles, and PR text are fully attacker-controlled +- **Mandatory channel:** Attacker text MUST cross from GitHub Actions expression layer into shell only through named env variables, read via quoted parameter expansion +- **Forbidden anti-patterns:** direct interpolation, untrusted command strings, `printf` format-slot usage, awk program interpolation, `awk -v` mutation +- **Per-hop requirements:** Actions assignment, shell locals, printf literals, pipe via stdin, awk static programs, grep fixed-string mode +- **Verification requirement:** gate must inspect compiled gh-aw YAML, not just markdown + +## Measurement + +Payloads tested via environment channel: `$(touch owned)`, backticks, `"; touch owned #`, `%s%n`, `-e`, `--version`, no-command +Result: **SAFE_PIPELINE_SIDE_EFFECT=NO** + +Anti-pattern (direct interpolation) measured: **DIRECT_INTERPOLATION_SIDE_EFFECT=YES** (shell substitution executes before printf receives args) + +## Residual Risk + +No compiled gh-aw workflow lock in this repository to inspect. Hop-1 (GitHub Actions β†’ shell) channel implementation is decided by gh-aw compiler + LLM, unmeasurable here. Gate verification deferred to #1834. + +## Reference + +- Charter: `.squad/agents/retro/charter.md` +- PR: github.com/bradygaster/friendly-guide/pull/1832 +- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- Follow-up gate: #1834 From 6d8bb3fc811235620dab6b25ff0e3822ef6bfc5a Mon Sep 17 00:00:00 2001 From: brady gaster Date: Sat, 22 Aug 2026 20:26:51 -0700 Subject: [PATCH 3/6] fix(squad): restore 3 archives lost by the 2026-08-20 summarization run A Scribe run at 2026-08-20T11:59:44-0700 wrote provenance pointing at history-archive-2026-08-20T11-59-44-0700.md into eecom, pao and procedures. None of the three files was ever created. The pointers dangled for two days with `git status` clean, because .squad/ was in .git/info/exclude (#1826) and new files there are silently unstageable. The trim landed in c508d866 -- titled "record gh-aw triage session state and repair archives". It performed the loss it claimed to repair. Recovered from the last committed pre-trim state (c508d866^ / 3dace32e). Not a proven byte-exact snapshot of disk at pointer-write time; uncommitted drift may have existed. Verified by blob SHA equality via `git ls-files -s`: eecom 771d9e0d3d20b238e3d52118ea3e5f1f027b4515 15,063 B / 129 lines pao 012ea60535946f77be53d24eaaf542e351e845c9 13,605 B / 120 lines procedures 1298528a8d4d6b8925b80f021eead775b30bc347 13,653 B / 119 lines Content loss was invisible to size: procedures/history.md is 15,370 B today vs 13,653 B pre-trim -- 1,717 bytes LARGER -- and was still missing 35 non-blank lines. Later sessions appended while trimmed material stayed gone. Only content comparison detects this. pao was missing 44 lines. Also restored eecom/history.md provenance (H1 + 4 lines) stripped in an earlier repair attempt. Swept all 9 archive pointers across every agent: 0 remaining dangling. Refs #1836, #1826 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0e20e987-a753-41c4-a6f8-992d863a32cd --- ...istory-archive-2026-08-20T11-59-44-0700.md | 129 ++++++++++++++++++ .squad/agents/eecom/history.md | 114 +++++++++------- ...istory-archive-2026-08-20T11-59-44-0700.md | 120 ++++++++++++++++ ...istory-archive-2026-08-20T11-59-44-0700.md | 119 ++++++++++++++++ 4 files changed, 433 insertions(+), 49 deletions(-) create mode 100644 .squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md create mode 100644 .squad/agents/pao/history-archive-2026-08-20T11-59-44-0700.md create mode 100644 .squad/agents/procedures/history-archive-2026-08-20T11-59-44-0700.md diff --git a/.squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md b/.squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md new file mode 100644 index 000000000..771d9e0d3 --- /dev/null +++ b/.squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md @@ -0,0 +1,129 @@ +# Eecom history + +## 2026-08-20 β€” #1772 dispatch probe gate fix + +- Root cause confirmed: dispatch-workflow: max: 1 causes first-wins semantics; LLM empty probe consumes slot; real dispatch silently dropped. +- Prior fix #1766 (prompt wording) confirmed insufficient via live run evidence. +- Fix: raised max to 2 (squad-implement-worker.md) + extended check-workflow-input-interpolation.mjs with checkDispatchWorkflowSchemas() static gate. +- Static gate validates JSON dispatch examples adjacent to dispatch_workflow references: requires non-empty workflow_name, non-empty inputs, inputs.issue_number. +- Added 6 new tests in test/gh-aw-quality.test.ts; key structural test fails against max:1 state, passes after fix. +- Build passes. Decision recorded at .squad/decisions/inbox/eecom-1772-dispatch-probe-gate.md. +- Coordination needed: Procedures to add squad.md empty-command guard (separate PR). + +Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. +Full pre-summary history archived at `.squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md`. + +## Condensed index + +- Preserved 367 original line(s) in the archive. +- Detected 39 heading(s) and 26 dated reference line(s). +- This file now keeps a compact index plus the most recent tail so active context remains visible. + +## Notable retained signals + +- Replaced all hardcoded "Brady" in template examples with generic `{user}`/`{name}` placeholders. Canonical sources: `.squad-templates/squad.agent.md` and `.copilot/skills/init-mode/SKILL.md`. Template sync only covers `.squad-templates/`; init-mode SKILL.md package copies required manual edits. Key distinction: only files copied to user repos were changed; Brady references in project docs are legitimate content. +- ### PR #942 rebase β€” cherry-pick from insider-based fork branch (2026-04-12) +- When cherry-picking from an insider-based branch to dev, expect modify/delete conflicts for files that only exist on insider. Always verify the base assumptions of each change β€” imports referencing insider-only modules must be dropped or adapted. Opened #963 as clean replacement, closed #942. +- ### archiveDecisions() count-based fallback (#626) (2025-07-24) +- **Cross-platform filename & config fixes (#348, #356):** Use centralized `safeTimestamp()` everywhere. Removed machine-specific `teamRoot` from config.json (computed at runtime via `git rev-parse`). +- **PR #427 cross-fork rebase:** When rebasing with git worktrees, always create a dedicated worktree for complex operations. In rebase context, "ours" = upstream, "theirs" = your branch. Use `git worktree list` to diagnose unexpected branch switching. +- **PR #483 (platform-adapter timeout):** `{ ...EXEC_OPTS, timeout: 3_000 }` pattern for external CLI calls that might hang. Existing catch block with fallback handles timeout errors. +- **PR #480 (history race condition):** Three-layer defense: async mutex, atomic file operations (write-then-rename), 14 tests. +- **PR #486 (SIGINT handling):** Two layers: parent SIGINT handler + child process cleanup (kill children, close handles, flush buffers). 22 tests. +- **Fix:** Replaced all hardcoded "Brady" in template examples with generic `{user}` / `{name}` placeholders. Canonical sources: `.squad-templates/squad.agent.md` and `.copilot/skills/init-mode/SKILL.md`. Template sync (`node scripts/sync-templates.mjs`) propagated squad.agent.md to `.github/agents/` but did NOT sync init-mode SKILL.md to package templates β€” those required manual edits in both `packages/squad-cli/templates/skills/init-mode/SKILL.md` and `packages/squad-sdk/templates/skills/init-mode/SKILL.md`. +- **Context:** PR #942 from tamirdresher's fork was retargeted from `insider` to `dev`, causing 29 files in the diff when only 3 commits (4 files relevant to dev) were the actual fix. Cherry-picked the 3 fix commits onto a clean `squad/942-rebase-type-safety` branch from dev, resolving conflicts where insider-only files (skill.ts, cross-package-exports.test.ts) didn't exist on dev. Dropped the `escapeYamlValue` import and APM YAML generation function from init.ts since skill.ts doesn't exist on dev. Opened #963 as the clean replacement, closed #942. +- **Key lesson:** When cherry-picking from an insider-based branch to dev, expect modify/delete conflicts for files that only exist on insider. Always verify the base assumptions of each change β€” imports referencing insider-only modules must be dropped or adapted. +- **Context:** Three Copilot review comments on PR #767: (1) `teamRoot` was set to `workTreeRoot` but `.squad/` may live in the main checkout when running inside a git worktree β€” should derive from `detectSquadDir().path`, (2) `generateLoopFile()` hardcoded the full loop.md scaffold inline, duplicating `templates/loop.md`, (3) docs said `gh` was optional but code hard-requires `gh copilot` unless `--agent-cmd` is passed. +- **Context:** Copilot code review on PR #767 flagged three issues in the loop command: (1) `execFile` buffered stdout/stderr but never printed it β€” users saw no Copilot output during loop rounds, (2) `loop.md` was resolved relative to `dest` but execution used `teamRoot` (derived from `.squad/` parent), creating a CWD mismatch in worktree scenarios, (3) docs said `description` defaults to `""` but code uses `'Squad Loop'`. +- **Context:** `archiveDecisions()` in `packages/squad-cli/src/cli/core/nap.ts` silently returned `null` when all `###` entries were <30 days old (`old.length === 0`), even if the file was well over 20KB. Active projects generating many decisions per session could hit 145KB+ β€” 35K tokens burned per agent spawn. +- **Fix:** Added a count-based fallback after the age-based split. When `old.length === 0` and total file size exceeds `DECISION_THRESHOLD` (20KB), the fallback separates recent entries into dated vs undated, sorts dated by age (most recent first), keeps entries that fit under the threshold budget, and archives the rest. Undated entries are always preserved β€” they are foundational directives per Procedures' guidance. +- ### CLI Version Subcommand Pattern (2026-03-23 Release Incident) +- πŸ“Œ **Team update (2026-03-22T09-35Z β€” Wave 1):** Economy mode fully implemented: ECONOMY_MODEL_MAP + resolveModel() integration in SDK, `squad economy on|off` CLI command, `--economy` flag, 34 tests passing. PR #504 open for review. Soft dependency: #464 rate limit UX should offer economy mode as recovery. Next: Phase 1 of ambient personal squad (T1–T5, T19) β€” ready to start immediately after merging current work. Procedures wrote governance proposals for squad.agent.md β€” awaiting Flight review. +- **Root cause:** The catch block in `shell/index.ts` line ~1119 always emitted `genericGuidance()` unless `SQUAD_DEBUG=1`. Rate limit errors never got special treatment despite `RateLimitError` existing in `adapter/errors.ts`. +- `npm pack` produces a complete, installable tarball (~275KB packed, 1.2MB unpacked). Package includes dist/, templates/, scripts/, README.md per package.json "files" field. Postinstall script (patch-esm-imports.mjs) patches @github/copilot-sdk for Node 24+ compatibility. Tarball can be installed locally (`npm install ./tarball.tgz`) and commands execute via `node node_modules/@bradygaster/squad-cli/dist/cli-entry.js`. Both squad-cli and squad-sdk must be installed together β€” cli depends on sdk with "*" version specifier. All 27+ CLI commands are lazy-loaded at runtime; `--help` validates command routing without executing full logic. +- **Context:** Two cross-platform bugs broke Squad on Windows: (1) log filenames contained colons in ISO 8601 timestamps (illegal on Windows), (2) `.squad/config.json` contained absolute machine-specific `teamRoot` path. +- 3. Updated live `.squad/config.json` in repo to remove machine-specific path +- **Test Impact:** All 150 tests pass. Communication adapter test doesn't validate specific filename format (structural test, not behavioral). +- **Context:** CastingEngine class (Issue #138, M3-2) existed in SDK with curated universe templates (The Usual Suspects, Ocean's Eleven) but was completely bypassed during `squad init`. LLM picked arbitrary names, and charter generation used regex-based `personalityForRole()` instead of template backstories. + +## Recent preserved tail + +**Fix pattern:** Race conditions in history operations require three-layer defense: (1) async mutex for write serialization, (2) atomic file operations (write-then-rename), (3) comprehensive test coverage (14 tests for edge cases). This pattern applies to any persistent state under concurrent access. + +**Key learning:** File system race conditions aren't just "add a lock" β€” need atomicity guarantees (rename is atomic), serialization (mutex), and exhaustive test coverage to validate edge cases (concurrent writes, stale reads, partial failures). + +### PR #486 Review & Merge β€” SIGINT Handling (2026-03-22) + +Reviewed and merged PR #486 (two-layer signal handling + 22 tests). Improves graceful shutdown under SIGINT (Ctrl+C) by cleaning up both parent and child processes. + +**Fix pattern:** Signal handling in Node.js requires two layers: (1) parent process SIGINT handler that triggers graceful shutdown, (2) child process cleanup (kill child processes, close file handles, flush buffers). Incomplete cleanup leaves zombie processes or orphaned file locks. Test coverage essential: 22 tests verify process tree cleanup, signal propagation, and edge cases (nested children, immediate re-signals). + +**Key learning:** SIGINT handling is more complex than "add a signal handler" β€” need explicit child process cleanup logic + comprehensive tests. Pattern applies to any process spawning child processes (CLI spawning subshells, REPL spawning child REPL instances, etc.). +### Economy Mode Implementation (#500) (2026-03-20) + +**Context:** Issue #500 requested economy mode β€” a session-level and persistent modifier that shifts model selection to cheaper alternatives. + +**Architecture decision:** Economy mode is a Layer 3/4 modifier only. Layers 0–2 (explicit user preferences: config.json, session directive, charter) are never downgraded. This preserves user intent while enabling cost savings on auto-selected tasks. + +**Implementation:** +1. `ECONOMY_MODEL_MAP` + `applyEconomyMode()` in `config/models.ts` β€” pure mapping function for premiumβ†’standard and standardβ†’fast downgrades +2. `readEconomyMode()` + `writeEconomyMode()` β€” config.json read/write functions (same merge-without-clobber pattern as `writeModelPreference()`) +3. `resolveModel()` in `config/models.ts` updated with `economyMode?: boolean` option; falls back to reading from `squadDir` if not provided +4. `resolveModel()` in `agents/model-selector.ts` updated with `economyMode?: boolean` β€” both SDK resolvers are economy-aware +5. `squad economy [on|off]` command in CLI for persistent toggle +6. `--economy` global flag in `cli-entry.ts` sets `SQUAD_ECONOMY_MODE=1` env var for session scope +7. 34 new tests in `test/economy-mode.test.ts` β€” all pass + +**Key pattern:** Both resolveModel implementations follow identical principle: explicit overrides (user choice) are sacred; economy only affects computed auto-selection. + +**PR:** #500 branch `squad/500-economy-mode` + +### node:sqlite Hard-Fail Fix (#502) (2026-03-21) + +**Context:** Workshop participants (reported by Doron Ben Elazar) were blocked by `ERR_UNKNOWN_BUILTIN_MODULE` crashes. `node:sqlite` (used by Copilot SDK for session storage) requires Node 22.5.0+. The existing soft-warn-and-continue approach let users limp into a cryptic crash. + +**Root cause:** `engines.node` said `>=20` but `node:sqlite` needs `>=22.5.0`. The pre-flight check warned but didn't exit, so users saw confusing failures deep in SDK code. + +**Fix:** +1. **cli-entry.ts:** Replaced `try { await import('node:sqlite') } catch { warn }` with a synchronous version check that calls `process.exit(1)` immediately with a clear upgrade message. Removed the now-dead `checkNodeSqlite()` function and its call site. +2. **doctor.ts:** Added `checkNodeVersion()` to `squad doctor` β€” exported with optional version param for testability. +3. **package.json (Γ—3):** Corrected `engines.node` to `>=22.5.0` so npm/npx warn at install time. +4. **Tests:** 5 new tests for `checkNodeVersion()` (Node 20.x fail, 22.4.x fail, 22.5.0 pass, 24.x pass, current env pass). Updated check-count assertion. + +**Pattern:** git branch confusion β€” `git checkout -b` switches HEAD but edits to files on wrong branch are lost when switching. Always confirm `git branch` before making file edits. File edits don't follow you to a new branch if you forgot to switch first. + +**PR:** #506 branch `squad/502-node-sqlite-dependency` + +### Rate Limit Recovery UX (#464) (2026-03-22) + +**Context:** Rate limit errors showed generic message with no actionable recovery. Brady directive: offer model switching + economy mode as recovery options. + +**Implementation:** +1. `error-messages.ts` β€” `rateLimitGuidance()` shows actual reason + 3 recovery options (retry time, `squad economy on`, config.json model override) +2. `shell/index.ts` β€” Detects rate limits via `instanceof RateLimitError` or regex; writes `.squad/rate-limit-status.json` +3. `doctor.ts` β€” `checkRateLimitStatus()` reads status file and warns if recent +4. 36 new tests β€” all pass + +**PR:** #505 `squad/464-rate-limit-ux` β€” merged (rebased after #504) + +### Session 2 Summary (2026-03-22) + +Executed 3 tasks across 2 waves: economy mode (#500, PR #504), node:sqlite fix (#502, PR #506), rate limit UX (#464, PR #505). All PRs merged to dev. + + +### Personal Squad Init via npx (#576) (2026-03-23) + +**Context:** `init --global` (used via npx to set up personal squad) created a full `.squad/` structure at `~/.config/squad/` but never created the `personal-squad/` subdirectory. `resolvePersonalSquadDir()` looks for `personal-squad/`, so subsequent repo-level `init` couldn't discover the user's personal agents. + +**Root cause:** Two separate concepts - `init --global` scaffolds a full squad, `personal init` creates `personal-squad/`. The `--global` flag never bridged between them. + +**Fix:** +1. `resolution.ts` - Added `ensurePersonalSquadDir()` idempotent helper to SDK. +2. `cli-entry.ts` - `init --global` now suppresses workflows and passes `isGlobal` flag. +3. `init.ts` - After global init, calls `ensurePersonalSquadDir()`. After repo init, detects personal squad. +4. `personal.ts` - Refactored to reuse `ensurePersonalSquadDir()`. +5. `resolution.test.ts` - Added 3 tests. + +**Pattern:** `resolveGlobalSquadPath()` returns the container; `ensurePersonalSquadDir()` creates the subdirectory the rest of the system looks for. +πŸ“Œ **Team update (2026-03-25T18:11Z):** Fixed #590 personal squad path regression β€” getPersonalSquadRoot() now uses canonical personal-squad/ subdirectory like +resolvePersonalSquadDir() and ensurePersonalSquadDir(). Committed on squad/590-fix-personal-squad-root. FIDO found same bug in shell/index.ts β†’ work passed to CONTROL for full sweep revision. Awaiting FIDO re-review. diff --git a/.squad/agents/eecom/history.md b/.squad/agents/eecom/history.md index 09ac5fdb6..712d5eab7 100644 --- a/.squad/agents/eecom/history.md +++ b/.squad/agents/eecom/history.md @@ -1,59 +1,75 @@ -# Eecom history - +ο»Ώ# Eecom history Summarized by Scribe on 2026-08-20T11:59:44-07:00 because this history exceeded 15KB. -Full pre-summary history archived at `.squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md`. -Prior archive at `.squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md`. -## 2026-08-20 β€” #1772 dispatch probe gate fix - -- Root cause confirmed: dispatch-workflow: max: 1 causes first-wins semantics; LLM empty probe consumes slot; real dispatch silently dropped. -- Prior fix #1766 (prompt wording) confirmed insufficient via live run evidence. -- Fix: raised max to 2 (squad-implement-worker.md) + extended check-workflow-input-interpolation.mjs with checkDispatchWorkflowSchemas() static gate. -- Static gate validates JSON dispatch examples adjacent to dispatch_workflow references: requires non-empty workflow_name, non-empty inputs, inputs.issue_number. -- Added 6 new tests in test/gh-aw-quality.test.ts; key structural test fails against max:1 state, passes after fix. -- Build passes. Decision recorded at .squad/decisions/inbox/eecom-1772-dispatch-probe-gate.md. -- Coordination needed: Procedures to add squad.md empty-command guard (separate PR). - -Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. -Full pre-summary history archived at `.squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md`. - -## Condensed index - -- Replaced all hardcoded "Brady" in template examples with generic `{user}`/`{name}` placeholders. Canonical sources: `.squad-templates/squad.agent.md` and `.copilot/skills/init-mode/SKILL.md`. -- PR #942 rebase: cherry-pick from insider-based fork branch; expect modify/delete conflicts for insider-only files. Opened #963 as clean replacement. -- `archiveDecisions()` count-based fallback (#626): when `old.length === 0` and file > 20KB, sort dated entries by age, keep entries under threshold, archive the rest. Undated entries always preserved. -- Cross-platform filename & config fixes (#348, #356): `safeTimestamp()` everywhere; removed machine-specific `teamRoot` from config.json. -- PR #480 history race condition: three-layer defense β€” async mutex, atomic file operations (write-then-rename), 14 tests. -- PR #486 SIGINT handling: parent handler + child process cleanup (kill children, close handles, flush buffers). 22 tests. -- Economy mode (#500): `ECONOMY_MODEL_MAP` + `resolveModel()` with economy flag. Layer 3/4 modifier only; Layers 0-2 (explicit user preferences) never downgraded. 34 tests. -- node:sqlite hard-fail fix (#502): synchronous version check + `process.exit(1)`; `engines.node` corrected to `>=22.5.0`. 5 tests. -- Rate limit recovery UX (#464): `rateLimitGuidance()` with 3 recovery options; `.squad/rate-limit-status.json`; `checkRateLimitStatus()` in doctor. 36 tests. -- Personal squad init (#576): `ensurePersonalSquadDir()` idempotent helper. `init --global` calls it; `personal.ts` reuses it. - -## Recent preserved tail β€” P0 Triage (2026-08-20) - -Performed read-only triage of 10 open gh-aw issues for Brady's pre-E2E pass. - -- **#1772 (P0) β€” STILL REAL.** Commit b6804305 added prompt wording; structural defect at `squad-implement-worker.md:204` (`dispatch-workflow max: 1`) untouched. Fix must be structural β€” extend `scripts/check-workflow-input-interpolation.mjs` or add runtime rejection for empty dispatch payloads. -- **#1758 (P0) β€” STILL REAL, all 3 defects.** (1) squad-plan-accept Step 1 at L654 hardcodes plan artifact lookup (L648 behavior note is prose only). (2) Epic Dispatch at L529-554 dispatches Epics in 3-level tree. (3) Validate at L867 is after accept-scope. Wave:3 (depends on #1759); code work now, live E2E proof after #1772 fixed. -- **#1730, #1731** β€” well-specified. Ship for review-gate path (contested with Flight's wave:1 cap). -- **#1604, #1609** β€” CLOSE. Scope sprawl relative to core E2E correctness goal. -- **#1733, #1735, #1605, #1606, #1731** β€” DEFER. +Full pre-summary history archived at .squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md. +Prior archive at .squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md. +## 2026-08-20 β€” #1772 dispatch probe gate fix + +- Root cause confirmed: dispatch-workflow: max: 1 causes first-wins semantics; LLM empty probe consumes slot; real dispatch silently dropped. +- Prior fix #1766 (prompt wording) confirmed insufficient via live run evidence. +- Fix: raised max to 2 (squad-implement-worker.md) + extended check-workflow-input-interpolation.mjs with checkDispatchWorkflowSchemas() static gate. +- Static gate validates JSON dispatch examples adjacent to dispatch_workflow references: requires non-empty workflow_name, non-empty inputs, inputs.issue_number. +- Added 6 new tests in test/gh-aw-quality.test.ts; key structural test fails against max:1 state, passes after fix. +- Build passes. Decision recorded at .squad/decisions/inbox/eecom-1772-dispatch-probe-gate.md. +- Coordination needed: Procedures to add squad.md empty-command guard (separate PR). + +Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. +Full pre-summary history archived at `.squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md`. + +## Condensed index + +- Replaced all hardcoded "Brady" in template examples with generic `{user}`/`{name}` placeholders. Canonical sources: `.squad-templates/squad.agent.md` and `.copilot/skills/init-mode/SKILL.md`. +- PR #942 rebase: cherry-pick from insider-based fork branch; expect modify/delete conflicts for insider-only files. Opened #963 as clean replacement. +- `archiveDecisions()` count-based fallback (#626): when `old.length === 0` and file > 20KB, sort dated entries by age, keep entries under threshold, archive the rest. Undated entries always preserved. +- Cross-platform filename & config fixes (#348, #356): `safeTimestamp()` everywhere; removed machine-specific `teamRoot` from config.json. +- PR #480 history race condition: three-layer defense β€” async mutex, atomic file operations (write-then-rename), 14 tests. +- PR #486 SIGINT handling: parent handler + child process cleanup (kill children, close handles, flush buffers). 22 tests. +- Economy mode (#500): `ECONOMY_MODEL_MAP` + `resolveModel()` with economy flag. Layer 3/4 modifier only; Layers 0-2 (explicit user preferences) never downgraded. 34 tests. +- node:sqlite hard-fail fix (#502): synchronous version check + `process.exit(1)`; `engines.node` corrected to `>=22.5.0`. 5 tests. +- Rate limit recovery UX (#464): `rateLimitGuidance()` with 3 recovery options; `.squad/rate-limit-status.json`; `checkRateLimitStatus()` in doctor. 36 tests. +- Personal squad init (#576): `ensurePersonalSquadDir()` idempotent helper. `init --global` calls it; `personal.ts` reuses it. + +## Recent preserved tail β€” P0 Triage (2026-08-20) + +Performed read-only triage of 10 open gh-aw issues for Brady's pre-E2E pass. + +- **#1772 (P0) β€” STILL REAL.** Commit b6804305 added prompt wording; structural defect at `squad-implement-worker.md:204` (`dispatch-workflow max: 1`) untouched. Fix must be structural β€” extend `scripts/check-workflow-input-interpolation.mjs` or add runtime rejection for empty dispatch payloads. +- **#1758 (P0) β€” STILL REAL, all 3 defects.** (1) squad-plan-accept Step 1 at L654 hardcodes plan artifact lookup (L648 behavior note is prose only). (2) Epic Dispatch at L529-554 dispatches Epics in 3-level tree. (3) Validate at L867 is after accept-scope. Wave:3 (depends on #1759); code work now, live E2E proof after #1772 fixed. +- **#1730, #1731** β€” well-specified. Ship for review-gate path (contested with Flight's wave:1 cap). +- **#1604, #1609** β€” CLOSE. Scope sprawl relative to core E2E correctness goal. +- **#1733, #1735, #1605, #1606, #1731** β€” DEFER. + +Decision record: `decisions/inbox/eecom-p0-triage-2026-08-20.md` β†’ merged. + +## πŸ“Œ Team update β€” 2026-08-20T11:59:44-07:00 + +gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: CLOSE 7 issues (#1738,#1762,#1764,#1768,#1763,#1604,#1609); SHIP-NOW 5 (#1772,#1758,#1759,#1732-compile,#1761); 2 contested (#1730,#1756); 12 deferred. Both P0s (#1772,#1758) still real β€” structural defects unresolved. Wave:1 cap=6. Tomorrow is a full-day E2E series against aspiregregator-squad-e2e. E2E will break at S3 if #1772 is not fixed first. + +## πŸ“Œ Team update β€” 2026-08-20T13:20:20-07:00 + +Batch 2 complete. Fixed #1772 (P0): `max: 1` β†’ `max: 2` in squad-implement-worker.md + `checkDispatchWorkflowSchemas()` static gate + 6 tests. All tests verified to fail against pre-fix state. CI run 32410579973 confirms gate active. PR #1777 green, awaiting Flight gate. `max: 2` is the worker's outbound budget; Procedures' guard is squad.md's inbound validation β€” complementary layers. + -Decision record: `decisions/inbox/eecom-p0-triage-2026-08-20.md` β†’ merged. +## 2026-08-22 β€” gh-aw triage team update -## πŸ“Œ Team update β€” 2026-08-20T11:59:44-07:00 +πŸ“Œ Team update (2026-08-22T17:10:52-07:00): EECOM is in flight on #1793 phantom CRLF diffs causing stuck sessions in sub-session 5cba11df-facd-44c9-a1d9-437259728019. Related context: coordinator must avoid broad staging while the CRLF issue exists. -gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: CLOSE 7 issues (#1738,#1762,#1764,#1768,#1763,#1604,#1609); SHIP-NOW 5 (#1772,#1758,#1759,#1732-compile,#1761); 2 contested (#1730,#1756); 12 deferred. Both P0s (#1772,#1758) still real β€” structural defects unresolved. Wave:1 cap=6. Tomorrow is a full-day E2E series against aspiregregator-squad-e2e. E2E will break at S3 if #1772 is not fixed first. +## πŸ“Œ Team update β€” 2026-08-22T18:25:00-07:00 -## πŸ“Œ Team update β€” 2026-08-20T13:20:20-07:00 +PR #1831 merged as `9378a379` for #1793. EECOM shipped local CRLF working-tree detection/repair, resolved three Copilot review threads, and captured the follow-on principle that gate remediation/verification instructions must cover the same artifact set as the check itself. +## πŸ“Œ Team update β€” 2026-08-22T19:42:25-07:00 -Batch 2 complete. Fixed #1772 (P0): `max: 1` β†’ `max: 2` in squad-implement-worker.md + `checkDispatchWorkflowSchemas()` static gate + 6 tests. All tests verified to fail against pre-fix state. CI run 32410579973 confirms gate active. PR #1777 green, awaiting Flight gate. `max: 2` is the worker's outbound budget; Procedures' guard is squad.md's inbound validation β€” complementary layers. +Rework of PR #1832 under Reviewer Rejection Protocol (Procedures locked out after FIDO Pass 2 found BLOCKING dispatch regression). +**Problem:** Bare workflow_dispatch commands (implement, esearch, etc.) regress to loud failure. PC-1 requires /squad token; dispatch sends bare command value. Pre-fix worked; post-fix: NO_COMMAND β†’ PC-3 hard fail. -## 2026-08-22 β€” gh-aw triage team update +**Solution:** Commit 6e7628c5 β€” add Step PC-0 normalization layer before PC-1: +- workflow_dispatch bare command β†’ synthesize /squad prefix +- Idempotent: already-prefixed text unchanged +- All 6 documented dispatch modes resolve +- PC-1 NOT loosened (guard fires on mutation) +- Greedy last-token defect fixed (Finding 3) +- Tests 15 β†’ 27 (all pass, all mutations red-and-naming) -πŸ“Œ Team update (2026-08-22T17:10:52-07:00): EECOM is in flight on #1793 phantom CRLF diffs causing stuck sessions in sub-session 5cba11df-facd-44c9-a1d9-437259728019. Related context: coordinator must avoid broad staging while the CRLF issue exists. - -## πŸ“Œ Team update β€” 2026-08-22T18:25:00-07:00 +FIDO Pass 3 verified all measurements. CI green. PC-0 NR==1 leading-newline edge case noted as latent nit (unreachable via real producers). -PR #1831 merged as `9378a379` for #1793. EECOM shipped local CRLF working-tree detection/repair, resolved three Copilot review threads, and captured the follow-on principle that gate remediation/verification instructions must cover the same artifact set as the check itself. \ No newline at end of file +PR merged; issue closed. \ No newline at end of file diff --git a/.squad/agents/pao/history-archive-2026-08-20T11-59-44-0700.md b/.squad/agents/pao/history-archive-2026-08-20T11-59-44-0700.md new file mode 100644 index 000000000..012ea6053 --- /dev/null +++ b/.squad/agents/pao/history-archive-2026-08-20T11-59-44-0700.md @@ -0,0 +1,120 @@ +# Pao history + +Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. +Full pre-summary history archived at `.squad/agents/pao/history-archive-2026-08-19T13-11-34.130-07-00.md`. + +## Condensed index + +- Preserved 315 original line(s) in the archive. +- Detected 41 heading(s) and 17 dated reference line(s). +- This file now keeps a compact index plus the most recent tail so active context remains visible. + +## Notable retained signals + +- Rewrote PUBLISH-README.md from v0.8.22 stub (58 lines) to living 232-line version-agnostic playbook with 11 sections: Overview, Pre-Flight Checklist, Publish via CI (recommended), workflow_dispatch fallback, Insider Channel, Workspace Publish Policy, Manual Local Publish, 422 Race Condition & npm Errors, Post-Publish Verification, Version Bump, Legacy Scripts. Pattern: living playbook absorbs multiple issues (#558, #559, #560) into unified decision tree. Microsoft Style Guide enforced; `` placeholder; all commands copy-pasteable. +- πŸ“Œ **Team update (2026-03-24T06-release-hardening):** Release playbook rewrite (#564) completed. Absorbed issues #558, #559, #560 into unified decision tree. +- Full PRD at `docs/research/jsdoc-api-reference-prd.md`. Key decisions: TypeDoc + typedoc-plugin-markdown (not Starlight, not api-extractor) β€” zero migration, Markdown-first, Pagefind-compatible. Astro integration hook auto-runs TypeDoc on build. Output β†’ `docs/src/content/docs/reference/api/`. JSDoc improvement priority: config/schema.ts (8%β†’100%), state/io/ @param/@return tags. Total effort: 13–18 hours. PRD structure: chosen path + tactical roadmap (not advisory β€” directive). +- 6 discussions closed as resolved (features shipped in v0.9.1: per-agent models #463/#402, local-only #324, CLI vs agent #299, human members #143, skills system #169). 8 discussions kept open with substantive replies. Pattern: feature-release timing + follow-up responses critical for community trust. **Teams MCP critical:** Office 365 Connectors retired Dec 2024 β†’ Power Automate Workflows is successor. Purge all old connector references. +- **Boundary review:** "Squad Ships It" litmus test β€” if Squad doesn't ship the code, it's IRL content. Platform features: clarify whose feature it is. Delete external infrastructure docs; reframe platform integration docs; keep Squad behavior/config docs. Pattern from PR #331. +- **npx purge:** `npm install -g @bradygaster/squad-cli` is only supported install path. Remove all user-facing `npx` references. Keep `npx` only for dev tools (changeset, vitest, astro, pagefind). Agency copilot example β†’ `gh copilot`. +- **PR #11 TypeDoc review (2026-03-24):** Generated docs require crosslinks from curated guides. When adding new docs section, ensure old curated page has a visible pointer to the new section. Blocking issues: missing sdk.md crosslink banner, navigation URL inconsistency (`reference/api/index` β†’ `reference/api`). +- ### Discussion Triage Patterns (2026-03-23 Release Incident) +- **Triage workflow:** +- **Critical finding:** Teams MCP docs need urgent update β€” Office 365 Connectors deprecated Dec 2024. Docs must purge old connector references and document Power Automate Workflows path (new successor). +- ### Chinese README Workflow (2026-03-23 Release Incident) +- Community contributor (PR #572) provided Chinese README translation. Approved and merged as part of v0.9.1 release. Pattern: accept community translations; list contributors in CONTRIBUTORS.md; acknowledge in release notes. +- External tool integrations deprecate. Office 365 Connectors retired Dec 2024. Docs mentioning deprecated tools create support burden and user confusion. Action: audit all external tool integration docs for deprecation; update with successor guidance (Power Automate Workflows for Teams). +- Explicitly state what a skill produces and does NOT produce. Deterministic skills prevent agents from generating unnecessary code when templates exist. +- External tool integrations require explicit "where to get it" guidance. Placeholder paths need clarification that users must provide actual MCP server implementations. +- When rebasing doc PRs with conflicts from other merged doc PRs, the main branch version (already merged) should generally take priority. For Node.js version references, maintain LTS terminology when present (e.g., `nvm install --lts` over specific version numbers like `nvm install 20`). Conflict resolution pattern: preserve new content from PR branch only where it doesn't duplicate or contradict already-merged changes. Use `git -c core.editor=true rebase --continue` to bypass interactive editor issues on Windows. +- Two-way communication layer between Squad and work environment. Outbound: Teams webhook notifications (breaking, briefings, recaps, flashes) sent via Adaptive Cards β€” only when newsworthy. Inbound: WorkIQ/Playwright scanning of Teams channels and email β†’ auto-create GitHub issues with teams-bridge label, anti-duplicate logic enforced. Loop: inbound creates issues β†’ Ralph dispatches β†’ agents work β†’ outbound notifies results. Human stays informed on mobile. Prerequisites are enhancements, not requirements. +- πŸ“Œ **Team update (2026-03-11T01:27:57Z):** Proactive communication patterns and PR trust levels (full/selective/self-managing spectrum) documented in decisions.md. Pattern rationale reinforced: Ralph 24/7 autonomous deployment requires awareness loop (Teams webhooks for outbound) and external work integration (WorkIQ scanning for inbound). Trust levels enable context-appropriate oversight without bottlenecking teams. +- ### PR #487 Review & Merge β€” CLI Docs Expansion (2026-03-22) +- Reviewed and merged PR #487 (CLI documentation expansion + broken docs link fix). Improved CLI command reference coverage and fixed internal link validation. +- **Pattern identified:** Broken internal links hurt user navigation and SEO. Recommendations: (1) add link validation to docs build pipeline (crawl all internal references, report 404s), (2) make validation a CI gate (fail build on broken links), (3) maintain link checklist when refactoring docs structure. +- **Key learning:** Documentation maintenance requires systematic link validation. A single broken link creates friction for users following guides. Automated validation should be non-negotiable in CI/CD. +- ### PR #482 Review & Merge β€” Pagefind Search Integration (2026-03-22) +- Reviewed and merged PR #482. Search functionality integrated into docs site for improved discoverability. + +## Recent preserved tail + +- #143 (Human team members now first-class feature) +- #169 (Skills system shipped as core infrastructure) + +**8 discussions kept open with substantive replies:** +- #534 (enterprise features) β€” asked clarifying questions on scope +- #499 (Brady's v1.0 announcement) β€” explained `.squad/` regenerability plan +- #440 (branch naming change) β€” acknowledged disruption, offered migration guidance +- #401 (mobile/async control) β€” acknowledged use case, roadmap signal +- #376 (best practices) β€” provided triage and routing patterns +- #306 (multi-root support) β€” acknowledged limitation, kept open for feedback +- #95 (casting system) β€” explained mature re-casting flow +- #140 (Teams MCP) β€” critical guidance on Office 365 Connectors retirement β†’ Power Automate Workflows + +**Pattern observed:** Feature-release timing + follow-up responses critical for community trust. v0.9.1 directly addressed 5+ discussions (models, skills, human members) that were open 2-4 weeks. Community triage now operational: 14 discussions reviewed, 6 closed, 8 kept active = 43% closure rate on resolved items. + +**Key insight:** Retirement of Microsoft Office 365 Connectors (Dec 2024) caught users mid-setup. Proactive notification of Teams Workflows alternative + Power Automate guidance essential for Teams MCP users. + +### Release Playbook Rewrite (#564, 2026-07-22) + +**Task:** Rewrite PUBLISH-README.md from a v0.8.22 version-specific stub (58 lines) into a living, version-agnostic release playbook. + +**Outcome:** 232-line playbook replacing entirely with 11 sections per Flight's spec: +1. Overview β€” two publish channels, package order (SDK β†’ CLI) +2. Pre-Flight Checklist β€” runnable checklist with `grep`/`npm` commands +3. Publish via CI (Recommended Path) β€” GitHub Release workflow +4. Publish via workflow_dispatch β€” manual trigger fallback +5. Insider Channel β€” insider branch + `@insider` tag for testing +6. Workspace Publish Policy β€” reference to CI lint rule #557 (enforces `-w` flag) +7. Manual Local Publish β€” emergency fallback with step-by-step commands +8. 422 Race Condition & npm Errors β€” v0.9.1 incident + troubleshooting +9. Post-Publish Verification β€” `npm view` + npx cold-install test +10. Version Bump After Publish β€” preview version increment pattern +11. Legacy Publish Scripts β€” deprecation notice for PowerShell scripts + +**Key decisions:** +- Microsoft Style Guide enforced: sentence-case headings, active voice, "you" not "we", present tense +- Version-agnostic: `` placeholder, no hardcoded version numbers +- Scannability: checklist format, code blocks (bash not PowerShell for portability), tables for error reference +- Accuracy: pulled from actual workflows (`squad-npm-publish.yml`, `squad-insider-publish.yml`) β€” preflight job, smoke test, publish stages, registry propagation retry logic (5Γ— 15-second intervals) +- Runnable: all commands copy-pasteable (e.g., `npm -w packages/squad-sdk pack --dry-run`) + +**Pattern:** Living playbook absorbs three related issues (#558 race conditions, #559 manual publish, #560 pre-flight checklist) into unified reference. No separate documents; all under one decision tree: try CI first, use manual only if CI broken. Workspace publish policy section references CI lint rule #557 (being added in parallel by FIDO); both docs + lint create enforcement + education. + +**Commit:** `docs: rewrite PUBLISH-README.md as release playbook (#564)` on squad/release-hardening branch. + +πŸ“Œ **Team update (2026-03-24T06-release-hardening):** Release playbook rewrite (#564) completed. PUBLISH-README.md transformed from v0.8.22 stub to living 232-line playbook with 11 sections: Overview, Pre-Flight Checklist, Publish via CI (recommended), Publish via workflow_dispatch, Insider Channel, Workspace Publish Policy, Manual Local Publish (emergency fallback), 422 Race Condition & npm Errors, Post-Publish Verification, Version Bump After Publish, Legacy Publish Scripts. Absorbed issues #558, #559, #560 into unified decision tree. Microsoft Style Guide enforced; version-agnostic; all commands runnable. Scannability: checklist format, bash code blocks, error reference table. Committed to squad/release-hardening. +### JSDoc API Reference PRD (2026-03-24) + +Completed full PRD based on research findings. **Document:** `docs/research/jsdoc-api-reference-prd.md`. + +**Structure (8 major sections):** +1. Problem Statement β€” 5 concrete gaps (no dedicated API ref, uneven JSDoc coverage, discoverability, StorageProvider docs lag, Pagefind misses API symbols) +2. Goals & Success Metrics β€” 4 primary goals, 8 measurable targets (100% JSDoc coverage, 50+ auto-documented symbols, searchable API) +3. Key User Scenarios β€” 4 personas (SDK consumer, contributor, agent author, evaluator) with today vs future workflows +4. Scope β€” clear in/out boundaries (TypeDoc + JSDoc improvements in; CLI ref gen, Starlight migration, multi-version docs out) +5. Approach β€” architecture (TypeDoc in Astro hook), config template (typedoc.json), output/URL structure, build integration code, JSDoc improvement plan with effort table +6. Implementation Phases β€” 4 phases: Phase 0 (setup/PoC, 1–2 days), Phase 1 (JSDoc audit, 5–6 hrs), Phase 2 (integration/nav, 3–4 hrs), Phase 3 (CI/CD optional, 2–4 hrs) +7. Risks & Mitigations β€” 7 risks (TypeDoc breaks on changes, stale markdown, link validation strictness, Pagefind misses, config maintenance, build perf, breaking changes) with specific mitigations +8. Architecture Review section β€” 4 items for CONTROL to review (TypeScript export strategy, TypeDoc config, JSDoc standards, stability commitments) + +**Key decisions baked into PRD:** +- TypeDoc + typedoc-plugin-markdown (not Starlight, not api-extractor) β€” zero migration, Markdown-first, Pagefind-compatible +- Astro integration hook auto-runs TypeDoc on build (single step: `npm run build`) +- Generated output goes to docs/src/content/docs/reference/api/ (one file per symbol) +- JSDoc improvement priority: config/schema.ts (8% β†’ 100%), state/io/ functions (@param/@return tags), StorageProvider interface audit +- Total effort: 13–18 hours (8–12 JSDoc + 5–6 setup) + +**Style & Tone:** +- Written for Flight-level review/approval (actionable, opinionated, specific) +- Includes code examples (typedoc.json, Astro hook, JSDoc template) +- References research doc for detailed findings +- PRD as decision/commitment document β€” not advisory, but directive + +**Learnings:** +- PRD structure differs from research (research = exploratory findings/options; PRD = chosen path + tactical roadmap) +- Recommendation section in PRD serves as binding decision (TypeDoc chosen, rationale locked in) +- Architecture Review section ensures TypeScript team reviews export strategy and JSDoc standards early β€” prevents rework later +- Four-phase approach breaks large effort into digestible increments (Phase 0 validation before JSDoc audit helps mitigate risk of TypeDoc setup failing) + +**Decision:** PRD approved for handoff to implementation team. Ready for execution on next sprint. diff --git a/.squad/agents/procedures/history-archive-2026-08-20T11-59-44-0700.md b/.squad/agents/procedures/history-archive-2026-08-20T11-59-44-0700.md new file mode 100644 index 000000000..1298528a8 --- /dev/null +++ b/.squad/agents/procedures/history-archive-2026-08-20T11-59-44-0700.md @@ -0,0 +1,119 @@ +# Procedures history + +Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. +Full pre-summary history archived at `.squad/agents/procedures/history-archive-2026-08-19T13-11-34.130-07-00.md`. + +## Condensed index + +- Preserved 231 original line(s) in the archive. +- Detected 16 heading(s) and 19 dated reference line(s). +- This file now keeps a compact index plus the most recent tail so active context remains visible. + +## Notable retained signals + +- **#485 (Agent Specification PRD)** β†’ squad:flight + squad:procedures (architecture decision + formal spec structure) +- Pattern: Agent specification gap identified. Procedures owns formal spec structure and documentation; Flight owns architecture decisions. +- πŸ“Œ **Team update (2026-03-26T06:41:00Z β€” Crash Recovery Execution & Model Catalog Merge):** Procedures executed Round 2 PR merge action: rebased PR #619 (model catalog refresh, issue #588) onto dev branch from main, resolved 3 merge conflicts, and successfully merged. Model catalog now current: default model bumped to `claude-sonnet-4.6` (latest standard-tier Claude), specialist bumped to `gpt-5.3-codex` (latest code-writing specialist), fallback chains restructured to include new models (`gpt-5.4`, `gpt-5.4-mini`) and removed dead models (`claude-opus-4.6-fast`). All 6 original merge-plan PRs (#620, #627, #624, #611, #617, #619) now βœ… complete. Dev branch green (5,038 tests). Decision inbox merged to decisions.md and deleted. Next: Ready for follow-on feature PRs. +- πŸ“Œ **Team update (2026-03-22T06:44:01Z):** Flight issued comprehensive triage. Procedures owns Agent Specification PRD structure (#485). Architecture decisions from Flight. Coordinate on formal spec format and standard structure for future agent definitions. +- **Deterministic skill pattern (2026-03-10):** Skills must have explicit SCOPE (what they produce/don't) and AGENT WORKFLOW (deterministic steps with STOP condition). Same input β†’ same output, every time. +- **Three governance policies (2026-03-15):** Agent Error Lockout (2 errors β†’ reassign), Product Isolation Rule (tests/CI/code never depend on squad names), Peer Quality Check (run tests before finishing). Applied to all 19 charters. +- **Team-wide reskill (2026-03-16):** 17.4% size reduction β€” NEVER/ALWAYS sections compress to single-paragraph summaries; essential workflow details stay verbose. +- **Personal squad governance (2026-03-22):** `CONSULT_MODE: true` as spawn signal. Governance changes go to `decisions/inbox/` for Flight review β€” don't edit squad.agent.md directly. +- **VS Code routing investigation (2026-03-25):** CLI-centric enforcement language causes coordinator to work inline in VS Code. Fix: platform-neutral dispatch language + reinforcement at prompt bottom. +- **VS Code routing fix (2026-07):** Fix 1 + Fix 2 shipped. CRITICAL RULE rewritten to dispatcher-identity framing ("DISPATCHER, not a DOER") with dispatch mechanism table. Routing Enforcement Reminder added as final section. Remaining P1 fixes (template renaming, prompt slimming) deferred. +- **PR #619 rebase (2026-07):** When a PR has accumulated dev merge commits, use `git rebase --onto dev ` to cherry-pick only relevant commits. +- **Trim copilot-instructions.md (#999, 2026-04-17):** 1300w/9KB β†’ 397w/3KB. Extracted Protected Files to skill, consolidated Git Safety, removed duplication. Pattern: main instructions = routing/workflow; skills = domain-specific reference (lazy-loaded on demand). +- πŸ“Œ **Team update (2026-03-22T09-35Z β€” Wave 1):** Economy mode governance proposal and personal squad consult-mode governance proposal authored for squad.agent.md β€” both DRAFT, awaiting Flight review before merging. Economy mode adds Layer 3 table + spawn convention (`πŸ’° economy`) + model catalog audit. Personal squad adds consult mode detection, path reference table, spawn guidance. Persistent model preference (Layer 0) documented. Proposed new skill: `.squad/skills/consult-mode/SKILL.md` (post-approval). Deterministic skill pattern proven effective. PR #503 open with skills module. Next: Flight review β†’ merge governance to squad.agent.md. No blocking issues. +- **Problem:** Skills were too loose. The distributed-mesh skill was tested in a real project (mesh-demo), and agents generated 76 lines of validator code, 5 test files with 43 tests, regenerated sync scripts that should have been copied from templates, and left decision files empty. The skill document let agents interpret intent instead of following explicit steps. +- ❌ THIS SKILL DOES NOT PRODUCE β€” explicit negative list to prevent scope creep +- 2. **AGENT WORKFLOW section** β€” Step-by-step deterministic instructions +- WRITE: exactly which decision entry to write, with template +- STOP: explicit stopping condition, with negative list of what NOT to do +- Phase descriptions β†’ note that phases are project-level decisions, not auto-advanced +- 4. **Decision template** β€” inline markdown showing exactly what to write +- 5. **Anti-patterns for code generation** β€” explicit list of things NOT to build +- **Pattern for other skills:** All skills should have SCOPE (what it produces, what it doesn't) and AGENT WORKFLOW (deterministic steps with STOP condition). Same input β†’ same output, every time. Zero ambiguity. +- πŸ“Œ Team update (2026-03-14T22-01-14Z): Distributed mesh integrated with deterministic skill pattern β€” decided by Procedures, PAO, Flight, Network +- 2. **Update SKILL.md workflow:** + +## Recent preserved tail + +- Scribe spawn template (hardcoded `name: "scribe"`) + +Also updated: examples section (showing `name` + `description` pairs), anti-pattern #4 (now covers both `name` and `description`), and Constraints section (requiring `name` on every spawn). + +**Pattern:** Every `task` tool spawn MUST include `name` set to the agent's lowercase cast name. Without it, the platform defaults to generic slugs. The `description` parameter is for the human-readable summary; `name` is for the agent ID. + +πŸ“Œ **Team update (2026-03-23T23:15Z):** Orchestration complete. Agent name display refactor shipped: spawn templates updated with mandatory `name` parameter across all 4 template variants. VOX and FIDO coordinated on parser extraction and cascading pattern strategies. All decisions merged to decisions.md. Canonical source: `.squad-templates/squad.agent.md` (all derived copies secondary). + +πŸ“Œ **Team update (2026-03-25T18:11Z):** Model catalog updated to current platform offerings β€” removed 2 stale models (claude-opus-4.6-fast, gpt-5), added 5 new models (claude-sonnet-4.6, claude-opus-4.6-1m, gpt-5.4, gpt-5.3-codex, gpt-5.4-mini), bumped defaults (code: claude-sonnet-4.6, specialist: gpt-5.3-codex), restructured fallbacks. All 5 squad.agent.md template copies synchronized. Merged in #588. + +### 2025-07: Model catalog refresh (#588) + +**Problem:** The valid models catalog, fallback chains, role-to-model mappings, and default model references in `squad.agent.md` were stale β€” missing `claude-sonnet-4.6`, `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.4-mini`, `claude-opus-4.6-1m` and still referencing removed models `claude-opus-4.6-fast` and standalone `gpt-5`. + +**Fix:** Full catalog refresh across all model-referencing sections: +- Catalog: added 5 new models, removed 2 stale ones +- Defaults: code-writing tasks bumped to `claude-sonnet-4.6` (newest standard); code specialist bumped to `gpt-5.3-codex` +- Fallback chains: restructured with new models in sensible positions (e.g., `gpt-5.4-mini` in fast tier, `gpt-5.4` in standard) +- All 5 copies synced via `sync-templates.mjs` + +**Pattern:** Model catalogs drift. When the platform adds/removes models, every section referencing models needs updating β€” not just the catalog list. Search for all model name strings before considering the refresh complete. +### 2026-03-25: VS Code routing enforcement investigation (#613) + +**Problem:** In VS Code, the coordinator reads routing rules but doesn't enforce them β€” continues working inline instead of dispatching via `runSubagent`. Andreas (andikrueger) reproduced and the agent itself admitted it violated the rules. + +**Root cause (dominant):** CLI-centric enforcement language. The CRITICAL RULE says "MUST use the `task` tool" β€” but in VS Code the dispatch tool is `runSubagent`. When `task` isn't available, the coordinator falls through Platform Detection's "Fallback mode" (work inline) instead of using `runSubagent`. The VS Code adaptations section is buried 360 lines below the CRITICAL RULE and reads as optional, not mandatory. + +**Amplifying factors:** +1. Prompt saturation: 950 lines / 80KB. Routing constraint competes with 900+ lines of governance, lifecycle, and reference material. Core dispatch loop is ~200 lines; rest is noise. +2. Template duplication: CLI 1.0.11 discovers all `*.agent.md` from cwd to git root. Squad has 5 copies β€” only `.github/agents/squad.agent.md` should be discoverable. + +**Proposed fixes (5 total, prioritized):** +- P0: Rewrite enforcement language to be platform-neutral ("dispatch tool" not "`task` tool") +- P0: Add routing reinforcement at bottom of prompt (LLMs weight start/end more than middle) +- P1: Rename template copies to `.agent.md.template` to prevent CLI discovery +- P1: Extract ~350 lines to lazy-loaded reference files (worktree, Ralph, casting, MCP) +- P1: Move VS Code dispatch block immediately after CRITICAL RULE + +**Key pattern learned:** Enforcement language must name ALL dispatch mechanisms, not just the CLI one. Platform-specific instructions buried deep in a long prompt get lost β€” they need to be co-located with the constraint they modify. LLM attention patterns favor prompt boundaries (top/bottom) over the middle. + +**Proposal filed:** `.squad/decisions/inbox/procedures-vscode-routing-fix.md` + +### 2026-07: VS Code routing enforcement β€” Fix 1 + Fix 2 shipped (#613) + +**Implemented** P0 fixes from the VS Code routing proposal: + +- **Fix 1 (Platform-Neutral Enforcement):** Rewrote CRITICAL RULE from CLI-specific "`task` tool" language to dispatcher-identity framing ("You are a DISPATCHER, not a DOER") with explicit dispatch mechanism table (CLI β†’ `task`, VS Code β†’ `runSubagent`, fallback β†’ inline as last resort). Updated all 7 enforcement-context references throughout squad.agent.md: anti-patterns #1/#2/#3, constraints block, and spawn template header. + +- **Fix 2 (Top-and-Bottom Reinforcement):** Added `## ⚠️ Routing Enforcement Reminder` as final section, exploiting LLM prompt-boundary attention bias. Reinforces dispatcher identity at both top and bottom of the prompt. + +**Branch:** `squad/613-vscode-routing-enforcement` β€” canonical source edited, synced to all 5 copies via `scripts/sync-templates.mjs`, build verified clean. + +**Remaining P1 fixes** (template renaming, prompt slimming, VS Code block relocation) deferred to separate PRs per the proposal's ship order. + +### 2026-07: PR #619 rebase and merge β€” model catalog final sync + +**Problem:** PR #619 (model catalog update, #588) was the last of 6 PRs in the pre-crash triage merge plan. It had accumulated old dev merge commits and was behind after PRs #620, #627, #624, #611, and #617 merged first. Template renames from #624 (`.agent.md` β†’ `.agent.md.template`) changed which files needed updating. + +**Fix:** Used targeted `git rebase --onto dev ` to replay only the 2 actual PR commits (skipping accumulated dev merge noise). Rebase applied cleanly β€” one commit landed, one was auto-dropped as already upstream. After rebase, only `packages/squad-sdk/templates/squad.agent.md.template` and `templates/squad.agent.md.template` needed changes since the canonical and other copies already had the model updates from earlier merges. + +**Pattern:** When a PR branch has accumulated merge commits from dev, use `git rebase --onto dev ` to cherry-pick only the relevant commits. This avoids conflict noise from old merge commits that are already in dev. Also: after template renames, the sync script may overwrite version stamps in the canonical file β€” revert those before pushing. + +### 2026-04-17: Trim copilot-instructions.md (#999) + +**Task:** Reduce `.github/copilot-instructions.md` from ~1,300 words / 9KB to ≀750 words / ≀4KB to reduce attention dilution for the Copilot coding agent. + +**Key decisions:** +- Extracted Protected Files (file list, rules, SDK/CLI boundary, anti-patterns) to `.copilot/skills/protected-files/SKILL.md` β€” replaced with 2-sentence pointer +- Consolidated Git Safety from 4 sub-sections (Staging, Pushing, Pre-Push Checklist, Branch Contamination Prevention) into a single 7-item flat list; resolved contradictory `git fetch upstream` vs `git fetch origin` (kept `origin`) +- Compacted Changeset Requirement from 7 lines + code block to 2 sentences +- Reordered: Team Context, Capability Self-Check, Branch Naming now appear before Git Safety (essential workflow first, safety rules second) +- Removed duplication with `.squad/copilot-instructions.md` (5 sections were verbatim copies; kept compact versions since both files load) +- Sweeping Refactor Rules condensed from 5-step list to 2-sentence pointer + +**Result:** 397 words / 3KB β€” well within target. PR #1002. + +**Files modified:** `.github/copilot-instructions.md`, `.copilot/skills/protected-files/SKILL.md` (new). + +**Pattern:** When trimming agent instructions, extract domain-specific reference content to skills (lazy-loaded on demand) and keep the main instructions file as a routing/workflow document. Skills are the right abstraction for "read this when you touch X" β€” they don't consume tokens until needed. From 16843e656d1fb25c6eae368a6d502553d1bba368 Mon Sep 17 00:00:00 2001 From: brady gaster Date: Sat, 22 Aug 2026 20:29:21 -0700 Subject: [PATCH 4/6] docs(squad): record the declared-vs-enforced principle and its corollary A requirement with no observer is documentation, not a rule. Six confirmations measured this working day, including the positive case -- RETRO's hop-1 shell contract, which openly labels itself unenforced and files the gate (#1834). That is the safe form; the failure mode is prose that reads as a guarantee. Sub-pattern: an unenforced requirement does not merely fail silently, it can emit an affirmative false claim of compliance -- "Roster set read from team.md" over a preset list; a commit titled "repair archives" that performed the loss (c508d866). False provenance is the worst case. Corollary -- a measured number that misstates its unit collapses the same way: the observation happened, but the number does not mean what it claims. Six instances on one file in one day, terminating in a false verdict: Scribe's "UNRECOVERABLE -- all commits < 10KB" against paths holding 41 commits at 13,605 B. A false measurement that becomes a conclusion to stop looking. Two rules: state the unit and the producing command for every number; prefer a measure nothing can reinterpret. During the repair, char count, line count and heading containment all passed on a BOM'd, newline-stripped file. Only the blob SHA could observe it. The record carries zero navigational line numbers -- every citation is a grep anchor that revalidates on read. Drift pressure scales with writer count, so decisions.md (union merge, every agent appending) is the last place to cite a line: the permanently-green restatement moved ~L604 -> L598 in one session, unannounced. Refs #1836, #1824, #1812, #1834 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0e20e987-a753-41c4-a6f8-992d863a32cd --- .../inbox/flight-declared-vs-enforced.md | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .squad/decisions/inbox/flight-declared-vs-enforced.md diff --git a/.squad/decisions/inbox/flight-declared-vs-enforced.md b/.squad/decisions/inbox/flight-declared-vs-enforced.md new file mode 100644 index 000000000..b7d2e7b0d --- /dev/null +++ b/.squad/decisions/inbox/flight-declared-vs-enforced.md @@ -0,0 +1,78 @@ +### 2026-08-22: A requirement with no observer is documentation, not a rule (declared vs. enforced) + +**By:** Flight (Lead), requested by bradygaster + +**Principle (quotable):** *A requirement expressed only as prose β€” in a prompt or a document β€” is not enforced. If compliance and non-compliance produce identical observable output, the requirement will be violated in plain sight and nothing will turn red. If a rule matters, something must be able to observe its violation and fail.* + +**The test to apply to anything you write as a "requirement":** *If this rule were violated right now, what turns red? If the answer is "nothing," it is documentation, not a rule β€” either label it as unenforced or build the gate.* + +#### Why this is distinct from "a permanently green gate is no gate" (2026-08-20) + +The 2026-08-20 test bar (`### 2026-08-20: Test bar for the gh-aw workstream`, `git grep -n 'Test bar for the gh-aw'`, restated at `git grep -n 'permanently green gate'`) presupposes a gate **exists** and asks whether it can fail: a check whose output is constant regardless of input is worthless. The #1793 refinement (`git grep -n 'instructions a gate prints'`) extended that inward β€” *the instructions a gate prints are part of the gate*, so a remediation hint scoped narrower than the check (verify `*.mjs` / 42 paths for a check covering 174) is the same defect. This principle sits one step **earlier** on the same spectrum: it is about requirements that were **never gates at all** β€” prose with no observing mechanism whatsoever. There is no gate to be green or red; there is nothing to observe. The three form a ladder: + +- (0) **no observer exists** β€” this record +- (1) an observer exists but structurally cannot fail β€” permanently-green +- (2) an observer can fail but its paired instructions cannot β€” #1793 + +Distinct failure, distinct fix. This is not a restatement. + +#### Five confirmations in one working day (measured this session) + +*Provenance caveat: instances 1 and 2 are verified from this session's evidence, not from the tree that recorded this file. This worktree is 2 commits behind `origin/dev` (1208 vs 1365 lines; `PC-3` 0/6, `UNTRUSTED_` 0/4). Every `workflows/squad.md` citation in this record is a **content anchor** (`git grep -n …`), not a line number β€” precisely because the same text sits at different lines in the two trees (the `TEAM_PRESENT` guard is L287 here, L444 on dev; the `Name`-column prose is 674/683/704 here, 831/840/861 on dev). Anchors revalidate on read; line numbers drift silently and stay syntactically plausible. A record about false provenance must not itself carry unverified provenance.* + +1. **PC-3's "exit non-zero" is a prompt directive, not code.** The `/squad` router defines preconditions PC-0..PC-3 in `workflows/squad.md`; PC-3 instructs the agent to exit non-zero on failure, but the agent chooses its own exit status β€” nothing enforces it. Accepted as a known limitation in #1824. The mitigation that *works*: steps 1–3 emit output that survives the run and can be asserted afterward, independent of exit status. + +2. **RETRO's shell-input security contract is prose β€” and correctly says so.** Its hop-1 requirement (attacker-controlled event text reaches shell only via named `env:` vars) defines four greppable anti-pattern tokens (`UNTRUSTED_TEMPLATE_IN_RUN`, `UNTRUSTED_COMMAND_STRING`, `UNTRUSTED_PRINTF_FORMAT`, `UNTRUSTED_AWK_PROGRAM_OR_VAR`). The compiler-channel hop is explicitly **unmeasured** (this repo ships no compiled gh-aw output) and the gate is deferred to #1834. This is the **positive** example, not a failure: a declared requirement that openly labels itself unenforced and files the gate is far safer than one that reads as a guarantee. + +3. **Scribe's Archival Safety Rules A–E were violated while sitting in Scribe's own prompt.** In one run Scribe: (a) reported a decisions.md count of "31 + 3 = 34" when measured was 48 β†’ 56; (b) reported "History summarization: SKIPPED β€” no moves performed" while rewriting `eecom/history.md` by +67/βˆ’50 lines; (c) later read a **line count of 129 as a byte count** and declared recoverable history unrecoverable. Rule D ("never report a gate outcome you did not measure") was broken three ways while Rule D was in the prompt. Two-day prehistory: a 2026-08-20 run trimmed **eecom, pao, and procedures** histories, each citing the same archive file (`history-archive-2026-08-20T11-59-44-0700.md`) that was never committed β€” three dangling pointers from one run, `git status` clean for two days (#1826). The commit that performed the loss, `c508d866` (2026-08-20 13:41), was titled *"chore(squad): record gh-aw triage session state and repair archives"* β€” it **asserted repair in its own message while performing the loss** (pao 13,605 B β†’ 3,636 B, procedures 13,653 B β†’ 3,997 B) and read as evidence of repair for two days. A commit message is a declaration with nothing enforcing it. Content stayed recoverable at commit `3dace32e` β€” the blob measures **15,063 bytes** (`git cat-file -s 771d9e0d`), the one figure no shell layer can reinterpret. **Decisively:** merged PR `f4cfaca3` (#1782) had already repaired this identical failure on 2026-08-19; its remedy was a content fix *plus adding Rules A–E to the prompt*. The prose remedy did not prevent recurrence one day later. Now #1836. + +4. **#1812 β€” activate's roster binding has been prose-hardened five times and still fails.** `workflows/squad.md`'s `Name`-column binding prose (``git grep -n 'Name` column'``) instructs to read the `## Members` table from `.squad/team.md` and bind against the `Name` column verbatim. Measured: activate reported *"Roster set read from `.squad/team.md`"* while listing `lead, reviewer, devrel, security, docs` β€” the `squad init --preset default` scaffold, not the fixture roster (`Keaton, McManus, Fenster, Hockney, Kint`). Two defects: wrong source, and **false provenance** β€” a wrong answer wearing a citation. + +5. **#1784's Condition 2 passed for the wrong reason.** Downstream of #4: the planner read `team.md` correctly, activate compared against a hardcoded list, matched nothing, and therefore applied **no** label. The acceptance condition "passed" only because of that refusal. "Refused everything" and "bound everything correctly" were indistinguishable to the check. + +**Recurring sub-pattern (instances 3 & 4):** an unenforced prose requirement does not merely fail silently β€” it can emit an affirmative **false claim of compliance** ("Roster set read from team.md", "History summarization: SKIPPED"). False provenance is the worst case of declared-not-enforced. + +#### The fix shape β€” the structural counter-example + +The `TEAM_PRESENT` / `TEAM_ABSENT` guard in `workflows/squad.md` (`git grep -n TEAM_PRESENT`) is the pattern that works: + +``` +git show HEAD:.squad/team.md | awk '…/^## Members/…' | grep -q . && echo TEAM_PRESENT || echo TEAM_ABSENT +``` + +A command whose **output survives the run and can be asserted afterward** β€” an observable artifact, not an instruction the agent may or may not honor. In every failing instance above the requirement produced no observable artifact, so compliance and non-compliance looked identical. The actionable form of the principle: **convert requirements into emitted artifacts a later step asserts against β€” make provenance true by construction, not asserted in prose.** And prefer **anchors that revalidate on read** (a grep) over **coordinates that drift** (a line number): Procedures grep-anchored every #1812 edit, this session's stale line numbers reached it, and nothing needed redoing β€” the same claim, checkable at read time instead of asserted once and left to rot. Drift pressure is proportional to a file's writer count: `decisions.md` carries a **union merge driver** and every agent appends to it concurrently, so its lines move without anyone editing near them β€” the permanently-green restatement drifted from ~L604 to L598 inside a single session today, unannounced. It is the highest-drift file in the repo and therefore the **last** place a line number should ever be cited. The useful form of the rule is not "line numbers drift" but "predict which citations rot first, and anchor those hardest." + +#### Corollary β€” a measured number that misstates its unit is the same collapse + +Declared-vs-enforced is *"nothing can observe the violation."* This is its neighbour on a different axis: *"the observation happened, but the number does not mean what it claims."* Both collapse the same way β€” **a report that reads as verification but is not one** β€” which is why this is a corollary of the principle, not a separate one: same failure surface, different mechanism (missing observer vs. mislabelled observation). Same working day, one `eecom/history.md` blob, four agents: + +- Scribe read a **line count (129) as a byte count** and nearly declared real history unrecoverable; +- Scribe reported an **estimated** decisions.md entry count (34) against a measured 56; +- Scribe asserted "no moves performed" while making a +67/βˆ’50 rewrite; +- Flight (this Lead) reported **CRLF-inflated `Out-String` chars** as the file size β€” while lecturing Scribe on measurement discipline in the same message; +- Lead and coordinator produced **92 vs 129 lines** for the same blob with no unit stated (non-blank vs total β€” both correct, neither comparable). + +The blob read as **15,063 / 14,989 / 14,861 chars** and **129 / 92 lines** across agents; every figure was "right" under some methodology and none were comparable. + +**The terminal form β€” a false number that becomes a false verdict.** Asked to recover pao and procedures, Scribe reported *"PAO & Procedures: UNRECOVERABLE β€” pre-summary versions not found in git history (all commits < 10KB)."* pao has **41 commits at 13,605 bytes**; procedures ~30 at **13,653** β€” both above the stated 10 KB threshold, both sitting in git, and the content was recovered from the very blobs the sweep declared absent. The prior five mis-stated a *measurement*; this one converted an unreproducible number into a **conclusion to stop looking**. That is the failure mode's endpoint: not a wrong figure in a report, but a wrong figure used to close the investigation. + +**Two actionable rules:** +1. **State the unit and the command that produced every number.** `15,063 bytes (git cat-file -s)` is checkable; a bare `15,119` is not. +2. **Prefer a measure nothing can reinterpret.** During Scribe's repair, char count, line count, and heading-containment checks **all passed** on a file carrying a UTF-8 BOM and a stripped trailing newline; only the **blob SHA** caught it. That is the parent principle turned on the checks themselves β€” three observers that structurally could not see the failure, and one that could. A size-or-growth heuristic is one rung more dangerous than the BOM case β€” not a check that was fooled, but one that could never be right: + +| agent | pre-trim | today | non-blank lines still missing | +|---|---|---|---| +| pao | 120 / 13,605 B | 114 / 10,634 B | 44 | +| procedures | 119 / 13,653 B | 135 / **15,370 B** | 35 | + +`procedures` is 1,717 bytes **larger** today and still missing 35 lines β€” later sessions appended while the trimmed material stayed gone, so every size or growth check reports it healthy. Only content comparison detects it. + +#### The honest boundary β€” when prose is legitimate + +Prose is not worthless, and "never write prose requirements" would be wrong and ignored. Prose is legitimate when **all** of these hold: + +- it is **explicitly marked unenforced** (RETRO's contract, instance 2, does exactly this); +- a **gate issue is filed alongside it** (RETRO β†’ #1834), so the enforcement gap is tracked, not lost; +- the reader is **not misled** into believing it is a guarantee. + +The failure is not prose β€” it is prose that *reads as enforcement*. Instance 2 is good practice; instances 1, 3, 4, 5 are the same words without the label. Apply the test above to every rule you write; if nothing turns red on violation, add the "(unenforced)" label and the gate issue, or build the observer. From 25bda0c5ef076c1555da49ec52915f541a7e03ea Mon Sep 17 00:00:00 2001 From: brady gaster Date: Sat, 22 Aug 2026 21:31:06 -0700 Subject: [PATCH 5/6] chore(squad): merge 3 decision records, log the #1812 roster-binding wave Merges the gh-aw wave-1 decision inbox into decisions.md (56 -> 59 entries) and records the #1812 orchestration. Records merged: - procedures-1812-activate-roster-binding (Team Guard Step TG-2) - fido-1837-review (adversarial review, APPROVE WITH NITS) - flight-declared-vs-enforced (the governing principle) Archival was DISABLED for this run by coordinator override. decisions.md is 89,955 B, past the 51,200 aggressive gate, and that archival path has silently destroyed history twice in four days (repaired by #1782, then again in 6d8bb3fc). A large decisions.md is a performance problem; a lossy archive is a correctness one. Tracked as #1836. Scribe reported this as "skipped by override" rather than "not required" -- it did not claim a measurement it never took. New files under .squad/log/ and .squad/orchestration-log/ required 'git add -f' (#1826). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0e20e987-a753-41c4-a6f8-992d863a32cd --- .squad/agents/fido/history.md | 12 +- .squad/agents/procedures/history.md | 10 +- .squad/decisions.md | 315 ++++++++++++++++++ .../inbox/flight-declared-vs-enforced.md | 78 ----- ...procedures-1812-activate-roster-binding.md | 146 -------- ...08-22T21-20-17-0700-1812-roster-binding.md | 26 ++ .../2026-08-22T21-20-17-0700-fido.md | 24 ++ .../2026-08-22T21-20-17-0700-procedures.md | 25 ++ 8 files changed, 410 insertions(+), 226 deletions(-) delete mode 100644 .squad/decisions/inbox/flight-declared-vs-enforced.md delete mode 100644 .squad/decisions/inbox/procedures-1812-activate-roster-binding.md create mode 100644 .squad/log/2026-08-22T21-20-17-0700-1812-roster-binding.md create mode 100644 .squad/orchestration-log/2026-08-22T21-20-17-0700-fido.md create mode 100644 .squad/orchestration-log/2026-08-22T21-20-17-0700-procedures.md diff --git a/.squad/agents/fido/history.md b/.squad/agents/fido/history.md index 664623a6b..41b8a1af1 100644 --- a/.squad/agents/fido/history.md +++ b/.squad/agents/fido/history.md @@ -29,4 +29,14 @@ Three-turn review of PR #1832 (issue #1824). **Pattern:** Test incomplete in isolation (dispatch path missed). Reviewer's domain context caught it. New coverage added in revision. -PR merged; issue closed. \ No newline at end of file +PR merged; issue closed. + +## πŸ“Œ Team update β€” 2026-08-22T21:20:17-07:00 + +**Adversarial review of PR #1837 (Closes #1812, roster false-provenance).** VERDICT: APPROVE WITH NITS. + +Confirmed all 7 mutations RED and naming input. Verified M8 (CR-strip) genuinely unreddable on Windows git-bash: CR lands in post-last-pipe field ($4), never read. Verified postcondition `applied_labels βŠ† emitted_roster_members` not shell-assertable: agent job has `issues: read`; labels applied by separate executor job via safe-output β€” confirmed from actual frontmatter L28–32, not reasoning. Both honesty claims verified by measurement. + +Found **one real non-blocking gap at L1117**: Step 3 validator still named `.squad/team.md` while binder (L1111) and Check 10 both TG-2-bound. Adjudicated non-blocking (Check 10 is the authoritative gate); recommended merge as-is with tracked follow-up. Fixed by Procedures in `ab8649e3`. + +Reusable technique: always verify architectural claims against actual file contents, not memory or reasoning. Proved `issues: read` from frontmatter bytes, not inferred from context. \ No newline at end of file diff --git a/.squad/agents/procedures/history.md b/.squad/agents/procedures/history.md index 3ae20bc4d..4c4605057 100644 --- a/.squad/agents/procedures/history.md +++ b/.squad/agents/procedures/history.md @@ -132,4 +132,12 @@ FIDO's Pass 2 found BLOCKING dispatch regression (bare command:"implement" β†’ N **Lesson:** Mutation testing in isolation can miss callers. FIDO's first pass shared the same frame; the blind spot was enumeration of all parser call paths (command-dispatch path was unexercised in new suite). -PR #1832 merged; issue #1824 closed. Decision records merged to .squad/decisions.md. \ No newline at end of file +PR #1832 merged; issue #1824 closed. Decision records merged to .squad/decisions.md. + +## πŸ“Œ Team update β€” 2026-08-22T21:20:17-07:00 + +**#1812 β€” Roster provenance fix shipped.** Implemented Team Guard Step TG-2 in `workflows/squad.md`: reads git-committed HEAD `.squad/team.md`, finds `Name` column by header, emits `ROSTER_MEMBER: {name}` per row (lowercased) or `ROSTER_UNREADABLE: {reason}`. All five minting/binding sites rewired to TG-2's certified stdout β€” provenance true by construction, not prose. 7 mutations (M1–M7) proven RED and naming input. 172 tests passed / 13 skipped. PR #1837 +531/βˆ’61 across 3 files, squash-merged as `4b32f7be`. + +FIDO adversarial review: APPROVE WITH NITS. Found L1117 nit (Step 3 validator still named `.squad/team.md`). Fixed in follow-up commit `ab8649e3` β€” validator now TG-2-bound, consistent with L1111 and Check 10. Issue #1812 auto-closed. + +Decision record merged to `.squad/decisions.md`. \ No newline at end of file diff --git a/.squad/decisions.md b/.squad/decisions.md index 071184caf..b48362efb 100644 --- a/.squad/decisions.md +++ b/.squad/decisions.md @@ -1210,3 +1210,318 @@ offending text** rather than merely that a diagnostic exists. worth a separate issue; out of scope for #1824 and would blow the diff budget. - **#1812 not touched.** Confirmed separate: #1812 is in `plan activate`'s roster source, downstream of routing. It shares no code path with Parse Command. + +### 2026-08-22: Roster provenance is certified by an emitting command (Team Guard Step TG-2), not by prose +**Date:** 2026-08-22 +**Raised by:** Procedures +**Status:** Decided +**Issue:** #1812 (re-diagnoses #1784) + +#### Context + +`/squad plan activate` on fixture `aspiregregator-squad-e2e` (run `32471509974`) printed a +provenance sentence claiming it read the roster from `.squad/team.md` `## Members` β†’ `Name` +column, and reported `lead, reviewer, devrel, security, docs`. The fixture's real cast is +`Keaton, McManus, Fenster, Hockney, Kint`. The five reported names are exactly the +`squad init --preset default` scaffold in +`packages/squad-sdk/src/presets/builtin/default/preset.json`. Two defects: + +1. Activate bound against the hardcoded preset roster, not the repository's committed cast. +2. It **claimed provenance it did not have** β€” a wrong answer wearing a citation. + +Downstream: at E4 the planner read `team.md` correctly and emitted the real names; activate +compared them against the hardcoded list, matched none, and applied **no** `squad:{agent}` +label. #1784's Condition 2 "passed" only because activate refused everything. **Refusal and +correct binding are indistinguishable from the outside** β€” the through-line of this workstream. + +`workflows/squad.md` had already been hardened with bold, repeated prose instructing the agent +to read `## Members` from *this repository's* `team.md`, take the `Name` column verbatim, and +treat no other column as valid. That text was present; the defect happened anyway. A *declared* +requirement is not an *enforced* one. + +#### Decision + +Add **Team Guard Step TG-2 β€” Certify the Roster Set**: a bash block modeled on the existing +TG-1 line-444 `TEAM_PRESENT`/`TEAM_ABSENT` guard. It reads the **git-committed HEAD** revision +of `.squad/team.md` (`git show HEAD:.squad/team.md` β€” working-tree preset scaffolds are +invisible), finds the `Name` column of the `## Members` table **by header** (not by position), +and emits one lowercased `ROSTER_MEMBER: {name}` per data row β€” or a single +`ROSTER_UNREADABLE: {reason}` naming why (`absent from HEAD`, `no ## Members section`, +`no Name column in ## Members table`, `## Members has no data rows`). + +Every downstream site that mints a `squad:{name}` label or binds an `Owner`/`Agent` value binds +**only** to TG-2's stdout. Because the summary can only reproduce `ROSTER_MEMBER:` lines the +command actually produced, **the provenance claim becomes true by construction**. On +`ROSTER_UNREADABLE:` the binder halts with the named reason β€” never a provenance sentence for a +read that did not happen, never a silent preset fallback. + +#### Why structural, not more prose + +The prose fix is the exact move that already failed here repeatedly, and is the anti-pattern +this workstream is clearing. TG-2's stdout is an **observable artifact of the run** that a test +can assert against; a prose directive's compliance cannot be observed. This is the same +distinction as TG-1's `TEAM_PRESENT`/`TEAM_ABSENT` β€” a requirement vs. a rule. Modeling on +PC-3 was explicitly rejected: PC-3's "exit non-zero on failure" is itself an unenforced prompt +directive (accepted limitation, #1824). TG-2 sits in the Team Guard family because the problem +**is** file provenance, not command-string normalization; modeling it on PC-* would have +manufactured a parallel structure rather than reusing the right one. + +#### Why header-driven column detection, not `$2` + +An earlier draft extracted a fixed column position. That silently binds the wrong data if a repo +authors `## Members` as `| Role | Name |` β€” it would emit the Role column, reproducing the exact +#1812 anti-pattern with a *true-looking* provenance claim. TG-2 instead scans the header row for +the cell whose trimmed text is `Name` and extracts that column; a table with no `Name` column +yields `ROSTER_UNREADABLE: no Name column in ## Members table` rather than a confident wrong +answer. (Mutation M2 proves this: pinning the column to position 2 reddens the header-order case, +naming the leaked `ROSTER_MEMBER: lead` / `reviewer`.) + +#### Enforcement boundary β€” emission enforced, consumption directive (the good kind of unenforced) + +TG-2 makes **emission** shell-enforced and assertable: the new test extracts the block and runs +it against real committed-HEAD git repos, proving the certified set is correct in isolation. +**Consumption** β€” the model actually binding only to `ROSTER_MEMBER:` lines β€” remains a prompt +directive. Nothing can compel the model to read its own emitted set. This is the *good* kind of +unenforced: like RETRO's hop-1 contract, the limitation labels itself. The defect was never an +unenforced directive; it was prose that read as a guarantee. This sentence stays in the record so +the boundary is named, not silent. + +#### Postcondition `applied_labels βŠ† emitted_roster_members` is NOT reachable β€” named boundary + +A machine-checked postcondition (a shell step asserting every applied `squad:{name}` label is a +subset of the emitted roster, failing loudly and naming the offending label) would close +acceptance 2a's second half by machine rather than by reviewer. It is **not reachable** under +gh-aw safe-outputs: the agent job runs read-only and writes `create-issue` requests to +`/tmp/gh-aw/safeoutputs/outputs.jsonl`; a **separate executor job** (with `issues: write`) applies +labels afterward. TG-2's stdout lives in the agent's bash sandbox and is not promotable to a +cross-job artifact the executor consumes; the only agentβ†’executor channel is the model-filled +safe-output, which reintroduces the very model-memory trust the postcondition was meant to remove. +So emission is assertable in-run; consumption cannot be asserted at label-application time in this +architecture. Recorded as a boundary, not a silence β€” if safe-outputs later exposes the applied +set to a same-job shell step, this postcondition becomes worth its bytes and closes 2a fully. + +#### CRLF / CR-strip could not be measured on this substrate β€” named boundary + +TG-2's extraction carries `{sub(/\r$/,"")}` to normalize CRLF-authored `team.md` on Linux +runners. Mutation M8 (removing that strip) **could not be reddened** on the Windows git-bash test +host: `git show HEAD:.squad/team.md` there emits LF (git-for-windows normalizes CR out before awk +sees it, despite `core.autocrlf false`), and for regular GitHub tables the trailing pipe already +quarantines any CR into a post-pipe field that is never read. Two empirical probes (with/without +strip, on trailing-pipe and Name-last-no-trailing-pipe CRLF fixtures) produced identical clean +output. The strip is **retained as defense-in-depth** (correct and load-bearing on Linux runners +for irregular tables); its load-bearing behavior is **reasoned for Linux, not measured on +Windows**. The dedicated CRLF test was rewritten to assert the end-to-end parse invariant (clean +lowercased cast from a CRLF file) β€” which *is* reddenable (mutations M1/M4 flip it, naming the +offending `ROSTER_MEMBER:` output) β€” and no longer claims to prove the strip in isolation. + +#### Prose removed β€” enumerated, each checked against `test/gh-aw-*` + +The verbose per-site roster prose was superseded by TG-2 emission + short binders that point at +the certified set. Removed / compressed blocks: the plan `Owner/Agent binding rule` sub-steps +(a–d) β†’ one binder paragraph; the plan `Owner` re-check reminder β†’ one pointer; the accept +`squad:{owner}` minting paragraph β†’ TG-2-bound sentence; the impl `Agent binding rule` working- +notes paragraph β†’ TG-2-bound sentence; the impl `Agent` re-check reminder β†’ one pointer; the +Check 10 four-step block β†’ TG-2-bound restatement. Every test-pinned substring was verified to +survive: `Owner/Agent binding rule` (plan), `Agent binding rule` + `appears verbatim in the +`Name` column` (impl), `Name` column (all binders), the Check 10 `Never report a value as a +valid roster name unless …` sentence, and the no-backticked-role-token invariant across all five +skill blocks. All four existing gh-aw suites + the new one pass (172 passed / 13 skipped), which +confirms no pinned assertion was dropped. No prose was removed that a `test/gh-aw-*` test asserts +on. + +#### Caller enumeration (FIDO requirement) + +Every roster/owner/agent site across `workflows/` was enumerated: + +**Minting / binding β€” all bound to TG-2's certified set:** +- `squad.md` accept `squad:{owner}` mint (Β§ "For each work item, create-issue") +- `squad.md` activate Label Pre-flight gate `squad:{agent}` (runs TG-2, false-provenance + defenses, β‰₯1-label completeness rule) β€” governs the epic/task label declarations that follow it +- `squad.md` plan `Owner/Agent binding rule` +- `squad.md` impl `Agent binding rule` + its validation check +- `squad.md` Check 10 roster validation + +**Pure consumers β€” NOT #1812 vectors (no independent roster derivation):** +- `squad-implement-worker.md` "Route work to the member named by the `squad:{member}` label" β€” + consumes an already-certified label; reads `team.md` only for that member's charter/routing. +- `shared/squad.md` `squad init` cast-preservation guard (#1657) β€” existence check via + `grep -q '^[|]'`, no name extraction for labels; aligned with the anti-preset-clobber intent. + +No second minting path shares the defect. No compiled `.lock.yml` artifacts are committed +(gh-aw compiles at deploy time), so no regeneration is required. + +#### Risk + +Consumption remains model-trusted (see boundary above). If a future gh-aw version exposes the +applied-label set to a same-job shell step, add the subset postcondition to machine-check +acceptance 2a's second half. Until then, the β‰₯1-label completeness rule (activate must apply at +least one `squad:{agent}` label, else fail) is the guard that keeps "refused everything" from +masquerading as "bound correctly" β€” the failure mode that gave #1784 its false pass. + +### 2026-08-22: FIDO adversarial review β€” PR #1837 (Closes #1812, roster false-provenance) + +**Reviewer:** FIDO (tests & quality / CI gates) +**PR:** #1837 `bradygaster-activate-roster-binding-1812` β†’ `dev` Β· +531/βˆ’61 Β· 3 files Β· `MERGEABLE`/`CLEAN` +**Worktree measured in:** `C:\src\copilot-worktrees\squad\bradygaster-automatic-broccoli` (HEAD `41d3058b`, node_modules present) +**Method:** measure, don't reason. Every claim reproduced independently; every mutation required to go RED *and name the offending input* (a status-only assertion passes a truncating parser). + +#### VERDICT: APPROVE WITH NITS + +TG-2 makes roster **emission** shell-enforced and every one of the new assertions is failable (7 mutations, all red + naming input). The compression dropped nothing load-bearing β€” all four legacy constraints survived and several were strengthened by re-keying to TG-2's certified stdout. Both honesty claims verified by measurement, not taken on trust. One real single-source-consistency nit (L1117), non-blocking because the authoritative downstream gate (Check 10) is correctly TG-2-bound. + +--- + +#### Standing asks β€” all MET + +##### 1. Per-case mutation evidence, naming the offending input +Ran against `test/gh-aw-activate-roster-binding.test.ts` (10 tests, ~5.5s). Each mutation applied to `workflows/squad.md`, run, restored via `git checkout --`. + +| Mutation | Target | Result | Names input? | +|---|---|---|---| +| **M1** drop `tolower(n)` | lowercasing | RED (4 failed) | βœ… `got: ROSTER_MEMBER: Kint` (uppercase leaks) | +| **M2** pin `col=2` (position, not header) | #1812 anti-pattern | RED (2 failed) | βœ… leaks `ROSTER_MEMBER: lead`/`reviewer` on Role-first table + no-Name-col test | +| **M3** drop `__NOCOL__` sentinel | reason specificity | RED (1 failed) | βœ… names the *specific* reason (`no Name column` vs `no data rows`), not status-only | +| **M4** `git show HEAD:`β†’`cat` | committed-HEAD read | RED (2 failed) | βœ… extraction-guard fails + working-tree preset leak test names the leak | +| **M5–M7 + 4th** each `ROSTER_UNREADABLE:` echo β†’ `ROSTER_MEMBER: ghost{n}` | all 4 named reasons | RED (5 failed) | βœ… e.g. `no member may be emitted without a Name column; got: ['ghost3 no name column']` | + +All 7 structural mutations red **and** name the input. No vacuous/status-only assertions found. + +##### 2. Caller enumeration β€” cross-checked, incl. OUTSIDE `workflows/` +- Coordinator's two "not a vector" claims **hold**: `shared/squad.md` is a `grep -q` existence check (#1657, extracts no names); `squad-implement-worker.md` **consumes** an already-certified `squad:{member}` label (reads team.md only for that member's charter) β€” never mints from roster. +- **Repo-wide grep outside `workflows/`** (`packages/`, `scripts/`): every `squad:{member}` hit is a template/changelog/CLI consumer that **reacts to already-applied labels** (`ralph-commands.ts` lists issues by label) or **produces** team.md itself (`cast.ts`, `team-md.ts`). **None** reads team.md's `Name` column to mint a label. The only rosterβ†’label minting path is `workflows/squad.md`, now TG-2-bound. **No third caller** β€” the #1832 caller-blindness trap is clean here. + +##### 3. Each new assertion proven failable β€” see table above. Confirmed. + +--- + +#### Honesty claims β€” both VERIFIED by measurement + +##### Claim 1 β€” M8 (CR-strip) could not be reddened on Windows git-bash +**Measured:** removed BOTH TG-2 `sub(/\r$/,"")` strips (presence-check awk + extraction awk), re-ran the CRLF test β†’ **still PASSES (1 passed)**. Confirms the strip has no observable effect on this substrate: a GitHub table row `| Keaton | Lead |\r` splits under `-F'|'` so the CR lands in the post-last-pipe field ($4), never read; the extracted name ($2) carries no CR. Procedures retained the strip as **reasoned-for-Linux defense-in-depth** and rewrote the CRLF test to assert the **end-to-end parse invariant** (reddenable by M1/M4), *not* the strip. The test claims only what it proves. **Honest.** +**#1833 compounding:** does NOT compound it. #1833 is `gh-aw-quality.test.ts` (POSIX-gated tests skip on Windows). This NEW suite ran **10/10, 0 skips** on this box β€” `resolvePosixShell()` falls back to Git-for-Windows `bash.exe`, and the first test hard-fails if no shell resolves, so a skipped suite cannot masquerade as green. + +##### Claim 2 β€” postcondition `applied_labels βŠ† emitted_roster_members` not assertable in-run +**Measured against the actual frontmatter** (`workflows/squad.md` L28–32): the agent job has **`issues: read`, NOT `issues: write`**. It cannot apply labels directly. Labels flow through the `create-issue` safe-output (L97–98, `labels: [squad]`), executed by a **separate gh-aw executor job** with elevated perms. TG-2's stdout lives in the agent's bash sandbox and genuinely cannot cross into the label-applying job; the only agentβ†’executor channel is the model-filled safe-output. So the subset postcondition is **not shell-assertable in-run** β€” the architectural claim is **correct**. Consumption stays a model-filled directive: the acceptable "self-labeling" form (like RETRO's hop-1 contract, #1834). Emission is shell-enforced/assertable (what the 10 tests measure); consumption is prose-directed. Correct given gh-aw's read-only-agent + separate-executor model. + +--- + +#### Completeness rule (#1784 Condition-2) β€” CONFIRMED +Activation step 6 (added): *"when the plan names at least one roster `Agent`, at least one `squad:{agent}` label MUST be applied… Zero labels on a plan with roster owners is a binding failure, not a pass β€” report it, don't proceed silently."* This directly prevents "refused everything" from masquerading as "bound correctly" β€” the exact false-pass that gave #1784 its green. It is necessarily a directive (label application lives in the executor job, per Claim 2), which is the correct/only form available. + +#### Prose compression β€” nothing load-bearing removed +Examined the **authoritative** βˆ’61 (my local `dev` was stale; local `dev...HEAD` showed +366/βˆ’66 polluted by ~286 lines of unrelated drift β€” reconciled against `gh pr diff`, squad.md = +80/βˆ’61). All βˆ’61 is the OLD file-based "read team.md, copy the Name column verbatim, trust your recall" binding language β€” the untrusted-source pattern #1812 is about β€” replaced by TG-2's certified `ROSTER_MEMBER:` binding. Every load-bearing constraint survived: + +| Constraint | Removed? | Survives in +80? | +|---|---|---| +| Role-column exclusion (anti-#1812) | yes (old prose) | βœ… all 3 rewired sites: "no other column, the `Role` column included" | +| "no roster β†’ ❌ Critical β†’ stop" (#1784) | yes | βœ… Check 10 step 1, now keyed on `ROSTER_UNREADABLE:` (stronger) | +| "name the offending value" | yes | βœ… Check 10 step 4 | +| lowercasing | yes | βœ… activation step 4 + TG-2 `tolower` at source | + +Cross-checked against Procedures' own enumeration in the shipped decision record β€” all test-pinned substrings survive; suite green confirms no dropped assertion. + +--- + +#### THE FINDING (coordinator's main ask) β€” L1117, adjudicated + +`workflows/squad.md` has **three** validation sites; the PR rewired two and left one: +- **L1111** (Step 2, Agent binding rule) β†’ binds to **TG-2 certified set** βœ… +- **L1165–1179** (Check 10, in `squad-plan-validate`) β†’ rewired to **`ROSTER_MEMBER:`** βœ… +- **L1117** (Step 3, "Validate Structure", inline pre-check during impl-plan drafting) β†’ **STILL names the file**: *"agent validity (every `Agent` value appears verbatim in the `Name` column of the `## Members` table in `.squad/team.md`, or is `@copilot`)"* ❗ + +Confirmed unchanged by this PR (not in the βˆ’61 or +80). Procedures' shipped caller enumeration lists four TG-2-bound sites and does not mention this one β€” it was overlooked. + +**Adjudication: REAL inconsistency, NON-BLOCKING nit.** (Reasoned, not shell-measured β€” L1117 is LLM prose, not executable.) +- Non-blocking because: the authoritative **minting** site (accept `squad:{owner}`) and the authoritative **gate** (Check 10, a separate `squad-plan-validate` run) both bind to TG-2. L1117 is an *inline sanity pre-check* during impl-plan generation, re-validating `Agent` values that Step 2's binding rule already sourced from TG-2, in the same agent context where TG-2 stdout is present. Any leak it misses is caught downstream by the TG-2-bound Check 10 before activation. +- But it is a real should-fix: it reintroduces the untrusted source (file/recall) *at a validation gate* β€” the exact residual shape ("the criterion a check applies is part of the check") that let #1812 recur 5Γ—. A future refactor that removed Check 10 would leave L1117 as the only gate, naming the wrong source. +- **Fix (one line, trivial):** rebind L1117 to *"appears in Team Guard Step TG-2's certified roster set (`ROSTER_MEMBER:` lines), or is `@copilot`"* to match L1111/Check 10. +- (Note: L1250, the revise-path "agent validity (scoped to target items)", does NOT name the file β€” benign, leave it.) + +#### CI β€” all green +`gh pr checks 1837`: **`test` = pass (4m41s)**; Architectural Review, Security Review, Diff Size Guard, Policy Gates, Changeset Drift, Lint, Bootstrap Protection, Squad File Leakage, readiness, impact, samples-build, sdk-exports-validation all pass. Two expected path-filter skips (docs-quality, Scope Boundary). Local suite 10/10, tree left clean. + +--- + +#### Fix routing +Only nit is the L1117 one-liner. Procedures is locked out of its own revision under reviewer protocol β†’ if the coordinator wants it fixed pre-merge, name **EECOM** (or fold into a fast follow-up). It does **not** block merge. **Recommend: merge as-is, L1117 as a tracked one-line follow-up.** + +β€” FIDO, 2026-08-22T21:20-07:00 + +### 2026-08-22: A requirement with no observer is documentation, not a rule (declared vs. enforced) + +**By:** Flight (Lead), requested by bradygaster + +**Principle (quotable):** *A requirement expressed only as prose β€” in a prompt or a document β€” is not enforced. If compliance and non-compliance produce identical observable output, the requirement will be violated in plain sight and nothing will turn red. If a rule matters, something must be able to observe its violation and fail.* + +**The test to apply to anything you write as a "requirement":** *If this rule were violated right now, what turns red? If the answer is "nothing," it is documentation, not a rule β€” either label it as unenforced or build the gate.* + +#### Why this is distinct from "a permanently green gate is no gate" (2026-08-20) + +The 2026-08-20 test bar (`### 2026-08-20: Test bar for the gh-aw workstream`, `git grep -n 'Test bar for the gh-aw'`, restated at `git grep -n 'permanently green gate'`) presupposes a gate **exists** and asks whether it can fail: a check whose output is constant regardless of input is worthless. The #1793 refinement (`git grep -n 'instructions a gate prints'`) extended that inward β€” *the instructions a gate prints are part of the gate*, so a remediation hint scoped narrower than the check (verify `*.mjs` / 42 paths for a check covering 174) is the same defect. This principle sits one step **earlier** on the same spectrum: it is about requirements that were **never gates at all** β€” prose with no observing mechanism whatsoever. There is no gate to be green or red; there is nothing to observe. The three form a ladder: + +- (0) **no observer exists** β€” this record +- (1) an observer exists but structurally cannot fail β€” permanently-green +- (2) an observer can fail but its paired instructions cannot β€” #1793 + +Distinct failure, distinct fix. This is not a restatement. + +#### Five confirmations in one working day (measured this session) + +*Provenance caveat: instances 1 and 2 are verified from this session's evidence, not from the tree that recorded this file. This worktree is 2 commits behind `origin/dev` (1208 vs 1365 lines; `PC-3` 0/6, `UNTRUSTED_` 0/4). Every `workflows/squad.md` citation in this record is a **content anchor** (`git grep -n …`), not a line number β€” precisely because the same text sits at different lines in the two trees (the `TEAM_PRESENT` guard is L287 here, L444 on dev; the `Name`-column prose is 674/683/704 here, 831/840/861 on dev). Anchors revalidate on read; line numbers drift silently and stay syntactically plausible. A record about false provenance must not itself carry unverified provenance.* + +1. **PC-3's "exit non-zero" is a prompt directive, not code.** The `/squad` router defines preconditions PC-0..PC-3 in `workflows/squad.md`; PC-3 instructs the agent to exit non-zero on failure, but the agent chooses its own exit status β€” nothing enforces it. Accepted as a known limitation in #1824. The mitigation that *works*: steps 1–3 emit output that survives the run and can be asserted afterward, independent of exit status. + +2. **RETRO's shell-input security contract is prose β€” and correctly says so.** Its hop-1 requirement (attacker-controlled event text reaches shell only via named `env:` vars) defines four greppable anti-pattern tokens (`UNTRUSTED_TEMPLATE_IN_RUN`, `UNTRUSTED_COMMAND_STRING`, `UNTRUSTED_PRINTF_FORMAT`, `UNTRUSTED_AWK_PROGRAM_OR_VAR`). The compiler-channel hop is explicitly **unmeasured** (this repo ships no compiled gh-aw output) and the gate is deferred to #1834. This is the **positive** example, not a failure: a declared requirement that openly labels itself unenforced and files the gate is far safer than one that reads as a guarantee. + +3. **Scribe's Archival Safety Rules A–E were violated while sitting in Scribe's own prompt.** In one run Scribe: (a) reported a decisions.md count of "31 + 3 = 34" when measured was 48 β†’ 56; (b) reported "History summarization: SKIPPED β€” no moves performed" while rewriting `eecom/history.md` by +67/βˆ’50 lines; (c) later read a **line count of 129 as a byte count** and declared recoverable history unrecoverable. Rule D ("never report a gate outcome you did not measure") was broken three ways while Rule D was in the prompt. Two-day prehistory: a 2026-08-20 run trimmed **eecom, pao, and procedures** histories, each citing the same archive file (`history-archive-2026-08-20T11-59-44-0700.md`) that was never committed β€” three dangling pointers from one run, `git status` clean for two days (#1826). The commit that performed the loss, `c508d866` (2026-08-20 13:41), was titled *"chore(squad): record gh-aw triage session state and repair archives."* β€” it **asserted repair in its own message while performing the loss** (pao 13,605 B β†’ 3,636 B, procedures 13,653 B β†’ 3,997 B) and read as evidence of repair for two days. A commit message is a declaration with nothing enforcing it. Content stayed recoverable at commit `3dace32e` β€” the blob measures **15,063 bytes** (`git cat-file -s 771d9e0d`), the one figure no shell layer can reinterpret. **Decisively:** merged PR `f4cfaca3` (#1782) had already repaired this identical failure on 2026-08-19; its remedy was a content fix *plus adding Rules A–E to the prompt*. The prose remedy did not prevent recurrence one day later. Now #1836. + +4. **#1812 β€” activate's roster binding has been prose-hardened five times and still fails.** `workflows/squad.md`'s `Name`-column binding prose (``git grep -n 'Name` column'``) instructs to read the `## Members` table from `.squad/team.md` and bind against the `Name` column verbatim. Measured: activate reported *"Roster set read from `.squad/team.md`"* while listing `lead, reviewer, devrel, security, docs` β€” the `squad init --preset default` scaffold, not the fixture roster (`Keaton, McManus, Fenster, Hockney, Kint`). Two defects: wrong source, and **false provenance** β€” a wrong answer wearing a citation. + +5. **#1784's Condition 2 passed for the wrong reason.** Downstream of #4: the planner read `team.md` correctly, activate compared against a hardcoded list, matched nothing, and therefore applied **no** label. The acceptance condition "passed" only because of that refusal. "Refused everything" and "bound everything correctly" were indistinguishable to the check. + +**Recurring sub-pattern (instances 3 & 4):** an unenforced prose requirement does not merely fail silently β€” it can emit an affirmative **false claim of compliance** ("Roster set read from team.md", "History summarization: SKIPPED"). False provenance is the worst case of declared-not-enforced. + +#### The fix shape β€” the structural counter-example + +The `TEAM_PRESENT` / `TEAM_ABSENT` guard in `workflows/squad.md` (`git grep -n TEAM_PRESENT`) is the pattern that works: + +``` +git show HEAD:.squad/team.md | awk '…/^## Members/…' | grep -q . && echo TEAM_PRESENT || echo TEAM_ABSENT +``` + +A command whose **output survives the run and can be asserted afterward** β€” an observable artifact, not an instruction the agent may or may not honor. In every failing instance above the requirement produced no observable artifact, so compliance and non-compliance looked identical. The actionable form of the principle: **convert requirements into emitted artifacts a later step asserts against β€” make provenance true by construction, not asserted in prose.** And prefer **anchors that revalidate on read** (a grep) over **coordinates that drift** (a line number): Procedures grep-anchored every #1812 edit, this session's stale line numbers reached it, and nothing needed redoing β€” the same claim, checkable at read time instead of asserted once and left to rot. Drift pressure is proportional to a file's writer count: `decisions.md` carries a **union merge driver** and every agent appends to it concurrently, so its lines move without anyone editing near them β€” the permanently-green restatement drifted from ~L604 to L598 inside a single session today, unannounced. It is the highest-drift file in the repo and therefore the **last** place a line number should ever be cited. The useful form of the rule is not "line numbers drift" but "predict which citations rot first, and anchor those hardest." + +#### Corollary β€” a measured number that misstates its unit is the same collapse + +Declared-vs-enforced is *"nothing can observe the violation."* This is its neighbour on a different axis: *"the observation happened, but the number does not mean what it claims."* Both collapse the same way β€” **a report that reads as verification but is not one** β€” which is why this is a corollary of the principle, not a separate one: same failure surface, different mechanism (missing observer vs. mislabelled observation). Same working day, one `eecom/history.md` blob, four agents: + +- Scribe read a **line count (129) as a byte count** and nearly declared real history unrecoverable; +- Scribe reported an **estimated** decisions.md entry count (34) against a measured 56; +- Scribe asserted "no moves performed" while making a +67/βˆ’50 rewrite; +- Flight (this Lead) reported **CRLF-inflated `Out-String` chars** as the file size β€” while lecturing Scribe on measurement discipline in the same message; +- Lead and coordinator produced **92 vs 129 lines** for the same blob with no unit stated (non-blank vs total β€” both correct, neither comparable). + +The blob read as **15,063 / 14,989 / 14,861 chars** and **129 / 92 lines** across agents; every figure was "right" under some methodology and none were comparable. + +**The terminal form β€” a false number that becomes a false verdict.** Asked to recover pao and procedures, Scribe reported *"PAO & Procedures: UNRECOVERABLE β€” pre-summary versions not found in git history (all commits < 10KB)."* pao has **41 commits at 13,605 bytes**; procedures ~30 at **13,653** β€” both above the stated 10 KB threshold, both sitting in git, and the content was recovered from the very blobs the sweep declared absent. The prior five mis-stated a *measurement*; this one converted an unreproducible number into a **conclusion to stop looking**. That is the failure mode's endpoint: not a wrong figure in a report, but a wrong figure used to close the investigation. + +**Two actionable rules:** +1. **State the unit and the command that produced every number.** `15,063 bytes (git cat-file -s)` is checkable; a bare `15,119` is not. +2. **Prefer a measure nothing can reinterpret.** During Scribe's repair, char count, line count, and heading-containment checks **all passed** on a file carrying a UTF-8 BOM and a stripped trailing newline; only the **blob SHA** caught it. That is the parent principle turned on the checks themselves β€” three observers that structurally could not see the failure, and one that could. A size-or-growth heuristic is one rung more dangerous than the BOM case β€” not a check that was fooled, but one that could never be right: + +| agent | pre-trim | today | non-blank lines still missing | +|---|---|---|---| +| pao | 120 / 13,605 B | 114 / 10,634 B | 44 | +| procedures | 119 / 13,653 B | 135 / **15,370 B** | 35 | + +`procedures` is 1,717 bytes **larger** today and still missing 35 lines β€” later sessions appended while the trimmed material stayed gone, so every size or growth check reports it healthy. Only content comparison detects it. + +#### The honest boundary β€” when prose is legitimate + +Prose is not worthless, and "never write prose requirements" would be wrong and ignored. Prose is legitimate when **all** of these hold: + +- it is **explicitly marked unenforced** (RETRO's contract, instance 2, does exactly this); +- a **gate issue is filed alongside it** (RETRO β†’ #1834), so the enforcement gap is tracked, not lost; +- the reader is **not misled** into believing it is a guarantee. + +The failure is not prose β€” it is prose that *reads as enforcement*. Instance 2 is good practice; instances 1, 3, 4, 5 are the same words without the label. Apply the test above to every rule you write; if nothing turns red on violation, add the "(unenforced)" label and the gate issue, or build the observer. diff --git a/.squad/decisions/inbox/flight-declared-vs-enforced.md b/.squad/decisions/inbox/flight-declared-vs-enforced.md deleted file mode 100644 index b7d2e7b0d..000000000 --- a/.squad/decisions/inbox/flight-declared-vs-enforced.md +++ /dev/null @@ -1,78 +0,0 @@ -### 2026-08-22: A requirement with no observer is documentation, not a rule (declared vs. enforced) - -**By:** Flight (Lead), requested by bradygaster - -**Principle (quotable):** *A requirement expressed only as prose β€” in a prompt or a document β€” is not enforced. If compliance and non-compliance produce identical observable output, the requirement will be violated in plain sight and nothing will turn red. If a rule matters, something must be able to observe its violation and fail.* - -**The test to apply to anything you write as a "requirement":** *If this rule were violated right now, what turns red? If the answer is "nothing," it is documentation, not a rule β€” either label it as unenforced or build the gate.* - -#### Why this is distinct from "a permanently green gate is no gate" (2026-08-20) - -The 2026-08-20 test bar (`### 2026-08-20: Test bar for the gh-aw workstream`, `git grep -n 'Test bar for the gh-aw'`, restated at `git grep -n 'permanently green gate'`) presupposes a gate **exists** and asks whether it can fail: a check whose output is constant regardless of input is worthless. The #1793 refinement (`git grep -n 'instructions a gate prints'`) extended that inward β€” *the instructions a gate prints are part of the gate*, so a remediation hint scoped narrower than the check (verify `*.mjs` / 42 paths for a check covering 174) is the same defect. This principle sits one step **earlier** on the same spectrum: it is about requirements that were **never gates at all** β€” prose with no observing mechanism whatsoever. There is no gate to be green or red; there is nothing to observe. The three form a ladder: - -- (0) **no observer exists** β€” this record -- (1) an observer exists but structurally cannot fail β€” permanently-green -- (2) an observer can fail but its paired instructions cannot β€” #1793 - -Distinct failure, distinct fix. This is not a restatement. - -#### Five confirmations in one working day (measured this session) - -*Provenance caveat: instances 1 and 2 are verified from this session's evidence, not from the tree that recorded this file. This worktree is 2 commits behind `origin/dev` (1208 vs 1365 lines; `PC-3` 0/6, `UNTRUSTED_` 0/4). Every `workflows/squad.md` citation in this record is a **content anchor** (`git grep -n …`), not a line number β€” precisely because the same text sits at different lines in the two trees (the `TEAM_PRESENT` guard is L287 here, L444 on dev; the `Name`-column prose is 674/683/704 here, 831/840/861 on dev). Anchors revalidate on read; line numbers drift silently and stay syntactically plausible. A record about false provenance must not itself carry unverified provenance.* - -1. **PC-3's "exit non-zero" is a prompt directive, not code.** The `/squad` router defines preconditions PC-0..PC-3 in `workflows/squad.md`; PC-3 instructs the agent to exit non-zero on failure, but the agent chooses its own exit status β€” nothing enforces it. Accepted as a known limitation in #1824. The mitigation that *works*: steps 1–3 emit output that survives the run and can be asserted afterward, independent of exit status. - -2. **RETRO's shell-input security contract is prose β€” and correctly says so.** Its hop-1 requirement (attacker-controlled event text reaches shell only via named `env:` vars) defines four greppable anti-pattern tokens (`UNTRUSTED_TEMPLATE_IN_RUN`, `UNTRUSTED_COMMAND_STRING`, `UNTRUSTED_PRINTF_FORMAT`, `UNTRUSTED_AWK_PROGRAM_OR_VAR`). The compiler-channel hop is explicitly **unmeasured** (this repo ships no compiled gh-aw output) and the gate is deferred to #1834. This is the **positive** example, not a failure: a declared requirement that openly labels itself unenforced and files the gate is far safer than one that reads as a guarantee. - -3. **Scribe's Archival Safety Rules A–E were violated while sitting in Scribe's own prompt.** In one run Scribe: (a) reported a decisions.md count of "31 + 3 = 34" when measured was 48 β†’ 56; (b) reported "History summarization: SKIPPED β€” no moves performed" while rewriting `eecom/history.md` by +67/βˆ’50 lines; (c) later read a **line count of 129 as a byte count** and declared recoverable history unrecoverable. Rule D ("never report a gate outcome you did not measure") was broken three ways while Rule D was in the prompt. Two-day prehistory: a 2026-08-20 run trimmed **eecom, pao, and procedures** histories, each citing the same archive file (`history-archive-2026-08-20T11-59-44-0700.md`) that was never committed β€” three dangling pointers from one run, `git status` clean for two days (#1826). The commit that performed the loss, `c508d866` (2026-08-20 13:41), was titled *"chore(squad): record gh-aw triage session state and repair archives"* β€” it **asserted repair in its own message while performing the loss** (pao 13,605 B β†’ 3,636 B, procedures 13,653 B β†’ 3,997 B) and read as evidence of repair for two days. A commit message is a declaration with nothing enforcing it. Content stayed recoverable at commit `3dace32e` β€” the blob measures **15,063 bytes** (`git cat-file -s 771d9e0d`), the one figure no shell layer can reinterpret. **Decisively:** merged PR `f4cfaca3` (#1782) had already repaired this identical failure on 2026-08-19; its remedy was a content fix *plus adding Rules A–E to the prompt*. The prose remedy did not prevent recurrence one day later. Now #1836. - -4. **#1812 β€” activate's roster binding has been prose-hardened five times and still fails.** `workflows/squad.md`'s `Name`-column binding prose (``git grep -n 'Name` column'``) instructs to read the `## Members` table from `.squad/team.md` and bind against the `Name` column verbatim. Measured: activate reported *"Roster set read from `.squad/team.md`"* while listing `lead, reviewer, devrel, security, docs` β€” the `squad init --preset default` scaffold, not the fixture roster (`Keaton, McManus, Fenster, Hockney, Kint`). Two defects: wrong source, and **false provenance** β€” a wrong answer wearing a citation. - -5. **#1784's Condition 2 passed for the wrong reason.** Downstream of #4: the planner read `team.md` correctly, activate compared against a hardcoded list, matched nothing, and therefore applied **no** label. The acceptance condition "passed" only because of that refusal. "Refused everything" and "bound everything correctly" were indistinguishable to the check. - -**Recurring sub-pattern (instances 3 & 4):** an unenforced prose requirement does not merely fail silently β€” it can emit an affirmative **false claim of compliance** ("Roster set read from team.md", "History summarization: SKIPPED"). False provenance is the worst case of declared-not-enforced. - -#### The fix shape β€” the structural counter-example - -The `TEAM_PRESENT` / `TEAM_ABSENT` guard in `workflows/squad.md` (`git grep -n TEAM_PRESENT`) is the pattern that works: - -``` -git show HEAD:.squad/team.md | awk '…/^## Members/…' | grep -q . && echo TEAM_PRESENT || echo TEAM_ABSENT -``` - -A command whose **output survives the run and can be asserted afterward** β€” an observable artifact, not an instruction the agent may or may not honor. In every failing instance above the requirement produced no observable artifact, so compliance and non-compliance looked identical. The actionable form of the principle: **convert requirements into emitted artifacts a later step asserts against β€” make provenance true by construction, not asserted in prose.** And prefer **anchors that revalidate on read** (a grep) over **coordinates that drift** (a line number): Procedures grep-anchored every #1812 edit, this session's stale line numbers reached it, and nothing needed redoing β€” the same claim, checkable at read time instead of asserted once and left to rot. Drift pressure is proportional to a file's writer count: `decisions.md` carries a **union merge driver** and every agent appends to it concurrently, so its lines move without anyone editing near them β€” the permanently-green restatement drifted from ~L604 to L598 inside a single session today, unannounced. It is the highest-drift file in the repo and therefore the **last** place a line number should ever be cited. The useful form of the rule is not "line numbers drift" but "predict which citations rot first, and anchor those hardest." - -#### Corollary β€” a measured number that misstates its unit is the same collapse - -Declared-vs-enforced is *"nothing can observe the violation."* This is its neighbour on a different axis: *"the observation happened, but the number does not mean what it claims."* Both collapse the same way β€” **a report that reads as verification but is not one** β€” which is why this is a corollary of the principle, not a separate one: same failure surface, different mechanism (missing observer vs. mislabelled observation). Same working day, one `eecom/history.md` blob, four agents: - -- Scribe read a **line count (129) as a byte count** and nearly declared real history unrecoverable; -- Scribe reported an **estimated** decisions.md entry count (34) against a measured 56; -- Scribe asserted "no moves performed" while making a +67/βˆ’50 rewrite; -- Flight (this Lead) reported **CRLF-inflated `Out-String` chars** as the file size β€” while lecturing Scribe on measurement discipline in the same message; -- Lead and coordinator produced **92 vs 129 lines** for the same blob with no unit stated (non-blank vs total β€” both correct, neither comparable). - -The blob read as **15,063 / 14,989 / 14,861 chars** and **129 / 92 lines** across agents; every figure was "right" under some methodology and none were comparable. - -**The terminal form β€” a false number that becomes a false verdict.** Asked to recover pao and procedures, Scribe reported *"PAO & Procedures: UNRECOVERABLE β€” pre-summary versions not found in git history (all commits < 10KB)."* pao has **41 commits at 13,605 bytes**; procedures ~30 at **13,653** β€” both above the stated 10 KB threshold, both sitting in git, and the content was recovered from the very blobs the sweep declared absent. The prior five mis-stated a *measurement*; this one converted an unreproducible number into a **conclusion to stop looking**. That is the failure mode's endpoint: not a wrong figure in a report, but a wrong figure used to close the investigation. - -**Two actionable rules:** -1. **State the unit and the command that produced every number.** `15,063 bytes (git cat-file -s)` is checkable; a bare `15,119` is not. -2. **Prefer a measure nothing can reinterpret.** During Scribe's repair, char count, line count, and heading-containment checks **all passed** on a file carrying a UTF-8 BOM and a stripped trailing newline; only the **blob SHA** caught it. That is the parent principle turned on the checks themselves β€” three observers that structurally could not see the failure, and one that could. A size-or-growth heuristic is one rung more dangerous than the BOM case β€” not a check that was fooled, but one that could never be right: - -| agent | pre-trim | today | non-blank lines still missing | -|---|---|---|---| -| pao | 120 / 13,605 B | 114 / 10,634 B | 44 | -| procedures | 119 / 13,653 B | 135 / **15,370 B** | 35 | - -`procedures` is 1,717 bytes **larger** today and still missing 35 lines β€” later sessions appended while the trimmed material stayed gone, so every size or growth check reports it healthy. Only content comparison detects it. - -#### The honest boundary β€” when prose is legitimate - -Prose is not worthless, and "never write prose requirements" would be wrong and ignored. Prose is legitimate when **all** of these hold: - -- it is **explicitly marked unenforced** (RETRO's contract, instance 2, does exactly this); -- a **gate issue is filed alongside it** (RETRO β†’ #1834), so the enforcement gap is tracked, not lost; -- the reader is **not misled** into believing it is a guarantee. - -The failure is not prose β€” it is prose that *reads as enforcement*. Instance 2 is good practice; instances 1, 3, 4, 5 are the same words without the label. Apply the test above to every rule you write; if nothing turns red on violation, add the "(unenforced)" label and the gate issue, or build the observer. diff --git a/.squad/decisions/inbox/procedures-1812-activate-roster-binding.md b/.squad/decisions/inbox/procedures-1812-activate-roster-binding.md deleted file mode 100644 index 4dd8151d9..000000000 --- a/.squad/decisions/inbox/procedures-1812-activate-roster-binding.md +++ /dev/null @@ -1,146 +0,0 @@ -### 2026-08-22: Roster provenance is certified by an emitting command (Team Guard Step TG-2), not by prose -**Date:** 2026-08-22 -**Raised by:** Procedures -**Status:** Decided -**Issue:** #1812 (re-diagnoses #1784) - -#### Context - -`/squad plan activate` on fixture `aspiregregator-squad-e2e` (run `32471509974`) printed a -provenance sentence claiming it read the roster from `.squad/team.md` `## Members` β†’ `Name` -column, and reported `lead, reviewer, devrel, security, docs`. The fixture's real cast is -`Keaton, McManus, Fenster, Hockney, Kint`. The five reported names are exactly the -`squad init --preset default` scaffold in -`packages/squad-sdk/src/presets/builtin/default/preset.json`. Two defects: - -1. Activate bound against the hardcoded preset roster, not the repository's committed cast. -2. It **claimed provenance it did not have** β€” a wrong answer wearing a citation. - -Downstream: at E4 the planner read `team.md` correctly and emitted the real names; activate -compared them against the hardcoded list, matched none, and applied **no** `squad:{agent}` -label. #1784's Condition 2 "passed" only because activate refused everything. **Refusal and -correct binding are indistinguishable from the outside** β€” the through-line of this workstream. - -`workflows/squad.md` had already been hardened with bold, repeated prose instructing the agent -to read `## Members` from *this repository's* `team.md`, take the `Name` column verbatim, and -treat no other column as valid. That text was present; the defect happened anyway. A *declared* -requirement is not an *enforced* one. - -#### Decision - -Add **Team Guard Step TG-2 β€” Certify the Roster Set**: a bash block modeled on the existing -TG-1 line-444 `TEAM_PRESENT`/`TEAM_ABSENT` guard. It reads the **git-committed HEAD** revision -of `.squad/team.md` (`git show HEAD:.squad/team.md` β€” working-tree preset scaffolds are -invisible), finds the `Name` column of the `## Members` table **by header** (not by position), -and emits one lowercased `ROSTER_MEMBER: {name}` per data row β€” or a single -`ROSTER_UNREADABLE: {reason}` naming why (`absent from HEAD`, `no ## Members section`, -`no Name column in ## Members table`, `## Members has no data rows`). - -Every downstream site that mints a `squad:{name}` label or binds an `Owner`/`Agent` value binds -**only** to TG-2's stdout. Because the summary can only reproduce `ROSTER_MEMBER:` lines the -command actually produced, **the provenance claim becomes true by construction**. On -`ROSTER_UNREADABLE:` the binder halts with the named reason β€” never a provenance sentence for a -read that did not happen, never a silent preset fallback. - -#### Why structural, not more prose - -The prose fix is the exact move that already failed here repeatedly, and is the anti-pattern -this workstream is clearing. TG-2's stdout is an **observable artifact of the run** that a test -can assert against; a prose directive's compliance cannot be observed. This is the same -distinction as TG-1's `TEAM_PRESENT`/`TEAM_ABSENT` β€” a requirement vs. a rule. Modeling on -PC-3 was explicitly rejected: PC-3's "exit non-zero on failure" is itself an unenforced prompt -directive (accepted limitation, #1824). TG-2 sits in the Team Guard family because the problem -**is** file provenance, not command-string normalization; modeling it on PC-* would have -manufactured a parallel structure rather than reusing the right one. - -#### Why header-driven column detection, not `$2` - -An earlier draft extracted a fixed column position. That silently binds the wrong data if a repo -authors `## Members` as `| Role | Name |` β€” it would emit the Role column, reproducing the exact -#1812 anti-pattern with a *true-looking* provenance claim. TG-2 instead scans the header row for -the cell whose trimmed text is `Name` and extracts that column; a table with no `Name` column -yields `ROSTER_UNREADABLE: no Name column in ## Members table` rather than a confident wrong -answer. (Mutation M2 proves this: pinning the column to position 2 reddens the header-order case, -naming the leaked `ROSTER_MEMBER: lead` / `reviewer`.) - -#### Enforcement boundary β€” emission enforced, consumption directive (the good kind of unenforced) - -TG-2 makes **emission** shell-enforced and assertable: the new test extracts the block and runs -it against real committed-HEAD git repos, proving the certified set is correct in isolation. -**Consumption** β€” the model actually binding only to `ROSTER_MEMBER:` lines β€” remains a prompt -directive. Nothing can compel the model to read its own emitted set. This is the *good* kind of -unenforced: like RETRO's hop-1 contract, the limitation labels itself. The defect was never an -unenforced directive; it was prose that read as a guarantee. This sentence stays in the record so -the boundary is named, not silent. - -#### Postcondition `applied_labels βŠ† emitted_roster_members` is NOT reachable β€” named boundary - -A machine-checked postcondition (a shell step asserting every applied `squad:{name}` label is a -subset of the emitted roster, failing loudly and naming the offending label) would close -acceptance 2a's second half by machine rather than by reviewer. It is **not reachable** under -gh-aw safe-outputs: the agent job runs read-only and writes `create-issue` requests to -`/tmp/gh-aw/safeoutputs/outputs.jsonl`; a **separate executor job** (with `issues: write`) applies -labels afterward. TG-2's stdout lives in the agent's bash sandbox and is not promotable to a -cross-job artifact the executor consumes; the only agentβ†’executor channel is the model-filled -safe-output, which reintroduces the very model-memory trust the postcondition was meant to remove. -So emission is assertable in-run; consumption cannot be asserted at label-application time in this -architecture. Recorded as a boundary, not a silence β€” if safe-outputs later exposes the applied -set to a same-job shell step, this postcondition becomes worth its bytes and closes 2a fully. - -#### CRLF / CR-strip could not be measured on this substrate β€” named boundary - -TG-2's extraction carries `{sub(/\r$/,"")}` to normalize CRLF-authored `team.md` on Linux -runners. Mutation M8 (removing that strip) **could not be reddened** on the Windows git-bash test -host: `git show HEAD:.squad/team.md` there emits LF (git-for-windows normalizes CR out before awk -sees it, despite `core.autocrlf false`), and for regular GitHub tables the trailing pipe already -quarantines any CR into a post-pipe field that is never read. Two empirical probes (with/without -strip, on trailing-pipe and Name-last-no-trailing-pipe CRLF fixtures) produced identical clean -output. The strip is **retained as defense-in-depth** (correct and load-bearing on Linux runners -for irregular tables); its load-bearing behavior is **reasoned for Linux, not measured on -Windows**. The dedicated CRLF test was rewritten to assert the end-to-end parse invariant (clean -lowercased cast from a CRLF file) β€” which *is* reddenable (mutations M1/M4 flip it, naming the -offending `ROSTER_MEMBER:` output) β€” and no longer claims to prove the strip in isolation. - -#### Prose removed β€” enumerated, each checked against `test/gh-aw-*` - -The verbose per-site roster prose was superseded by TG-2 emission + short binders that point at -the certified set. Removed / compressed blocks: the plan `Owner/Agent binding rule` sub-steps -(a–d) β†’ one binder paragraph; the plan `Owner` re-check reminder β†’ one pointer; the accept -`squad:{owner}` minting paragraph β†’ TG-2-bound sentence; the impl `Agent binding rule` working- -notes paragraph β†’ TG-2-bound sentence; the impl `Agent` re-check reminder β†’ one pointer; the -Check 10 four-step block β†’ TG-2-bound restatement. Every test-pinned substring was verified to -survive: `Owner/Agent binding rule` (plan), `Agent binding rule` + `appears verbatim in the -`Name` column` (impl), `Name` column (all binders), the Check 10 `Never report a value as a -valid roster name unless …` sentence, and the no-backticked-role-token invariant across all five -skill blocks. All four existing gh-aw suites + the new one pass (172 passed / 13 skipped), which -confirms no pinned assertion was dropped. No prose was removed that a `test/gh-aw-*` test asserts -on. - -#### Caller enumeration (FIDO requirement) - -Every roster/owner/agent site across `workflows/` was enumerated: - -**Minting / binding β€” all bound to TG-2's certified set:** -- `squad.md` accept `squad:{owner}` mint (Β§ "For each work item, create-issue") -- `squad.md` activate Label Pre-flight gate `squad:{agent}` (runs TG-2, false-provenance - defenses, β‰₯1-label completeness rule) β€” governs the epic/task label declarations that follow it -- `squad.md` plan `Owner/Agent binding rule` -- `squad.md` impl `Agent binding rule` + its validation check -- `squad.md` Check 10 roster validation - -**Pure consumers β€” NOT #1812 vectors (no independent roster derivation):** -- `squad-implement-worker.md` "Route work to the member named by the `squad:{member}` label" β€” - consumes an already-certified label; reads `team.md` only for that member's charter/routing. -- `shared/squad.md` `squad init` cast-preservation guard (#1657) β€” existence check via - `grep -q '^[|]'`, no name extraction for labels; aligned with the anti-preset-clobber intent. - -No second minting path shares the defect. No compiled `.lock.yml` artifacts are committed -(gh-aw compiles at deploy time), so no regeneration is required. - -#### Risk - -Consumption remains model-trusted (see boundary above). If a future gh-aw version exposes the -applied-label set to a same-job shell step, add the subset postcondition to machine-check -acceptance 2a's second half. Until then, the β‰₯1-label completeness rule (activate must apply at -least one `squad:{agent}` label, else fail) is the guard that keeps "refused everything" from -masquerading as "bound correctly" β€” the failure mode that gave #1784 its false pass. diff --git a/.squad/log/2026-08-22T21-20-17-0700-1812-roster-binding.md b/.squad/log/2026-08-22T21-20-17-0700-1812-roster-binding.md new file mode 100644 index 000000000..0f587076e --- /dev/null +++ b/.squad/log/2026-08-22T21-20-17-0700-1812-roster-binding.md @@ -0,0 +1,26 @@ +# Session Log β€” 2026-08-22T21-20-17-0700 β€” #1812 roster-binding wave + +**Recorded by:** Scribe +**Timestamp:** 2026-08-22T21:20:17-07:00 +**Worktree:** freshly rebased onto `origin/dev` at merge commit `4b32f7be` + +## Agents + +| Agent | Mode | Role | +|---|---|---| +| Procedures | sub-session | Implement TG-2 roster emission guard (#1812) | +| FIDO | background | Adversarial review of PR #1837 | +| Procedures | sub-session | Fix L1117 nit (single-source consistency) | +| Coordinator | β€” | Independent verification of TG-2 shell block | + +## Outcomes + +- **PR #1837** (`bradygaster-activate-roster-binding-1812` β†’ `dev`) squash-merged as `4b32f7be`; issue **#1812** auto-closed. +- TG-2 added at `workflows/squad.md` L456. Emits `ROSTER_MEMBER:` per committed `team.md` Name-column row; halts with `ROSTER_UNREADABLE:` on any failure. 7 mutations proven; 172 tests passed. +- L1117 nit fixed in `ab8649e3` (Step 3 validator now TG-2-bound, consistent with L1111 and Check 10). +- Coordinator ran TG-2 verbatim: 21 names / 21 rows β€” exact match. Caller enumeration clean. +- **Flight decision record** (`flight-declared-vs-enforced.md`) and **FIDO review record** (`fido-1837-review.md`) merged into `decisions.md` this session. + +## Archival + +Archival skipped by coordinator override. `.squad/decisions.md` is 76% past the Tier 2 gate; archival path has 2-for-2 failure record (#1826). Supervised archival tracked as #1836. diff --git a/.squad/orchestration-log/2026-08-22T21-20-17-0700-fido.md b/.squad/orchestration-log/2026-08-22T21-20-17-0700-fido.md new file mode 100644 index 000000000..0bb24b87a --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T21-20-17-0700-fido.md @@ -0,0 +1,24 @@ +# Orchestration Log β€” FIDO Β· 2026-08-22T21-20-17-0700 + +**Wave:** #1812 activate roster-binding fix +**Mode:** background +**Task:** Adversarial review of PR #1837 + +## Outcome + +**VERDICT: APPROVE WITH NITS** + +All 7 mutations confirmed red and naming input. Caller enumeration clean repo-wide (no third +minting path). M8 (CR-strip) genuinely unreddable on Windows git-bash substrate β€” independently +verified. Postcondition `applied_labels βŠ† emitted_roster_members` confirmed non-reachable: +measured against actual frontmatter β€” agent job has `issues: read`, not `issues: write`; labels +applied by separate executor job. Architectural claim correct. + +**One real non-blocking gap found at L1117:** Step 3 validator still named `.squad/team.md` +while its binder (L1111) already named TG-2. Real inconsistency; non-blocking because +authoritative Check 10 gate is correctly TG-2-bound. Recommended: merge as-is, L1117 as +tracked one-line follow-up. + +**CI:** all green β€” `test` pass (4m41s); all other gates pass; two expected path-filter skips. + +L1117 subsequently fixed in commit `ab8649e3` by Procedures (second sub-session). diff --git a/.squad/orchestration-log/2026-08-22T21-20-17-0700-procedures.md b/.squad/orchestration-log/2026-08-22T21-20-17-0700-procedures.md new file mode 100644 index 000000000..545849b0c --- /dev/null +++ b/.squad/orchestration-log/2026-08-22T21-20-17-0700-procedures.md @@ -0,0 +1,25 @@ +# Orchestration Log β€” Procedures Β· 2026-08-22T21-20-17-0700 + +**Wave:** #1812 activate roster-binding fix +**Mode:** sub-session +**Task:** Bind `squad:{member}` minting to committed `team.md` instead of the SDK preset roster + +## Outcome + +**COMPLETED β€” PR #1837 merged as squash commit `4b32f7be`; issue #1812 auto-closed.** + +Added **Team Guard Step TG-2 β€” Certify the Roster Set** at `workflows/squad.md` L456. TG-2 +reads the git-committed HEAD revision of `.squad/team.md`, finds the `Name` column by header +(not position), and emits one lowercased `ROSTER_MEMBER: {name}` per data row, or a single +`ROSTER_UNREADABLE: {reason}`. Every downstream minting/binding site rewired to TG-2's stdout. + +**Diff:** +531/βˆ’61 across 3 files. **Mutations:** 7 (M1–M7), each proven RED and naming the +offending input. **Test suite:** 172 passed / 13 skipped (all four legacy suites + new suite). + +**L1117 nit** (Step 3 validator still named `.squad/team.md` while its binder named TG-2) filed +by FIDO; fixed in follow-up commit `ab8649e3`. Validator now derives membership from TG-2's +certified source. + +**Coordinator independent verification:** ran TG-2's shell block verbatim against live +`team.md` β€” 21 names emitted, 21 `## Members` data rows β€” exact match. Caller enumeration +confirmed: both "not a vector" claims held. From 678afdb297bcc663e2a9ac01a9b73602686b5998 Mon Sep 17 00:00:00 2001 From: brady gaster Date: Sat, 22 Aug 2026 21:57:18 -0700 Subject: [PATCH 6/6] fix(squad): repair BOM, CR, heading and link defects found in review GitHub's automated reviewer flagged four defect classes on PR #1838. All independently verified against the filesystem before repair. BOM (regression introduced by this PR): four history.md files carried a UTF-8 BOM (EF BB BF). parseHistory() preserves it but serializeHistory() matches titles with ^#\s+, so a BOM'd H1 fails to match and the title is silently dropped on round-trip. Char counts, line counts and heading containment all pass on a BOM'd file -- .NET ReadAllText strips BOMs silently, so only byte-level inspection observes it. Verified clean on origin/dev and BOM'd at HEAD, confirming this PR introduced them. Bare CR: eecom/history.md held one bare CR that had consumed the "r" of "research", rendering "esearch". HEAD bytes read "implement, " 0D "esearch" -- the CR replaced the letter rather than splitting around it, so restoring it required CR->r, not CR->space. Verified: 0 bare CR, 46 CRLF pairs preserved, 75 lines before and after, exactly one line differing. Adjacent H3 headings: three dated wrappers in decisions.md were each followed by an undemoted duplicate source heading, plus one ADDENDUM subsection using H3. Each caused the parser to flush a record with no body, producing four phantom decisions. The Scribe merge contract requires a spliced body's shallowest heading to land at H4; its parenthetical example shows only "## -> ####", and the rule was applied faithfully to H2 (measured: 0 stray H2) but never generalized to H3. Demoted to H4: 55 H3 / 85 H4, conserved, zero adjacent pairs remaining. Wrong repository: ten links pointed at bradygaster/friendly-guide -- a worktree name, not a repository -- across five log and orchestration-log files. Corrected to bradygaster/squad. Left untouched: the H3 inside a fenced block at decisions.md:986. The content is a normative example and is correct; the parser is the defect. Tracked separately as #1839. Refs #1838, #1839 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0e20e987-a753-41c4-a6f8-992d863a32cd --- .squad/agents/eecom/history.md | 96 +++++++++---------- .squad/agents/fido/history.md | 2 +- .squad/agents/procedures/history.md | 2 +- .squad/agents/retro/history.md | 2 +- .squad/decisions.md | 8 +- .../2026-08-22T19-42-25-0700-gh-aw-wave-1.md | 4 +- .../2026-08-22T19-42-25-0700-eecom.md | 4 +- .../2026-08-22T19-42-25-0700-fido.md | 4 +- .../2026-08-22T19-42-25-0700-procedures.md | 4 +- .../2026-08-22T19-42-25-0700-retro.md | 4 +- 10 files changed, 65 insertions(+), 65 deletions(-) diff --git a/.squad/agents/eecom/history.md b/.squad/agents/eecom/history.md index 712d5eab7..6f43f29e8 100644 --- a/.squad/agents/eecom/history.md +++ b/.squad/agents/eecom/history.md @@ -1,53 +1,53 @@ -ο»Ώ# Eecom history +# Eecom history Summarized by Scribe on 2026-08-20T11:59:44-07:00 because this history exceeded 15KB. Full pre-summary history archived at .squad/agents/eecom/history-archive-2026-08-20T11-59-44-0700.md. Prior archive at .squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md. -## 2026-08-20 β€” #1772 dispatch probe gate fix - -- Root cause confirmed: dispatch-workflow: max: 1 causes first-wins semantics; LLM empty probe consumes slot; real dispatch silently dropped. -- Prior fix #1766 (prompt wording) confirmed insufficient via live run evidence. -- Fix: raised max to 2 (squad-implement-worker.md) + extended check-workflow-input-interpolation.mjs with checkDispatchWorkflowSchemas() static gate. -- Static gate validates JSON dispatch examples adjacent to dispatch_workflow references: requires non-empty workflow_name, non-empty inputs, inputs.issue_number. -- Added 6 new tests in test/gh-aw-quality.test.ts; key structural test fails against max:1 state, passes after fix. -- Build passes. Decision recorded at .squad/decisions/inbox/eecom-1772-dispatch-probe-gate.md. -- Coordination needed: Procedures to add squad.md empty-command guard (separate PR). - -Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. -Full pre-summary history archived at `.squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md`. - -## Condensed index - -- Replaced all hardcoded "Brady" in template examples with generic `{user}`/`{name}` placeholders. Canonical sources: `.squad-templates/squad.agent.md` and `.copilot/skills/init-mode/SKILL.md`. -- PR #942 rebase: cherry-pick from insider-based fork branch; expect modify/delete conflicts for insider-only files. Opened #963 as clean replacement. -- `archiveDecisions()` count-based fallback (#626): when `old.length === 0` and file > 20KB, sort dated entries by age, keep entries under threshold, archive the rest. Undated entries always preserved. -- Cross-platform filename & config fixes (#348, #356): `safeTimestamp()` everywhere; removed machine-specific `teamRoot` from config.json. -- PR #480 history race condition: three-layer defense β€” async mutex, atomic file operations (write-then-rename), 14 tests. -- PR #486 SIGINT handling: parent handler + child process cleanup (kill children, close handles, flush buffers). 22 tests. -- Economy mode (#500): `ECONOMY_MODEL_MAP` + `resolveModel()` with economy flag. Layer 3/4 modifier only; Layers 0-2 (explicit user preferences) never downgraded. 34 tests. -- node:sqlite hard-fail fix (#502): synchronous version check + `process.exit(1)`; `engines.node` corrected to `>=22.5.0`. 5 tests. -- Rate limit recovery UX (#464): `rateLimitGuidance()` with 3 recovery options; `.squad/rate-limit-status.json`; `checkRateLimitStatus()` in doctor. 36 tests. -- Personal squad init (#576): `ensurePersonalSquadDir()` idempotent helper. `init --global` calls it; `personal.ts` reuses it. - -## Recent preserved tail β€” P0 Triage (2026-08-20) - -Performed read-only triage of 10 open gh-aw issues for Brady's pre-E2E pass. - -- **#1772 (P0) β€” STILL REAL.** Commit b6804305 added prompt wording; structural defect at `squad-implement-worker.md:204` (`dispatch-workflow max: 1`) untouched. Fix must be structural β€” extend `scripts/check-workflow-input-interpolation.mjs` or add runtime rejection for empty dispatch payloads. -- **#1758 (P0) β€” STILL REAL, all 3 defects.** (1) squad-plan-accept Step 1 at L654 hardcodes plan artifact lookup (L648 behavior note is prose only). (2) Epic Dispatch at L529-554 dispatches Epics in 3-level tree. (3) Validate at L867 is after accept-scope. Wave:3 (depends on #1759); code work now, live E2E proof after #1772 fixed. -- **#1730, #1731** β€” well-specified. Ship for review-gate path (contested with Flight's wave:1 cap). -- **#1604, #1609** β€” CLOSE. Scope sprawl relative to core E2E correctness goal. -- **#1733, #1735, #1605, #1606, #1731** β€” DEFER. - -Decision record: `decisions/inbox/eecom-p0-triage-2026-08-20.md` β†’ merged. - -## πŸ“Œ Team update β€” 2026-08-20T11:59:44-07:00 - -gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: CLOSE 7 issues (#1738,#1762,#1764,#1768,#1763,#1604,#1609); SHIP-NOW 5 (#1772,#1758,#1759,#1732-compile,#1761); 2 contested (#1730,#1756); 12 deferred. Both P0s (#1772,#1758) still real β€” structural defects unresolved. Wave:1 cap=6. Tomorrow is a full-day E2E series against aspiregregator-squad-e2e. E2E will break at S3 if #1772 is not fixed first. - -## πŸ“Œ Team update β€” 2026-08-20T13:20:20-07:00 - -Batch 2 complete. Fixed #1772 (P0): `max: 1` β†’ `max: 2` in squad-implement-worker.md + `checkDispatchWorkflowSchemas()` static gate + 6 tests. All tests verified to fail against pre-fix state. CI run 32410579973 confirms gate active. PR #1777 green, awaiting Flight gate. `max: 2` is the worker's outbound budget; Procedures' guard is squad.md's inbound validation β€” complementary layers. - +## 2026-08-20 β€” #1772 dispatch probe gate fix + +- Root cause confirmed: dispatch-workflow: max: 1 causes first-wins semantics; LLM empty probe consumes slot; real dispatch silently dropped. +- Prior fix #1766 (prompt wording) confirmed insufficient via live run evidence. +- Fix: raised max to 2 (squad-implement-worker.md) + extended check-workflow-input-interpolation.mjs with checkDispatchWorkflowSchemas() static gate. +- Static gate validates JSON dispatch examples adjacent to dispatch_workflow references: requires non-empty workflow_name, non-empty inputs, inputs.issue_number. +- Added 6 new tests in test/gh-aw-quality.test.ts; key structural test fails against max:1 state, passes after fix. +- Build passes. Decision recorded at .squad/decisions/inbox/eecom-1772-dispatch-probe-gate.md. +- Coordination needed: Procedures to add squad.md empty-command guard (separate PR). + +Summarized by Scribe on 2026-08-19T13:11:34.130-07:00 because this history exceeded 15KB. +Full pre-summary history archived at `.squad/agents/eecom/history-archive-2026-08-19T13-11-34.130-07-00.md`. + +## Condensed index + +- Replaced all hardcoded "Brady" in template examples with generic `{user}`/`{name}` placeholders. Canonical sources: `.squad-templates/squad.agent.md` and `.copilot/skills/init-mode/SKILL.md`. +- PR #942 rebase: cherry-pick from insider-based fork branch; expect modify/delete conflicts for insider-only files. Opened #963 as clean replacement. +- `archiveDecisions()` count-based fallback (#626): when `old.length === 0` and file > 20KB, sort dated entries by age, keep entries under threshold, archive the rest. Undated entries always preserved. +- Cross-platform filename & config fixes (#348, #356): `safeTimestamp()` everywhere; removed machine-specific `teamRoot` from config.json. +- PR #480 history race condition: three-layer defense β€” async mutex, atomic file operations (write-then-rename), 14 tests. +- PR #486 SIGINT handling: parent handler + child process cleanup (kill children, close handles, flush buffers). 22 tests. +- Economy mode (#500): `ECONOMY_MODEL_MAP` + `resolveModel()` with economy flag. Layer 3/4 modifier only; Layers 0-2 (explicit user preferences) never downgraded. 34 tests. +- node:sqlite hard-fail fix (#502): synchronous version check + `process.exit(1)`; `engines.node` corrected to `>=22.5.0`. 5 tests. +- Rate limit recovery UX (#464): `rateLimitGuidance()` with 3 recovery options; `.squad/rate-limit-status.json`; `checkRateLimitStatus()` in doctor. 36 tests. +- Personal squad init (#576): `ensurePersonalSquadDir()` idempotent helper. `init --global` calls it; `personal.ts` reuses it. + +## Recent preserved tail β€” P0 Triage (2026-08-20) + +Performed read-only triage of 10 open gh-aw issues for Brady's pre-E2E pass. + +- **#1772 (P0) β€” STILL REAL.** Commit b6804305 added prompt wording; structural defect at `squad-implement-worker.md:204` (`dispatch-workflow max: 1`) untouched. Fix must be structural β€” extend `scripts/check-workflow-input-interpolation.mjs` or add runtime rejection for empty dispatch payloads. +- **#1758 (P0) β€” STILL REAL, all 3 defects.** (1) squad-plan-accept Step 1 at L654 hardcodes plan artifact lookup (L648 behavior note is prose only). (2) Epic Dispatch at L529-554 dispatches Epics in 3-level tree. (3) Validate at L867 is after accept-scope. Wave:3 (depends on #1759); code work now, live E2E proof after #1772 fixed. +- **#1730, #1731** β€” well-specified. Ship for review-gate path (contested with Flight's wave:1 cap). +- **#1604, #1609** β€” CLOSE. Scope sprawl relative to core E2E correctness goal. +- **#1733, #1735, #1605, #1606, #1731** β€” DEFER. + +Decision record: `decisions/inbox/eecom-p0-triage-2026-08-20.md` β†’ merged. + +## πŸ“Œ Team update β€” 2026-08-20T11:59:44-07:00 + +gh-aw workstream triage complete (7-agent read-only pass). Reconciled outcome: CLOSE 7 issues (#1738,#1762,#1764,#1768,#1763,#1604,#1609); SHIP-NOW 5 (#1772,#1758,#1759,#1732-compile,#1761); 2 contested (#1730,#1756); 12 deferred. Both P0s (#1772,#1758) still real β€” structural defects unresolved. Wave:1 cap=6. Tomorrow is a full-day E2E series against aspiregregator-squad-e2e. E2E will break at S3 if #1772 is not fixed first. + +## πŸ“Œ Team update β€” 2026-08-20T13:20:20-07:00 + +Batch 2 complete. Fixed #1772 (P0): `max: 1` β†’ `max: 2` in squad-implement-worker.md + `checkDispatchWorkflowSchemas()` static gate + 6 tests. All tests verified to fail against pre-fix state. CI run 32410579973 confirms gate active. PR #1777 green, awaiting Flight gate. `max: 2` is the worker's outbound budget; Procedures' guard is squad.md's inbound validation β€” complementary layers. + ## 2026-08-22 β€” gh-aw triage team update @@ -60,7 +60,7 @@ PR #1831 merged as `9378a379` for #1793. EECOM shipped local CRLF working-tree d Rework of PR #1832 under Reviewer Rejection Protocol (Procedures locked out after FIDO Pass 2 found BLOCKING dispatch regression). -**Problem:** Bare workflow_dispatch commands (implement, esearch, etc.) regress to loud failure. PC-1 requires /squad token; dispatch sends bare command value. Pre-fix worked; post-fix: NO_COMMAND β†’ PC-3 hard fail. +**Problem:** Bare workflow_dispatch commands (implement, research, etc.) regress to loud failure. PC-1 requires /squad token; dispatch sends bare command value. Pre-fix worked; post-fix: NO_COMMAND β†’ PC-3 hard fail. **Solution:** Commit 6e7628c5 β€” add Step PC-0 normalization layer before PC-1: - workflow_dispatch bare command β†’ synthesize /squad prefix diff --git a/.squad/agents/fido/history.md b/.squad/agents/fido/history.md index 41b8a1af1..bc4bbe4df 100644 --- a/.squad/agents/fido/history.md +++ b/.squad/agents/fido/history.md @@ -1,4 +1,4 @@ -ο»Ώ# Fido history +# Fido history Summarized by Scribe on 2026-08-22T18:25:00-07:00 because this history exceeded 15KB. Full pre-summary history appended to `.squad/agents/fido/history-archive-2026-08-19T13-11-34.130-07-00.md`. diff --git a/.squad/agents/procedures/history.md b/.squad/agents/procedures/history.md index 4c4605057..267fa7849 100644 --- a/.squad/agents/procedures/history.md +++ b/.squad/agents/procedures/history.md @@ -1,4 +1,4 @@ -ο»Ώ# Procedures history +# Procedures history Summarized by Scribe on 2026-08-20T11:59:44-07:00 because this history exceeded 15KB. Full pre-summary history archived at `.squad/agents/procedures/history-archive-2026-08-20T11-59-44-0700.md`. diff --git a/.squad/agents/retro/history.md b/.squad/agents/retro/history.md index f3b75cb7f..bb0fc760a 100644 --- a/.squad/agents/retro/history.md +++ b/.squad/agents/retro/history.md @@ -1,4 +1,4 @@ -ο»Ώ# RETRO +# RETRO > Retrofire Officer diff --git a/.squad/decisions.md b/.squad/decisions.md index b48362efb..404d72811 100644 --- a/.squad/decisions.md +++ b/.squad/decisions.md @@ -685,7 +685,7 @@ Both deliberate non-actions are sound: ### 2026-08-22: FIDO review β€” PR #1832 (closes #1824): fail loudly when /squad parses no command -### FIDO review β€” PR #1832 (closes #1824): fail loudly when `/squad` parses no command +#### FIDO review β€” PR #1832 (closes #1824): fail loudly when `/squad` parses no command **Reviewer:** FIDO (Quality Owner) Β· **Author:** Procedures Β· **Date:** 2026-08-22 **Verdict:** βœ… **APPROVE WITH NITS** (posted as `COMMENTED` β€” GitHub blocks a formal Approve on an own-account PR) @@ -773,7 +773,7 @@ for the real `/bin/sh` 102-skip cleanup (out of scope here per Diff Size Guard). --- -### ADDENDUM β€” 2026-08-22 (adjudicating the automated reviewer's findings) +#### ADDENDUM β€” 2026-08-22 (adjudicating the automated reviewer's findings) Coordinator asked me to adjudicate two findings my first pass did not cover (injection; a `workflow_dispatch` regression) plus confirm one convergence. Measured, not reasoned. Where I could not @@ -972,7 +972,7 @@ worth a follow-up test + first-non-empty-line scan, not a merge blocker. ### 2026-08-22: RETRO security contract β€” /squad shell input channel -### RETRO security contract β€” `/squad` shell input channel +#### RETRO security contract β€” `/squad` shell input channel **Scope:** PR #1832 / issue #1824, the `/squad` command parser in `workflows/squad.md`, and the gh-aw compiled workflow YAML produced from it. @@ -1129,7 +1129,7 @@ I could measure POSIX shell behavior for the command shapes above. I could not d ### 2026-08-22: Decision β€” /squad command parsing must fail loudly (#1824) -### Decision β€” `/squad` command parsing must fail loudly (#1824) +#### Decision β€” `/squad` command parsing must fail loudly (#1824) **By:** Procedures (Prompt Architecture) **Date:** 2026-08-22 diff --git a/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md b/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md index e2a959707..1133583bb 100644 --- a/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md +++ b/.squad/log/2026-08-22T19-42-25-0700-gh-aw-wave-1.md @@ -46,8 +46,8 @@ Three new entries added to `.squad/decisions.md`: ## References -- PR: github.com/bradygaster/friendly-guide/pull/1832 -- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- PR: github.com/bradygaster/squad/pull/1832 +- Issue: github.com/bradygaster/squad/issues/1824 - Commit (EECOM revision): `6e7628c5` - Follow-up gate: #1834 diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md index 7fd201fed..ce755c25f 100644 --- a/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-eecom.md @@ -51,6 +51,6 @@ PR #1832 merged; issue #1824 closed. ## Reference - Charter: `.squad/agents/eecom/charter.md` -- PR: github.com/bradygaster/friendly-guide/pull/1832 -- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- PR: github.com/bradygaster/squad/pull/1832 +- Issue: github.com/bradygaster/squad/issues/1824 - Commit: `6e7628c5` diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md index 563d45a30..354277911 100644 --- a/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-fido.md @@ -44,6 +44,6 @@ PR #1832 merged; issue #1824 closed. ## Reference - Charter: `.squad/agents/fido/charter.md` -- PR: github.com/bradygaster/friendly-guide/pull/1832 -- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- PR: github.com/bradygaster/squad/pull/1832 +- Issue: github.com/bradygaster/squad/issues/1824 - Commit (EECOM revision): `6e7628c5` diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md index e18bf05c6..150533516 100644 --- a/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-procedures.md @@ -30,6 +30,6 @@ Under Reviewer Rejection Protocol: **Procedures locked out**, EECOM did the revi ## Reference - Charter: `.squad/agents/procedures/charter.md` -- PR: github.com/bradygaster/friendly-guide/pull/1832 -- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- PR: github.com/bradygaster/squad/pull/1832 +- Issue: github.com/bradygaster/squad/issues/1824 - Commit (EECOM revision): `6e7628c5` diff --git a/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md b/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md index a3c334475..7a97c340a 100644 --- a/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md +++ b/.squad/orchestration-log/2026-08-22T19-42-25-0700-retro.md @@ -35,6 +35,6 @@ No compiled gh-aw workflow lock in this repository to inspect. Hop-1 (GitHub Act ## Reference - Charter: `.squad/agents/retro/charter.md` -- PR: github.com/bradygaster/friendly-guide/pull/1832 -- Issue: github.com/bradygaster/friendly-guide/issues/1824 +- PR: github.com/bradygaster/squad/pull/1832 +- Issue: github.com/bradygaster/squad/issues/1824 - Follow-up gate: #1834