@mmerterden/multi-agent-pipeline 18.0.0 → 19.1.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 (234) hide show
  1. package/CHANGELOG.md +287 -0
  2. package/README.md +36 -20
  3. package/README.tr.md +14 -16
  4. package/docs/adr/0002-instruction-driven-flag.md +1 -0
  5. package/docs/adr/0005-lazy-phase-docs.md +11 -1
  6. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +1 -0
  7. package/docs/adr/0010-own-code-graph.md +1 -0
  8. package/docs/adr/0014-six-phase-consolidation.md +134 -0
  9. package/docs/adr/README.md +2 -1
  10. package/docs/architecture.md +37 -38
  11. package/docs/best-practices.md +1 -1
  12. package/docs/ecosystem.md +46 -27
  13. package/docs/engineering.md +1 -1
  14. package/docs/facts.json +61 -0
  15. package/docs/features.md +55 -54
  16. package/docs/performance.md +5 -5
  17. package/docs/recovery-guide.md +17 -17
  18. package/docs/token-budget-history.md +3 -1
  19. package/index.js +2 -2
  20. package/install/_codex-agents.mjs +1 -1
  21. package/install/templates/claude-hooks.json +1 -1
  22. package/install/templates/codex-instructions.md +1 -1
  23. package/install/templates/copilot-instructions.md +28 -28
  24. package/manifest.json +234 -216
  25. package/package.json +2 -2
  26. package/pipeline/agents/dev-critic.md +7 -7
  27. package/pipeline/commands/figma-to-swiftui.md +1 -1
  28. package/pipeline/commands/multi-agent/SKILL.md +9 -9
  29. package/pipeline/commands/multi-agent/analysis/SKILL.md +15 -15
  30. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +2 -2
  31. package/pipeline/commands/multi-agent/autopilot/SKILL.md +7 -7
  32. package/pipeline/commands/multi-agent/channels/SKILL.md +15 -15
  33. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +6 -6
  34. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
  35. package/pipeline/commands/multi-agent/graph/SKILL.md +1 -1
  36. package/pipeline/commands/multi-agent/help/SKILL.md +62 -62
  37. package/pipeline/commands/multi-agent/language/SKILL.md +2 -2
  38. package/pipeline/commands/multi-agent/local/SKILL.md +11 -11
  39. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +13 -13
  40. package/pipeline/commands/multi-agent/log/SKILL.md +2 -2
  41. package/pipeline/commands/multi-agent/manual-test/SKILL.md +9 -9
  42. package/pipeline/commands/multi-agent/model/SKILL.md +69 -0
  43. package/pipeline/commands/multi-agent/refactor/SKILL.md +3 -3
  44. package/pipeline/commands/multi-agent/resume/SKILL.md +4 -4
  45. package/pipeline/commands/multi-agent/resume-local/SKILL.md +19 -17
  46. package/pipeline/commands/multi-agent/review/SKILL.md +2 -2
  47. package/pipeline/commands/multi-agent/review-analysis/SKILL.md +1 -1
  48. package/pipeline/commands/multi-agent/route-off/SKILL.md +36 -0
  49. package/pipeline/commands/multi-agent/route-on/SKILL.md +74 -0
  50. package/pipeline/commands/multi-agent/route-status/SKILL.md +56 -0
  51. package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
  52. package/pipeline/commands/multi-agent/status/SKILL.md +5 -5
  53. package/pipeline/commands/multi-agent/steer/SKILL.md +2 -2
  54. package/pipeline/commands/multi-agent/sync/SKILL.md +12 -13
  55. package/pipeline/commands/multi-agent/test/SKILL.md +1 -1
  56. package/pipeline/lib/credential-inventory.sh +1 -1
  57. package/pipeline/lib/fetch-fortify.sh +1 -1
  58. package/pipeline/lib/model-dispatch.sh +140 -0
  59. package/pipeline/lib/model-rung.sh +142 -0
  60. package/pipeline/lib/outbound-gate.mjs +14 -0
  61. package/pipeline/lib/phase-schema.mjs +88 -0
  62. package/pipeline/lib/plan-todos.sh +5 -5
  63. package/pipeline/lib/route-state.sh +161 -0
  64. package/pipeline/lib/run-paths.sh +2 -2
  65. package/pipeline/multi-agent-refs/_account-picker.md +1 -1
  66. package/pipeline/multi-agent-refs/_dev-context.md +6 -6
  67. package/pipeline/multi-agent-refs/_input-parser.md +1 -1
  68. package/pipeline/multi-agent-refs/analysis/evidence.md +2 -11
  69. package/pipeline/multi-agent-refs/analysis/intake.md +7 -7
  70. package/pipeline/multi-agent-refs/analysis/locked.md +48 -22
  71. package/pipeline/multi-agent-refs/analysis/redesign.md +1 -1
  72. package/pipeline/multi-agent-refs/analysis/render.md +10 -10
  73. package/pipeline/multi-agent-refs/analysis/resolve.md +1 -1
  74. package/pipeline/multi-agent-refs/analysis/review.md +2 -2
  75. package/pipeline/multi-agent-refs/analysis/synthesis.md +13 -7
  76. package/pipeline/multi-agent-refs/analysis-template-corporate.md +9 -9
  77. package/pipeline/multi-agent-refs/analysis-template.md +19 -19
  78. package/pipeline/multi-agent-refs/android-guide.md +1 -1
  79. package/pipeline/multi-agent-refs/audit-guide.md +13 -13
  80. package/pipeline/multi-agent-refs/channels/issue-comment.md +2 -2
  81. package/pipeline/multi-agent-refs/channels/jira.md +3 -3
  82. package/pipeline/multi-agent-refs/channels/pr.md +4 -4
  83. package/pipeline/multi-agent-refs/channels/wiki.md +1 -1
  84. package/pipeline/multi-agent-refs/component-dispatch.md +8 -8
  85. package/pipeline/multi-agent-refs/conventions-defaults.md +2 -2
  86. package/pipeline/multi-agent-refs/cross-cli-contract.md +31 -6
  87. package/pipeline/multi-agent-refs/features/analysis-jira.md +1 -1
  88. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +4 -4
  89. package/pipeline/multi-agent-refs/features/code-graph.md +5 -5
  90. package/pipeline/multi-agent-refs/features/design-conformance.md +1 -1
  91. package/pipeline/multi-agent-refs/features/dev-critic.md +3 -3
  92. package/pipeline/multi-agent-refs/features/doctor.md +3 -3
  93. package/pipeline/multi-agent-refs/features/external-context-injection.md +3 -3
  94. package/pipeline/multi-agent-refs/features/maturity-followup.md +3 -3
  95. package/pipeline/multi-agent-refs/features/model-fallback.md +41 -5
  96. package/pipeline/multi-agent-refs/features/plan-todos.md +1 -1
  97. package/pipeline/multi-agent-refs/features/repo-map.md +1 -1
  98. package/pipeline/multi-agent-refs/features/review-delta.md +3 -3
  99. package/pipeline/multi-agent-refs/features/review-multi-repo.md +2 -2
  100. package/pipeline/multi-agent-refs/features/scope-check.md +4 -4
  101. package/pipeline/multi-agent-refs/features/skill-conformance.md +2 -2
  102. package/pipeline/multi-agent-refs/features/stack-skill-routing.md +1 -1
  103. package/pipeline/multi-agent-refs/features/url-enrichment.md +1 -1
  104. package/pipeline/multi-agent-refs/features/verify-by-test.md +4 -4
  105. package/pipeline/multi-agent-refs/features/visual-evidence.md +19 -19
  106. package/pipeline/multi-agent-refs/features/worktree-finalize.md +6 -6
  107. package/pipeline/multi-agent-refs/issue-jira-triad.md +10 -10
  108. package/pipeline/multi-agent-refs/knowledge.md +11 -11
  109. package/pipeline/multi-agent-refs/multi-repo-integration-build.md +13 -13
  110. package/pipeline/multi-agent-refs/payload-contracts.md +8 -8
  111. package/pipeline/multi-agent-refs/phases/log-format.md +10 -10
  112. package/pipeline/multi-agent-refs/phases/modes.md +30 -30
  113. package/pipeline/multi-agent-refs/phases/operations.md +8 -8
  114. package/pipeline/multi-agent-refs/phases/phase-0-init.md +24 -24
  115. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +599 -0
  116. package/pipeline/multi-agent-refs/phases/{phase-3-dev.md → phase-2-dev.md} +129 -49
  117. package/pipeline/multi-agent-refs/phases/{phase-4-review.md → phase-3-review.md} +225 -107
  118. package/pipeline/multi-agent-refs/phases/{phase-6-commit.md → phase-4-commit.md} +23 -23
  119. package/pipeline/multi-agent-refs/phases/{phase-7-report.md → phase-5-report.md} +29 -29
  120. package/pipeline/multi-agent-refs/phases.md +44 -48
  121. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  122. package/pipeline/multi-agent-refs/progress-contract.md +6 -6
  123. package/pipeline/multi-agent-refs/readiness-review.md +1 -1
  124. package/pipeline/multi-agent-refs/rules.md +7 -7
  125. package/pipeline/multi-agent-refs/swiftui-guide.md +2 -2
  126. package/pipeline/multi-agent-refs/tracker-contract.md +31 -32
  127. package/pipeline/multi-agent-refs/wiki-capture.md +14 -14
  128. package/pipeline/preferences-template.json +9 -1
  129. package/pipeline/rules/figma-pipeline.md +8 -8
  130. package/pipeline/rules/outside-the-pipeline.md +1 -1
  131. package/pipeline/schemas/agent-state.schema.json +50 -50
  132. package/pipeline/schemas/analysis-output.schema.json +3 -3
  133. package/pipeline/schemas/analysis-spec.schema.json +2 -2
  134. package/pipeline/schemas/autopilot-config.schema.json +1 -1
  135. package/pipeline/schemas/code-graph.schema.json +1 -1
  136. package/pipeline/schemas/criteria-manifest.schema.json +1 -1
  137. package/pipeline/schemas/dev-critic-output.schema.json +1 -1
  138. package/pipeline/schemas/diff-risk.schema.json +1 -1
  139. package/pipeline/schemas/figma-project-config.schema.json +1 -1
  140. package/pipeline/schemas/migrations/prefs-2.4.0-to-2.5.0.mjs +2 -2
  141. package/pipeline/schemas/migrations/prefs-2.6.0-to-2.7.0.mjs +31 -0
  142. package/pipeline/schemas/migrations/state-2.1.0-to-2.2.0.mjs +129 -0
  143. package/pipeline/schemas/phases.json +105 -0
  144. package/pipeline/schemas/plan-todos.schema.json +5 -5
  145. package/pipeline/schemas/planning-output.schema.json +1 -1
  146. package/pipeline/schemas/prefs.schema.json +102 -58
  147. package/pipeline/schemas/reviewer-output.schema.json +3 -3
  148. package/pipeline/schemas/route-config.schema.json +74 -0
  149. package/pipeline/schemas/scope-check.schema.json +1 -1
  150. package/pipeline/schemas/secret-patterns.json +124 -0
  151. package/pipeline/schemas/test-gap.schema.json +1 -1
  152. package/pipeline/schemas/token-budget.json +12 -18
  153. package/pipeline/schemas/triage-output.schema.json +6 -6
  154. package/pipeline/scripts/README.md +3 -3
  155. package/pipeline/scripts/_code-graph.mjs +2 -2
  156. package/pipeline/scripts/_run-paths.mjs +2 -2
  157. package/pipeline/scripts/_smoke-root.sh +1 -1
  158. package/pipeline/scripts/aggregate-metrics.mjs +1 -1
  159. package/pipeline/scripts/build-references.mjs +2 -2
  160. package/pipeline/scripts/bulk-read.sh +10 -1
  161. package/pipeline/scripts/capture-flush.sh +8 -8
  162. package/pipeline/scripts/capture-resume.sh +3 -3
  163. package/pipeline/scripts/classify-plan-safety.mjs +1 -1
  164. package/pipeline/scripts/cost-table.json +8 -1
  165. package/pipeline/scripts/diff-explain.mjs +1 -1
  166. package/pipeline/scripts/doctor.mjs +3 -3
  167. package/pipeline/scripts/gc-abandoned.sh +3 -3
  168. package/pipeline/scripts/gc-tmp.sh +1 -1
  169. package/pipeline/scripts/gc-worktrees.sh +1 -1
  170. package/pipeline/scripts/gen-facts.mjs +280 -0
  171. package/pipeline/scripts/gen-mode-dispatch.mjs +32 -37
  172. package/pipeline/scripts/gen-ref-toc.mjs +1 -1
  173. package/pipeline/scripts/graph-report.mjs +1 -1
  174. package/pipeline/scripts/jira-attach.sh +1 -1
  175. package/pipeline/scripts/learn-from-transcripts.mjs +1 -1
  176. package/pipeline/scripts/learning-curve.mjs +2 -2
  177. package/pipeline/scripts/log-metric.sh +17 -4
  178. package/pipeline/scripts/memory-save.sh +1 -1
  179. package/pipeline/scripts/migrate-prefs.mjs +22 -5
  180. package/pipeline/scripts/phase-banner.sh +20 -20
  181. package/pipeline/scripts/phase-tracker.sh +12 -12
  182. package/pipeline/scripts/plan-coverage-gate.mjs +2 -2
  183. package/pipeline/scripts/pre-commit-check.sh +30 -1
  184. package/pipeline/scripts/render-agent-log-cost.sh +1 -1
  185. package/pipeline/scripts/render-work-summary.sh +3 -3
  186. package/pipeline/scripts/review-file-filter.mjs +1 -1
  187. package/pipeline/scripts/run-aggregator.mjs +13 -6
  188. package/pipeline/scripts/run-metrics.mjs +1 -1
  189. package/pipeline/scripts/runs-index.mjs +11 -1
  190. package/pipeline/scripts/scan-skills.sh +26 -0
  191. package/pipeline/scripts/smoke-cross-cli-behavior.sh +6 -6
  192. package/pipeline/scripts/smoke-schema-validation.sh +26 -7
  193. package/pipeline/scripts/token-budget-report.mjs +13 -2
  194. package/pipeline/scripts/triage-memory.mjs +2 -2
  195. package/pipeline/scripts/validate-analysis-doc.mjs +274 -43
  196. package/pipeline/scripts/validate-planning.mjs +1 -1
  197. package/pipeline/scripts/validate-reviewer.mjs +1 -1
  198. package/pipeline/scripts/validate-state.mjs +45 -5
  199. package/pipeline/scripts/validate-triage.mjs +3 -3
  200. package/pipeline/scripts/verify-citations.mjs +1 -1
  201. package/pipeline/scripts/worktree-finalize.sh +5 -5
  202. package/pipeline/scripts/write-state.mjs +32 -0
  203. package/pipeline/skills/.skill-manifest.json +38 -22
  204. package/pipeline/skills/.skills-index.json +49 -5
  205. package/pipeline/skills/shared/README.md +10 -6
  206. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +8 -8
  207. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +8 -8
  208. package/pipeline/skills/shared/core/multi-agent/SKILL.md +81 -82
  209. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +3 -3
  210. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +14 -14
  211. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +5 -5
  212. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +1 -1
  213. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +25 -23
  214. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -2
  215. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +2 -2
  216. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +8 -8
  217. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +6 -6
  218. package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +71 -0
  219. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +3 -3
  220. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
  221. package/pipeline/skills/shared/core/multi-agent-resume-local/SKILL.md +7 -7
  222. package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +39 -0
  223. package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +76 -0
  224. package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +59 -0
  225. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
  226. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +5 -5
  227. package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -2
  228. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +6 -5
  229. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +1 -1
  230. package/pipeline/skills/shared/external/signal-community/SKILL.md +8 -1
  231. package/pipeline/skills/skills-index.md +8 -4
  232. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +0 -263
  233. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +0 -344
  234. package/pipeline/multi-agent-refs/phases/phase-5-test.md +0 -182
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env bash
2
+ # model-rung.sh - read or flip the top model rung, and keep cost pricing with it.
3
+ #
4
+ # Backs /multi-agent:model. Two preference keys move as ONE write:
5
+ # prefs.global.modelFallback.fableEnabled the rung itself
6
+ # prefs.global.costBudget.pricingModel what the ledger prices against
7
+ #
8
+ # They were always meant to move together - model-fallback.md says so in prose -
9
+ # but nothing enforced it, so a hand edit that flipped one left the estimate
10
+ # pricing every call at a rung that was not in play. With the rung off and
11
+ # pricing still `fable`, the budget ceiling trips early and triggers a downgrade
12
+ # nothing needed. One write, or none.
13
+ #
14
+ # Usage:
15
+ # model-rung.sh report current state (exit 0)
16
+ # model-rung.sh on enable the fable rung
17
+ # model-rung.sh off disable it
18
+ #
19
+ # Exit codes:
20
+ # 0 - reported or applied
21
+ # 2 - bad argument
22
+ # 3 - preferences file missing or unparseable (nothing written)
23
+
24
+ set -uo pipefail
25
+
26
+ PREFS="${MULTI_AGENT_PREFS:-$HOME/.claude/multi-agent-preferences.json}"
27
+ ACTION="${1:-report}"
28
+
29
+ case "$ACTION" in
30
+ report | on | off) ;;
31
+ *)
32
+ echo "usage: model-rung.sh [on|off]" >&2
33
+ exit 2
34
+ ;;
35
+ esac
36
+
37
+ # A missing `jq` must not look like a missing setting. Without this the reads
38
+ # below return empty, the command reports the rung as already off, and a user
39
+ # who asked to turn it off is told it was never on.
40
+ if ! command -v jq >/dev/null 2>&1; then
41
+ echo "model-rung: jq not found - cannot read or write preferences (install: brew install jq)" >&2
42
+ exit 3
43
+ fi
44
+
45
+ if [ ! -f "$PREFS" ]; then
46
+ echo "model-rung: preferences not found at $PREFS - run /multi-agent:setup first" >&2
47
+ exit 3
48
+ fi
49
+
50
+ if ! jq -e . "$PREFS" >/dev/null 2>&1; then
51
+ echo "model-rung: $PREFS is not valid JSON - refusing to write over it" >&2
52
+ exit 3
53
+ fi
54
+
55
+ CUR=$(jq -r '.global.modelFallback.fableEnabled // false' "$PREFS")
56
+ PRICING=$(jq -r '.global.costBudget.pricingModel // "fable"' "$PREFS")
57
+
58
+ host_note() {
59
+ # Which host this is decides whether the switch is a switch or a status line.
60
+ # Saying "enabled" on a host where the rung means something else entirely is
61
+ # the surprise this block exists to avoid.
62
+ case "${MULTI_AGENT_HOST:-claude}" in
63
+ claude)
64
+ echo "Claude Code: the fable rung is Fable 5. This switch is live here."
65
+ ;;
66
+ copilot)
67
+ echo "Copilot CLI: Fable 5 is not offered; its personas never sat on this rung."
68
+ echo "This setting is recorded but changes nothing on this host."
69
+ ;;
70
+ codex)
71
+ echo "Codex CLI: the fable rung means gpt-5.6 @ xhigh, a different model on a"
72
+ echo "different account. This switch deliberately does NOT touch it - a knob"
73
+ echo "named after an Anthropic model must not silently retune a Codex run."
74
+ ;;
75
+ *)
76
+ echo "Unknown host '${MULTI_AGENT_HOST}'; reporting the stored value only."
77
+ ;;
78
+ esac
79
+ }
80
+
81
+ if [ "$ACTION" = "report" ]; then
82
+ echo "fable rung: $CUR"
83
+ echo "cost pricing: $PRICING"
84
+ if [ "$CUR" = "true" ] && [ "$PRICING" != "fable" ]; then
85
+ echo "MISMATCH: rung is on but the ledger prices against '$PRICING' - run 'model on' to realign"
86
+ elif [ "$CUR" != "true" ] && [ "$PRICING" = "fable" ]; then
87
+ echo "MISMATCH: rung is off but the ledger still prices against fable - this trips"
88
+ echo " the budget ceiling early. Run 'model off' to realign."
89
+ fi
90
+ echo ""
91
+ host_note
92
+ exit 0
93
+ fi
94
+
95
+ if [ "$ACTION" = "on" ]; then
96
+ WANT=true
97
+ WANT_PRICING=fable
98
+ else
99
+ WANT=false
100
+ WANT_PRICING=opus
101
+ fi
102
+
103
+ TMP=$(mktemp) || { echo "model-rung: mktemp failed" >&2; exit 3; }
104
+ trap 'rm -f "$TMP"' EXIT
105
+
106
+ # Both keys in one filter. A two-step write can leave the pair half-applied if
107
+ # the second step fails, which is the exact state this command exists to prevent.
108
+ if ! jq --argjson want "$WANT" --arg pricing "$WANT_PRICING" '
109
+ .global.modelFallback //= {}
110
+ | .global.modelFallback.fableEnabled = $want
111
+ | .global.costBudget //= {}
112
+ | .global.costBudget.pricingModel = $pricing
113
+ ' "$PREFS" > "$TMP"; then
114
+ echo "model-rung: jq failed - preferences left untouched" >&2
115
+ exit 3
116
+ fi
117
+
118
+ if ! jq -e . "$TMP" >/dev/null 2>&1; then
119
+ echo "model-rung: produced invalid JSON - preferences left untouched" >&2
120
+ exit 3
121
+ fi
122
+
123
+ mv "$TMP" "$PREFS"
124
+ trap - EXIT
125
+
126
+ echo "fable rung: $CUR -> $WANT"
127
+ echo "cost pricing: $PRICING -> $WANT_PRICING"
128
+ echo ""
129
+
130
+ if [ "$WANT" = "false" ]; then
131
+ # Said at the moment of the change rather than left in a doc: the panel
132
+ # shrinking is the part people discover later and read as a bug.
133
+ echo "Phase 3 reviewer panel: 3 models -> 2 (opus + sonnet)."
134
+ echo "Reviewer 1 lands on opus, which Reviewer 2 already holds, and dispatching"
135
+ echo "one model twice is not cross-model review. consensus.reviewerCount records 2."
136
+ echo "Triage also runs on opus, so it shares a model with Reviewer 1 - the Phase 3"
137
+ echo "Step 3 anonymisation requirement is not optional while the rung is off."
138
+ echo ""
139
+ fi
140
+
141
+ host_note
142
+ exit 0
@@ -68,6 +68,20 @@ export const RULES = [
68
68
  { name: "anthropic-key", certain: true, re: /\bsk-ant-[A-Za-z0-9_-]{32,}\b/g },
69
69
  { name: "figma-token", certain: true, re: /\bfig[a-z]_[A-Za-z0-9_-]{20,}\b/g },
70
70
  { name: "npm-token", certain: true, re: /\bnpm_[A-Za-z0-9]{36}\b/g },
71
+ // This list and the one in scripts/pre-commit-check.sh cover the same
72
+ // provider set. smoke-secret-parity.sh holds them to it by running a fake
73
+ // token of each shape through both, rather than comparing the regexes: a
74
+ // pattern that matches in one dialect and not the other reads as agreement
75
+ // and is not.
76
+ { name: "gitlab-pat", certain: true, re: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
77
+ { name: "stripe-key", certain: true, re: /\b[sr]k_live_[A-Za-z0-9]{20,}\b/g },
78
+ { name: "perplexity-key", certain: true, re: /\bpplx-[A-Za-z0-9]{32,}\b/g },
79
+ { name: "huggingface-token", certain: true, re: /\bhf_[A-Za-z0-9]{30,}\b/g },
80
+ {
81
+ name: "service-account-json",
82
+ certain: true,
83
+ re: /"type"\s*:\s*"service_account"/g,
84
+ },
71
85
  {
72
86
  name: "jwt",
73
87
  certain: true,
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @file phase-schema.mjs - read a phase number that may have been written
3
+ * under either phase vocabulary.
4
+ *
5
+ * metrics.jsonl is append-only and v19.0.0 renumbered the phases, so the same
6
+ * field means two different things depending on when the line was written:
7
+ * `phase: 3` is Dev in a pre-v19 row and Review in a post-v19 one. Rows from
8
+ * v19.0.0 on carry `phaseSchema: 2`; rows without the field are generation 1.
9
+ *
10
+ * Every aggregator that compares a phase number to a literal, or prints a
11
+ * phase name, goes through here. Comparing directly is the bug this module
12
+ * exists to prevent - it does not throw, it silently attributes work to the
13
+ * wrong phase and the roll-up still looks plausible.
14
+ *
15
+ * @module pipeline/lib/phase-schema
16
+ */
17
+
18
+ import { readFileSync } from "node:fs";
19
+
20
+ const CONTRACT = JSON.parse(
21
+ readFileSync(new URL("../schemas/phases.json", import.meta.url), "utf8"),
22
+ );
23
+
24
+ export const CURRENT_SCHEMA = CONTRACT.phaseSchema;
25
+
26
+ /** Generation 1 number -> current number, derived from each phase's `was`. */
27
+ const GEN1_TO_CURRENT = new Map();
28
+ for (const p of CONTRACT.phases) {
29
+ for (const old of p.was) GEN1_TO_CURRENT.set(Number(old), p.id);
30
+ }
31
+
32
+ const CURRENT_NAMES = new Map(CONTRACT.phases.map((p) => [p.id, p.name]));
33
+ const GEN1_NAMES = new Map(
34
+ Object.entries(CONTRACT.legacyPhaseNames)
35
+ .filter(([k]) => /^\d+$/.test(k))
36
+ .map(([k, v]) => [Number(k), v]),
37
+ );
38
+
39
+ /**
40
+ * Which vocabulary a metrics row was written under.
41
+ *
42
+ * @param {object} row - a parsed metrics.jsonl line
43
+ * @returns {number} - 1 or 2
44
+ */
45
+ export function schemaOf(row) {
46
+ const s = Number(row?.phaseSchema);
47
+ return Number.isInteger(s) && s > 0 ? s : 1;
48
+ }
49
+
50
+ /**
51
+ * A row's phase expressed in the CURRENT vocabulary, so rows from both
52
+ * generations can be counted together.
53
+ *
54
+ * @param {string|number} phase
55
+ * @param {number} schema - from schemaOf()
56
+ * @returns {number|null} - null when the value is not a phase number at all
57
+ */
58
+ export function toCurrentPhase(phase, schema) {
59
+ const n = Number(phase);
60
+ if (!Number.isInteger(n)) return null;
61
+ if (schema >= CURRENT_SCHEMA) return CURRENT_NAMES.has(n) ? n : null;
62
+ return GEN1_TO_CURRENT.has(n) ? GEN1_TO_CURRENT.get(n) : null;
63
+ }
64
+
65
+ /**
66
+ * The name the phase number carried WHEN IT WAS WRITTEN. A historical row is
67
+ * labelled with its own vocabulary's name; relabelling it with today's name
68
+ * would make the archive disagree with the log it came from.
69
+ *
70
+ * @param {string|number} phase
71
+ * @param {number} schema
72
+ * @returns {string}
73
+ */
74
+ export function phaseNameAsWritten(phase, schema) {
75
+ const n = Number(phase);
76
+ const table = schema >= CURRENT_SCHEMA ? CURRENT_NAMES : GEN1_NAMES;
77
+ return table.get(n) ?? `Phase ${phase}`;
78
+ }
79
+
80
+ /**
81
+ * Convenience for the common shape: a row in, its current-vocabulary phase out.
82
+ *
83
+ * @param {object} row
84
+ * @returns {number|null}
85
+ */
86
+ export function rowPhase(row) {
87
+ return toCurrentPhase(row?.phase, schemaOf(row));
88
+ }
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env bash
2
2
  #
3
- # plan-todos.sh - manage the Phase 2 plan as a live Todo list.
3
+ # plan-todos.sh - manage the Phase 1 plan as a live Todo list.
4
4
  #
5
- # The Phase 2 plan is broken into a live, reviewable Todo list that updates
5
+ # The Phase 1 plan is broken into a live, reviewable Todo list that updates
6
6
  # step-by-step as Phase 3 works through it.
7
7
  #
8
8
  # State lives in `agent-state.json` under `.plan.todos[]` per
9
9
  # pipeline/schemas/plan-todos.schema.json. Phase 2 (Planning) emits the
10
10
  # initial plan; Phase 3 (Dev) iterates step-by-step; Phase 4 (Review)
11
- # inspects completion; Phase 7 (Report) renders the rollup.
11
+ # inspects completion; Phase 5 (Report) renders the rollup.
12
12
  #
13
13
  # Subcommands:
14
14
  # init <task-id> [title] Initialize with empty todos[] (Phase 2 usually pipes the JSON instead)
@@ -19,7 +19,7 @@
19
19
  # skip <task-id> <todo-id> <reason> Mark skipped (counts as satisfied for dependents)
20
20
  # next <task-id> Print next pending todo (deps-respecting); empty if none
21
21
  # list <task-id> Render Markdown checklist
22
- # status <task-id> Print one-line summary: "3/7 done, 1 in progress"
22
+ # status <task-id> Print one-line summary: "2/5 done, 1 in progress"
23
23
  # show <task-id> Print the full plan JSON
24
24
  #
25
25
  # Exit codes:
@@ -117,7 +117,7 @@ do_set() {
117
117
  fi
118
118
  # A planning-output document is accepted directly and converted here.
119
119
  #
120
- # The conversion used to live as a jq blob inside phase-2-planning.md, which
120
+ # The conversion used to live as a jq blob inside phase-1-plan.md, which
121
121
  # made the mapping from `tasks[]` to `todos[]` a thing two files defined - and
122
122
  # the phase doc was the copy nothing tested. Accepting both shapes costs four
123
123
  # lines and removes the second definition.
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env bash
2
+ # route-state.sh - read and write prefs.global.modelRouting.
3
+ #
4
+ # Backs /multi-agent:route-on, route-off and route-status. Ships disabled and
5
+ # stays that way until someone turns it on; while `enabled` is false nothing in
6
+ # this file changes one dispatch.
7
+ #
8
+ # The `off` contract is borrowed from autopilot-off and for the same reason: it
9
+ # clears the ON STATE, never the rules. Turning routing back on must not re-ask
10
+ # for a configuration the user already gave.
11
+ #
12
+ # Usage:
13
+ # route-state.sh status print the current policy
14
+ # route-state.sh on [--strategy=S] [--scope=a,b]
15
+ # route-state.sh off
16
+ # route-state.sh set-rules <file.json> replace rules[] from a JSON array
17
+ #
18
+ # Exit codes:
19
+ # 0 - done
20
+ # 2 - bad usage
21
+ # 3 - preferences missing/unparseable, or a scope value this refuses
22
+
23
+ set -uo pipefail
24
+
25
+ PREFS="${MULTI_AGENT_PREFS:-$HOME/.claude/multi-agent-preferences.json}"
26
+
27
+ # The scope values this accepts, spelled once. `host-session` is NOT here and
28
+ # must never be added: it would mean rewriting the host's base URL, which routes
29
+ # the user's whole session - work that has nothing to do with this pipeline
30
+ # included - through a third layer, breaks the subscription's auth model, and
31
+ # silently changes which model answers. The schema encodes the same list so a
32
+ # hand-edited preferences file is rejected too, rather than only this entry point.
33
+ ALLOWED_SCOPE="subagent bulk-read research"
34
+
35
+ die() { echo "route-state: $1" >&2; exit "${2:-3}"; }
36
+
37
+ # A missing `jq` must not look like routing being off. Every read below would
38
+ # come back empty, `route-status` would report disabled, and a user with rules
39
+ # armed would be told there are none.
40
+ command -v jq >/dev/null 2>&1 || die "jq not found - cannot read or write preferences (install: brew install jq)"
41
+ [ -f "$PREFS" ] || die "preferences not found at $PREFS - run /multi-agent:setup first"
42
+ jq -e . "$PREFS" >/dev/null 2>&1 || die "$PREFS is not valid JSON - refusing to write over it"
43
+
44
+ ACTION="${1:-status}"; shift 2>/dev/null || true
45
+
46
+ write_prefs() {
47
+ local filter="$1"; shift
48
+ local tmp
49
+ tmp=$(mktemp) || die "mktemp failed"
50
+ if ! jq "$@" "$filter" "$PREFS" > "$tmp"; then rm -f "$tmp"; die "jq failed - preferences left untouched"; fi
51
+ jq -e . "$tmp" >/dev/null 2>&1 || { rm -f "$tmp"; die "produced invalid JSON - preferences left untouched"; }
52
+ mv "$tmp" "$PREFS"
53
+ }
54
+
55
+ case "$ACTION" in
56
+ status)
57
+ ENABLED=$(jq -r '.global.modelRouting.enabled // false' "$PREFS")
58
+ STRATEGY=$(jq -r '.global.modelRouting.strategy // "manual"' "$PREFS")
59
+ SCOPE=$(jq -r '(.global.modelRouting.scope // ["subagent"]) | join(", ")' "$PREFS")
60
+ NRULES=$(jq -r '(.global.modelRouting.rules // []) | length' "$PREFS")
61
+ CEIL=$(jq -r '.global.modelRouting.budgetCeilingUsd // "none"' "$PREFS")
62
+ REC=$(jq -r '.global.modelRouting.recordDecisions // true' "$PREFS")
63
+
64
+ echo "routing: $ENABLED"
65
+ echo "strategy: $STRATEGY"
66
+ echo "scope: $SCOPE"
67
+ echo "rules: $NRULES"
68
+ echo "ceiling: $CEIL"
69
+ echo "decisions: $REC"
70
+ echo ""
71
+
72
+ if [ "$ENABLED" != "true" ]; then
73
+ echo "Disabled. Rules are stored but read by nothing; dispatch is unchanged."
74
+ [ "$NRULES" -gt 0 ] && echo "route-on turns these $NRULES rule(s) back on without re-asking."
75
+ exit 0
76
+ fi
77
+
78
+ if [ "$NRULES" -eq 0 ]; then
79
+ echo "Armed with no rules. Nothing matches, so nothing is routed - this is a"
80
+ echo "configuration state, not an error."
81
+ else
82
+ jq -r '(.global.modelRouting.rules // [])[] |
83
+ " when " + ([.when | to_entries[] | "\(.key)=\(.value)"] | join(" ")) +
84
+ " -> " + (.prefer | join(" > "))' "$PREFS"
85
+ fi
86
+
87
+ echo ""
88
+ # The limit is printed every time rather than documented once, because the
89
+ # question it answers ("routing is on, why is the reviewer still on Opus")
90
+ # otherwise arrives days later as a bug report.
91
+ echo "Honest limit: on Claude Code a subagent cannot be sent to a non-Anthropic"
92
+ echo "model - subagent dispatch belongs to the host. Phase 1/2/3 personas stay"
93
+ echo "inside the Anthropic ladder whatever the rules say. External providers apply"
94
+ echo "only where this pipeline makes the call itself (bulk-read, research)."
95
+ ;;
96
+
97
+ on)
98
+ STRATEGY="manual"; SCOPE_ARG=""
99
+ for arg in "$@"; do
100
+ case "$arg" in
101
+ --strategy=*) STRATEGY="${arg#*=}" ;;
102
+ --scope=*) SCOPE_ARG="${arg#*=}" ;;
103
+ *) die "unknown option: $arg" 2 ;;
104
+ esac
105
+ done
106
+ case "$STRATEGY" in
107
+ manual|task-fit|cost-ceiling) ;;
108
+ *) die "strategy must be manual, task-fit or cost-ceiling (got '$STRATEGY')" 2 ;;
109
+ esac
110
+
111
+ if [ -n "$SCOPE_ARG" ]; then
112
+ SCOPE_JSON="[]"
113
+ IFS=',' read -r -a parts <<< "$SCOPE_ARG"
114
+ for one in "${parts[@]}"; do
115
+ one="${one// /}"
116
+ # shellcheck disable=SC2076
117
+ case " $ALLOWED_SCOPE " in
118
+ *" $one "*) ;;
119
+ *) die "scope '$one' is not allowed (allowed: $ALLOWED_SCOPE). 'host-session' is refused by design: it would route the whole session, not this pipeline's calls." ;;
120
+ esac
121
+ SCOPE_JSON=$(jq -c --arg s "$one" '. + [$s]' <<< "$SCOPE_JSON")
122
+ done
123
+ write_prefs '
124
+ .global.modelRouting //= {}
125
+ | .global.modelRouting.enabled = true
126
+ | .global.modelRouting.strategy = $st
127
+ | .global.modelRouting.scope = ($sc | fromjson)
128
+ ' --arg st "$STRATEGY" --arg sc "$SCOPE_JSON"
129
+ else
130
+ write_prefs '
131
+ .global.modelRouting //= {}
132
+ | .global.modelRouting.enabled = true
133
+ | .global.modelRouting.strategy = $st
134
+ | .global.modelRouting.scope //= ["subagent"]
135
+ ' --arg st "$STRATEGY"
136
+ fi
137
+ echo "routing enabled (strategy: $STRATEGY)"
138
+ exec "$0" status
139
+ ;;
140
+
141
+ off)
142
+ # Rules survive on purpose. Clearing them here would make route-off a
143
+ # destructive action wearing the name of a toggle.
144
+ write_prefs '.global.modelRouting //= {} | .global.modelRouting.enabled = false'
145
+ echo "routing disabled. Rules kept - route-on restores this configuration as it is."
146
+ ;;
147
+
148
+ set-rules)
149
+ FILE="${1:-}"
150
+ [ -n "$FILE" ] || die "set-rules needs a JSON file containing an array of rules" 2
151
+ [ -f "$FILE" ] || die "no such file: $FILE" 2
152
+ jq -e 'type == "array"' "$FILE" >/dev/null 2>&1 || die "$FILE must contain a JSON ARRAY of rules" 2
153
+ write_prefs '.global.modelRouting //= {} | .global.modelRouting.rules = $r' --slurpfile _ignore /dev/null --argjson r "$(cat "$FILE")"
154
+ echo "rules replaced: $(jq -r 'length' "$FILE")"
155
+ ;;
156
+
157
+ *)
158
+ echo "usage: route-state.sh [status|on|off|set-rules <file>]" >&2
159
+ exit 2
160
+ ;;
161
+ esac
@@ -40,7 +40,7 @@ ma_logs_root() {
40
40
  }
41
41
 
42
42
  # ma_is_run_dir <dir> -> 0 when the directory holds at least one run marker
43
- # Phase 6 removes the worktree and salvages the run's files into `artifacts/`
43
+ # Phase 4 removes the worktree and salvages the run's files into `artifacts/`
44
44
  # inside the same run directory, so a shipped run keeps its state one level
45
45
  # deeper. A reader that only looks at the top level reports it as stateless.
46
46
  MA_ARTIFACTS_SUBDIR=artifacts
@@ -242,7 +242,7 @@ ma_resolve_run_file() {
242
242
  printf '%s\n' "$dir/$filename"
243
243
  return 0
244
244
  fi
245
- # The salvaged copy Phase 6 leaves behind.
245
+ # The salvaged copy Phase 4 leaves behind.
246
246
  if [ -f "$dir/$MA_ARTIFACTS_SUBDIR/$filename" ]; then
247
247
  printf '%s\n' "$dir/$MA_ARTIFACTS_SUBDIR/$filename"
248
248
  return 0
@@ -12,7 +12,7 @@ First step of every `multi-agent` flow **that touches a remote provider**.
12
12
  > question, no token lookup. Detection: `freetext` flow first fetches local
13
13
  > repos (`repo-cache.sh local "$HOME"`); if the picker resolves to local-only
14
14
  > repos, account-picker is bypassed and the state file's `accountId` is left
15
- > `null` with `tokens={}`. Phases 6/7 read these as "local-only" signals.
15
+ > `null` with `tokens={}`. Phases 4/5 read these as "local-only" signals.
16
16
 
17
17
  > **Language**: see `picker-contract.md` + `rules.md` Language Application matrix.
18
18
 
@@ -63,14 +63,14 @@ Selects extra repos the pipeline may touch beyond the primary repo(s) - typica
63
63
  entry, plus any selected `extras[]` that is not being given a worktree. The
64
64
  phases that consume them run hours later and have no access to the picker's
65
65
  return value, so a result that is not written here is a result nothing can
66
- read. Phase 4's platform-parity cross-check reads `state.siblings[]` as the
66
+ read. Phase 3's platform-parity cross-check reads `state.siblings[]` as the
67
67
  fourth of its four counterpart sources, after `--with`,
68
68
  `prefs.projects[<slug>].counterpartRoots[]` and the primary checkout's sibling
69
69
  directories (`platform-parity.md`), so a submodule or a hand-picked repo that
70
70
  is not written here is a candidate the check can never see.
71
71
 
72
72
  Resolve each entry's `stack` from its local checkout, with the marker table
73
- in `phases/phase-1-analysis.md` Step 2 (`.xcodeproj` / `Package.swift` →
73
+ in `phases/phase-1-plan.md` Step 2 (`.xcodeproj` / `Package.swift` →
74
74
  `ios`, `build.gradle(.kts)` → `android`, and so on). No checkout, or no
75
75
  marker matched → `stack: "unknown"` and `root: null`. Never infer a stack
76
76
  from the repo NAME: `my-app-android` is a naming convention, not a marker,
@@ -142,14 +142,14 @@ When `MULTI_AGENT_AUTOPILOT=1`:
142
142
 
143
143
  ## Pipeline contract for read-only siblings
144
144
 
145
- When a read-only sibling is present (e.g. a vendored SDK checkout), Phase 3 (Dev) MUST:
145
+ When a read-only sibling is present (e.g. a vendored SDK checkout), Phase 2 (Dev) MUST:
146
146
  - Treat it as **read-only context** - code may be read for understanding, never edited or committed.
147
147
  - Prefer solving the task in the primary repo(s) (e.g. by wrapping/extending in consumer code) rather than patching the sibling.
148
- - Surface this constraint in the Phase 3 plan output so reviewers know why a workaround was chosen.
148
+ - Surface this constraint in the Phase 2 plan output so reviewers know why a workaround was chosen.
149
149
 
150
150
  A **counterpart app repo** is a legitimate read-only sibling: the same product's
151
- other mobile platform, added here so Phase 4 can compare the change against it.
152
- Phase 3 treats it exactly like any other sibling - read, never edited. Phase 4
151
+ other mobile platform, added here so Phase 3 can compare the change against it.
152
+ Phase 2 treats it exactly like any other sibling - read, never edited. Phase 3
153
153
  additionally runs the parity cross-check over it
154
154
  (`$HOME/.claude/multi-agent-refs/platform-parity.md`), which is also read-only.
155
155
  Adding one is worthwhile when the feature exists on both platforms and their
@@ -35,7 +35,7 @@ The top-level `multi-agent` command classifies user arguments per the rules belo
35
35
 
36
36
  ¹ Account picker is **skipped** when the resolved primary repo is local-only
37
37
  (`provider="local"`). No token lookup, no provider auth - the pipeline
38
- proceeds with `accountId=null` and Phases 6/7 honor the local-only mode.
38
+ proceeds with `accountId=null` and Phases 4/5 honor the local-only mode.
39
39
 
40
40
  ² Free-text flow merges `github`+`bitbucket`+`local` repo caches into a
41
41
  single picker list; `(local)` rows come from `repo-cache.sh local "$HOME"`.
@@ -164,7 +164,7 @@ The index answers "does this component exist and is it bound". It does not answe
164
164
 
165
165
  Output: `state.analysisSpec.evidence.variantMatrix[<component>] = { axis, allValues[], usedValues[] }`, which fills Section 6.X.
166
166
 
167
- Why it lives here and nowhere later: Locked 30 forbids Figma access from Phase 2 onward, so an axis not captured now cannot be recovered - Section 13.6 Preview and Section 15.2 Snapshot would then be validated against a subset nobody could check.
167
+ Why it lives here and nowhere later: Locked 29 forbids Figma access from Phase 2 onward, so an axis not captured now cannot be recovered - Section 13.6 Preview and Section 15.2 Snapshot would then be validated against a subset nobody could check.
168
168
 
169
169
  A component with no variant axis (a plain component, not a set) records `axis: null` and is not a finding.
170
170
 
@@ -202,7 +202,7 @@ Phase 2 Section 20 Risks reads this list and emits one open question per entry.
202
202
 
203
203
  **Fallback source**: when `confidence == "none"` AND `evidence.standards[]` does not contain an explicit rule for that field, the renderer reads `$HOME/.claude/multi-agent-refs/conventions-defaults.md` and applies the platform default.
204
204
 
205
- **Caching (Locked 27)**: compute `evidence_digest = sha256(featureName || sorted(platforms) || options.redesign || hash(evidence.repoEvidence) || hash(evidence.conventions))`. `options.redesign` is a digest input: without it a redesign within a day of a normal run on the same feature reuses that cache, skips Phase 1b, and renders an empty current-behaviour table every redesign check then passes over. Cache key on disk: `/tmp/multi-agent-analysis-cache/<digest>.json` with mtime <= 24h. Cache hit skips Phase 1b and Phase 1c. `--no-cache` flag forces re-run.
205
+ **Caching (Locked 26)**: compute `evidence_digest = sha256(featureName || sorted(platforms) || options.redesign || hash(evidence.repoEvidence) || hash(evidence.conventions))`. `options.redesign` is a digest input: without it a redesign within a day of a normal run on the same feature reuses that cache, skips Phase 1b, and renders an empty current-behaviour table every redesign check then passes over. Cache key on disk: `/tmp/multi-agent-analysis-cache/<digest>.json` with mtime <= 24h. Cache hit skips Phase 1b and Phase 1c. `--no-cache` flag forces re-run.
206
206
 
207
207
  Phase 1d is deliberately absent from the digest inputs. Community signal changes by the hour, so folding it in would produce a new digest on every run, invalidate the cache every time, and re-run the two expensive repo phases the cache exists to skip. The consequence is worth stating plainly: a cache hit reuses yesterday's signal rows. That is the correct trade for an advisory tier, and `--no-cache` is the way to refresh them.
208
208
 
@@ -225,12 +225,3 @@ The tier boundary is not advisory. A signal row that reaches Section 4 (business
225
225
 
226
226
  Per source: reachable and answered, reachable and empty, or unreachable. All three are recorded; only the third produces a `fetchErrors[]` entry, and none of them halts.
227
227
 
228
- **Lite mode auto-detection (Locked 25, v9.1.0 scoring)**: at the end of Phase 1c, evaluate three signals and score each:
229
-
230
- | Signal | True condition | Score |
231
- |---|---|---|
232
- | Confluence spec body lines | < 100 | 1 |
233
- | Figma frames count | <= 1 | 1 |
234
- | Repo evidence direct-match count | >= 8 | 1 |
235
-
236
- `liteModeAuto = (totalScore >= 2)`. Two of three signals true is enough; the v8.12.0..v9.0.x AND-threshold (all three) forced too many small features into Full mode when one signal was marginal (e.g. a tiny spec with 2 Figma frames). User overrides via `--full` or `--lite` always win over scoring.
@@ -1,6 +1,6 @@
1
1
  # Intake (analysis Phase 0)
2
2
 
3
- > The picker chain that fills `state.analysisSpec.*` before any fetch runs. Loaded by `/multi-agent:analysis`. Pipeline Phase 1 does NOT load this file: in a pipeline run the account, project, repos and task already came from the orchestrator's own Phase 0, and only the source and coverage batches below are asked (see `phase-1-analysis.md` Step 4).
3
+ > The picker chain that fills `state.analysisSpec.*` before any fetch runs. Loaded by `/multi-agent:analysis`. Pipeline Phase 1 does NOT load this file: in a pipeline run the account, project, repos and task already came from the orchestrator's own Phase 0, and only the source and coverage batches below are asked (see `phase-1-plan.md` Step 4).
4
4
 
5
5
  ### Phase 0 - Intake
6
6
 
@@ -19,7 +19,7 @@ Result: `state.analysisSpec.featureName` (state key kept for backward compatibil
19
19
 
20
20
  #### Step 1b - Analysis profile
21
21
 
22
- Asked once, immediately after the analysis name and before anything is fetched, because the profile decides which template the whole run renders against (Locked 32). Never re-asked mid-run.
22
+ Asked once, immediately after the analysis name and before anything is fetched, because the profile decides which template the whole run renders against (Locked 31). Never re-asked mid-run.
23
23
 
24
24
  Read the available profiles from `prefs.global.analysisProfiles` (default `["global", "corporate"]`). When only one is available, auto-resolve and print the breadcrumb with the resolution noted rather than asking a question whose answer is already settled.
25
25
 
@@ -36,7 +36,7 @@ options:
36
36
 
37
37
  Result: `state.analysisSpec.profile` (`global` | `corporate`). Empty submit re-asks; an empty answer does not imply the default (`feedback_no-inferred-defaults-from-empty-answer`).
38
38
 
39
- The profile changes nothing about intake, fetching, repo evidence or convention extraction - those are shared. It selects the template at Phase 3 and switches the omission rule for the corporate backbone (Locked 33).
39
+ The profile changes nothing about intake, fetching, repo evidence or convention extraction - those are shared. It selects the template at Phase 3 and switches the omission rule for the corporate backbone (Locked 32).
40
40
 
41
41
  **Corporate profile bindings.** Publication targets and house terminology are read from `prefs.global.analysisProfile.corporate` when present: `confluenceSpaceKey`, `confluenceParentPageId`, `titleFormat`, `titlePrefix`, `apiSpecCommand` and a `glossary` map. The key set is closed in `prefs.schema.json`, so a typo is caught by `validate-prefs.mjs` rather than silently ignored at emit time. They are deployment configuration, not part of the shipped template: an unconfigured corporate run still renders the full document and asks for the destination at Phase 3.5 like any other run.
42
42
 
@@ -69,13 +69,13 @@ Empty submit → re-ask. Result: `state.analysisSpec.platforms[]`.
69
69
  `web` is the canonical id; the pre-rename `frontend` is still read back (older state,
70
70
  `:stack frontend`, the `ai-frontend-toolkit` plugin id) and normalises to `web`.
71
71
 
72
- **`No platform yet` is a real answer, not a cancel** (Locked 35). It leaves
72
+ **`No platform yet` is a real answer, not a cancel** (Locked 34). It leaves
73
73
  `platforms[]` empty, skips Step 4 entirely, and the run continues: evidence is still
74
74
  fetched from every declared source, and the document renders every layer that does not
75
75
  need a target repository. Only the development layer and the Pass B projection drop,
76
76
  and Section 20 records that they await a repo selection.
77
77
 
78
- **The channel split is then derived from the evidence, not abandoned** (Locked 35,
78
+ **The channel split is then derived from the evidence, not abandoned** (Locked 34,
79
79
  which carries the reasoning). After evidence collection, classify the run's channels
80
80
  from what the sources say:
81
81
 
@@ -135,7 +135,7 @@ tool call, and an improvised retry separates the spec sources from each other.
135
135
  - **Batch 2/2 - what constrains it**: Swagger, Standards, Firebase.
136
136
 
137
137
  **Development-layer questions are gated on a platform being selected.** With
138
- `platforms[]` empty that layer does not render (Locked 35), so a question feeding only
138
+ `platforms[]` empty that layer does not render (Locked 34), so a question feeding only
139
139
  it spends attention on an answer nothing consumes.
140
140
 
141
141
  Two questions feed only that layer and are therefore skipped:
@@ -270,7 +270,7 @@ layer; `options.a11yDepth` gates the Section 16 VoiceOver / TalkBack walkthrough
270
270
  does not. Both default to the lighter choice so the doc stays lean unless the user opts in.
271
271
 
272
272
  `options.redesign` gates Sections 4.5, 4.6 and 9.5 and loads `analysis/redesign.md`, read
273
- on no other run (Locked 37).
273
+ on no other run (Locked 36).
274
274
 
275
275
  #### Step 5b - Repo-evidence collector (automatic, no prompt)
276
276