@mmerterden/multi-agent-pipeline 12.7.0 → 12.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/install/_common.mjs +48 -0
  3. package/install/_dev-only-files.mjs +125 -5
  4. package/install/claude.mjs +14 -8
  5. package/install/copilot.mjs +5 -8
  6. package/package.json +17 -2
  7. package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
  8. package/pipeline/lib/credential-store.sh +20 -0
  9. package/pipeline/multi-agent-refs/_account-picker.md +1 -1
  10. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  11. package/pipeline/multi-agent-refs/_repo-picker.md +1 -1
  12. package/pipeline/multi-agent-refs/features/review-multi-repo.md +65 -0
  13. package/pipeline/multi-agent-refs/features/url-enrichment.md +93 -0
  14. package/pipeline/multi-agent-refs/phases/operations.md +28 -0
  15. package/pipeline/multi-agent-refs/phases/phase-0-init.md +3 -83
  16. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
  17. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -2
  18. package/pipeline/multi-agent-refs/phases/phase-4-review.md +50 -62
  19. package/pipeline/schemas/prefs.schema.json +6 -0
  20. package/pipeline/scripts/_smoke-root.sh +61 -0
  21. package/pipeline/scripts/agent-guard.py +57 -3
  22. package/pipeline/scripts/audit-log.sh +25 -0
  23. package/pipeline/scripts/smoke-cross-cli-behavior.sh +21 -7
  24. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +0 -25
  25. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +0 -30
  26. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +0 -20
  27. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +0 -15
  28. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +0 -14
  29. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +0 -12
  30. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +0 -29
  31. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +0 -43
  32. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +0 -35
  33. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +0 -35
  34. package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +0 -14
  35. package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +0 -12
  36. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-1-analysis.json +0 -29
  37. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-2-plan.json +0 -42
  38. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-review.json +0 -20
  39. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-triage.json +0 -15
  40. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/metadata.json +0 -14
  41. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/task.json +0 -12
  42. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-1-analysis.json +0 -29
  43. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-2-plan.json +0 -40
  44. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-review.json +0 -20
  45. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-triage.json +0 -15
  46. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/metadata.json +0 -14
  47. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/task.json +0 -12
  48. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-1-analysis.json +0 -29
  49. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-2-plan.json +0 -42
  50. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-review.json +0 -28
  51. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-triage.json +0 -27
  52. package/pipeline/eval/golden-tasks/05-ios-security-keychain/metadata.json +0 -14
  53. package/pipeline/eval/golden-tasks/05-ios-security-keychain/task.json +0 -12
  54. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-1-analysis.json +0 -29
  55. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-2-plan.json +0 -41
  56. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-review.json +0 -12
  57. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-triage.json +0 -6
  58. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/metadata.json +0 -14
  59. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/task.json +0 -12
  60. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-1-analysis.json +0 -29
  61. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-2-plan.json +0 -42
  62. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-review.json +0 -28
  63. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-triage.json +0 -27
  64. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/metadata.json +0 -14
  65. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/task.json +0 -12
  66. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-1-analysis.json +0 -25
  67. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-2-plan.json +0 -31
  68. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-review.json +0 -12
  69. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-triage.json +0 -18
  70. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/metadata.json +0 -14
  71. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/task.json +0 -12
  72. package/pipeline/eval/golden-tasks/README.md +0 -65
  73. package/pipeline/eval/intent-cases.json +0 -40
  74. package/pipeline/eval/run-metrics-fixture.json +0 -93
  75. package/pipeline/eval/triage/01-empty-findings/expected.json +0 -6
  76. package/pipeline/eval/triage/01-empty-findings/input.json +0 -5
  77. package/pipeline/eval/triage/01-empty-findings/notes.md +0 -7
  78. package/pipeline/eval/triage/02-real-blocker/expected.json +0 -15
  79. package/pipeline/eval/triage/02-real-blocker/input.json +0 -14
  80. package/pipeline/eval/triage/02-real-blocker/notes.md +0 -7
  81. package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +0 -18
  82. package/pipeline/eval/triage/03-out-of-scope-defer/input.json +0 -14
  83. package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +0 -10
  84. package/pipeline/eval/triage/04-false-positive-reject/expected.json +0 -18
  85. package/pipeline/eval/triage/04-false-positive-reject/input.json +0 -14
  86. package/pipeline/eval/triage/04-false-positive-reject/notes.md +0 -10
  87. package/pipeline/eval/triage/05-mixed-classification/expected.json +0 -43
  88. package/pipeline/eval/triage/05-mixed-classification/input.json +0 -38
  89. package/pipeline/eval/triage/05-mixed-classification/notes.md +0 -17
  90. package/pipeline/eval/triage/06-severity-mismatch/expected.json +0 -15
  91. package/pipeline/eval/triage/06-severity-mismatch/input.json +0 -14
  92. package/pipeline/eval/triage/06-severity-mismatch/notes.md +0 -9
  93. package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +0 -27
  94. package/pipeline/eval/triage/07-duplicate-reviewers/input.json +0 -22
  95. package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +0 -9
  96. package/pipeline/eval/triage/08-style-misclassified/expected.json +0 -18
  97. package/pipeline/eval/triage/08-style-misclassified/input.json +0 -14
  98. package/pipeline/eval/triage/08-style-misclassified/notes.md +0 -9
  99. package/pipeline/eval/triage/09-cascading-finding/expected.json +0 -23
  100. package/pipeline/eval/triage/09-cascading-finding/input.json +0 -22
  101. package/pipeline/eval/triage/09-cascading-finding/notes.md +0 -9
  102. package/pipeline/eval/triage/10-deferred-crossref/expected.json +0 -18
  103. package/pipeline/eval/triage/10-deferred-crossref/input.json +0 -14
  104. package/pipeline/eval/triage/10-deferred-crossref/notes.md +0 -9
  105. package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +0 -27
  106. package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +0 -22
  107. package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +0 -14
  108. package/pipeline/eval/triage/README.md +0 -54
  109. package/pipeline/scripts/benchmark-phase-0.sh +0 -128
  110. package/pipeline/scripts/check-md-links.mjs +0 -88
  111. package/pipeline/scripts/eval-golden-tasks-live.mjs +0 -302
  112. package/pipeline/scripts/eval-golden-tasks.mjs +0 -224
  113. package/pipeline/scripts/eval-intent.mjs +0 -107
  114. package/pipeline/scripts/eval-mine-corpus.mjs +0 -211
  115. package/pipeline/scripts/eval-triage.mjs +0 -171
  116. package/pipeline/scripts/fixtures/diff-risk-android.diff +0 -40
  117. package/pipeline/scripts/fixtures/diff-risk-ios.diff +0 -48
  118. package/pipeline/scripts/fixtures/diff-risk-test-removal.diff +0 -40
  119. package/pipeline/scripts/fixtures/install-layout.tsv +0 -19
  120. package/pipeline/scripts/fixtures/pack-expected-count.txt +0 -1
  121. package/pipeline/scripts/fixtures/test-gap-node.diff +0 -30
  122. package/pipeline/scripts/fixtures/test-gap-python.diff +0 -32
  123. package/pipeline/scripts/lint-mcp-refs.mjs +0 -218
  124. package/pipeline/scripts/lint-skills.mjs +0 -154
  125. package/pipeline/scripts/run-smokes.mjs +0 -130
  126. package/pipeline/scripts/scorecard.mjs +0 -258
  127. package/pipeline/scripts/smoke-add-detail.sh +0 -137
  128. package/pipeline/scripts/smoke-agent-guard.sh +0 -74
  129. package/pipeline/scripts/smoke-agent-log-cost.sh +0 -262
  130. package/pipeline/scripts/smoke-agent-model-routing.sh +0 -87
  131. package/pipeline/scripts/smoke-ask-choice.sh +0 -42
  132. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +0 -36
  133. package/pipeline/scripts/smoke-bitbucket-contract.sh +0 -255
  134. package/pipeline/scripts/smoke-changelog-version.sh +0 -47
  135. package/pipeline/scripts/smoke-channels-approval-gate.sh +0 -60
  136. package/pipeline/scripts/smoke-channels-flow.sh +0 -130
  137. package/pipeline/scripts/smoke-ci-workflows.sh +0 -88
  138. package/pipeline/scripts/smoke-clarify.sh +0 -148
  139. package/pipeline/scripts/smoke-command-inventory.sh +0 -81
  140. package/pipeline/scripts/smoke-commands-skills-parity.sh +0 -87
  141. package/pipeline/scripts/smoke-community-gates.sh +0 -75
  142. package/pipeline/scripts/smoke-compliance-skills.sh +0 -119
  143. package/pipeline/scripts/smoke-config-hygiene.sh +0 -58
  144. package/pipeline/scripts/smoke-context-budget.sh +0 -72
  145. package/pipeline/scripts/smoke-cost-budget.sh +0 -70
  146. package/pipeline/scripts/smoke-cost-summary.sh +0 -139
  147. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +0 -128
  148. package/pipeline/scripts/smoke-description-tr.sh +0 -82
  149. package/pipeline/scripts/smoke-dev-critic.sh +0 -144
  150. package/pipeline/scripts/smoke-diff-explain.sh +0 -147
  151. package/pipeline/scripts/smoke-diff-risk.sh +0 -190
  152. package/pipeline/scripts/smoke-dynamic-skill-loading.sh +0 -160
  153. package/pipeline/scripts/smoke-eval-live.sh +0 -136
  154. package/pipeline/scripts/smoke-evidence-gate.sh +0 -93
  155. package/pipeline/scripts/smoke-extract-conventions.sh +0 -163
  156. package/pipeline/scripts/smoke-fetchers-offline.sh +0 -448
  157. package/pipeline/scripts/smoke-figma-dispatch.sh +0 -112
  158. package/pipeline/scripts/smoke-gate-hooks.sh +0 -74
  159. package/pipeline/scripts/smoke-gc-tmp.sh +0 -130
  160. package/pipeline/scripts/smoke-gc-worktrees.sh +0 -125
  161. package/pipeline/scripts/smoke-generate-issue.sh +0 -120
  162. package/pipeline/scripts/smoke-handoff-contract.sh +0 -92
  163. package/pipeline/scripts/smoke-identity-isolation.sh +0 -70
  164. package/pipeline/scripts/smoke-install-layout.sh +0 -248
  165. package/pipeline/scripts/smoke-intent-guard.sh +0 -86
  166. package/pipeline/scripts/smoke-issue-comment-template.sh +0 -86
  167. package/pipeline/scripts/smoke-issue-jira-triad.sh +0 -120
  168. package/pipeline/scripts/smoke-keychain.sh +0 -158
  169. package/pipeline/scripts/smoke-language-axis.sh +0 -109
  170. package/pipeline/scripts/smoke-learning-curve.sh +0 -61
  171. package/pipeline/scripts/smoke-learnings-ledger.sh +0 -86
  172. package/pipeline/scripts/smoke-lib-scripts.sh +0 -448
  173. package/pipeline/scripts/smoke-mcp-gate.sh +0 -68
  174. package/pipeline/scripts/smoke-md-links.sh +0 -8
  175. package/pipeline/scripts/smoke-md2confluence.sh +0 -126
  176. package/pipeline/scripts/smoke-metrics-cache-ratio.sh +0 -72
  177. package/pipeline/scripts/smoke-migrate-state.sh +0 -102
  178. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +0 -161
  179. package/pipeline/scripts/smoke-model-fallback.sh +0 -89
  180. package/pipeline/scripts/smoke-multi-repo-integration.sh +0 -116
  181. package/pipeline/scripts/smoke-multi-repo-worktree.sh +0 -61
  182. package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +0 -194
  183. package/pipeline/scripts/smoke-no-token-prompt.sh +0 -85
  184. package/pipeline/scripts/smoke-own-punctuation.sh +0 -103
  185. package/pipeline/scripts/smoke-pack-contents.sh +0 -140
  186. package/pipeline/scripts/smoke-pat-audit.sh +0 -128
  187. package/pipeline/scripts/smoke-per-repo-memory.sh +0 -156
  188. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +0 -170
  189. package/pipeline/scripts/smoke-phase-6-multi.sh +0 -79
  190. package/pipeline/scripts/smoke-phase-banner.sh +0 -101
  191. package/pipeline/scripts/smoke-phase-tracker.sh +0 -324
  192. package/pipeline/scripts/smoke-phase0-bridge-contract.sh +0 -241
  193. package/pipeline/scripts/smoke-phase4-gates.sh +0 -45
  194. package/pipeline/scripts/smoke-phase4-triage.sh +0 -229
  195. package/pipeline/scripts/smoke-plan-approval-gate.sh +0 -71
  196. package/pipeline/scripts/smoke-plan-safety.sh +0 -139
  197. package/pipeline/scripts/smoke-plan-todos.sh +0 -196
  198. package/pipeline/scripts/smoke-pr-review-actions.sh +0 -152
  199. package/pipeline/scripts/smoke-pre-commit.sh +0 -170
  200. package/pipeline/scripts/smoke-pref-migration.sh +0 -226
  201. package/pipeline/scripts/smoke-prefs-language.sh +0 -134
  202. package/pipeline/scripts/smoke-progress-contract.sh +0 -127
  203. package/pipeline/scripts/smoke-prune-logs.sh +0 -137
  204. package/pipeline/scripts/smoke-purge.sh +0 -138
  205. package/pipeline/scripts/smoke-push-retry.sh +0 -75
  206. package/pipeline/scripts/smoke-repo-map.sh +0 -300
  207. package/pipeline/scripts/smoke-review-readiness.sh +0 -92
  208. package/pipeline/scripts/smoke-review-watch.sh +0 -146
  209. package/pipeline/scripts/smoke-routines.sh +0 -84
  210. package/pipeline/scripts/smoke-run-aggregator.sh +0 -216
  211. package/pipeline/scripts/smoke-run-metrics.sh +0 -50
  212. package/pipeline/scripts/smoke-search.sh +0 -187
  213. package/pipeline/scripts/smoke-shadow-git.sh +0 -224
  214. package/pipeline/scripts/smoke-skill-authoring.sh +0 -137
  215. package/pipeline/scripts/smoke-skill-language.sh +0 -83
  216. package/pipeline/scripts/smoke-skill-manifest.sh +0 -138
  217. package/pipeline/scripts/smoke-skill-scan.sh +0 -198
  218. package/pipeline/scripts/smoke-source-parity.sh +0 -85
  219. package/pipeline/scripts/smoke-subagent-validators.sh +0 -108
  220. package/pipeline/scripts/smoke-sync-parity.sh +0 -92
  221. package/pipeline/scripts/smoke-tasklist-ordering.sh +0 -112
  222. package/pipeline/scripts/smoke-telemetry.sh +0 -147
  223. package/pipeline/scripts/smoke-test-gap.sh +0 -183
  224. package/pipeline/scripts/smoke-token-budget.sh +0 -67
  225. package/pipeline/scripts/smoke-token-preflight.sh +0 -82
  226. package/pipeline/scripts/smoke-tracker-contract.sh +0 -191
  227. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +0 -73
  228. package/pipeline/scripts/smoke-triage-memory.sh +0 -174
  229. package/pipeline/scripts/smoke-update-check.sh +0 -135
  230. package/pipeline/scripts/smoke-url-enrichment.sh +0 -70
  231. package/pipeline/scripts/smoke-validate-analysis-doc.sh +0 -161
  232. package/pipeline/scripts/smoke-validator-contradiction.sh +0 -67
  233. package/pipeline/scripts/smoke-validator-gates.sh +0 -164
  234. package/pipeline/scripts/smoke-vercel-deploy-redact.sh +0 -129
  235. package/pipeline/scripts/smoke-verify-by-test.sh +0 -148
  236. package/pipeline/scripts/smoke-wiki-integration.sh +0 -122
  237. package/pipeline/scripts/smoke-work-summary.sh +0 -163
  238. package/pipeline/scripts/smoke-workflow-audit.sh +0 -101
  239. package/pipeline/scripts/smoke-worktree-path-convention.sh +0 -86
  240. package/pipeline/scripts/smoke-wrapper-preservation.sh +0 -68
  241. package/pipeline/scripts/smoke-write-state.sh +0 -159
  242. package/pipeline/scripts/sync-parity-check.sh +0 -135
  243. package/pipeline/scripts/test-gap-rules/android.json +0 -25
  244. package/pipeline/scripts/test-gap-rules/ios.json +0 -34
  245. package/pipeline/scripts/test-gap-rules/node.json +0 -29
  246. package/pipeline/scripts/test-gap-rules/python.json +0 -25
  247. package/pipeline/scripts/validate-schemas.mjs +0 -88
@@ -1,40 +0,0 @@
1
- {
2
- "approach": "TDD-first. Add a render test that mounts the header and asserts there is no hydration warning and that the count is present after mount (RED). Make useCart return an SSR-safe initial value and hydrate from localStorage in an effect; consume it in CartBadge so server and first client paint agree (GREEN). Refactor any direct localStorage reads to go through the hook.",
3
- "tasks": [
4
- {
5
- "id": "T1",
6
- "title": "Add failing hydration/render test for CartBadge",
7
- "type": "test",
8
- "files": ["components/CartBadge.test.tsx"],
9
- "dependsOn": [],
10
- "acceptanceCriteria": [
11
- "Test renders the badge and asserts no React hydration warning is emitted",
12
- "After mount/effect flush, the badge shows the persisted count"
13
- ]
14
- },
15
- {
16
- "id": "T2",
17
- "title": "Make useCart SSR-safe (stable initial value, hydrate on mount)",
18
- "type": "code",
19
- "files": ["hooks/useCart.ts"],
20
- "dependsOn": ["T1"],
21
- "acceptanceCriteria": [
22
- "Initial server and first client render return the same value",
23
- "localStorage is read inside an effect, not during render"
24
- ]
25
- },
26
- {
27
- "id": "T3",
28
- "title": "Consume the SSR-safe count in CartBadge",
29
- "type": "code",
30
- "files": ["components/CartBadge.tsx"],
31
- "dependsOn": ["T2"],
32
- "acceptanceCriteria": [
33
- "CartBadge reads the count only from useCart",
34
- "No direct localStorage access remains in the component"
35
- ]
36
- }
37
- ],
38
- "approved": true,
39
- "userFeedback": null
40
- }
@@ -1,20 +0,0 @@
1
- [
2
- {
3
- "reviewer": "opus",
4
- "findings": [
5
- {
6
- "severity": "blocking",
7
- "file": "components/CartBadge.tsx",
8
- "line": 17,
9
- "issue": "The mounted-guard returns null until mount but never renders the count afterward on the first client pass, so the badge stays empty when items exist; the guard fixes the warning but breaks the feature",
10
- "fix": "Render the hydrated count once mounted instead of returning null permanently; only the initial server-equal value should gate on mount"
11
- }
12
- ],
13
- "approved": false
14
- },
15
- {
16
- "reviewer": "sonnet",
17
- "findings": [],
18
- "approved": true
19
- }
20
- ]
@@ -1,15 +0,0 @@
1
- {
2
- "accepted": [
3
- {
4
- "severity": "blocking",
5
- "file": "components/CartBadge.tsx",
6
- "line": 17,
7
- "issue": "The mounted-guard returns null until mount but never renders the count afterward on the first client pass, so the badge stays empty when items exist; the guard fixes the warning but breaks the feature",
8
- "fix": "Render the hydrated count once mounted instead of returning null permanently; only the initial server-equal value should gate on mount",
9
- "reviewer": "opus"
10
- }
11
- ],
12
- "deferred": [],
13
- "rejected": [],
14
- "approved": false
15
- }
@@ -1,14 +0,0 @@
1
- {
2
- "focus": "Frontend (Next.js/React/TypeScript) bugfix path - verifies frontend stack detection and that Phase 4 catches a correctness blocker (a hydration guard that hides the count past first paint).",
3
- "exercises": [
4
- "Phase 1 stack detection (frontend / TypeScript / Next.js)",
5
- "Phase 2 TDD ordering (failing render test before the fix)",
6
- "Phase 4 Reviewer-1 (opus) flags that the mounted-guard leaves the badge empty even after mount; Reviewer-2 (sonnet) approves",
7
- "Triage keeps the correctness blocker accepted, no deferrals, not approved"
8
- ],
9
- "regressionsCaught": [
10
- "If frontend detection regresses to 'unknown', the stack-match check fails",
11
- "If a plan task references a file absent from touchedAreas, the subset check fails",
12
- "If reviewer findings stop tracing to a planned file or triage, the traceability check fails"
13
- ]
14
- }
@@ -1,12 +0,0 @@
1
- {
2
- "title": "Fix cart badge hydration mismatch in Next.js header",
3
- "description": "The cart item count renders on the server as 0 but the client reads it from localStorage, causing a React hydration mismatch warning and a flash of the wrong count. Make the badge render consistently on first paint.",
4
- "inputType": "free-text",
5
- "expectedStack": "frontend",
6
- "expectedLanguage": "TypeScript",
7
- "expectedFramework": "Next.js",
8
- "expectedBlockers": 1,
9
- "expectedDeferrals": 0,
10
- "baseBranch": "main",
11
- "taskBranch": "bugfix/cart-badge-hydration"
12
- }
@@ -1,29 +0,0 @@
1
- {
2
- "stack": {
3
- "primary": "ios",
4
- "language": "Swift 6",
5
- "framework": "SwiftUI"
6
- },
7
- "touchedAreas": [
8
- {
9
- "path": "Sources/Auth/TokenStore.swift",
10
- "why": "New Keychain-backed store replacing the UserDefaults read/write of the token"
11
- },
12
- {
13
- "path": "Sources/Auth/SessionManager.swift",
14
- "why": "Reads and writes the token through TokenStore instead of UserDefaults"
15
- },
16
- {
17
- "path": "Sources/Auth/TokenStoreTests.swift",
18
- "why": "Round-trip save/load/delete tests against a Keychain test double"
19
- }
20
- ],
21
- "risks": [
22
- {
23
- "risk": "Existing users already have a token in UserDefaults; a naive switch logs everyone out on upgrade",
24
- "severity": "medium",
25
- "mitigation": "Plan a one-time migration that reads the legacy UserDefaults value, writes it to the Keychain, then clears it"
26
- }
27
- ],
28
- "summary": "The auth token lives in UserDefaults (insecure). Introduce a Keychain-backed TokenStore and route SessionManager through it. The main hazard is logging out existing users on upgrade unless a one-time migration moves legacy tokens; that migration is the likely deferral if the security fix lands first."
29
- }
@@ -1,42 +0,0 @@
1
- {
2
- "approach": "TDD-first. Write round-trip tests for a Keychain-backed TokenStore (save, load, delete) against a test double (RED). Implement TokenStore over the Keychain (GREEN). Route SessionManager through TokenStore and remove the UserDefaults access (refactor). Legacy-token migration is scoped as a follow-up if the security fix is prioritized first.",
3
- "tasks": [
4
- {
5
- "id": "T1",
6
- "title": "Add failing TokenStore round-trip tests",
7
- "type": "test",
8
- "files": ["Sources/Auth/TokenStoreTests.swift"],
9
- "dependsOn": [],
10
- "acceptanceCriteria": [
11
- "save then load returns the same token",
12
- "delete removes the token and load returns nil",
13
- "tests run against a Keychain double, no real Keychain dependency"
14
- ]
15
- },
16
- {
17
- "id": "T2",
18
- "title": "Implement Keychain-backed TokenStore",
19
- "type": "code",
20
- "files": ["Sources/Auth/TokenStore.swift"],
21
- "dependsOn": ["T1"],
22
- "acceptanceCriteria": [
23
- "Uses kSecClassGenericPassword with an app-specific service",
24
- "No token value is ever passed to a logger",
25
- "Returns typed errors, not optional-swallowing"
26
- ]
27
- },
28
- {
29
- "id": "T3",
30
- "title": "Route SessionManager through TokenStore",
31
- "type": "code",
32
- "files": ["Sources/Auth/SessionManager.swift"],
33
- "dependsOn": ["T2"],
34
- "acceptanceCriteria": [
35
- "All token reads/writes go through TokenStore",
36
- "No UserDefaults access for the token remains"
37
- ]
38
- }
39
- ],
40
- "approved": true,
41
- "userFeedback": null
42
- }
@@ -1,28 +0,0 @@
1
- [
2
- {
3
- "reviewer": "opus",
4
- "findings": [
5
- {
6
- "severity": "blocking",
7
- "file": "Sources/Auth/SessionManager.swift",
8
- "line": 54,
9
- "issue": "os_log(\"restored session token=\\(token)\") logs the raw token in plaintext; moving storage to the Keychain is undone if the value still leaks to the device log",
10
- "fix": "Remove the token from the log statement, or log a redacted fingerprint only"
11
- }
12
- ],
13
- "approved": false
14
- },
15
- {
16
- "reviewer": "sonnet",
17
- "findings": [
18
- {
19
- "severity": "important",
20
- "file": "Sources/Auth/SessionManager.swift",
21
- "line": 70,
22
- "issue": "Existing users with a token in UserDefaults are not migrated, so this change logs them all out on first launch after upgrade",
23
- "fix": "Add a one-time migration: read the legacy UserDefaults token, write it to TokenStore, then clear UserDefaults"
24
- }
25
- ],
26
- "approved": false
27
- }
28
- ]
@@ -1,27 +0,0 @@
1
- {
2
- "accepted": [
3
- {
4
- "severity": "blocking",
5
- "file": "Sources/Auth/SessionManager.swift",
6
- "line": 54,
7
- "issue": "os_log(\"restored session token=\\(token)\") logs the raw token in plaintext; moving storage to the Keychain is undone if the value still leaks to the device log",
8
- "fix": "Remove the token from the log statement, or log a redacted fingerprint only",
9
- "reviewer": "opus"
10
- }
11
- ],
12
- "deferred": [
13
- {
14
- "finding": {
15
- "severity": "important",
16
- "file": "Sources/Auth/SessionManager.swift",
17
- "line": 70,
18
- "issue": "Existing users with a token in UserDefaults are not migrated, so this change logs them all out on first launch after upgrade",
19
- "fix": "Add a one-time migration: read the legacy UserDefaults token, write it to TokenStore, then clear UserDefaults",
20
- "reviewer": "sonnet"
21
- },
22
- "reason": "Security fix (stop the plaintext leak) ships first; the migration is a separate, lower-risk follow-up that needs its own upgrade test, so it is deferred rather than blocking this PR."
23
- }
24
- ],
25
- "rejected": [],
26
- "approved": false
27
- }
@@ -1,14 +0,0 @@
1
- {
2
- "focus": "iOS security path with a mixed triage outcome - one accepted blocker plus one deferred finding. Verifies the deferred bucket count, not just blockers.",
3
- "exercises": [
4
- "Phase 1 stack detection (iOS / Swift / SwiftUI) on a security task",
5
- "Phase 4 Reviewer-1 (opus) catches a blocking secret-logging leak; Reviewer-2 (sonnet) raises a non-blocking migration gap",
6
- "Triage accepts the blocker and DEFERS the migration finding (expectedDeferrals = 1)",
7
- "Reviewer findings trace to planned files / triage entries"
8
- ],
9
- "regressionsCaught": [
10
- "If the deferred-count assertion regresses, a 1-deferred fixture catches it (01-04 all have 0 deferrals)",
11
- "If validate-triage stops allowing a populated deferred bucket with approved=false, this fixture fails",
12
- "If stack detection misroutes a security-flavored iOS task, the stack-match check fails"
13
- ]
14
- }
@@ -1,12 +0,0 @@
1
- {
2
- "title": "Move the auth token from UserDefaults into the Keychain",
3
- "description": "The session auth token is stored in UserDefaults, which is not secure storage. Move it into the Keychain behind a TokenStore abstraction and update SessionManager to read/write through it.",
4
- "inputType": "free-text",
5
- "expectedStack": "ios",
6
- "expectedLanguage": "Swift",
7
- "expectedFramework": "SwiftUI",
8
- "expectedBlockers": 1,
9
- "expectedDeferrals": 1,
10
- "baseBranch": "develop",
11
- "taskBranch": "feature/keychain-token-store"
12
- }
@@ -1,29 +0,0 @@
1
- {
2
- "stack": {
3
- "primary": "android",
4
- "language": "Kotlin 2.1",
5
- "framework": "Jetpack Compose"
6
- },
7
- "touchedAreas": [
8
- {
9
- "path": "feature/booking/BookingUseCase.kt",
10
- "why": "New use case that holds the booking business rules extracted from the ViewModel"
11
- },
12
- {
13
- "path": "feature/booking/BookingViewModel.kt",
14
- "why": "Delegates rule evaluation to BookingUseCase, keeps only UI state mapping"
15
- },
16
- {
17
- "path": "feature/booking/BookingViewModelTest.kt",
18
- "why": "Existing behavior tests stay green to prove the refactor preserves behavior"
19
- }
20
- ],
21
- "risks": [
22
- {
23
- "risk": "If the extraction accidentally changes coroutine dispatcher or state emission order, the UI could behave differently despite passing logic tests",
24
- "severity": "low",
25
- "mitigation": "Keep the same dispatcher and StateFlow emission points; rely on the existing ViewModel tests as the behavior contract"
26
- }
27
- ],
28
- "summary": "BookingViewModel mixes UI state and booking rules. Extract the rules into a BookingUseCase and have the ViewModel delegate, with no behavior change. The existing ViewModel tests act as the contract; risk is low as long as dispatcher and emission order are preserved."
29
- }
@@ -1,41 +0,0 @@
1
- {
2
- "approach": "Behavior-preserving refactor. First confirm the existing BookingViewModel tests pass and cover the rules (no new RED needed; the tests are the safety net). Extract the rules into BookingUseCase, then make the ViewModel delegate. Re-run the same tests to prove behavior is unchanged.",
3
- "tasks": [
4
- {
5
- "id": "T1",
6
- "title": "Pin behavior with the existing ViewModel tests (safety net)",
7
- "type": "test",
8
- "files": ["feature/booking/BookingViewModelTest.kt"],
9
- "dependsOn": [],
10
- "acceptanceCriteria": [
11
- "Existing booking-rule tests pass before the refactor",
12
- "Tests assert observable StateFlow outputs, not internal calls"
13
- ]
14
- },
15
- {
16
- "id": "T2",
17
- "title": "Extract booking rules into BookingUseCase",
18
- "type": "refactor",
19
- "files": ["feature/booking/BookingUseCase.kt"],
20
- "dependsOn": ["T1"],
21
- "acceptanceCriteria": [
22
- "BookingUseCase exposes the rules via a single operator invoke",
23
- "No Android framework types leak into the use case"
24
- ]
25
- },
26
- {
27
- "id": "T3",
28
- "title": "Delegate from BookingViewModel to BookingUseCase",
29
- "type": "refactor",
30
- "files": ["feature/booking/BookingViewModel.kt"],
31
- "dependsOn": ["T2"],
32
- "acceptanceCriteria": [
33
- "ViewModel keeps only UI-state mapping and calls the use case",
34
- "Same dispatcher and StateFlow emission points as before",
35
- "All existing tests still pass"
36
- ]
37
- }
38
- ],
39
- "approved": true,
40
- "userFeedback": null
41
- }
@@ -1,12 +0,0 @@
1
- [
2
- {
3
- "reviewer": "opus",
4
- "findings": [],
5
- "approved": true
6
- },
7
- {
8
- "reviewer": "sonnet",
9
- "findings": [],
10
- "approved": true
11
- }
12
- ]
@@ -1,6 +0,0 @@
1
- {
2
- "accepted": [],
3
- "deferred": [],
4
- "rejected": [],
5
- "approved": true
6
- }
@@ -1,14 +0,0 @@
1
- {
2
- "focus": "Android refactor with a clean approval - 0 blockers, 0 deferrals, both reviewers approve. Verifies the happy path (empty triage, approved=true), which the bug-finding fixtures never exercise.",
3
- "exercises": [
4
- "Phase 1 stack detection (Android / Kotlin / Jetpack Compose)",
5
- "Phase 2 plan with a behavior-preserving test gate before extraction",
6
- "Phase 4 both reviewers return zero findings and approve",
7
- "Triage with all-empty buckets and approved=true passes validate-triage"
8
- ],
9
- "regressionsCaught": [
10
- "If validate-triage stops accepting an all-empty approved triage, this fixture fails",
11
- "If the eval ever assumes at least one finding exists, a zero-finding fixture catches it",
12
- "If Android detection regresses, the stack-match check fails"
13
- ]
14
- }
@@ -1,12 +0,0 @@
1
- {
2
- "title": "Extract booking logic from BookingViewModel into a UseCase",
3
- "description": "BookingViewModel mixes UI state with booking business rules. Extract the rules into a BookingUseCase (Clean Architecture) with no behavior change, and have the ViewModel delegate to it. Pure refactor, covered by existing behavior tests.",
4
- "inputType": "free-text",
5
- "expectedStack": "android",
6
- "expectedLanguage": "Kotlin",
7
- "expectedFramework": "Jetpack Compose",
8
- "expectedBlockers": 0,
9
- "expectedDeferrals": 0,
10
- "baseBranch": "develop",
11
- "taskBranch": "refactor/booking-usecase"
12
- }
@@ -1,29 +0,0 @@
1
- {
2
- "stack": {
3
- "primary": "backend",
4
- "language": "JavaScript",
5
- "framework": "Express"
6
- },
7
- "touchedAreas": [
8
- {
9
- "path": "src/payments/idempotency.js",
10
- "why": "New middleware that reads Idempotency-Key, stores the first response, and replays duplicates"
11
- },
12
- {
13
- "path": "src/payments/router.js",
14
- "why": "Wires the middleware ahead of the POST /payments handler"
15
- },
16
- {
17
- "path": "test/idempotency.test.js",
18
- "why": "Covers first-call passthrough, duplicate-key replay, and TTL expiry"
19
- }
20
- ],
21
- "risks": [
22
- {
23
- "risk": "A store keyed only by the header lets a client collide another client's key; the key should be namespaced per authenticated account",
24
- "severity": "medium",
25
- "mitigation": "Namespace the stored key with the account id so keys cannot collide across users"
26
- }
27
- ],
28
- "summary": "POST /payments can double-charge on retry. Add Idempotency-Key middleware that stores and replays the first response within a TTL, wired ahead of the handler. Main hazard is cross-account key collision, mitigated by namespacing the key per account."
29
- }
@@ -1,42 +0,0 @@
1
- {
2
- "approach": "TDD-first. Write tests for first-call passthrough, duplicate-key replay (same response, no second charge), and TTL expiry (RED). Implement the idempotency middleware with a per-account-namespaced key and a TTL store (GREEN). Wire it ahead of the payments handler (integration).",
3
- "tasks": [
4
- {
5
- "id": "T1",
6
- "title": "Add failing idempotency tests (passthrough, replay, TTL)",
7
- "type": "test",
8
- "files": ["test/idempotency.test.js"],
9
- "dependsOn": [],
10
- "acceptanceCriteria": [
11
- "First request with a key passes through and is stored",
12
- "Duplicate key within TTL replays the stored response without re-charging",
13
- "After TTL expiry the key is treated as new"
14
- ]
15
- },
16
- {
17
- "id": "T2",
18
- "title": "Implement idempotency middleware",
19
- "type": "code",
20
- "files": ["src/payments/idempotency.js"],
21
- "dependsOn": ["T1"],
22
- "acceptanceCriteria": [
23
- "Reads the Idempotency-Key header and validates its length and charset",
24
- "Namespaces the stored key by authenticated account id",
25
- "Stores first response with a TTL and replays on duplicate"
26
- ]
27
- },
28
- {
29
- "id": "T3",
30
- "title": "Wire the middleware ahead of POST /payments",
31
- "type": "code",
32
- "files": ["src/payments/router.js"],
33
- "dependsOn": ["T2"],
34
- "acceptanceCriteria": [
35
- "Middleware runs before the payment handler",
36
- "Requests without the header still work (idempotency optional)"
37
- ]
38
- }
39
- ],
40
- "approved": true,
41
- "userFeedback": null
42
- }
@@ -1,28 +0,0 @@
1
- [
2
- {
3
- "reviewer": "opus",
4
- "findings": [
5
- {
6
- "severity": "blocking",
7
- "file": "src/payments/idempotency.js",
8
- "line": 22,
9
- "issue": "The Idempotency-Key header is used as a store key with no length or charset validation; a client can send a multi-megabyte key and exhaust the store, and odd bytes can corrupt the keyspace",
10
- "fix": "Reject keys that are not 1-255 chars of [A-Za-z0-9-_] before using them as a store key"
11
- }
12
- ],
13
- "approved": false
14
- },
15
- {
16
- "reviewer": "sonnet",
17
- "findings": [
18
- {
19
- "severity": "important",
20
- "file": "src/payments/router.js",
21
- "line": 14,
22
- "issue": "The handler call looks like it is missing an await, so the response may be sent before the charge resolves",
23
- "fix": "Await the charge before responding"
24
- }
25
- ],
26
- "approved": false
27
- }
28
- ]
@@ -1,27 +0,0 @@
1
- {
2
- "accepted": [
3
- {
4
- "severity": "blocking",
5
- "file": "src/payments/idempotency.js",
6
- "line": 22,
7
- "issue": "The Idempotency-Key header is used as a store key with no length or charset validation; a client can send a multi-megabyte key and exhaust the store, and odd bytes can corrupt the keyspace",
8
- "fix": "Reject keys that are not 1-255 chars of [A-Za-z0-9-_] before using them as a store key",
9
- "reviewer": "opus"
10
- }
11
- ],
12
- "deferred": [],
13
- "rejected": [
14
- {
15
- "finding": {
16
- "severity": "important",
17
- "file": "src/payments/router.js",
18
- "line": 14,
19
- "issue": "The handler call looks like it is missing an await, so the response may be sent before the charge resolves",
20
- "fix": "Await the charge before responding",
21
- "reviewer": "sonnet"
22
- },
23
- "reason": "False positive: the handler is registered with express-async-handler, which awaits the returned promise, and the charge is already awaited inside it. No missing await."
24
- }
25
- ],
26
- "approved": false
27
- }
@@ -1,14 +0,0 @@
1
- {
2
- "focus": "Backend (Node/Express) feature that exercises the REJECTED triage bucket - one accepted blocker plus one rejected false-positive. The only fixture that populates rejected.",
3
- "exercises": [
4
- "Phase 1 stack detection (backend / JavaScript / Express)",
5
- "Phase 4 Reviewer-1 (opus) raises a real input-validation blocker; Reviewer-2 (sonnet) raises a false-positive 'missing await'",
6
- "Triage accepts the blocker and REJECTS the false positive with a reason",
7
- "validate-triage accepts a populated rejected bucket (finding + reason shape)"
8
- ],
9
- "regressionsCaught": [
10
- "If the rejected-bucket {finding, reason} shape regresses, this fixture fails validate-triage",
11
- "If triage drops the reviewer attribution on a rejected finding, it fails",
12
- "If the eval's finding-traceability check breaks on rejected entries, this catches it"
13
- ]
14
- }
@@ -1,12 +0,0 @@
1
- {
2
- "title": "Add idempotency keys to the payments POST endpoint",
3
- "description": "POST /payments can double-charge on client retry. Accept an Idempotency-Key header, store the first response keyed by it, and replay that response for duplicate keys within a TTL.",
4
- "inputType": "free-text",
5
- "expectedStack": "backend",
6
- "expectedLanguage": "JavaScript",
7
- "expectedFramework": "Express",
8
- "expectedBlockers": 1,
9
- "expectedDeferrals": 0,
10
- "baseBranch": "main",
11
- "taskBranch": "feature/payments-idempotency"
12
- }
@@ -1,25 +0,0 @@
1
- {
2
- "stack": {
3
- "primary": "ios",
4
- "language": "Swift 6",
5
- "framework": "SwiftUI"
6
- },
7
- "touchedAreas": [
8
- {
9
- "path": "Sources/Auth/TokenStore.swift",
10
- "why": "Wrap the Keychain read in an LAContext biometric evaluation before returning the token"
11
- },
12
- {
13
- "path": "Sources/Auth/TokenStoreTests.swift",
14
- "why": "Cover the gated read: success after auth, failure/cancel returns no token"
15
- }
16
- ],
17
- "risks": [
18
- {
19
- "risk": "Biometric evaluation is async and can fail/cancel; a wrong fallback could either lock users out or defeat the gate",
20
- "severity": "medium",
21
- "mitigation": "Define explicit behavior for cancel / not-enrolled / lockout, and test each path"
22
- }
23
- ],
24
- "summary": "Add a biometric (LAContext) check in front of the existing Keychain-backed TokenStore read. Security-sensitive surface: the correctness hinges on the failure-path policy (cancel / not-enrolled / lockout), which is exactly the kind of judgment call where two same-family reviewers approving is not independent proof."
25
- }
@@ -1,31 +0,0 @@
1
- {
2
- "approach": "TDD-first. Add failing tests for the gated read: a successful biometric evaluation returns the token; a cancelled or failed evaluation returns no token and does not fall back to an ungated read (RED). Wrap the existing Keychain read in an LAContext evaluation, keeping the TokenStore API unchanged (GREEN). Define explicit behavior for cancel / not-enrolled / lockout (refactor).",
3
- "tasks": [
4
- {
5
- "id": "T1",
6
- "title": "Add failing biometric-gated read tests",
7
- "type": "test",
8
- "files": ["Sources/Auth/TokenStoreTests.swift"],
9
- "dependsOn": [],
10
- "acceptanceCriteria": [
11
- "success after auth returns the stored token",
12
- "cancelled / failed auth returns nil and never reads the Keychain ungated",
13
- "evaluation runs against an injectable LAContext double"
14
- ]
15
- },
16
- {
17
- "id": "T2",
18
- "title": "Gate the Keychain read behind LAContext",
19
- "type": "code",
20
- "files": ["Sources/Auth/TokenStore.swift"],
21
- "dependsOn": ["T1"],
22
- "acceptanceCriteria": [
23
- "TokenStore public API is unchanged",
24
- "Token is only returned after a successful biometric evaluation",
25
- "cancel / not-enrolled / lockout each have explicit, tested behavior"
26
- ]
27
- }
28
- ],
29
- "approved": true,
30
- "userFeedback": null
31
- }
@@ -1,12 +0,0 @@
1
- [
2
- {
3
- "reviewer": "opus",
4
- "findings": [],
5
- "approved": true
6
- },
7
- {
8
- "reviewer": "sonnet",
9
- "findings": [],
10
- "approved": true
11
- }
12
- ]
@@ -1,18 +0,0 @@
1
- {
2
- "accepted": [],
3
- "deferred": [],
4
- "rejected": [],
5
- "approved": true,
6
- "consensus": {
7
- "reviewerCount": 2,
8
- "verdict": "unverified",
9
- "disagreements": [
10
- {
11
- "file": "Sources/Auth/TokenStore.swift",
12
- "line": 0,
13
- "issue": "biometric failure-path policy (cancel / not-enrolled / lockout) on a Keychain-gated read",
14
- "note": "Both reviewers approved, but this is a security/auth judgment surface - the agreement is unverified. A human should confirm the cancel / not-enrolled / lockout behavior before trusting the pass."
15
- }
16
- ]
17
- }
18
- }