maestro-flow 0.4.21 → 0.4.23
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/.agents/skills/maestro-analyze/SKILL.md +78 -34
- package/.agents/skills/maestro-blueprint/SKILL.md +57 -24
- package/.agents/skills/maestro-brainstorm/SKILL.md +69 -34
- package/.agents/skills/maestro-execute/SKILL.md +45 -15
- package/.agents/skills/maestro-grill/SKILL.md +63 -38
- package/.agents/skills/maestro-init/SKILL.md +59 -17
- package/.agents/skills/maestro-milestone-audit/SKILL.md +48 -5
- package/.agents/skills/maestro-milestone-complete/SKILL.md +48 -6
- package/.agents/skills/maestro-milestone-release/SKILL.md +42 -11
- package/.agents/skills/maestro-plan/SKILL.md +19 -13
- package/.agents/skills/maestro-roadmap/SKILL.md +59 -29
- package/.agents/skills/maestro-verify/SKILL.md +46 -11
- package/.agents/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
- package/.agents/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
- package/.agents/skills/team-adversarial-swarm/scripts/aco.py +15 -15
- package/.agents/skills/team-adversarial-swarm/scripts/pheromone.py +2 -2
- package/.agents/skills/team-adversarial-swarm/scripts/scoring.py +1 -1
- package/.agents/skills/team-swarm/scripts/aco.py +15 -15
- package/.agents/skills/team-swarm/scripts/pheromone.py +2 -2
- package/.agents/skills/team-swarm/scripts/scoring.py +1 -1
- package/.agy/skills/maestro-analyze/SKILL.md +78 -34
- package/.agy/skills/maestro-blueprint/SKILL.md +57 -24
- package/.agy/skills/maestro-brainstorm/SKILL.md +69 -34
- package/.agy/skills/maestro-execute/SKILL.md +45 -15
- package/.agy/skills/maestro-grill/SKILL.md +63 -38
- package/.agy/skills/maestro-init/SKILL.md +59 -17
- package/.agy/skills/maestro-milestone-audit/SKILL.md +48 -5
- package/.agy/skills/maestro-milestone-complete/SKILL.md +48 -6
- package/.agy/skills/maestro-milestone-release/SKILL.md +42 -11
- package/.agy/skills/maestro-plan/SKILL.md +19 -13
- package/.agy/skills/maestro-roadmap/SKILL.md +59 -29
- package/.agy/skills/maestro-verify/SKILL.md +46 -11
- package/.agy/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
- package/.agy/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
- package/.agy/skills/team-adversarial-swarm/scripts/aco.py +15 -15
- package/.agy/skills/team-adversarial-swarm/scripts/pheromone.py +2 -2
- package/.agy/skills/team-adversarial-swarm/scripts/scoring.py +1 -1
- package/.agy/skills/team-swarm/scripts/aco.py +15 -15
- package/.agy/skills/team-swarm/scripts/pheromone.py +2 -2
- package/.agy/skills/team-swarm/scripts/scoring.py +1 -1
- package/.claude/commands/maestro-analyze.md +78 -34
- package/.claude/commands/maestro-blueprint.md +57 -24
- package/.claude/commands/maestro-brainstorm.md +69 -34
- package/.claude/commands/maestro-execute.md +45 -15
- package/.claude/commands/maestro-grill.md +63 -38
- package/.claude/commands/maestro-init.md +59 -17
- package/.claude/commands/maestro-milestone-audit.md +48 -5
- package/.claude/commands/maestro-milestone-complete.md +48 -6
- package/.claude/commands/maestro-milestone-release.md +42 -11
- package/.claude/commands/maestro-plan.md +19 -13
- package/.claude/commands/maestro-roadmap.md +59 -29
- package/.claude/commands/maestro-verify.md +46 -11
- package/.claude/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
- package/.claude/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
- package/.claude/skills/team-adversarial-swarm/scripts/aco.py +15 -15
- package/.claude/skills/team-adversarial-swarm/scripts/pheromone.py +2 -2
- package/.claude/skills/team-adversarial-swarm/scripts/scoring.py +1 -1
- package/.claude/skills/team-swarm/scripts/aco.py +15 -15
- package/.claude/skills/team-swarm/scripts/pheromone.py +2 -2
- package/.claude/skills/team-swarm/scripts/scoring.py +1 -1
- package/package.json +1 -1
- package/workflows/command-authoring.md +823 -0
- package/workflows/interview-mechanics.md +7 -0
|
@@ -17,6 +17,8 @@ allowed-tools:
|
|
|
17
17
|
|
|
18
18
|
<purpose>
|
|
19
19
|
Package a completed milestone into a releasable version. Bumps the project version (e.g. `package.json`, `pyproject.toml`, or language-specific manifest), generates or appends a changelog entry from phase/milestone summaries and git log, creates an annotated git tag, and optionally pushes to the remote. Runs after `/maestro-milestone-complete` has archived the milestone; serves as the final delivery step in the SDLC loop.
|
|
20
|
+
|
|
21
|
+
Pipeline position: downstream of `/maestro-milestone-complete` (consumes archived milestone + audit verdict). Terminal command — no downstream consumer.
|
|
20
22
|
</purpose>
|
|
21
23
|
|
|
22
24
|
<required_reading>
|
|
@@ -27,11 +29,14 @@ Package a completed milestone into a releasable version. Bumps the project versi
|
|
|
27
29
|
$ARGUMENTS -- optional explicit version string and flags.
|
|
28
30
|
|
|
29
31
|
**Flags:**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
|
|
33
|
+
| Flag | Effect | Default |
|
|
34
|
+
|------|--------|---------|
|
|
35
|
+
| `<version>` | Explicit version (e.g. `1.2.0`). If omitted, version is derived from `--bump` or prompted | — |
|
|
36
|
+
| `--bump patch\|minor\|major` | Semver bump relative to the current version | `minor` |
|
|
37
|
+
| `--dry-run` | Compute the next version, changelog diff, and tag name without writing files or creating tags | `false` |
|
|
38
|
+
| `--no-tag` | Skip git tag creation (version bump + changelog only) | `false` |
|
|
39
|
+
| `--no-push` | Skip `git push --follow-tags` after tagging | `false` |
|
|
35
40
|
|
|
36
41
|
**State files:**
|
|
37
42
|
- `.workflow/state.json` -- current_milestone, previous release version
|
|
@@ -45,6 +50,13 @@ $ARGUMENTS -- optional explicit version string and flags.
|
|
|
45
50
|
- Working tree must be clean (no uncommitted changes) unless `--dry-run`
|
|
46
51
|
</context>
|
|
47
52
|
|
|
53
|
+
<interview_protocol>
|
|
54
|
+
Follows @~/.maestro/workflows/interview-mechanics.md standard.
|
|
55
|
+
|
|
56
|
+
**Decision points**: version bump type (major / minor / patch / custom), changelog review and confirmation
|
|
57
|
+
**Scope guard**: only release decisions; do not prejudge next milestone scope
|
|
58
|
+
</interview_protocol>
|
|
59
|
+
|
|
48
60
|
<execution>
|
|
49
61
|
Follow '~/.maestro/workflows/milestone-release.md' completely.
|
|
50
62
|
|
|
@@ -57,7 +69,12 @@ Follow '~/.maestro/workflows/milestone-release.md' completely.
|
|
|
57
69
|
6. Create annotated git tag `v{version}` with release notes body (unless `--no-tag`)
|
|
58
70
|
7. Push commit + tag to remote (unless `--no-push`)
|
|
59
71
|
|
|
60
|
-
|
|
72
|
+
For `--dry-run`, print the computed version, changelog diff, and tag name without side effects.
|
|
73
|
+
</execution>
|
|
74
|
+
|
|
75
|
+
<completion>
|
|
76
|
+
### Standalone report
|
|
77
|
+
|
|
61
78
|
```
|
|
62
79
|
=== RELEASE COMPLETE ===
|
|
63
80
|
Version: v{previous} → v{new}
|
|
@@ -65,14 +82,28 @@ Milestone: {milestone_name}
|
|
|
65
82
|
Tag: v{new} {pushed|local-only}
|
|
66
83
|
Changelog: {N} entries written to CHANGELOG.md
|
|
67
84
|
Manifest: {file_path} updated
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Ralph-invoked completion
|
|
68
88
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
End the step by calling the CLI (no text block output):
|
|
90
|
+
```
|
|
91
|
+
maestro ralph complete <idx> --status {STATUS} [--evidence {path}]
|
|
72
92
|
```
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
|
|
94
|
+
Status verdicts:
|
|
95
|
+
- **DONE** — Normal completion
|
|
96
|
+
- **DONE_WITH_CONCERNS** — Completed with caveats; pass `--concerns`
|
|
97
|
+
- **NEEDS_RETRY** — Tooling error / transient issue; ralph will retry
|
|
98
|
+
- **BLOCKED** — External hard blocker; pass `--reason`
|
|
99
|
+
|
|
100
|
+
### Next-step routing
|
|
101
|
+
|
|
102
|
+
| Condition | Suggestion |
|
|
103
|
+
|-----------|-----------|
|
|
104
|
+
| Release successful, starting next milestone | `/maestro-plan {next_phase}` |
|
|
105
|
+
| Want to view project dashboard | `/manage-status` |
|
|
106
|
+
</completion>
|
|
76
107
|
|
|
77
108
|
<error_codes>
|
|
78
109
|
| Code | Severity | Condition | Recovery |
|
|
@@ -122,7 +122,13 @@ For each created TASK-{NNN}.json that has issue_id:
|
|
|
122
122
|
|
|
123
123
|
This ensures issue → TASK traceability. The `task_refs[]` and `task_plan_dir` fields on the issue allow the dashboard to resolve and display associated TASK details.
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
### Mode: Revise / Check
|
|
126
|
+
|
|
127
|
+
Follow workflow plan.md § "Revise Mode" and § "Check Mode" respectively. These modes bypass the standard P1-P5 create pipeline.
|
|
128
|
+
</execution>
|
|
129
|
+
|
|
130
|
+
<completion>
|
|
131
|
+
### Standalone report
|
|
126
132
|
|
|
127
133
|
```
|
|
128
134
|
=== PLAN READY ===
|
|
@@ -133,20 +139,16 @@ Collision: {collision_status}
|
|
|
133
139
|
|
|
134
140
|
Plan: scratch/{YYYYMMDD}-plan-P{N}-{slug}/plan.json
|
|
135
141
|
Tasks: scratch/{YYYYMMDD}-plan-P{N}-{slug}/.task/TASK-*.json
|
|
136
|
-
|
|
137
|
-
Next steps:
|
|
138
|
-
/maestro-execute -- Execute the plan
|
|
139
|
-
/maestro-execute --dir {dir} -- Execute specific plan
|
|
140
|
-
/maestro-plan {phase} -- Re-plan with modifications
|
|
141
142
|
```
|
|
142
143
|
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
### Ralph-invoked completion
|
|
145
|
+
|
|
146
|
+
End the step by calling the CLI (no text block output):
|
|
145
147
|
```
|
|
146
|
-
maestro ralph complete <idx> --status
|
|
148
|
+
maestro ralph complete <idx> --status {STATUS} [--evidence scratch/{YYYYMMDD}-plan-P{N}-{slug}/plan.json]
|
|
147
149
|
```
|
|
148
150
|
|
|
149
|
-
|
|
151
|
+
Status verdicts:
|
|
150
152
|
- **DONE** — Plan created/revised and confirmed → next step picks up automatically
|
|
151
153
|
- **DONE_WITH_CONCERNS** — Plan produced but with explicit caveats; pass `--concerns "..."`
|
|
152
154
|
- **NEEDS_RETRY** — Plan failed (tooling error, transient issue); ralph will retry
|
|
@@ -154,10 +156,14 @@ STATUS verdicts (CLI-enforced enum):
|
|
|
154
156
|
|
|
155
157
|
> Ambiguous requirements are NOT a completion status — resolve them in-place via `ask_question` during planning (≤3 rounds), then proceed to DONE. `NEEDS_CONTEXT` has been removed; context shortage is handled by the harness's automatic compaction.
|
|
156
158
|
|
|
157
|
-
###
|
|
159
|
+
### Next-step routing
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
| Condition | Suggestion |
|
|
162
|
+
|-----------|-----------|
|
|
163
|
+
| Plan confirmed for execution | `/maestro-execute` |
|
|
164
|
+
| Plan confirmed, specific directory | `/maestro-execute --dir {dir}` |
|
|
165
|
+
| Re-plan with modifications | `/maestro-plan {phase}` |
|
|
166
|
+
</completion>
|
|
161
167
|
|
|
162
168
|
<error_codes>
|
|
163
169
|
| Code | Severity | Condition | Recovery |
|
|
@@ -38,13 +38,16 @@ For formal specification documents (Product Brief, PRD, Architecture, Epics), us
|
|
|
38
38
|
$ARGUMENTS -- requirement text, @file reference, or upstream context source.
|
|
39
39
|
|
|
40
40
|
**Flags:**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
|
|
42
|
+
| Flag | Effect | Default |
|
|
43
|
+
|------|--------|---------|
|
|
44
|
+
| `-y` / `--yes` | Auto mode — skip interactive questions, use recommended defaults | false |
|
|
45
|
+
| `-c` / `--continue` | Resume from last checkpoint | false |
|
|
46
|
+
| `-m progressive\|direct\|auto` | Decomposition strategy | auto |
|
|
47
|
+
| `--from <source>` | Load upstream context package (brainstorm:ID, blueprint:BLP-xxx, analyze:ANL-xxx, @file, or path). Consumes context-package.json | — |
|
|
48
|
+
| `--from-brainstorm SESSION-ID` | Backward compat alias for `--from brainstorm:ID` | — |
|
|
49
|
+
| `--revise [instructions]` | Revise existing roadmap. If instructions provided, apply directly. If omitted, ask user. Preserves completed phase progress. | — |
|
|
50
|
+
| `--review` | Roadmap health assessment (read-only) | — |
|
|
48
51
|
|
|
49
52
|
**Input types:**
|
|
50
53
|
- Direct text: `"Implement user authentication system with OAuth and 2FA"`
|
|
@@ -63,24 +66,22 @@ maestro-roadmap → .workflow/roadmap.md (Milestone > Phase hierarchy)
|
|
|
63
66
|
maestro-analyze {phase} → maestro-plan → maestro-execute → maestro-verify
|
|
64
67
|
```
|
|
65
68
|
|
|
66
|
-
### Pre-load
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
### Pre-load
|
|
70
|
+
|
|
71
|
+
1. **Specs**: `maestro spec load --category arch` — load architecture constraints for phase decomposition
|
|
72
|
+
2. **Wiki search**: `maestro wiki search "{requirement keywords}" --json` → prior knowledge
|
|
73
|
+
3. All optional — proceed without if unavailable
|
|
69
74
|
</context>
|
|
70
75
|
|
|
71
76
|
<interview_protocol>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Decision points: scope (MVP / complete / phased) → strategy (progressive / direct / auto) → milestone boundaries → phase dependencies and order.
|
|
81
|
-
|
|
82
|
-
Exit: on consensus or explicit user signal to proceed, finalize the `Roadmap Decisions` section (rows already populated incrementally). Schema:
|
|
83
|
-
`| # | Decision | Choice | Source (user / code / default) |`
|
|
77
|
+
Follows @~/.maestro/workflows/interview-mechanics.md standard.
|
|
78
|
+
|
|
79
|
+
**Interaction mode**: convergent menu-driven
|
|
80
|
+
**Decision tree** (strict order): mode (create / revise / review) → requirement scope (MVP / complete / phased) → decomposition strategy (progressive / direct / auto) → milestone boundaries → phase dependencies and order
|
|
81
|
+
**Scope guard**: only roadmap shape; do not pre-resolve intra-phase task breakdown (belongs to plan)
|
|
82
|
+
**Writeback target**: .workflow/roadmap.md "Roadmap Decisions" section (create if absent)
|
|
83
|
+
**Additional skip conditions**: --revise, --review (skip to respective mode)
|
|
84
|
+
**Exit condition**: on consensus or explicit user signal → finalize Roadmap Decisions section
|
|
84
85
|
</interview_protocol>
|
|
85
86
|
|
|
86
87
|
<execution>
|
|
@@ -93,16 +94,45 @@ Sub-modes:
|
|
|
93
94
|
- **Revise** (`--revise`): Follow workflow roadmap.md "Mode: Revise" section
|
|
94
95
|
- **Review** (`--review`): Follow workflow roadmap.md "Mode: Review" section
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
</execution>
|
|
98
|
+
|
|
99
|
+
<completion>
|
|
100
|
+
### Standalone report
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
=== ROADMAP READY ===
|
|
104
|
+
Milestones: {count}
|
|
105
|
+
Phases: {total_phases}
|
|
106
|
+
Strategy: {progressive|direct|auto}
|
|
107
|
+
Output: .workflow/roadmap.md
|
|
108
|
+
--- COMPLETION STATUS ---
|
|
109
|
+
Status: {DONE|DONE_WITH_CONCERNS}
|
|
110
|
+
Concerns: {if any}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Ralph-invoked completion
|
|
114
|
+
|
|
115
|
+
End the step by calling the CLI (no text block output):
|
|
116
|
+
```
|
|
117
|
+
maestro ralph complete <idx> --status {STATUS} [--evidence {path}]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Status verdicts:
|
|
121
|
+
- **DONE** — Normal completion
|
|
122
|
+
- **DONE_WITH_CONCERNS** — Completed with caveats; pass `--concerns`
|
|
123
|
+
- **NEEDS_RETRY** — Tooling error / transient issue; ralph will retry
|
|
124
|
+
- **BLOCKED** — External hard blocker; pass `--reason`
|
|
125
|
+
|
|
126
|
+
### Next-step routing
|
|
97
127
|
|
|
98
128
|
| Condition | Suggestion |
|
|
99
129
|
|-----------|-----------|
|
|
100
|
-
| Roadmap approved, need analysis |
|
|
101
|
-
| Simple project, ready to plan |
|
|
102
|
-
| Need UI design first |
|
|
103
|
-
| View project dashboard |
|
|
104
|
-
| Need formal spec documents |
|
|
105
|
-
</
|
|
130
|
+
| Roadmap approved, need analysis | `/maestro-analyze 1` |
|
|
131
|
+
| Simple project, ready to plan | `/maestro-plan 1` |
|
|
132
|
+
| Need UI design first | `/maestro-impeccable build` |
|
|
133
|
+
| View project dashboard | `/manage-status` |
|
|
134
|
+
| Need formal spec documents | `/maestro-blueprint` |
|
|
135
|
+
</completion>
|
|
106
136
|
|
|
107
137
|
<error_codes>
|
|
108
138
|
| Code | Severity | Condition | Recovery |
|
|
@@ -39,7 +39,22 @@ Registers VRF artifact in state.json on completion.
|
|
|
39
39
|
<context>
|
|
40
40
|
$ARGUMENTS — phase number or no args for milestone-wide, with optional flags.
|
|
41
41
|
|
|
42
|
-
Flags
|
|
42
|
+
### Flags
|
|
43
|
+
|
|
44
|
+
| Flag | Effect | Default |
|
|
45
|
+
|------|--------|---------|
|
|
46
|
+
| `--skip-tests` | Skip Nyquist test coverage validation (V2), only run Goal-Backward verification | false |
|
|
47
|
+
| `--skip-antipattern` | Skip anti-pattern scan step | false |
|
|
48
|
+
| `--dir <path>` | Verify a single plan directory instead of milestone-wide | — (milestone mode) |
|
|
49
|
+
|
|
50
|
+
**Scope routing:**
|
|
51
|
+
| Input | Scope | Resolution |
|
|
52
|
+
|-------|-------|------------|
|
|
53
|
+
| `--dir scratch/{dir}` | single plan | Verify one plan, write verification.json into plan dir |
|
|
54
|
+
| numeric arg | phase | Verify all execute artifacts for that phase |
|
|
55
|
+
| no args | milestone | Aggregate all execute artifacts for current milestone |
|
|
56
|
+
|
|
57
|
+
Output paths and VRF artifact registration schema are defined in workflow `verify.md`.
|
|
43
58
|
|
|
44
59
|
### Pre-load context (before verification)
|
|
45
60
|
|
|
@@ -65,28 +80,48 @@ Follow '~/.maestro/workflows/verify.md' completely.
|
|
|
65
80
|
|
|
66
81
|
On confirm → `Skill("spec-add", "<category> <content>")`.
|
|
67
82
|
|
|
68
|
-
|
|
69
|
-
- All checks pass, no gaps → /quality-review
|
|
70
|
-
- Gaps found (must-have failures or anti-pattern blockers) → /maestro-plan --gaps
|
|
71
|
-
- Low test coverage (Nyquist gaps) → /quality-auto-test
|
|
83
|
+
</execution>
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
<completion>
|
|
86
|
+
### Standalone report
|
|
75
87
|
|
|
76
|
-
**Completion status:**
|
|
77
88
|
```
|
|
78
|
-
|
|
89
|
+
=== VERIFY COMPLETE ===
|
|
79
90
|
STATUS: DONE|DONE_WITH_CONCERNS|NEEDS_RETRY
|
|
80
91
|
CONCERNS: {description if applicable}
|
|
81
92
|
NEXT: /quality-review
|
|
82
|
-
|
|
93
|
+
=== END VERIFY ===
|
|
83
94
|
```
|
|
84
95
|
|
|
85
96
|
Status mapping:
|
|
86
97
|
- **DONE** — All checks pass, no gaps → NEXT: /quality-review
|
|
87
98
|
- **DONE_WITH_CONCERNS** — Gaps found (must-have failures or anti-pattern blockers) → NEXT: /maestro-execute (after /maestro-plan --gaps)
|
|
88
99
|
- **NEEDS_RETRY** — Verification could not complete (missing artifacts, corrupt data)
|
|
89
|
-
|
|
100
|
+
|
|
101
|
+
### Ralph-invoked completion
|
|
102
|
+
|
|
103
|
+
End the step by calling the CLI (no text block output):
|
|
104
|
+
```
|
|
105
|
+
maestro ralph complete <idx> --status {STATUS} [--evidence {path}]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Status verdicts:
|
|
109
|
+
- **DONE** — Normal completion
|
|
110
|
+
- **DONE_WITH_CONCERNS** — Completed with caveats; pass `--concerns`
|
|
111
|
+
- **NEEDS_RETRY** — Tooling error / transient issue; ralph will retry
|
|
112
|
+
- **BLOCKED** — External hard blocker; pass `--reason`
|
|
113
|
+
|
|
114
|
+
### Next-step routing
|
|
115
|
+
|
|
116
|
+
| Condition | Suggestion |
|
|
117
|
+
|-----------|-----------|
|
|
118
|
+
| All checks pass, no gaps | `/quality-review` |
|
|
119
|
+
| Gaps found (must-have failures or anti-pattern blockers) | `/maestro-plan --gaps` |
|
|
120
|
+
| Low test coverage (Nyquist gaps) | `/quality-auto-test` |
|
|
121
|
+
|
|
122
|
+
**Gap-fix closure loop:**
|
|
123
|
+
Gaps found → maestro-plan --gaps → maestro-execute → maestro-verify (re-run)
|
|
124
|
+
</completion>
|
|
90
125
|
|
|
91
126
|
<error_codes>
|
|
92
127
|
| Code | Severity | Condition | Recovery |
|
|
Binary file
|
|
Binary file
|
|
@@ -89,7 +89,7 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
89
89
|
paths = SessionPaths(Path(args.session))
|
|
90
90
|
if not paths.config.exists():
|
|
91
91
|
_fail(2, f"config not found: {paths.config}")
|
|
92
|
-
config = json.loads(paths.config.read_text())
|
|
92
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
93
93
|
|
|
94
94
|
paths.ensure_dirs()
|
|
95
95
|
|
|
@@ -107,7 +107,7 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
107
107
|
"start_nodes": config.get("task_space", {}).get("start_nodes", "any"),
|
|
108
108
|
"edges": config.get("task_space", {}).get("edges", "complete"),
|
|
109
109
|
}
|
|
110
|
-
paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False))
|
|
110
|
+
paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
111
111
|
|
|
112
112
|
# Initialize pheromone
|
|
113
113
|
aco_cfg = config.get("aco", {})
|
|
@@ -148,9 +148,9 @@ def _pick_start_node(nodes: List[str], state: PheromoneState, mode: str) -> str:
|
|
|
148
148
|
|
|
149
149
|
def cmd_select(args: argparse.Namespace) -> None:
|
|
150
150
|
paths = SessionPaths(Path(args.session))
|
|
151
|
-
config = json.loads(paths.config.read_text())
|
|
151
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
152
152
|
state = PheromoneState.load(paths.pheromone_current)
|
|
153
|
-
task_space = json.loads(paths.task_space.read_text())
|
|
153
|
+
task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
|
|
154
154
|
|
|
155
155
|
n_ants = config.get("swarm", {}).get("n_ants", 5)
|
|
156
156
|
nodes = task_space["nodes"]
|
|
@@ -190,7 +190,7 @@ def _load_iteration_artifacts(paths: SessionPaths, iteration: int) -> List[dict]
|
|
|
190
190
|
artifacts = []
|
|
191
191
|
for f in files:
|
|
192
192
|
try:
|
|
193
|
-
artifacts.append(json.loads(Path(f).read_text()))
|
|
193
|
+
artifacts.append(json.loads(Path(f).read_text(encoding="utf-8")))
|
|
194
194
|
except json.JSONDecodeError as e:
|
|
195
195
|
print(f"warning: skipped malformed artifact {f}: {e}", file=sys.stderr)
|
|
196
196
|
return artifacts
|
|
@@ -213,9 +213,9 @@ def _validate_artifact(art: dict, valid_nodes: set) -> Optional[str]:
|
|
|
213
213
|
|
|
214
214
|
def cmd_update(args: argparse.Namespace) -> None:
|
|
215
215
|
paths = SessionPaths(Path(args.session))
|
|
216
|
-
config = json.loads(paths.config.read_text())
|
|
216
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
217
217
|
state = PheromoneState.load(paths.pheromone_current)
|
|
218
|
-
task_space = json.loads(paths.task_space.read_text())
|
|
218
|
+
task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
|
|
219
219
|
valid_nodes = set(task_space["nodes"])
|
|
220
220
|
|
|
221
221
|
artifacts = _load_iteration_artifacts(paths, args.iter)
|
|
@@ -266,7 +266,7 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
266
266
|
# Elitist: re-load best history, deposit extra on best path
|
|
267
267
|
best_data = None
|
|
268
268
|
if paths.best.exists():
|
|
269
|
-
best_data = json.loads(paths.best.read_text())
|
|
269
|
+
best_data = json.loads(paths.best.read_text(encoding="utf-8"))
|
|
270
270
|
current_best = max(scored, key=lambda x: x["score"]) if scored else None
|
|
271
271
|
if current_best:
|
|
272
272
|
best_art = next(a for a in artifacts if a["ant_id"] == current_best["ant_id"])
|
|
@@ -281,7 +281,7 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
281
281
|
"evidence": best_art.get("evidence", []),
|
|
282
282
|
"updated_at": time.time(),
|
|
283
283
|
}
|
|
284
|
-
paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False))
|
|
284
|
+
paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
285
285
|
# Elite deposit
|
|
286
286
|
state.deposit(best_data["path"], best_data["score"])
|
|
287
287
|
|
|
@@ -292,14 +292,14 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
292
292
|
|
|
293
293
|
# Persist trails
|
|
294
294
|
trails_file = paths.trails / f"{args.iter}.jsonl"
|
|
295
|
-
trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log))
|
|
295
|
+
trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log), encoding="utf-8")
|
|
296
296
|
|
|
297
297
|
mean_score = sum(s["score"] for s in scored) / len(scored) if scored else 0.0
|
|
298
298
|
best_score = best_data["score"] if best_data else 0.0
|
|
299
299
|
prev_best = 0.0
|
|
300
300
|
history_files = sorted(paths.pheromone_history.glob("*.json"))
|
|
301
301
|
if len(history_files) >= 2:
|
|
302
|
-
prev = json.loads(history_files[-2].read_text())
|
|
302
|
+
prev = json.loads(history_files[-2].read_text(encoding="utf-8"))
|
|
303
303
|
prev_best = prev.get("stats", {}).get("best_known", best_score)
|
|
304
304
|
delta = best_score - prev_best
|
|
305
305
|
|
|
@@ -323,7 +323,7 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
323
323
|
|
|
324
324
|
def cmd_converged(args: argparse.Namespace) -> None:
|
|
325
325
|
paths = SessionPaths(Path(args.session))
|
|
326
|
-
config = json.loads(paths.config.read_text())
|
|
326
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
327
327
|
cv = config.get("convergence", {})
|
|
328
328
|
|
|
329
329
|
state = PheromoneState.load(paths.pheromone_current)
|
|
@@ -339,7 +339,7 @@ def cmd_converged(args: argparse.Namespace) -> None:
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
if paths.best.exists():
|
|
342
|
-
metrics["best_score"] = json.loads(paths.best.read_text()).get("score", 0.0)
|
|
342
|
+
metrics["best_score"] = json.loads(paths.best.read_text(encoding="utf-8")).get("score", 0.0)
|
|
343
343
|
|
|
344
344
|
# max_iterations
|
|
345
345
|
max_iter = cv.get("max_iterations", 5)
|
|
@@ -397,7 +397,7 @@ def cmd_report(args: argparse.Namespace) -> None:
|
|
|
397
397
|
|
|
398
398
|
best = None
|
|
399
399
|
if paths.best.exists():
|
|
400
|
-
best = json.loads(paths.best.read_text())
|
|
400
|
+
best = json.loads(paths.best.read_text(encoding="utf-8"))
|
|
401
401
|
|
|
402
402
|
# Top-K trails across all iterations
|
|
403
403
|
all_trails = []
|
|
@@ -410,7 +410,7 @@ def cmd_report(args: argparse.Namespace) -> None:
|
|
|
410
410
|
# Convergence curve
|
|
411
411
|
curve = []
|
|
412
412
|
for hf in sorted(paths.pheromone_history.glob("*.json"), key=lambda p: int(p.stem)):
|
|
413
|
-
snap = json.loads(hf.read_text())
|
|
413
|
+
snap = json.loads(hf.read_text(encoding="utf-8"))
|
|
414
414
|
curve.append({
|
|
415
415
|
"iteration": snap["iteration"],
|
|
416
416
|
"entropy": snap["stats"]["entropy"],
|
|
@@ -114,11 +114,11 @@ class PheromoneState:
|
|
|
114
114
|
|
|
115
115
|
def save(self, path: Path) -> None:
|
|
116
116
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
117
|
-
path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False))
|
|
117
|
+
path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8")
|
|
118
118
|
|
|
119
119
|
@classmethod
|
|
120
120
|
def load(cls, path: Path) -> "PheromoneState":
|
|
121
|
-
return cls.from_dict(json.loads(path.read_text()))
|
|
121
|
+
return cls.from_dict(json.loads(path.read_text(encoding="utf-8")))
|
|
122
122
|
|
|
123
123
|
def select_neighbors(
|
|
124
124
|
self,
|
|
@@ -62,7 +62,7 @@ def load_verified_scores(scores_file: Path) -> Dict[str, float]:
|
|
|
62
62
|
"""Load pre-computed verified_scores from scorer role output (if exists)."""
|
|
63
63
|
if not scores_file.exists():
|
|
64
64
|
return {}
|
|
65
|
-
data = json.loads(scores_file.read_text())
|
|
65
|
+
data = json.loads(scores_file.read_text(encoding="utf-8"))
|
|
66
66
|
return {
|
|
67
67
|
ant_id: entry["verified_score"]
|
|
68
68
|
for ant_id, entry in data.get("scores", {}).items()
|
|
@@ -89,7 +89,7 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
89
89
|
paths = SessionPaths(Path(args.session))
|
|
90
90
|
if not paths.config.exists():
|
|
91
91
|
_fail(2, f"config not found: {paths.config}")
|
|
92
|
-
config = json.loads(paths.config.read_text())
|
|
92
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
93
93
|
|
|
94
94
|
paths.ensure_dirs()
|
|
95
95
|
|
|
@@ -107,7 +107,7 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
107
107
|
"start_nodes": config.get("task_space", {}).get("start_nodes", "any"),
|
|
108
108
|
"edges": config.get("task_space", {}).get("edges", "complete"),
|
|
109
109
|
}
|
|
110
|
-
paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False))
|
|
110
|
+
paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
111
111
|
|
|
112
112
|
# Initialize pheromone
|
|
113
113
|
aco_cfg = config.get("aco", {})
|
|
@@ -148,9 +148,9 @@ def _pick_start_node(nodes: List[str], state: PheromoneState, mode: str) -> str:
|
|
|
148
148
|
|
|
149
149
|
def cmd_select(args: argparse.Namespace) -> None:
|
|
150
150
|
paths = SessionPaths(Path(args.session))
|
|
151
|
-
config = json.loads(paths.config.read_text())
|
|
151
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
152
152
|
state = PheromoneState.load(paths.pheromone_current)
|
|
153
|
-
task_space = json.loads(paths.task_space.read_text())
|
|
153
|
+
task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
|
|
154
154
|
|
|
155
155
|
n_ants = config.get("swarm", {}).get("n_ants", 5)
|
|
156
156
|
nodes = task_space["nodes"]
|
|
@@ -190,7 +190,7 @@ def _load_iteration_artifacts(paths: SessionPaths, iteration: int) -> List[dict]
|
|
|
190
190
|
artifacts = []
|
|
191
191
|
for f in files:
|
|
192
192
|
try:
|
|
193
|
-
artifacts.append(json.loads(Path(f).read_text()))
|
|
193
|
+
artifacts.append(json.loads(Path(f).read_text(encoding="utf-8")))
|
|
194
194
|
except json.JSONDecodeError as e:
|
|
195
195
|
print(f"warning: skipped malformed artifact {f}: {e}", file=sys.stderr)
|
|
196
196
|
return artifacts
|
|
@@ -213,9 +213,9 @@ def _validate_artifact(art: dict, valid_nodes: set) -> Optional[str]:
|
|
|
213
213
|
|
|
214
214
|
def cmd_update(args: argparse.Namespace) -> None:
|
|
215
215
|
paths = SessionPaths(Path(args.session))
|
|
216
|
-
config = json.loads(paths.config.read_text())
|
|
216
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
217
217
|
state = PheromoneState.load(paths.pheromone_current)
|
|
218
|
-
task_space = json.loads(paths.task_space.read_text())
|
|
218
|
+
task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
|
|
219
219
|
valid_nodes = set(task_space["nodes"])
|
|
220
220
|
|
|
221
221
|
artifacts = _load_iteration_artifacts(paths, args.iter)
|
|
@@ -266,7 +266,7 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
266
266
|
# Elitist: re-load best history, deposit extra on best path
|
|
267
267
|
best_data = None
|
|
268
268
|
if paths.best.exists():
|
|
269
|
-
best_data = json.loads(paths.best.read_text())
|
|
269
|
+
best_data = json.loads(paths.best.read_text(encoding="utf-8"))
|
|
270
270
|
current_best = max(scored, key=lambda x: x["score"]) if scored else None
|
|
271
271
|
if current_best:
|
|
272
272
|
best_art = next(a for a in artifacts if a["ant_id"] == current_best["ant_id"])
|
|
@@ -281,7 +281,7 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
281
281
|
"evidence": best_art.get("evidence", []),
|
|
282
282
|
"updated_at": time.time(),
|
|
283
283
|
}
|
|
284
|
-
paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False))
|
|
284
|
+
paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
285
285
|
# Elite deposit
|
|
286
286
|
state.deposit(best_data["path"], best_data["score"])
|
|
287
287
|
|
|
@@ -292,14 +292,14 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
292
292
|
|
|
293
293
|
# Persist trails
|
|
294
294
|
trails_file = paths.trails / f"{args.iter}.jsonl"
|
|
295
|
-
trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log))
|
|
295
|
+
trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log), encoding="utf-8")
|
|
296
296
|
|
|
297
297
|
mean_score = sum(s["score"] for s in scored) / len(scored) if scored else 0.0
|
|
298
298
|
best_score = best_data["score"] if best_data else 0.0
|
|
299
299
|
prev_best = 0.0
|
|
300
300
|
history_files = sorted(paths.pheromone_history.glob("*.json"))
|
|
301
301
|
if len(history_files) >= 2:
|
|
302
|
-
prev = json.loads(history_files[-2].read_text())
|
|
302
|
+
prev = json.loads(history_files[-2].read_text(encoding="utf-8"))
|
|
303
303
|
prev_best = prev.get("stats", {}).get("best_known", best_score)
|
|
304
304
|
delta = best_score - prev_best
|
|
305
305
|
|
|
@@ -323,7 +323,7 @@ def cmd_update(args: argparse.Namespace) -> None:
|
|
|
323
323
|
|
|
324
324
|
def cmd_converged(args: argparse.Namespace) -> None:
|
|
325
325
|
paths = SessionPaths(Path(args.session))
|
|
326
|
-
config = json.loads(paths.config.read_text())
|
|
326
|
+
config = json.loads(paths.config.read_text(encoding="utf-8"))
|
|
327
327
|
cv = config.get("convergence", {})
|
|
328
328
|
|
|
329
329
|
state = PheromoneState.load(paths.pheromone_current)
|
|
@@ -339,7 +339,7 @@ def cmd_converged(args: argparse.Namespace) -> None:
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
if paths.best.exists():
|
|
342
|
-
metrics["best_score"] = json.loads(paths.best.read_text()).get("score", 0.0)
|
|
342
|
+
metrics["best_score"] = json.loads(paths.best.read_text(encoding="utf-8")).get("score", 0.0)
|
|
343
343
|
|
|
344
344
|
# max_iterations
|
|
345
345
|
max_iter = cv.get("max_iterations", 5)
|
|
@@ -397,7 +397,7 @@ def cmd_report(args: argparse.Namespace) -> None:
|
|
|
397
397
|
|
|
398
398
|
best = None
|
|
399
399
|
if paths.best.exists():
|
|
400
|
-
best = json.loads(paths.best.read_text())
|
|
400
|
+
best = json.loads(paths.best.read_text(encoding="utf-8"))
|
|
401
401
|
|
|
402
402
|
# Top-K trails across all iterations
|
|
403
403
|
all_trails = []
|
|
@@ -410,7 +410,7 @@ def cmd_report(args: argparse.Namespace) -> None:
|
|
|
410
410
|
# Convergence curve
|
|
411
411
|
curve = []
|
|
412
412
|
for hf in sorted(paths.pheromone_history.glob("*.json"), key=lambda p: int(p.stem)):
|
|
413
|
-
snap = json.loads(hf.read_text())
|
|
413
|
+
snap = json.loads(hf.read_text(encoding="utf-8"))
|
|
414
414
|
curve.append({
|
|
415
415
|
"iteration": snap["iteration"],
|
|
416
416
|
"entropy": snap["stats"]["entropy"],
|
|
@@ -114,11 +114,11 @@ class PheromoneState:
|
|
|
114
114
|
|
|
115
115
|
def save(self, path: Path) -> None:
|
|
116
116
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
117
|
-
path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False))
|
|
117
|
+
path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8")
|
|
118
118
|
|
|
119
119
|
@classmethod
|
|
120
120
|
def load(cls, path: Path) -> "PheromoneState":
|
|
121
|
-
return cls.from_dict(json.loads(path.read_text()))
|
|
121
|
+
return cls.from_dict(json.loads(path.read_text(encoding="utf-8")))
|
|
122
122
|
|
|
123
123
|
def select_neighbors(
|
|
124
124
|
self,
|
|
@@ -62,7 +62,7 @@ def load_verified_scores(scores_file: Path) -> Dict[str, float]:
|
|
|
62
62
|
"""Load pre-computed verified_scores from scorer role output (if exists)."""
|
|
63
63
|
if not scores_file.exists():
|
|
64
64
|
return {}
|
|
65
|
-
data = json.loads(scores_file.read_text())
|
|
65
|
+
data = json.loads(scores_file.read_text(encoding="utf-8"))
|
|
66
66
|
return {
|
|
67
67
|
ant_id: entry["verified_score"]
|
|
68
68
|
for ant_id, entry in data.get("scores", {}).items()
|