@emiliosp/pi-maestro 0.9.5 → 0.10.1

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  This file summarizes meaningful changes to the codebase, including behavior, data formats, architecture, and development tools. Git tags identify version boundaries; GitHub Releases are not required. Version-only changes and routine maintenance are omitted.
4
4
 
5
+ ## Unreleased
6
+
7
+ 1. Added `success`, `failure`, and `unchanged` coverage labels to the `spec` template and `Maestro` guidance. Approval validation and `handoff` formats remain unchanged.
8
+ 2. Required `Maestro` to inspect existing tests before writing `acceptance criteria` and remove criteria whose exact scenarios already have coverage. Requirements remain documented in the `spec`.
9
+
10
+ ## 0.10.0
11
+
12
+ 1. Saved complete `owner` decision batches in their original `handoffs` before changing phase, including when the `spec` requires revision. See [PR #38](https://github.com/emilioSp/pi-maestro/pull/38).
13
+ 2. Added `revise-spec` decisions for `verifier` `findings`, with the owner's reason and agreed requirement change. Revision takes priority over code fixes and rejections.
14
+ 3. Unified both revision paths through `drafting-spec`, with renewed `GREEN FLAG` before separate approval and another `builder` `run`. Approval is allowed only from `drafting-spec`.
15
+ 4. Renamed workflow events to identify `builder` and `owner` actions. Both revision paths share `OWNER_REQUEST_SPEC_REVISION`.
16
+ 5. Breaking: supply the required boolean `specChangeRequired` when calling `maestro_resolve_escalations`.
17
+ 6. Breaking: saved decision phases are now `escalation-decisions` and `finding-decisions`. Existing workflows using older names require manual `owner` handling. No automatic migration is provided.
18
+
19
+ ## 0.9.5
20
+
21
+ 1. Added a shared check that requires every approved `spec` criterion ID in `builder` and `verifier` `handoffs`. See [PR #37](https://github.com/emilioSp/pi-maestro/pull/37).
22
+ 2. Missing IDs reject submission before saving a report or changing phase. Extra report IDs remain allowed, and existing report validation is unchanged.
23
+ 3. Reused the raw heading rule `^### AC(\d+):`, including leading zeros and matching lines inside code blocks. No matching headings impose no new restriction.
24
+ 4. Added unit tests for extraction and one missing-ID integration test per role.
25
+
5
26
  ## 0.9.4
6
27
 
7
28
  1. Added numbering validation to `spec` approval. Matched `acceptance criterion` headings must start at `AC1` and continue without gaps. See [PR #36](https://github.com/emilioSp/pi-maestro/pull/36).
package/README.md CHANGED
@@ -10,12 +10,13 @@ Pi extension for a spec-driven multiagent development workflow.
10
10
 
11
11
  A `specification` (`spec`) describes one reversible change. The `builder` implements it. An independent `verifier` checks every `acceptance criterion`. The `owner` performs the final review.
12
12
 
13
- Four principles hold the workflow together:
13
+ Five principles hold the workflow together:
14
14
 
15
15
  1. The approved `spec` defines the required work for the `builder` and `verifier`.
16
16
  2. No agent approves its own work.
17
17
  3. Every `acceptance criterion` is checked independently.
18
18
  4. The `owner` decides requirements, scope, and unresolved questions.
19
+ 5. Each agent has one and only one role. Specific and with clear instruction.
19
20
 
20
21
  ## The roles
21
22
 
@@ -79,7 +80,11 @@ The `owner` must not edit product files while the workflow runs.
79
80
  `Maestro` can perform temporary experiments with `owner` agreement during `spec` preparation and permitted revisions. See [Workflow](docs/workflow.md#spec-approval).
80
81
 
81
82
  An `escalation` asks the `owner` to decide an implementation question, and a `finding` records a technical issue reported by the `verifier`. The `owner` discusses both with `Maestro`, never directly with the `builder` or `verifier`.
82
- If a `spec` change is needed during an `escalation` or `finding` decision, the `owner` reviews the revised `spec` and replies `GREEN FLAG` again. `Maestro` then starts another `builder` `run`.
83
+ `Maestro` records all current `escalation` answers or `finding` decisions in the active `handoff` before changing phase.
84
+
85
+ If any decision requires a `spec` change, the workflow returns to `drafting-spec` before the `owner` and `Maestro` revise the same `spec`.
86
+ The `owner` reviews the revised `spec` and replies `GREEN FLAG` again.
87
+ `Maestro` records renewed approval separately before another `builder` `run`.
83
88
 
84
89
  The workflow ends at `candidate-ready`. Rejected `findings` retain their reasons. Later changes are outside the completed verification. The `owner` controls any later Git use, pull request, and merge.
85
90
 
package/ROADMAP.md CHANGED
@@ -6,6 +6,30 @@ This roadmap records planned outcomes, not permission to implement them. The `ow
6
6
 
7
7
  Item identifiers remain stable when priorities change. The `owner` approves changes to priorities and scope.
8
8
 
9
+ ## Overview
10
+
11
+ | ID | Title | Status | Summary |
12
+ |---|---|---|---|
13
+ | R-01 | [Improve status presentation and activation feedback](#r-01-improve-status-presentation-and-activation-feedback) | Completed | Show clearer status and configured agent details without adding model context. |
14
+ | R-02 | [Store escalations and owner decisions in builder handoffs](#r-02-store-escalations-and-owner-decisions-in-builder-handoffs) | Completed | Keep `escalation` questions and `owner` answers together in numbered `builder` `handoffs`. |
15
+ | R-03 | [Route builder failures through owner escalations](#r-03-route-builder-failures-through-owner-escalations) | Completed | Route reportable `builder` problems through `owner` `escalations` instead of a terminal failure phase. |
16
+ | R-12 | [Format glossary terms consistently](#r-12-format-glossary-terms-consistently) | Completed | Apply glossary formatting across documentation and record its exclusions. |
17
+ | R-14 | [Introduce Maestro at activation](#r-14-introduce-maestro-at-activation) | Completed | Introduce `Maestro` at activation and load relevant documentation only when needed. |
18
+ | R-15 | [Rename the test support directory](#r-15-rename-the-test-support-directory) | Completed | Rename `test/` to `tests/` and update affected references. |
19
+ | R-16 | [Verify code quality against AGENTS.md instructions](#r-16-verify-code-quality-against-agentsmd-instructions) | Completed | Require the `verifier` to review affected code against applicable `AGENTS.md` code-quality directives. |
20
+ | R-06 | [Check subagent extensions at activation](#r-06-check-subagent-extensions-at-activation) | Completed | Require a successful parent `pi-subagents` availability reply before activation. |
21
+ | R-05 | [Keep acceptance criterion numbering continuous](#r-05-keep-acceptance-criterion-numbering-continuous) | Completed | Reject gaps in `acceptance criterion` numbering before approving a `spec`. |
22
+ | R-10 | [Match handoff criteria to the approved spec](#r-10-match-handoff-criteria-to-the-approved-spec) | Completed | Require every approved `spec` criterion ID in each submitted `builder` and `verifier` `handoff`. |
23
+ | R-17 | [Record escalation resolutions when the spec changes](#r-17-record-escalation-resolutions-when-the-spec-changes) | Completed | Save all current `escalation` answers before changing phase, including when the `spec` requires revision. |
24
+ | R-20 | [Route finding-driven spec revisions through drafting-spec](#r-20-route-finding-driven-spec-revisions-through-drafting-spec) | Completed | Record `finding` decisions before `spec` revision and require renewed `GREEN FLAG` before another `builder` `run`. |
25
+ | R-18 | [Label acceptance criterion coverage](#r-18-label-acceptance-criterion-coverage) | Completed | Label each `acceptance criterion` as success, failure, or unchanged behavior. |
26
+ | R-19 | [Avoid acceptance criteria already covered by tests](#r-19-avoid-acceptance-criteria-already-covered-by-tests) | Completed | Omit `acceptance criteria` whose exact scenarios already have test coverage. |
27
+ | R-04 | [Rename the npm package](#r-04-rename-the-npm-package) | Later | Rename `@emiliosp/pi-maestro` to `pi-maestro-sdd` with compatibility decisions defined in the `spec`. |
28
+ | R-07 | [Guide initial configuration](#r-07-guide-initial-configuration) | Later | Help the `owner` create valid `Maestro` configuration through an interview. |
29
+ | R-08 | [Change agent models before a builder run](#r-08-change-agent-models-before-a-builder-run) | Later | Let the `owner` change `builder` and `verifier` models before subsequent `runs`. |
30
+ | R-09 | [Define workflow reconciliation](#r-09-define-workflow-reconciliation) | Later | Define how `Maestro` can reconcile saved `artifacts` and workflow state. |
31
+ | R-21 | [Add a simplifier with one clear purpose per agent](#r-21-add-a-simplifier-with-one-clear-purpose-per-agent) | Later | Add a simplifier after successful verification to reduce complexity without changing behavior. |
32
+
9
33
  ## Completed
10
34
 
11
35
  ### R-01: Improve status presentation and activation feedback
@@ -60,7 +84,7 @@ Renamed `test/` to `tests/` at the owner's request. Updated imports, fixture pat
60
84
 
61
85
  #### Evidence
62
86
 
63
- [Test support](tests/support/), [fixtures](tests/fixtures/), [lint configuration](biome.json), and [project instructions](AGENTS.md#tests).
87
+ [Test support](tests/support/), [fixtures](tests/fixtures/), and [lint configuration](biome.json).
64
88
 
65
89
  ### R-16: Verify code quality against AGENTS.md instructions
66
90
 
@@ -98,27 +122,102 @@ All 3 `acceptance criteria` passed with no `verifier` `findings`. The saved work
98
122
 
99
123
  [Specification](.specs/20261013-202811-check-acceptance-criterion-numbering-before-builder-execution/spec.md), [verifier report](.specs/20261013-202811-check-acceptance-criterion-numbering-before-builder-execution/handoffs/verifier/V1.json), and [merged PR #36](https://github.com/emilioSp/pi-maestro/pull/36).
100
124
 
101
- ## Now
102
-
103
125
  ### R-10: Match handoff criteria to the approved spec
104
126
 
127
+ Implemented in `0.9.5` with the narrower scope approved by the `owner`. Both `handoff` submissions require every `acceptance criterion` ID from the approved `spec` before saving a report or changing phase. Extra report IDs remain allowed. Existing report validation is unchanged, and no new check rejects duplicate `spec` IDs.
128
+
129
+ Both `acceptance criteria` passed independent verification with no `findings`. The saved workflow reached `candidate-ready`.
130
+
131
+ Later changes requested by the `owner` extracted the shared check and replaced repeated integration scenarios with unit tests. One missing-ID integration test remains per role. These changes are outside the completed independent verification. The final `npm run check` passed all 227 tests and coverage thresholds.
132
+
133
+ #### Evidence
134
+
135
+ [Specification](.specs/20261013-211629-match-handoff-criteria-to-the-approved-spec/spec.md), [verifier report](.specs/20261013-211629-match-handoff-criteria-to-the-approved-spec/handoffs/verifier/V1.json), and [merged PR #37](https://github.com/emilioSp/pi-maestro/pull/37).
136
+
137
+ ### R-17: Record escalation resolutions when the spec changes
138
+
105
139
  #### Objective
106
140
 
107
- Prevent `builder` and `verifier` reports from omitting or adding `acceptance criteria`. Each report must contain exactly the criterion IDs in the approved `spec`, with no duplicates in either place. Existing duplicate checks in reports do not establish this match.
141
+ Save every current `escalation` answer in the original `builder` `handoff`, whether the `spec` stays unchanged or requires revision.
142
+ Each `resolution` records the owner's chosen solution and reason. A decision requiring revision also identifies the `escalation` and describes the agreed `spec` change.
143
+
144
+ #### Agreed flow
145
+
146
+ `Maestro` records the complete decision batch through `maestro_resolve_escalations` before changing phase.
108
147
 
109
- The `specification` must define the criterion heading format used to extract IDs. For example, a heading can use `### AC1: ...`.
148
+ | Decision | Next phase and action |
149
+ |---|---|
150
+ | No `spec` change | `escalation-decisions` → `ready-for-builder`. The `builder` continues under the approved `spec`, without renewed approval. |
151
+ | `Spec` change required | `escalation-decisions` → `drafting-spec`. The `owner` and `Maestro` revise and review the same `spec`. |
152
+ | Revised `spec` receives renewed `GREEN FLAG` | `drafting-spec` → `ready-for-builder` through separate `maestro_mark_spec_ready` approval. |
153
+
154
+ Direct `spec` approval from `escalation-decisions` is rejected. Recording answers does not move to `ready-for-verifier`; that phase requires a completed `builder` `pass`.
155
+
156
+ #### Implementation boundaries
157
+
158
+ Reuse the existing resolution operation and `handoff` fields. Do not add a parallel decision store, tool, or workflow phase.
159
+ Define both resolution transitions explicitly in `src/workflow/transitions.ts` and apply them through `transitionWorkflow`. Direct phase assignment elsewhere is banned.
160
+ Preserve initial `spec` approval, `verifier` `finding` decisions, existing batch validation, and historical `handoffs`.
110
161
 
111
162
  #### Completed when
112
163
 
113
- Both `handoff` submissions reject missing, extra, or duplicate criterion IDs before saving a report or changing phase.
164
+ Saved `resolutions`, workflow phases, tool results, agent instructions, and human documentation follow the agreed flow.
165
+ Verification checks both observable behavior and use of the central transition definitions for each resolution branch. Passing behavior tests alone is not enough.
166
+ The new `spec` includes coverage labels and omits `acceptance criteria` already covered by tests of the same scenario.
167
+
168
+ ### R-20: Route finding-driven spec revisions through drafting-spec
169
+
170
+ Implemented the approved revision route. `Maestro` records every current `finding` decision before returning to `drafting-spec` when revision is required.
171
+ The `owner` reviews the same revised `spec` and gives renewed `GREEN FLAG` before separate approval and another `builder` `run`.
172
+ Revision takes priority in mixed batches. Direct approval from `finding-decisions` is rejected.
173
+
174
+ Later event naming cleanup identifies `builder` and `owner` actions explicitly. Both revision routes use `OWNER_REQUEST_SPEC_REVISION` without changing the phase flow. Batch resolution uses `RESOLVE_ESCALATIONS`, and the status label refers to `escalations` in the plural. The saved decision phases are named `escalation-decisions` and `finding-decisions`.
175
+
176
+ #### Evidence
177
+
178
+ [Specification](.specs/20261015-154812-route-finding-driven-spec-revisions-through-drafting-spec/spec.md) and [resolution integration tests](src/tools/main/resolve-findings.integration.test.ts).
179
+
180
+ ### R-18: Label acceptance criterion coverage
181
+
182
+ Implemented with R-19 as one task, as selected by the `owner`.
183
+ The `spec` template and `Maestro` guidance require one `Coverage` label per `acceptance criterion`:
114
184
 
115
- #### Implementation status
185
+ | Label | Purpose |
186
+ |---|---|
187
+ | `success` | A valid action produces the required result. |
188
+ | `failure` | An invalid action is correctly rejected. |
189
+ | `unchanged` | The change preserves existing behavior. |
116
190
 
117
- The [approved specification](.specs/20261013-211629-match-handoff-criteria-to-the-approved-spec/spec.md) limits this change to missing IDs. The implementation rejects missing `spec` IDs before saving either `handoff` or changing phase. Extra report IDs remain allowed. No new check rejects duplicate IDs in the `spec`.
191
+ Use `unchanged` when the criterion explicitly checks behavior that the change must preserve.
192
+ Labels describe scenarios, not test outcomes. A `failure` scenario passes when the invalid action is correctly rejected.
193
+ A `spec` does not need all three categories.
194
+ `Maestro` includes labels when presenting criteria to the `owner` and checks them against scenarios and `expected results` during review.
195
+ Approval validation and `handoff` formats remain unchanged.
118
196
 
119
- Both `acceptance criteria` passed independent verification with no `findings`. The saved workflow reached `candidate-ready`. The broader exact-match objective remains outside this approved scope.
197
+ The existing creation integration test now checks that the generated `spec` includes the coverage field.
198
+ The final `npm run check` passed all 238 tests and coverage thresholds. No model trials were performed.
120
199
 
121
- Later changes requested by the `owner` extract the shared presence check into one utility and cover extraction with unit tests. One missing-ID integration test remains per role to check rejection before saving. These changes are outside the completed independent verification.
200
+ #### Evidence
201
+
202
+ [Spec template](templates/spec.md), [Maestro guidance](src/maestro/instructions/getMaestroInstructions.ts), [creation integration test](src/specs/create.integration.test.ts), and [workflow documentation](docs/workflow.md#acceptance-criteria).
203
+
204
+ ### R-19: Avoid acceptance criteria already covered by tests
205
+
206
+ Implemented with R-18. `Maestro` inspects existing tests before writing `acceptance criteria`.
207
+ It omits a criterion only when a test covers the same starting conditions, action, and `expected result`.
208
+ Partial or uncertain coverage does not justify omission. Similar tests do not count.
209
+
210
+ During `spec` review, `Maestro` removes criteria whose exact scenarios already have test coverage.
211
+ It keeps numbering continuous from `AC1` and updates affected references. Required behavior remains documented in the requirements and constraints.
212
+ The same rules apply during `spec` revisions. No automatic approval check was added.
213
+
214
+ Verification consisted of inspecting the written guidance and running `npm run check`. No model trials were performed.
215
+
216
+ #### Evidence
217
+
218
+ [Maestro guidance](src/maestro/instructions/getMaestroInstructions.ts), [spec template](templates/spec.md), and [workflow documentation](docs/workflow.md#acceptance-criteria).
219
+
220
+ ## Now
122
221
 
123
222
  ## Next
124
223
 
@@ -167,3 +266,25 @@ Explore how `Maestro` can reconcile saved `artifacts` and workflow state. The re
167
266
  #### Completed when
168
267
 
169
268
  Not yet defined. The `owner` must define the intended outcome, recovery boundaries, and completion condition before this item can move forward.
269
+
270
+ ### R-21: Add a simplifier with one clear purpose per agent
271
+
272
+ #### Objective
273
+
274
+ Each agent has exactly one purpose. The `builder` implements the approved `spec`. The `verifier` independently checks its `acceptance criteria`. The simplifier refactors verified code.
275
+
276
+ Add the simplifier after the `verifier`. It receives code built by the `builder` only after verification confirms that all checks defined in the `acceptance criteria` pass.
277
+
278
+ The simplifier reduces complexity while preserving exact behavior. The goal is code that is easier to read, understand, modify, and debug, not fewer lines.
279
+ Every simplification must pass this test: "Would a new team member understand this faster than the original?"
280
+
281
+ #### Scope boundaries
282
+
283
+ Remove the "Review code quality" section from `agents/verifier.md`. This replaces the additional review introduced in R-16, not independent verification of `acceptance criteria`.
284
+
285
+ The simplifier's detailed instructions will be defined during `spec` preparation. This roadmap item does not define them.
286
+
287
+ #### Completed when
288
+
289
+ The workflow includes the simplifier after successful verification. Agent instructions keep implementation, verification, and simplification as separate responsibilities.
290
+ The simplifier preserves exact behavior and follows the instructions agreed in the approved `spec`.
@@ -115,5 +115,5 @@ Do not delete artifacts, change workflow state, or bypass the tool to force comp
115
115
  If restoration or submission cannot be completed safely, report the exact blocker and remaining changes to Maestro and stop.
116
116
 
117
117
  After a successful handoff, return a concise summary and the saved artifact path to Maestro and stop. Do not run more checks.
118
- The handoff produces `findings-decision` when findings exist and `candidate-ready` when none exist.
118
+ The handoff produces `finding-decisions` when findings exist and `candidate-ready` when none exist.
119
119
  Report that tool result without deciding whether the owner must accept, reject, or fix any finding.
package/docs/glossary.md CHANGED
@@ -21,6 +21,7 @@
21
21
  | `Escalation` | An implementation question or reportable technical problem that the `builder` records in its `handoff` for an `owner` decision. |
22
22
  | `GREEN FLAG` | The owner's explicit reply that approves the current `spec` and starts the `builder`. |
23
23
  | `fix-code` | An `owner` decision that requests code fixes without changing the approved `spec`. |
24
+ | `revise-spec` | An `owner` decision that records a reason and agreed requirement change, then returns to `drafting-spec` for revision and renewed approval. |
24
25
  | `reject` | An `owner` decision that declines a `finding` and records a reason. It does not mean that verification passed. |
25
26
  | `candidate-ready` | The completed workflow phase. The `verifier` reported no `findings`, or the `owner` rejected every `finding` with a reason. Final review remains with the `owner`. |
26
27
 
package/docs/workflow.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  The approved `spec.md` defines behavior, scope, constraints, technical decisions, and `acceptance criteria` for the change.
6
6
 
7
- An `acceptance criterion` contains a `probe`, an `expected result`, and an example. A `probe` is a scenario used to test behavior.
7
+ An `acceptance criterion` contains a coverage label, a `probe`, an `expected result`, and an example. A `probe` is a scenario used to test behavior.
8
8
 
9
9
  A `handoff` is a saved report from a `builder` or `verifier` `run`. It records the result, `probe` outcomes, and notes.
10
10
 
@@ -61,16 +61,16 @@ flowchart TD
61
61
  findings -->|None| candidate
62
62
 
63
63
  buildOutcome -->|Escalation| ownerEscalation{Owner decides every question}
64
- ownerEscalation -->|Spec unchanged| recordEscalation[Maestro records all answers]
65
- recordEscalation --> build
66
- ownerEscalation -->|Spec changes| reviseSpec[Owner and Maestro revise the spec]
64
+ ownerEscalation --> recordEscalation[Maestro records all answers]
65
+ recordEscalation -->|Spec unchanged| build
66
+ recordEscalation -->|Spec changes| reviseSpec[Owner and Maestro revise the spec]
67
67
  reviseSpec --> approval
68
68
 
69
69
  findings -->|One or more| ownerFindings[Owner decides every finding]
70
- ownerFindings -->|Reject all with reasons| candidate
71
- ownerFindings -->|Fix code| recordFixes[Maestro records the decisions]
72
- recordFixes --> build
73
- ownerFindings -->|Revise spec| reviseSpec
70
+ ownerFindings --> recordFindings[Maestro records all decisions]
71
+ recordFindings -->|Reject all with reasons| candidate
72
+ recordFindings -->|Fix code without spec changes| build
73
+ recordFindings -->|Spec changes| reviseSpec
74
74
 
75
75
  candidate --> summary
76
76
  summary --> review
@@ -86,13 +86,13 @@ The default path is `.specs/<spec-id>/workflow.json`. The `spec` directory is [c
86
86
 
87
87
  | Phase | Meaning |
88
88
  |---|---|
89
- | `drafting-spec` | The `owner` and `Maestro` are preparing the initial `spec`. |
89
+ | `drafting-spec` | The `owner` and `Maestro` prepare the initial `spec` or revise it after recorded `escalation` answers or `finding` decisions. |
90
90
  | `ready-for-builder` | The approved `spec` or recorded `owner` decisions permit a `builder` `run`. |
91
91
  | `builder-running` | A `builder` `run` is active. |
92
- | `escalation-decision` | The `owner` must decide how to handle every `escalation` question. |
92
+ | `escalation-decisions` | The `owner` must decide how to handle every `escalation` question. |
93
93
  | `ready-for-verifier` | The `builder` completed the work and the `verifier` can start. |
94
94
  | `verifier-running` | A `verifier` `run` is active. |
95
- | `findings-decision` | The `owner` must decide how to handle every current `finding`. |
95
+ | `finding-decisions` | The `owner` must decide how to handle every current `finding`. |
96
96
  | `candidate-ready` | The `verifier` reported no `findings`, or the `owner` rejected every `finding` with a reason. The workflow is complete. |
97
97
 
98
98
  ## Spec approval
@@ -104,7 +104,7 @@ For the initial `spec`:
104
104
  3. `Maestro` asks the `owner` to inspect the current `spec.md` and reply `GREEN FLAG` to approve it and start the `builder`.
105
105
  4. After that reply, `Maestro` saves `ready-for-builder` and starts the `builder` in the foreground.
106
106
 
107
- Approval freezes the `spec`. The `spec` and its visual prototypes remain unchanged during `builder` and `verifier` execution. `Spec` revisions are limited to the decision phases described in [Spec revision](#spec-revision).
107
+ Approval freezes the `spec`. The `spec` and its visual prototypes remain unchanged during `builder` and `verifier` execution. See [Spec revision](#spec-revision) for permitted revisions.
108
108
 
109
109
  ## Acceptance criteria
110
110
 
@@ -114,6 +114,7 @@ Each criterion contains these parts:
114
114
 
115
115
  | Part | Content |
116
116
  |---|---|
117
+ | Coverage | One label that states the scenario's purpose: `success`, `failure`, or `unchanged`. |
117
118
  | `Probe` | Starting conditions and the action or observation that checks the behavior. |
118
119
  | `Expected result` | The measurable result the `probe` observes. |
119
120
  | Example | Concrete starting conditions, an input or action, and the exact `expected result`. |
@@ -125,14 +126,17 @@ For instance a technical failure, an undefined behavior, a conflict with the `sp
125
126
 
126
127
  The `builder` saves all questions from one `pass` in the `escalations` list of its numbered `handoff`. `Maestro` identifies each question with both report and `escalation` IDs, such as `B1/E1`. See [Escalation references](glossary.md#escalation-references) for their scope.
127
128
 
128
- `Maestro` presents each question, evidence, options, consequences, and next steps. The workflow pauses in `escalation-decision` while the `owner` decides how to proceed.
129
+ `Maestro` presents each question, evidence, options, consequences, and next steps. The workflow pauses in `escalation-decisions` while the `owner` decides how to proceed.
129
130
 
130
- If the `spec` stays unchanged, the `owner` gives `Maestro` an answer and reason for every current question. The `owner` can select a listed option or give a different decision.
131
+ The `owner` gives `Maestro` an answer and reason for every current question, whether or not the `spec` must change.
132
+ The `owner` can select a listed option or give a different decision.
133
+
134
+ `Maestro` saves all answers in the current `builder` `handoff` before the workflow continues.
131
135
 
132
136
  | `Owner` choice | Result |
133
137
  |---|---|
134
- | Keep the current `spec` | `Maestro` saves all answers and reasons together in the active `builder` `handoff`, returns to `ready-for-builder`, and starts another `builder` `run`. |
135
- | Change the `spec` | The `owner` and `Maestro` revise the same `spec` and obtain renewed approval before another `builder` `run`. |
138
+ | Keep the current `spec` | `Maestro` starts another `builder` `run` without renewed approval. |
139
+ | Change the `spec` | The `owner` and `Maestro` revise the same `spec`. The `owner` reviews it and replies `GREEN FLAG` before another `builder` `run`. |
136
140
 
137
141
  `Owner` decisions update only the questions' `resolution` fields. The handoff's other content and earlier `handoffs` remain unchanged.
138
142
 
@@ -147,19 +151,27 @@ Every current `finding` requires an `owner` decision, regardless of severity. `M
147
151
  | Decision | Result |
148
152
  |---|---|
149
153
  | `reject` | Records the owner's reason. If every `finding` is rejected, the workflow reaches `candidate-ready`. |
150
- | `fix-code` | Keeps the current `spec` and returns to `ready-for-builder` for code fixes. |
154
+ | `fix-code` | Keeps the current `spec` and returns to `ready-for-builder` for code fixes when no decision requires revision. |
155
+ | `revise-spec` | Records the owner's reason and agreed requirement change, then returns to `drafting-spec`. |
151
156
 
152
- Any `fix-code` decision requires another `builder` `run`, including when other `findings` are rejected. After the `builder` completes the fixes, the `verifier` checks the work again.
157
+ `Maestro` saves every current decision together before the phase changes.
158
+ If any `finding` requires revision, revision takes priority over code fixes and rejections. See [Spec revision](#spec-revision).
153
159
 
154
- If the `spec` must change, the `owner` and `Maestro` use [Spec revision](#spec-revision) instead. Earlier `findings` then become historical context.
160
+ Without revision, any `fix-code` decision requires another `builder` `run`, including when other `findings` are rejected.
161
+ After the `builder` completes the fixes, the `verifier` checks the work again.
155
162
 
156
163
  ## Spec revision
157
164
 
158
- `Spec` revisions are allowed only in `escalation-decision` or `findings-decision`. `Maestro` revises the same `spec` with the `owner`, including its prototypes when needed.
165
+ For either `escalation` answers or `finding` decisions, `Maestro` records the complete batch before the workflow returns to `drafting-spec`.
166
+ This decision does not approve the `spec` or start an agent.
167
+ The `owner` and `Maestro` then revise the same `spec` together in `drafting-spec`.
159
168
 
160
- After review and cleanup, `Maestro` asks the `owner` to inspect the revised `spec` and reply `GREEN FLAG` again. `Maestro` then records `ready-for-builder` and starts another `builder` `run`.
169
+ The `owner` reviews the changes and replies `GREEN FLAG` again.
170
+ `Maestro` records that renewed approval separately, moves to `ready-for-builder`, and starts another `builder` `run`.
171
+ Approval is permitted only in `drafting-spec`, not directly from either decision phase.
161
172
 
162
- Previous `escalations`, `findings`, and `handoffs` remain as historical context. The revised `spec` defines the requirements for subsequent work.
173
+ The revised `spec` controls subsequent work.
174
+ Earlier `escalations`, `findings`, and their decisions remain historical context.
163
175
 
164
176
  ## Verification boundary
165
177
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emiliosp/pi-maestro",
3
- "version": "0.9.5",
3
+ "version": "0.10.1",
4
4
  "description": "A spec-driven multiagent development workflow for Pi.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -100,36 +100,15 @@ export class MaestroPaths {
100
100
  }
101
101
 
102
102
  public getSpecFilePath(specId: string): string {
103
- assertSpecId(specId);
104
-
105
- return resolve(
106
- this.projectRoot,
107
- this.specDirectoryFromRoot,
108
- specId,
109
- PATHS.SPEC_FILE,
110
- );
103
+ return resolve(this.getSpecPath(specId), PATHS.SPEC_FILE);
111
104
  }
112
105
 
113
106
  public getWorkflowPath(specId: string): string {
114
- assertSpecId(specId);
115
-
116
- return resolve(
117
- this.projectRoot,
118
- this.specDirectoryFromRoot,
119
- specId,
120
- PATHS.WORKFLOW_FILE,
121
- );
107
+ return resolve(this.getSpecPath(specId), PATHS.WORKFLOW_FILE);
122
108
  }
123
109
 
124
110
  public getHandoffsPath(specId: string): string {
125
- assertSpecId(specId);
126
-
127
- return resolve(
128
- this.projectRoot,
129
- this.specDirectoryFromRoot,
130
- specId,
131
- PATHS.HANDOFFS_PATH,
132
- );
111
+ return resolve(this.getSpecPath(specId), PATHS.HANDOFFS_PATH);
133
112
  }
134
113
 
135
114
  public getBuilderHandoffsPath(specId: string): string {
@@ -208,14 +187,7 @@ export class MaestroPaths {
208
187
  }
209
188
 
210
189
  public getPrototypesPath(specId: string): string {
211
- assertSpecId(specId);
212
-
213
- return resolve(
214
- this.projectRoot,
215
- this.specDirectoryFromRoot,
216
- specId,
217
- PATHS.PROTOTYPES_PATH,
218
- );
190
+ return resolve(this.getSpecPath(specId), PATHS.PROTOTYPES_PATH);
219
191
  }
220
192
 
221
193
  public getPrototypePath({
@@ -66,37 +66,31 @@ export function assertBuilderHandoff(
66
66
  throw new Error('Done builder handoff requires every probe to pass.');
67
67
  }
68
68
 
69
- if (handoff.status === BUILDER_HANDOFF_STATUSES.ESCALATION) {
70
- for (const [index, escalation] of handoff.escalations.entries()) {
71
- if (escalation.id !== `E${index + 1}`) {
72
- throw new Error('Escalation IDs must be sequential in array order.');
73
- }
74
-
75
- const optionIds = new Set(escalation.options.map(({ id }) => id));
76
-
77
- if (optionIds.size !== escalation.options.length) {
78
- throw new Error('Escalation option IDs must be unique.');
79
- }
80
-
81
- if (
82
- escalation.recommendation !== null &&
83
- !optionIds.has(escalation.recommendation.optionId)
84
- ) {
85
- throw new Error('Escalation recommendation references unknown option.');
86
- }
87
-
88
- if (
89
- escalation.resolution !== null &&
90
- escalation.resolution.selectedOptionId !== null &&
91
- !optionIds.has(escalation.resolution.selectedOptionId)
92
- ) {
93
- throw new Error('Escalation resolution references unknown option.');
94
- }
69
+ for (const [index, escalation] of handoff.escalations.entries()) {
70
+ if (escalation.id !== `E${index + 1}`) {
71
+ throw new Error('Escalation IDs must be sequential in array order.');
72
+ }
73
+
74
+ const optionIds = new Set(escalation.options.map(({ id }) => id));
75
+
76
+ if (optionIds.size !== escalation.options.length) {
77
+ throw new Error('Escalation option IDs must be unique.');
95
78
  }
96
- }
97
79
 
98
- if (!isValidSpecId(specId)) {
99
- throw new Error(`Invalid expected builder handoff spec ID: "${specId}".`);
80
+ if (
81
+ escalation.recommendation !== null &&
82
+ !optionIds.has(escalation.recommendation.optionId)
83
+ ) {
84
+ throw new Error('Escalation recommendation references unknown option.');
85
+ }
86
+
87
+ if (
88
+ escalation.resolution !== null &&
89
+ escalation.resolution.selectedOptionId !== null &&
90
+ !optionIds.has(escalation.resolution.selectedOptionId)
91
+ ) {
92
+ throw new Error('Escalation resolution references unknown option.');
93
+ }
100
94
  }
101
95
 
102
96
  if (handoff.specId !== specId) {
@@ -40,18 +40,17 @@ export function assertVerifierHandoff(
40
40
  throw new Error(`Invalid verifier handoff spec ID: "${handoff.specId}".`);
41
41
  }
42
42
 
43
- if (
44
- new Set(handoff.acceptanceCriteria.map((criterion) => criterion.id))
45
- .size !== handoff.acceptanceCriteria.length
46
- ) {
43
+ const acceptanceCriterionIds = new Set(
44
+ handoff.acceptanceCriteria.map((criterion) => criterion.id),
45
+ );
46
+
47
+ if (acceptanceCriterionIds.size !== handoff.acceptanceCriteria.length) {
47
48
  throw new Error(
48
49
  'Verifier handoff acceptance criterion IDs must be unique.',
49
50
  );
50
51
  }
51
52
 
52
- const acceptanceCriterionIds = new Set(
53
- handoff.acceptanceCriteria.map((criterion) => criterion.id),
54
- );
53
+ const criterionIdsWithFindings = new Set<string>();
55
54
 
56
55
  for (const [index, finding] of handoff.findings.entries()) {
57
56
  const expectedId = `F${index + 1}`;
@@ -62,26 +61,23 @@ export function assertVerifierHandoff(
62
61
  );
63
62
  }
64
63
 
65
- if (
66
- finding.acceptanceCriterion !== null &&
67
- !acceptanceCriterionIds.has(finding.acceptanceCriterion)
68
- ) {
64
+ if (finding.acceptanceCriterion === null) {
65
+ continue;
66
+ }
67
+
68
+ if (!acceptanceCriterionIds.has(finding.acceptanceCriterion)) {
69
69
  throw new Error(
70
70
  `Verifier handoff finding "${finding.id}" references unknown acceptance criterion "${finding.acceptanceCriterion}".`,
71
71
  );
72
72
  }
73
- }
74
73
 
75
- const findingCriteria = new Set(
76
- handoff.findings.flatMap((finding) =>
77
- finding.acceptanceCriterion === null ? [] : [finding.acceptanceCriterion],
78
- ),
79
- );
74
+ criterionIdsWithFindings.add(finding.acceptanceCriterion);
75
+ }
80
76
 
81
77
  for (const criterion of handoff.acceptanceCriteria) {
82
78
  if (
83
79
  criterion.probeStatus !== PROBE_STATUSES.PASSED &&
84
- !findingCriteria.has(criterion.id)
80
+ !criterionIdsWithFindings.has(criterion.id)
85
81
  ) {
86
82
  throw new Error(
87
83
  `Verifier handoff incomplete acceptance criterion "${criterion.id}" requires a finding.`,
@@ -35,10 +35,19 @@ const FindingEvidenceSchema = Type.Object(
35
35
  export const FINDING_DECISIONS = {
36
36
  REJECT: 'reject',
37
37
  FIX_CODE: 'fix-code',
38
+ REVISE_SPEC: 'revise-spec',
38
39
  } as const;
39
40
 
40
41
  const FindingDecisionSchema = Type.Union([
41
42
  Type.Null(),
43
+ Type.Object(
44
+ {
45
+ decision: Type.Literal(FINDING_DECISIONS.REVISE_SPEC),
46
+ reason: Type.String({ minLength: 1, pattern: '\\S' }),
47
+ specChange: Type.String({ minLength: 1, pattern: '\\S' }),
48
+ },
49
+ { additionalProperties: false },
50
+ ),
42
51
  Type.Object(
43
52
  {
44
53
  decision: Type.Literal(FINDING_DECISIONS.REJECT),