@entelligentsia/forgecli 0.10.0 → 0.11.2

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 (188) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +21 -3
  3. package/dist/CHANGELOG-forge-plugin.md +90 -0
  4. package/dist/bin/config.js +6 -0
  5. package/dist/bin/config.js.map +1 -1
  6. package/dist/extensions/forgecli/add-pipeline.d.ts +19 -0
  7. package/dist/extensions/forgecli/add-pipeline.js +143 -0
  8. package/dist/extensions/forgecli/add-pipeline.js.map +1 -0
  9. package/dist/extensions/forgecli/add-task.d.ts +20 -0
  10. package/dist/extensions/forgecli/add-task.js +154 -0
  11. package/dist/extensions/forgecli/add-task.js.map +1 -0
  12. package/dist/extensions/forgecli/calibrate.d.ts +61 -0
  13. package/dist/extensions/forgecli/calibrate.js +488 -0
  14. package/dist/extensions/forgecli/calibrate.js.map +1 -0
  15. package/dist/extensions/forgecli/fix-bug.d.ts +9 -1
  16. package/dist/extensions/forgecli/fix-bug.js +155 -45
  17. package/dist/extensions/forgecli/fix-bug.js.map +1 -1
  18. package/dist/extensions/forgecli/forge-commands.js +15 -22
  19. package/dist/extensions/forgecli/forge-commands.js.map +1 -1
  20. package/dist/extensions/forgecli/forge-subagent.d.ts +16 -1
  21. package/dist/extensions/forgecli/forge-subagent.js +45 -8
  22. package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
  23. package/dist/extensions/forgecli/forge-update-command.d.ts +9 -0
  24. package/dist/extensions/forgecli/forge-update-command.js +106 -7
  25. package/dist/extensions/forgecli/forge-update-command.js.map +1 -1
  26. package/dist/extensions/forgecli/health-check.d.ts +22 -1
  27. package/dist/extensions/forgecli/health-check.js +177 -4
  28. package/dist/extensions/forgecli/health-check.js.map +1 -1
  29. package/dist/extensions/forgecli/hook-dispatcher.d.ts +25 -1
  30. package/dist/extensions/forgecli/hook-dispatcher.js +104 -9
  31. package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
  32. package/dist/extensions/forgecli/hooks/check-update.d.ts +81 -0
  33. package/dist/extensions/forgecli/hooks/check-update.js +308 -0
  34. package/dist/extensions/forgecli/hooks/check-update.js.map +1 -0
  35. package/dist/extensions/forgecli/hooks/forge-permissions.d.ts +32 -0
  36. package/dist/extensions/forgecli/hooks/forge-permissions.js +119 -0
  37. package/dist/extensions/forgecli/hooks/forge-permissions.js.map +1 -0
  38. package/dist/extensions/forgecli/hooks/triage-error.d.ts +23 -0
  39. package/dist/extensions/forgecli/hooks/triage-error.js +62 -0
  40. package/dist/extensions/forgecli/hooks/triage-error.js.map +1 -0
  41. package/dist/extensions/forgecli/hooks/write-guard.d.ts +28 -0
  42. package/dist/extensions/forgecli/hooks/write-guard.js +225 -0
  43. package/dist/extensions/forgecli/hooks/write-guard.js.map +1 -0
  44. package/dist/extensions/forgecli/index.js +60 -0
  45. package/dist/extensions/forgecli/index.js.map +1 -1
  46. package/dist/extensions/forgecli/init-context.d.ts +1 -1
  47. package/dist/extensions/forgecli/init-context.js +21 -6
  48. package/dist/extensions/forgecli/init-context.js.map +1 -1
  49. package/dist/extensions/forgecli/materialize.d.ts +16 -0
  50. package/dist/extensions/forgecli/materialize.js +195 -0
  51. package/dist/extensions/forgecli/materialize.js.map +1 -0
  52. package/dist/extensions/forgecli/migrate.d.ts +19 -0
  53. package/dist/extensions/forgecli/migrate.js +258 -0
  54. package/dist/extensions/forgecli/migrate.js.map +1 -0
  55. package/dist/extensions/forgecli/migration-engine.d.ts +111 -0
  56. package/dist/extensions/forgecli/migration-engine.js +533 -0
  57. package/dist/extensions/forgecli/migration-engine.js.map +1 -0
  58. package/dist/extensions/forgecli/quiz-agent.d.ts +17 -0
  59. package/dist/extensions/forgecli/quiz-agent.js +98 -0
  60. package/dist/extensions/forgecli/quiz-agent.js.map +1 -0
  61. package/dist/extensions/forgecli/remove-command.d.ts +17 -0
  62. package/dist/extensions/forgecli/remove-command.js +124 -0
  63. package/dist/extensions/forgecli/remove-command.js.map +1 -0
  64. package/dist/extensions/forgecli/report-bug.d.ts +25 -0
  65. package/dist/extensions/forgecli/report-bug.js +159 -0
  66. package/dist/extensions/forgecli/report-bug.js.map +1 -0
  67. package/dist/extensions/forgecli/retrospective.d.ts +19 -0
  68. package/dist/extensions/forgecli/retrospective.js +156 -0
  69. package/dist/extensions/forgecli/retrospective.js.map +1 -0
  70. package/dist/extensions/forgecli/run-sprint.js +36 -3
  71. package/dist/extensions/forgecli/run-sprint.js.map +1 -1
  72. package/dist/extensions/forgecli/run-task.d.ts +9 -1
  73. package/dist/extensions/forgecli/run-task.js +66 -13
  74. package/dist/extensions/forgecli/run-task.js.map +1 -1
  75. package/dist/extensions/forgecli/session-registry.d.ts +40 -2
  76. package/dist/extensions/forgecli/session-registry.js +71 -1
  77. package/dist/extensions/forgecli/session-registry.js.map +1 -1
  78. package/dist/extensions/forgecli/status-command.d.ts +19 -0
  79. package/dist/extensions/forgecli/status-command.js +140 -0
  80. package/dist/extensions/forgecli/status-command.js.map +1 -0
  81. package/dist/extensions/forgecli/store-query.d.ts +22 -0
  82. package/dist/extensions/forgecli/store-query.js +107 -0
  83. package/dist/extensions/forgecli/store-query.js.map +1 -0
  84. package/dist/extensions/forgecli/store-repair.d.ts +17 -0
  85. package/dist/extensions/forgecli/store-repair.js +123 -0
  86. package/dist/extensions/forgecli/store-repair.js.map +1 -0
  87. package/dist/extensions/forgecli/test-orchestrate.js +1 -0
  88. package/dist/extensions/forgecli/test-orchestrate.js.map +1 -1
  89. package/dist/extensions/forgecli/thread-switcher.js +286 -41
  90. package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
  91. package/dist/extensions/forgecli/transition-guard.js +7 -2
  92. package/dist/extensions/forgecli/transition-guard.js.map +1 -1
  93. package/dist/extensions/forgecli/update-tools.d.ts +23 -0
  94. package/dist/extensions/forgecli/update-tools.js +136 -0
  95. package/dist/extensions/forgecli/update-tools.js.map +1 -0
  96. package/dist/extensions/forgecli/viewport-events.js +10 -0
  97. package/dist/extensions/forgecli/viewport-events.js.map +1 -1
  98. package/dist/extensions/forgecli/viewport-renderer.d.ts +18 -0
  99. package/dist/extensions/forgecli/viewport-renderer.js +27 -0
  100. package/dist/extensions/forgecli/viewport-renderer.js.map +1 -1
  101. package/dist/extensions/forgecli/viewport-theme.js +4 -0
  102. package/dist/extensions/forgecli/viewport-theme.js.map +1 -1
  103. package/dist/extensions/forgecli/whats-new-widget.d.ts +13 -8
  104. package/dist/extensions/forgecli/whats-new-widget.js +111 -42
  105. package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
  106. package/dist/forge-payload/.base-pack/workflows/architect_approve.md +29 -3
  107. package/dist/forge-payload/.base-pack/workflows/commit_task.md +15 -8
  108. package/dist/forge-payload/.base-pack/workflows/fix_bug.md +327 -185
  109. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +18 -10
  110. package/dist/forge-payload/.base-pack/workflows/plan_task.md +15 -9
  111. package/dist/forge-payload/.base-pack/workflows/review_code.md +14 -6
  112. package/dist/forge-payload/.base-pack/workflows/review_plan.md +18 -10
  113. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  114. package/dist/forge-payload/.schemas/bug.schema.json +3 -2
  115. package/dist/forge-payload/.schemas/config.schema.json +83 -0
  116. package/dist/forge-payload/.schemas/migrations.json +2049 -0
  117. package/dist/forge-payload/commands/regenerate.md +17 -1
  118. package/dist/forge-payload/meta/personas/README.md +16 -0
  119. package/dist/forge-payload/meta/personas/meta-architect.md +70 -0
  120. package/dist/forge-payload/meta/personas/meta-bug-fixer.md +73 -0
  121. package/dist/forge-payload/meta/personas/meta-collator.md +72 -0
  122. package/dist/forge-payload/meta/personas/meta-engineer.md +70 -0
  123. package/dist/forge-payload/meta/personas/meta-orchestrator.md +71 -0
  124. package/dist/forge-payload/meta/personas/meta-product-manager.md +82 -0
  125. package/dist/forge-payload/meta/personas/meta-qa-engineer.md +91 -0
  126. package/dist/forge-payload/meta/personas/meta-supervisor.md +92 -0
  127. package/dist/forge-payload/meta/skill-recommendations.md +154 -0
  128. package/dist/forge-payload/meta/skills/meta-architect-skills.md +43 -0
  129. package/dist/forge-payload/meta/skills/meta-bug-fixer-skills.md +43 -0
  130. package/dist/forge-payload/meta/skills/meta-collator-skills.md +41 -0
  131. package/dist/forge-payload/meta/skills/meta-engineer-skills.md +43 -0
  132. package/dist/forge-payload/meta/skills/meta-generic-skills.md +58 -0
  133. package/dist/forge-payload/meta/skills/meta-qa-engineer-skills.md +46 -0
  134. package/dist/forge-payload/meta/skills/meta-supervisor-skills.md +43 -0
  135. package/dist/forge-payload/meta/store-schema/bug.schema.md +71 -0
  136. package/dist/forge-payload/meta/store-schema/event.schema.md +76 -0
  137. package/dist/forge-payload/meta/store-schema/feature.schema.md +65 -0
  138. package/dist/forge-payload/meta/store-schema/sprint.schema.md +64 -0
  139. package/dist/forge-payload/meta/store-schema/task.schema.md +78 -0
  140. package/dist/forge-payload/meta/templates/meta-code-review.md +26 -0
  141. package/dist/forge-payload/meta/templates/meta-plan-review.md +28 -0
  142. package/dist/forge-payload/meta/templates/meta-plan.md +28 -0
  143. package/dist/forge-payload/meta/templates/meta-progress.md +25 -0
  144. package/dist/forge-payload/meta/templates/meta-retrospective.md +28 -0
  145. package/dist/forge-payload/meta/templates/meta-sprint-manifest.md +26 -0
  146. package/dist/forge-payload/meta/templates/meta-sprint-requirements.md +91 -0
  147. package/dist/forge-payload/meta/templates/meta-task-prompt.md +26 -0
  148. package/dist/forge-payload/meta/tool-specs/collate.spec.md +88 -0
  149. package/dist/forge-payload/meta/tool-specs/generation-manifest.spec.md +139 -0
  150. package/dist/forge-payload/meta/tool-specs/manage-config.spec.md +143 -0
  151. package/dist/forge-payload/meta/tool-specs/seed-store.spec.md +91 -0
  152. package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +328 -0
  153. package/dist/forge-payload/meta/tool-specs/validate-store.spec.md +191 -0
  154. package/dist/forge-payload/meta/workflows/_fragments/context-injection.md +75 -0
  155. package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +73 -0
  156. package/dist/forge-payload/meta/workflows/_fragments/finalize.md +13 -0
  157. package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +73 -0
  158. package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +38 -0
  159. package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +39 -0
  160. package/dist/forge-payload/meta/workflows/meta-approve.md +119 -0
  161. package/dist/forge-payload/meta/workflows/meta-collate.md +89 -0
  162. package/dist/forge-payload/meta/workflows/meta-commit.md +93 -0
  163. package/dist/forge-payload/meta/workflows/meta-enhance.md +286 -0
  164. package/dist/forge-payload/meta/workflows/meta-fix-bug.md +501 -0
  165. package/dist/forge-payload/meta/workflows/meta-implement.md +132 -0
  166. package/dist/forge-payload/meta/workflows/meta-migrate.md +455 -0
  167. package/dist/forge-payload/meta/workflows/meta-orchestrate.md +993 -0
  168. package/dist/forge-payload/meta/workflows/meta-plan-task.md +133 -0
  169. package/dist/forge-payload/meta/workflows/meta-quiz-agent.md +135 -0
  170. package/dist/forge-payload/meta/workflows/meta-retrospective.md +65 -0
  171. package/dist/forge-payload/meta/workflows/meta-review-implementation.md +119 -0
  172. package/dist/forge-payload/meta/workflows/meta-review-plan.md +108 -0
  173. package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +65 -0
  174. package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +76 -0
  175. package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +147 -0
  176. package/dist/forge-payload/meta/workflows/meta-update-implementation.md +76 -0
  177. package/dist/forge-payload/meta/workflows/meta-update-plan.md +76 -0
  178. package/dist/forge-payload/meta/workflows/meta-validate.md +111 -0
  179. package/dist/forge-payload/tools/check-structure.cjs +344 -0
  180. package/dist/forge-payload/tools/collate.cjs +34 -9
  181. package/dist/forge-payload/tools/list-skills.js +76 -0
  182. package/dist/forge-payload/tools/parse-gates.cjs +8 -2
  183. package/dist/forge-payload/tools/store-cli.cjs +56 -11
  184. package/dist/forge-payload/tools/store.cjs +61 -0
  185. package/dist/forge-payload/tools/substitute-placeholders.cjs +60 -8
  186. package/dist/forge-payload/tools/validate-store.cjs +6 -2
  187. package/dist/forge-payload/tools/verify-integrity.cjs +86 -0
  188. package/package.json +2 -2
@@ -1,219 +1,296 @@
1
1
  ---
2
2
  requirements:
3
- reasoning: Medium
3
+ reasoning: High
4
4
  context: Medium
5
5
  speed: Medium
6
6
  audience: orchestrator-only
7
7
  deps:
8
- personas: [bug-fixer]
9
- skills: [bug-fixer, generic]
8
+ personas: [bug-fixer, supervisor, architect, engineer, collator]
9
+ skills: [bug-fixer, supervisor, architect, engineer, generic]
10
10
  templates: [PROGRESS_TEMPLATE]
11
- sub_workflows: [review_code]
11
+ sub_workflows: [plan_task, implement_plan, review_plan, review_code, architect_approve, commit_task]
12
12
  kb_docs: [architecture/stack.md, architecture/routing.md]
13
+ context_pack: .forge/cache/context-pack.md
13
14
  config_fields: [commands.test, paths.engineering]
14
15
  ---
15
16
 
16
17
  # Fix Bug
18
+ ## Pipeline Phases
19
+
20
+ A fix-bug pipeline has these phases (mirrors `meta-orchestrate.md § Pipeline
21
+ Phases`):
22
+
23
+ | Phase | Role | Persona | Workflow | Path A | Path B |
24
+ |---|---|---|---|---|---|
25
+ | triage | `triage` | bug-fixer | (inline algorithm) | yes | yes |
26
+ | plan-fix | `plan` | engineer | `plan_task.md` (bug-mode) | no | yes |
27
+ | review-plan | `review-plan` | supervisor | `review_plan.md` | no | yes |
28
+ | implement | `implement` | engineer | `implement_plan.md` (bug-mode) | yes | yes |
29
+ | review-code | `review-code` | supervisor | `review_code.md` | yes | yes |
30
+ | approve | `approve` | architect | `architect_approve.md` (bug-mode) | yes | yes |
31
+ | commit | `commit` | engineer | `commit_task.md` (bug-mode) | yes | yes |
32
+ | finalize | `finalize` | collator | (inline algorithm) | yes | yes |
33
+
34
+ Phases past triage are the same workflows used by the run-task pipeline. The
35
+ generated orchestrator passes `--bug {bugId}` (in place of `--task {taskId}`)
36
+ to every sub-workflow and to `preflight-gate.cjs`. Sub-workflows resolve the
37
+ record kind from the flag and adjust their verdict-source mapping via
38
+ `BUG_PHASE_VERDICT_SOURCE` in `tools/read-verdict.cjs`.
39
+
40
+ ## Status State Machine
41
+
42
+ Bug status writes are owned by specific phases — never by the workflow source
43
+ in finalize, never by an LLM improvising on a task workflow.
44
+
45
+ ```
46
+ reported -> triaged -> in-progress -> fixed
47
+ (terminal)
48
+ ```
49
+
50
+ | Transition | Owner | Trigger |
51
+ |---|---|---|
52
+ | `reported → triaged` | triage subagent | after reproduction confirmed |
53
+ | `triaged → in-progress` | triage subagent | after route decision recorded in `summaries.triage.route` |
54
+ | `in-progress → fixed` | commit phase | after git commit succeeds (terminal) |
55
+
56
+ The schema's `approved` and `verified` enum members are vestigial — no phase in
57
+ this workflow writes them, and the verdict gate reads
58
+ `summaries.approve.verdict`, not `bug.status`. A follow-up cleanup should drop
59
+ both members from `bug.schema.json` to remove the runtime trap. Until then,
60
+ this workflow MUST NOT write either value. The Phase Gates below `forbid`
61
+ them defensively.
62
+
63
+ ## Triage Judgement (the only run-task deviation)
64
+
65
+ After the triage subagent reproduces the bug and confirms root cause, it MUST
66
+ record a **route** decision in its summary:
67
+
68
+ ```json
69
+ {
70
+ "objective": "Triage FORGE-BUG-NNN — reproduce, locate, decide route.",
71
+ "key_changes": [...],
72
+ "findings": [
73
+ "Root cause: <one line>",
74
+ "Reproduction: <one line>",
75
+ "Route decision: A | B",
76
+ "Rationale: <one line>"
77
+ ],
78
+ "verdict": "n/a",
79
+ "written_at": "<iso>",
80
+ "artifact_ref": "TRIAGE.md",
81
+ "route": "A"
82
+ }
83
+ ```
84
+
85
+ The `route` field is required. Allowed values: `"A"` or `"B"`.
86
+
87
+ > **Field-naming caution — runtime-tested.** The route field is named
88
+ > `route`, never `path`. The bug schema's top-level `path` field is the
89
+ > bug's **artifact directory** (e.g. `engineering/bugs/EMG-BUG-001-...`).
90
+ > Conflating the two caused EMBERGLOW-BUG-001 (v0.44.0 first run) to land
91
+ > its `TRIAGE.md` under `.forge/store/bugs/` instead of `engineering/bugs/`.
92
+ > Triage subagents MUST NOT touch `bug.path` — that field is set at bug
93
+ > creation and never modified by triage.
94
+
95
+ ### Path A — short-circuit (eligibility)
96
+
97
+ Path A is **eligible only when ALL** of the following hold. Triage subagent
98
+ must enumerate each in its findings:
99
+
100
+ - `bug.severity ∈ {minor}`
101
+ - Fix is contained in a single file
102
+ - Estimated diff ≤ ~20 lines (judgement call; one screen)
103
+ - No schema, API, migration, security, or build-system change
104
+ - A regression test is obvious from the reproduction script (single short
105
+ test case, no new fixtures, no test-harness change)
106
+
107
+ If any criterion fails, the triage subagent MUST select Path B.
108
+
109
+ ### Path B — full loop (default)
110
+
111
+ Path B runs the same plan/review/implement/review/approve/commit shape as
112
+ `meta-orchestrate.md`. It is the default. Any uncertainty defaults Path B.
113
+
114
+ ### Pipeline selection by path
115
+
116
+ ```
117
+ phases_A = [triage, implement, review-code, approve, commit, finalize]
118
+ phases_B = [triage, plan-fix, review-plan, implement, review-code, approve, commit, finalize]
119
+
120
+ if summaries.triage.route == "A": phases = phases_A
121
+ else: phases = phases_B
122
+ ```
123
+
124
+ The orchestrator MUST read `summaries.triage.route` from the bug record after
125
+ the triage subagent returns and select the phase list before entering the main
126
+ loop. The selection is final for the run — no mid-pipeline switching.
127
+
128
+ ## Pipeline Resolution
129
+
130
+ Fix-bug does **not** read `task.pipeline` from config. The path-branch decision
131
+ above replaces the task pipeline lookup. The orchestrator MAY honour
132
+ `config.pipelines.bug` to override the default Path A / Path B phase lists,
133
+ mirroring `meta-orchestrate.md § Pipeline Resolution`; if unset, the lists
134
+ above are used.
135
+
17
136
  ## Algorithm
18
137
 
138
+ The fix-bug orchestrator MUST follow this procedure exactly. The structure
139
+ mirrors `meta-orchestrate.md § Execution Algorithm` — same persona-map, same
140
+ banner-map, same cluster detection, same preflight gate, same event emission.
141
+ Differences are confined to the **triage** step and the **path branch**.
142
+
19
143
  ```
20
- 1. Triage:
21
- - If the bug ID is known, query the store for context before navigating the KB:
22
- ```sh
23
- node "$FORGE_ROOT/tools/store-cli.cjs" nlp "{bugId} with blocked tasks"
24
- ```
25
- If results include title, status, sprint, blocked tasks, and excerpt, use them directly.
26
- Fall back to reading MASTER_INDEX.md manually only if the query returns empty or low-confidence results.
144
+ 1. Pre-loop setup (mirrors meta-orchestrate.md):
145
+ - Resolve FORGE_ROOT.
146
+ - Detect execution cluster from ANTHROPIC_DEFAULT_*_MODEL env vars.
147
+ - Clear progress log: store-cli progress-clear bugs
148
+ - Read bug record. If status ∈ {blocked, escalated, fixed, abandoned}:
149
+ skip the run, emit a single `bug_skipped` event, return.
150
+
151
+ 2. Triage:
27
152
  - Locate or create the bug record (MANDATORY — do this before anything else):
28
153
  a. Determine the bug ID: if $ARGUMENTS is an existing FORGE-BUG-NNN ID, use it.
29
154
  Otherwise derive the next available ID by listing .forge/store/bugs/.
30
- b. If .forge/store/bugs/{BUG_ID}.json does NOT exist:
31
- - Derive a short slug from the bug title (kebab-case, 5 words)
32
- - Create the engineering folder:
33
- mkdir -p engineering/bugs/{BUG_ID}-{slug}
34
- - Write the bug record via store-cli NEVER write the file directly:
35
- node "$FORGE_ROOT/tools/store-cli.cjs" write bug '{
36
- "bugId": "{BUG_ID}",
37
- "title": "<from input>",
38
- "description": "<from input>",
39
- "severity": "<assessed: critical|major|minor>",
40
- "status": "reported",
41
- "path": "engineering/bugs/{BUG_ID}-{slug}",
42
- "reportedAt": "<current ISO timestamp>"
43
- }'
44
- - If $ARGUMENTS contains a GitHub issue URL, include it as "githubIssue"
45
- in the JSON above — it is a valid schema field.
46
- c. Read the now-guaranteed record:
47
- node "$FORGE_ROOT/tools/store-cli.cjs" read bug {BUG_ID} --json
48
- - Reproduce the bug: create a failing test case or a reproduction script
49
- - Confirm the root cause via codebase research
50
- - After creating the bug record, transition to in-progress:
51
- ```sh
52
- node "$FORGE_ROOT/tools/store-cli.cjs" update-status bug {BUG_ID} status triaged
53
- node "$FORGE_ROOT/tools/store-cli.cjs" update-status bug {BUG_ID} status in-progress
54
- ```
55
-
56
- 2. Plan:
57
- - Generate BUG_FIX_PLAN.md following the plan template
58
- - Define the "Success Condition": how the reproduction script/test will now pass
59
-
60
- 3. Implementation:
61
- - Implement the fix following the approved plan
62
- - Verify the fix using the reproduction script/test
63
- - Run regression tests to ensure no side effects
64
-
65
- 4. Documentation:
66
- - Update the bug record in the store with:
67
- - Root cause analysis
68
- - Fix description
69
- - Verification evidence
70
-
71
- 5. Summary Sidecars:
72
- - After each phase completes its artifact, emit a summary sidecar and register it via `set-bug-summary`.
73
- - **After Plan phase:**
74
- Write `BUG-FIX-PLAN-SUMMARY.json` in the bug directory:
75
- `{ "objective": "...", "key_changes": [...], "verdict": "n/a", "written_at": "...", "artifact_ref": "BUG_FIX_PLAN.md" }`
76
- Then: `node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary {bug_id} plan engineering/bugs/{bug_dir}/BUG-FIX-PLAN-SUMMARY.json`
77
- - **After Review phases:**
78
- Write `REVIEW-PLAN-SUMMARY.json` or `REVIEW-IMPL-SUMMARY.json` with `findings`, `verdict` (approved|revision), and `artifact_ref`.
79
- Then: `node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary {bug_id} review_plan|code_review ...SUMMARY.json`
80
- - **After Implement phase:**
81
- Write `IMPLEMENTATION-SUMMARY.json` with `key_changes` and `verdict: "n/a"`.
82
- Then: `node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary {bug_id} implementation ...SUMMARY.json`
83
- - **After Approve phase:**
84
- Write `APPROVE-SUMMARY.json` with `objective`, `verdict` (approved|revision), and `artifact_ref`.
85
- Then: `node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary {bug_id} approve ...APPROVE-SUMMARY.json`
86
- - If set-bug-summary exits non-zero, fix the JSON and retry before proceeding.
87
-
88
- 6. Finalize:
89
- first so the sidecar is written before the event directory is purged
90
- - Summarise accumulated cost data into the bug artifact:
91
- read all events from `.forge/store/events/{bugId}/`, aggregate
92
- inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, and
93
- estimatedCostUSD across all events that carry token fields, and
94
- append a `## Cost Summary` section to the bug's markdown artifact
95
- (e.g. `engineering/bugs/{bugDir}/BUG_ANALYSIS.md` or equivalent).
96
- Format: one line per phase event, total row at the bottom.
97
- If no events carry token data, skip this section silently.
98
- - Run `node "$FORGE_ROOT/tools/collate.cjs" {bugId} --purge-events`
99
- This purges `.forge/store/events/{bugId}/` deterministically.
100
- The cost summary written to the bug artifact above is the durable
101
- record; no COST_REPORT.md is generated for bug IDs (collate skips
102
- sprint processing when the ID is not a known sprint).
103
- - **Finalize gate: verify collate succeeded.** Run the finalize
104
- phase gate before marking the bug as fixed:
105
- `node "$FORGE_ROOT/tools/preflight-gate.cjs" --phase finalize --bug {bugId}`
106
- This checks that `INDEX.md` exists in the bug's engineering directory.
107
- If the gate fails (exit 1), collate did not produce the required
108
- INDEX.md — do NOT mark the bug as fixed. Escalate to the human
109
- with the missing artifacts listed on stderr.
110
- If exit 2 (misconfiguration), escalate immediately.
111
- - Update bug status via `node "$FORGE_ROOT/tools/store-cli.cjs" update-status bug {bugId} status fixed`
112
- - **Do NOT emit a phase event yourself.** The orchestrator (or kickoff handler) owns event emission — it composes the canonical event from runtime telemetry (model, provider, tokens, wall times) plus the SUMMARY you write in the next step. Subagents that call `store-cli emit` for phase events hallucinate runtime facts (see Plan 11 / Slice 2). Write the SUMMARY and return.
113
- (tombstone — written after the purge; the only event that will remain)
155
+ b. If .forge/store/bugs/{BUG_ID}.json does NOT exist, write a fresh record
156
+ via store-cli with status="reported".
157
+ c. Read the now-guaranteed record.
158
+ - Spawn the triage subagent (persona: bug-fixer). It MUST:
159
+ Reproduce the bug (failing test or reproduction script).
160
+ Confirm the root cause via codebase research.
161
+ • Decide Path A vs Path B by the criteria above.
162
+ Write TRIAGE.md and TRIAGE-SUMMARY.json (with `path` field).
163
+ Call set-bug-summary {bugId} triage TRIAGE-SUMMARY.json
164
+ - On return, orchestrator transitions status:
165
+ store-cli update-status bug {bugId} status triaged
166
+ store-cli update-status bug {bugId} status in-progress
167
+ - Read summaries.triage.route. If neither "A" nor "B": escalate
168
+ (verdict_malformed). Do not guess.
169
+
170
+ 3. Path selection:
171
+ - phases = phases_A if route == "A" else phases_B
172
+ - Begin main phase loop.
173
+
174
+ 4. Phase loop (identical to meta-orchestrate.md § Execution Algorithm):
175
+ for each phase in phases[1:]: # triage already done
176
+ - Resolve model (cluster + ROLE_TIER).
177
+ - Compute eventId, agent_name, banner_name (from PERSONA_MAP /
178
+ BANNER_MAP below).
179
+ - Announce phase: banner + "→ {bugId} [{display_model}]".
180
+ - Start progress Monitor on .forge/store/events/bugs/progress.log.
181
+ - Preflight gate: preflight-gate.cjs --phase {role} --bug {bugId}
182
+ Exit 1 or 2 → escalate (see meta-orchestrate.md § Escalation Procedure)
183
+ with bug_id substituted for task_id. Update bug.status to "escalated"
184
+ only if it is currently "in-progress" (do not downgrade other states).
185
+ - Compose role-block, architecture-block, summary-block, overlay (via
186
+ build-overlay.cjs --bug {bugId}).
187
+ - Spawn subagent via Agent tool. Subagent prompt passes:
188
+ sprint_or_bug_id = "bugs" # virtual sprint dir for emit/sidecar
189
+ record_id = {bugId}
190
+ sidecar_path = .forge/store/events/bugs/_{event_id}_usage.json
191
+ - On return: merge sidecar, emit canonical event (orchestrator-owned),
192
+ stop progress Monitor, print phase-exit signal (✓ / ↻ / ⚠), run
193
+ /compact with checkpoint line.
194
+ - If phase is a review and verdict == "revision": re-enter the loop
195
+ on the on_revision predecessor up to max_iterations. Exhaust →
196
+ escalate (see meta-orchestrate.md § Escalation Procedure).
197
+
198
+ 5. Phase-specific responsibilities (sub-workflow contracts):
199
+ - plan-fix (Path B): engineer writes BUG_FIX_PLAN.md and BUG-FIX-PLAN-SUMMARY.json
200
+ (verdict: "n/a"). No status write.
201
+ - review-plan (Path B): supervisor writes REVIEW-PLAN-SUMMARY.json
202
+ (verdict: approved | revision). No status write.
203
+ - implement: engineer (or bug-fixer for Path A) applies the fix, runs the
204
+ regression test, writes IMPLEMENTATION-SUMMARY.json (verdict: "n/a").
205
+ No status write — bug stays at "in-progress".
206
+ - review-code: supervisor reads the actual diff and the regression test,
207
+ writes REVIEW-CODE-SUMMARY.json (verdict: approved | revision).
208
+ - approve: architect writes ARCHITECT_APPROVAL.md and APPROVE-SUMMARY.json
209
+ (verdict: approved | revision). No status write — the verdict signal is
210
+ the summary, not bug.status (see read-verdict.cjs:44).
211
+ - commit: engineer makes the git commit and runs:
212
+ store-cli update-status bug {bugId} status fixed
213
+ Then writes COMMIT-SUMMARY.json (verdict: "n/a"). This is the ONLY
214
+ phase that writes bug.status post-triage.
215
+
216
+ 6. Finalize (collator, housekeeping):
217
+ - Aggregate cost data from .forge/store/events/bugs/*.json filtered by
218
+ this bugId, and append a "## Cost Summary" section to the bug's
219
+ INDEX.md artifact.
220
+ - Run `node "$FORGE_ROOT/tools/collate.cjs" {bugId} --purge-events`.
221
+ Collate purges only this bug's events from the shared bugs/ dir
222
+ (filtered by bugId reference) it does NOT purge other bugs' events.
223
+ - Run preflight finalize gate: preflight-gate.cjs --phase finalize --bug {bugId}.
224
+ Exit 1 escalate. Do NOT downgrade bug.status (it is already "fixed").
225
+ - Do NOT emit a phase event yourself. The orchestrator owns event
226
+ emission for finalize as it does for every other phase — composed from
227
+ runtime telemetry plus the collator's summary.
114
228
  ```
115
- ## Announcement Algorithm
116
229
 
117
- The generated `fix_bug.md` MUST include the following verbatim algorithm for phase announcements and symmetric persona/skill injection. This mirrors the pattern from `meta-orchestrate.md`.
230
+ ## Persona and Banner Maps
231
+
232
+ Mirrors `meta-orchestrate.md` for shared roles. Bug-only role is `triage`.
118
233
 
119
234
  ```
120
235
  # --- Role-to-noun mapping (persona and skill file lookups) ---
121
236
  ROLE_TO_NOUN = {
122
- "plan-fix": "bug-fixer",
123
- "review-plan": "supervisor",
124
- "implement": "bug-fixer",
237
+ "triage": "bug-fixer",
238
+ "plan": "engineer", # Path B only
239
+ "review-plan": "supervisor", # Path B only
240
+ "implement": "engineer",
125
241
  "review-code": "supervisor",
126
242
  "approve": "architect",
127
243
  "commit": "engineer",
244
+ "finalize": "collator",
128
245
  }
129
246
  # Default fallback: "bug-fixer"
130
247
 
131
248
  # --- Persona symbol lookup (emoji, name, tagline) ---
132
249
  PERSONA_MAP = {
133
- "plan-fix": ("🍂", "Bug Fixer", "I find what has decayed and restore it."),
250
+ "triage": ("🍂", "Bug Fixer", "I find what has decayed and decide the path."),
251
+ "plan": ("🌱", "Engineer", "I plan what will be built before any code is written."),
134
252
  "review-plan": ("🌿", "Supervisor", "I review before things move forward. I read the actual fix, not just the plan."),
135
- "implement": ("🍂", "Bug Fixer", "I find what has decayed and restore it."),
253
+ "implement": ("🌱", "Engineer", "I build what was planned. I do not move forward until the code is clean."),
136
254
  "review-code": ("🌿", "Supervisor", "I review before things move forward. I read the actual code, not the report."),
137
255
  "approve": ("🗻", "Architect", "I hold the shape of the whole. I give final sign-off before commit."),
138
256
  "commit": ("🌱", "Engineer", "I close out completed work with a clean, honest commit."),
257
+ "finalize": ("🍃", "Collator", "I gather what exists and arrange it into views."),
139
258
  }
140
- # Default fallback: ("🍂", "Bug Fixer", "I find what has decayed and restore it.")
259
+ # Default fallback: ("🍂", "Bug Fixer", "I find what has decayed and decide the path.")
141
260
 
142
261
  # --- Banner identity map (banner name per phase role) ---
143
- # Displayed by the orchestrator ONLY (badge before spawn, exit signal after return).
144
- # Subagents do NOT display banners — the orchestrator owns phase announcements.
145
262
  BANNER_MAP = {
146
- "plan-fix": "rift",
263
+ "triage": "rift",
264
+ "plan": "forge",
147
265
  "review-plan": "oracle",
148
- "implement": "rift",
266
+ "implement": "forge",
149
267
  "review-code": "oracle",
150
268
  "approve": "north",
151
269
  "commit": "forge",
270
+ "finalize": "drift",
152
271
  }
153
272
  # Default fallback: "rift"
273
+ ```
154
274
 
155
- # --- Clear progress log for this bug ---
156
- progress_log_path = ".forge/store/events/bugs/progress.log"
157
- run_bash(f'FORGE_ROOT=$(node -e "console.log(require(\'./.forge/config.json\').paths.forgeRoot)") && node "$FORGE_ROOT/tools/store-cli.cjs" progress-clear bugs')
158
-
159
- # --- Announce phase with identity banner (badge) + bug context ---
160
- emoji, persona_name, tagline = PERSONA_MAP.get(phase.role, ("🍂", "Bug Fixer", "I find what has decayed and restore it."))
161
- banner_name = BANNER_MAP.get(phase.role, "rift")
162
- run_bash(f'FORGE_ROOT=$(node -e "console.log(require(\'./.forge/config.json\').paths.forgeRoot)") && node "$FORGE_ROOT/tools/banners.cjs" --badge {banner_name}')
163
- print(f" → {bug_id} [{phase_model}]\n")
164
-
165
- # --- Compute agent name for progress IPC ---
166
- persona_noun = ROLE_TO_NOUN.get(phase.role, "bug-fixer")
167
- iteration = iteration_counts.get(phase.name, 0) + 1
168
- agent_name = f"{bug_id}:{persona_noun}:{phase.role}:{iteration}"
169
-
170
- # --- Start progress Monitor before spawning subagent ---
171
- start_monitor(
172
- command=f"tail -n +1 -F {progress_log_path} 2>/dev/null || true",
173
- description=f"Progress: {agent_name}",
174
- persistent=False
175
- )
275
+ ## Subagent Prompt Composition
176
276
 
177
- # --- Pre-flight gate check (see Phase Gates below) ---
178
- # Halts the fix-bug loop if prerequisites are missing or a predecessor
179
- # review did not clear. Same tool as meta-orchestrate.
180
- FORGE_ROOT = resolve_forge_root()
181
- preflight_result = run_bash(
182
- f'node "$FORGE_ROOT/tools/preflight-gate.cjs" --phase {phase.role} --bug {bug_id}'
183
- )
184
- if preflight_result.exit_code == 1:
185
- print(f" ✗ {bug_id} {phase.role} — gate failed\n{preflight_result.stderr}")
186
- escalate_to_human(bug, phase, reason=f"gate_failed: {preflight_result.stderr}")
187
- break
188
- elif preflight_result.exit_code == 2:
189
- print(f" ⚠ {bug_id} {phase.role} — gate misconfigured\n{preflight_result.stderr}")
190
- escalate_to_human(bug, phase, reason=f"gate_misconfigured: {preflight_result.stderr}")
191
- break
192
-
193
- # --- Symmetric Injection: noun resolved from ROLE_TO_NOUN ---
194
- # Mode is governed by FORGE_PROMPT_MODE (default: "reference"). See
195
- # meta-orchestrate.md § "Persona Injection Modes" for the helper definition —
196
- # the generated fix-bug orchestrator shares the same helper.
197
- role_block = compose_role_block(persona_noun)
198
-
199
- # --- Compose architecture context block (conditional on phase.context.architecture) ---
200
- # <!-- See _fragments/context-injection.md for canonical definition -->
201
- bug_architecture_block = (
202
- compose_architecture_block(".forge/cache/context-pack.md", ".forge/cache/context-pack.json")
203
- if phase.context.architecture else ""
204
- )
277
+ Identical pattern to `meta-orchestrate.md § Execution Algorithm`. The only
278
+ differences are:
205
279
 
206
- # --- Compose prior-phase summary block for bug context ---
207
- # <!-- See _fragments/context-injection.md for canonical definition -->
208
- bug_summary_block = compose_summary_block(bug_id, record_type="bug") if phase.context.prior_summaries != "none" else ""
280
+ - `--bug {bugId}` flag passed to preflight-gate.cjs and sub-workflows.
281
+ - `sprint_or_bug_id = "bugs"` for emit/sidecar/progress (virtual sprint dir).
282
+ - `build-overlay.cjs --bug {bugId}` for the overlay (matches the task pattern
283
+ `build-overlay.cjs --task {taskId}`).
284
+ - Sidecar path uses `.forge/store/events/bugs/_{event_id}_usage.json` — the
285
+ shared bugs virtual dir. Collate filters by bug reference at purge time.
209
286
 
287
+ ```
210
288
  # --- Materialize project overlay (replaces MASTER_INDEX.md read in subagent) ---
211
289
  overlay_result = run_bash(
212
290
  f'node "$FORGE_ROOT/tools/build-overlay.cjs" --bug {bug_id} --format md'
213
291
  )
214
292
  bug_overlay_md = overlay_result.stdout if overlay_result.exit_code == 0 else ""
215
293
 
216
- # --- Spawn subagent (no banner command in prompt) ---
217
294
  spawn_subagent(
218
295
  prompt=compose_subagent_prompt(
219
296
  agent_name=agent_name, progress_log_path=progress_log_path, banner_name=banner_name,
@@ -228,68 +305,119 @@ spawn_subagent(
228
305
  description=f"{emoji} {persona_name} — {phase.name} for {bug_id}",
229
306
  model=phase_model
230
307
  )
231
-
232
- # --- Stop progress Monitor ---
233
- stop_monitor(progress_log_path)
234
308
  ```
235
309
 
236
- **Orchestrator Iron Laws:** See `generic-skills.md § Orchestrator Iron Laws` for the six universal laws that apply to this workflow.
237
- <!-- See _fragments/event-emission-schema.md for event field reference -->
238
-
239
- **Key rules for the generated `fix_bug.md`:**
240
- - `ROLE_TO_NOUN` MUST cover all six phases: `plan-fix`, `review-plan`, `implement`, `review-code`, `approve`, `commit`.
241
- - `PERSONA_MAP` MUST use correct emoji/name/tagline per persona (bug-fixer, supervisor, architect, engineer — not all bug-fixer).
242
- - Persona/skill lookups MUST use `{persona_noun}.md` and `{persona_noun}-skills.md`, never `{phase.role}.md`.
243
- - Sidecar path uses `.forge/store/events/bugs/_{event_id}_usage.json` (not `events/{sprint_id}/`).
244
- - Announcement `print()` line MUST include `{tagline}` and `[{phase_model}]`.
245
- - Include progress IPC: clear log at bug start, compute agent names, Monitor before spawn, stop after return.
246
- - Include phase-exit signals and post-phase `/compact` with checkpoint line `[checkpoint] bug={bug_id} phase={phase.role} iterations={iteration_counts}`. Do NOT compact on escalation.
247
-
248
310
  ## Phase Gates
249
311
 
250
- Declarative pre-flight gates for each fix-bug phase. Evaluated by
251
- `forge/tools/preflight-gate.cjs` before every subagent spawn. Grammar is
252
- identical to `meta-orchestrate.md` see that file's "Phase Gates" section
253
- for the directive reference.
312
+ Declarative pre-flight gates. Evaluated by `forge/tools/preflight-gate.cjs`
313
+ before every subagent spawn. Grammar identical to `meta-orchestrate.md §
314
+ Phase Gates`. Gates encode both the path-A/path-B split (via `after`
315
+ predecessors that differ per path) and the status-trap defences.
254
316
 
255
- ```gates phase=plan-fix
317
+ ```gates phase=triage
256
318
  forbid bug.status == blocked
257
319
  forbid bug.status == escalated
258
320
  forbid bug.status == fixed
259
321
  forbid bug.status == abandoned
322
+ forbid bug.status == approved
323
+ forbid bug.status == verified
324
+ ```
325
+
326
+ ```gates phase=plan
327
+ artifact {engineering}/bugs/{bug}/TRIAGE.md min=200
328
+ after triage = n/a
329
+ forbid bug.status == fixed
330
+ forbid bug.status == approved
331
+ forbid bug.status == verified
332
+ forbid bug.status == blocked
333
+ forbid bug.status == escalated
260
334
  ```
261
335
 
262
336
  ```gates phase=review-plan
263
337
  artifact {engineering}/bugs/{bug}/BUG_FIX_PLAN.md min=200
338
+ forbid bug.status == fixed
339
+ forbid bug.status == approved
340
+ forbid bug.status == verified
341
+ forbid bug.status == blocked
342
+ forbid bug.status == escalated
264
343
  ```
265
344
 
266
345
  ```gates phase=implement
346
+ artifact {engineering}/bugs/{bug}/TRIAGE.md min=200
347
+ forbid bug.status == fixed
348
+ forbid bug.status == approved
349
+ forbid bug.status == verified
267
350
  forbid bug.status == blocked
268
351
  forbid bug.status == escalated
269
- artifact {engineering}/bugs/{bug}/BUG_FIX_PLAN.md min=200
270
- after review-plan = approved
271
- forbid bug.status == fixed
272
352
  ```
273
353
 
274
354
  ```gates phase=review-code
275
- after review-plan = approved
355
+ after implement = n/a
356
+ forbid bug.status == fixed
357
+ forbid bug.status == approved
358
+ forbid bug.status == verified
359
+ forbid bug.status == blocked
360
+ forbid bug.status == escalated
276
361
  ```
277
362
 
278
363
  ```gates phase=approve
279
364
  after review-code = approved
365
+ forbid bug.status == fixed
366
+ forbid bug.status == approved
367
+ forbid bug.status == verified
368
+ forbid bug.status == blocked
369
+ forbid bug.status == escalated
280
370
  ```
281
371
 
282
372
  ```gates phase=commit
283
373
  after approve = approved
374
+ forbid bug.status == fixed
375
+ forbid bug.status == approved
376
+ forbid bug.status == verified
377
+ forbid bug.status == blocked
378
+ forbid bug.status == escalated
284
379
  ```
285
380
 
286
381
  ```gates phase=finalize
287
382
  artifact {engineering}/bugs/{bug}/INDEX.md
288
383
  ```
289
384
 
385
+ Note: the `forbid bug.status == approved | verified` rows are defensive — no
386
+ phase in this workflow writes those values, and a follow-up cleanup should
387
+ drop them from `bug.schema.json` entirely. Until then, these gates halt any
388
+ LLM-improvised attempt to land in the run-task trap (see today's regression).
389
+ ## Iron Laws
390
+
391
+ <!-- Shared orchestrator laws live in generic-skills.md § Orchestrator Iron Laws. -->
392
+ > See `generic-skills.md § Orchestrator Iron Laws` for the six universal
393
+ > laws that apply to all orchestrators.
394
+
395
+ **Additional laws specific to fix-bug:**
396
+
397
+ 1. **Path is decided once.** The triage subagent records `summaries.triage.route`.
398
+ The orchestrator selects the phase list and does not switch paths mid-run.
399
+ If the architect or supervisor concludes Path A was wrong, the verdict is
400
+ `revision` — re-enter the loop, escalate on exhaustion. Never silently
401
+ promote a Path A run into Path B.
402
+
403
+ 2. **No status writes outside owned phases.** Only `triage` (`reported →
404
+ triaged → in-progress`) and `commit` (`in-progress → fixed`) write
405
+ `bug.status`. No phase writes `approved` or `verified`. No phase writes
406
+ anything in finalize. LLM improvisation that mirrors a task workflow's
407
+ status writes is a violation; the gates catch it, the iron law names it.
408
+
409
+ 3. **No silent skipping.** A bug at `fixed`/`abandoned`/`blocked`/`escalated`
410
+ is skipped at pre-loop with one `bug_skipped` event. Skipping inside the
411
+ phase loop (writing "phase skipped" summaries) is forbidden — that pattern
412
+ produced the inconsistent-skip drift that surfaced today's regression.
413
+
290
414
  ## Friction Emit
291
415
 
292
- When the Bug Fixer detects skill friction during fix-bug — a referenced skill is unused, fails on invocation, is missing from the registry, has gone stale relative to current architecture, or is redundant with another skill — emit a `friction` event so `/forge:enhance --phase 2` can act on the signal. This is the writer side of the channel whose reader landed in S13-T08; the reader is empty without these emits.
416
+ When the Bug Fixer, Supervisor, Architect, Engineer, or Collator detects skill
417
+ friction during fix-bug — a referenced skill is unused, fails on invocation,
418
+ is missing from the registry, has gone stale relative to current architecture,
419
+ or is redundant with another skill — emit a `friction` event so
420
+ `/forge:enhance --phase 2` can act on the signal.
293
421
 
294
422
  **Trigger conditions** (set `issue` to the matching token):
295
423
 
@@ -313,3 +441,17 @@ Log path: `.forge/store/events/bugs/progress.log`. Agent name format: `{bugId}:{
313
441
  ## Phase-Exit Signals
314
442
 
315
443
  After each subagent returns: `✓` for completed/approved, `↻` for revision required (with iteration count), `⚠` for escalated. Format mirrors `meta-orchestrate.md § Phase-Exit Signals` with `bug_id` in place of `task_id`.
444
+
445
+ ## Event Emission
446
+
447
+ <!-- See _fragments/event-emission-schema.md for canonical contract -->
448
+ > See `_fragments/event-emission-schema.md` for the actor split (subagent
449
+ > writes judgement-only SUMMARY; orchestrator composes the canonical event
450
+ > from runtime telemetry + SUMMARY and emits it).
451
+
452
+ The orchestrator is the only actor that calls `store-cli emit` for phase
453
+ events. All bug-phase events use `sprintId="bugs"` (the reserved virtual
454
+ sprint dir). The schema's `event.bugId` field carries the originating bug
455
+ ID for cross-bug filtering at collate time. Subagents write
456
+ `{PHASE}-SUMMARY.json` and return; the orchestrator composes the canonical
457
+ event and emits it.