@dtlabs/ai-toolkit 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
## 0.1.4 (2026-07-21)
|
|
2
|
+
## [0.24.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.23.2...v0.24.0) (2026-10-22)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **pm-phase2:** split WBS skeleton generation into phase enumeration + per-phase task generation (FTR-033) ([762684c](https://github.com/dtlab-tech/ai-toolkit/commit/762684c64aac4b3c9c9138cb6620d3c7d26146c9))
|
|
8
|
+
* **pm-phase2:** split WBS skeleton generation into phase enumeration + per-phase task generation (FTR-033) ([a817707](https://github.com/dtlab-tech/ai-toolkit/commit/a817707e7a6aaf7f9b09d51235659ef68435cd49))
|
|
9
|
+
|
|
10
|
+
## [0.23.2](https://github.com/dtlab-tech/ai-toolkit/compare/v0.23.1...v0.23.2) (2026-10-22)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **pm-phase2:** bound the WBS skeleton call's own Tech-Spec exploration ([6bca6b5](https://github.com/dtlab-tech/ai-toolkit/commit/6bca6b51f4d495b5912434f4ff83bdcefed2d979))
|
|
16
|
+
* **pm-phase2:** bound the WBS skeleton call's own Tech-Spec exploration (needsComponentDetail) ([804d2cc](https://github.com/dtlab-tech/ai-toolkit/commit/804d2ccf529e0e441b81f9e814a168a9a005a783))
|
|
17
|
+
|
|
2
18
|
## [0.23.1](https://github.com/dtlab-tech/ai-toolkit/compare/v0.23.0...v0.23.1) (2026-10-22)
|
|
3
19
|
|
|
4
20
|
|
package/lib/agent-registry.js
CHANGED
|
@@ -220,6 +220,19 @@ const CATALOG = [
|
|
|
220
220
|
deprecationTarget: null,
|
|
221
221
|
platforms: ['claude'],
|
|
222
222
|
},
|
|
223
|
+
{
|
|
224
|
+
agentId: 'gaia.agent.planner.work-breakdown-phase',
|
|
225
|
+
nativeNames: { claude: 'gaia-generate-work-breakdown-phase' },
|
|
226
|
+
relativeInstallPath: '.claude/agents/gaia-generate-work-breakdown-phase.md',
|
|
227
|
+
role: 'planner',
|
|
228
|
+
type: 'work-breakdown',
|
|
229
|
+
authorisedPhases: ['planning'],
|
|
230
|
+
allowedPipelines: ['implement-feature'],
|
|
231
|
+
minimumToolkitVersion: '0.13.0',
|
|
232
|
+
deprecated: false,
|
|
233
|
+
deprecationTarget: null,
|
|
234
|
+
platforms: ['claude'],
|
|
235
|
+
},
|
|
223
236
|
{
|
|
224
237
|
agentId: 'gaia.agent.planner.work-breakdown-task',
|
|
225
238
|
nativeNames: { claude: 'gaia-generate-work-breakdown-task' },
|
package/package.json
CHANGED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gaia-generate-work-breakdown-phase
|
|
3
|
+
description: "Generates one phase's own tasks (structural fields) and narrative context for a Work Breakdown, given that phase's scoped Requirements/Tech-Spec context and every prior phase's already-decided tasks. Input: the phase to generate, its scoped Requirements excerpt, the Tech-Spec skeleton, and prior-phase task projections"
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools: Read, Glob, Grep
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Generate Work Breakdown — Per-Phase Task Pass
|
|
9
|
+
|
|
10
|
+
You are an **expert software architect**. Given ONE phase's own scoped Requirements/Tech-Spec
|
|
11
|
+
context, decide that phase's own tasks and narrative context. A separate, lighter agent
|
|
12
|
+
(`gaia-generate-work-breakdown`) has already decided the full ORDERED list of phases (including
|
|
13
|
+
this one's own `id`/`type`/`title`/`sourceUC`/`commit`) before you were ever dispatched — you do
|
|
14
|
+
not decide that; you decompose THIS phase's own work into tasks.
|
|
15
|
+
|
|
16
|
+
## Input
|
|
17
|
+
|
|
18
|
+
Your prompt directly inlines:
|
|
19
|
+
1. **This phase's own skeleton entry** — `id`/`type`/`title`/`commit`/`sourceUC`, already decided,
|
|
20
|
+
FINAL (do not revise `sourceUC` — it already scopes the Requirements excerpt you were given).
|
|
21
|
+
2. **Scoped Requirements** — `req/index.md`'s own feature-wide content (Business Rules, Acceptance
|
|
22
|
+
Criteria table, NFRs — never per-UC-scoped) PLUS only the UC(s) THIS phase's own `sourceUC`
|
|
23
|
+
realizes (their own full flow detail). You do not need, and will not receive, any OTHER UC's
|
|
24
|
+
own flow detail.
|
|
25
|
+
3. **Tech-Spec — SKELETON ONLY**, same as every other tier in this pipeline (Section 9's
|
|
26
|
+
component index, feature-wide sections; never a component's own design body). If a task
|
|
27
|
+
decision genuinely needs a specific component's own body, see "Requesting Component Detail"
|
|
28
|
+
below — do NOT self-explore `spec/components/*` for it.
|
|
29
|
+
4. **Every PRIOR phase's own already-decided tasks** — as `id`/`title`/`outcome`/`domain` only
|
|
30
|
+
(not full task objects): use these to reference a real prerequisite in `dependsOn`, and to
|
|
31
|
+
recognize/avoid re-implementing something a prior phase already built. You will NEVER be given
|
|
32
|
+
a LATER phase's tasks — they do not exist yet; never invent a dependency on one.
|
|
33
|
+
|
|
34
|
+
## Step 0 — Read Project Conventions (MANDATORY)
|
|
35
|
+
|
|
36
|
+
Read `AGENTS.md` from the current working directory — tech stack/frameworks (domain
|
|
37
|
+
classification), directory structure (task file paths), build/verification commands. Ensures your
|
|
38
|
+
tasks reference the correct technologies, paths, and commands.
|
|
39
|
+
|
|
40
|
+
## Atomicity Contract
|
|
41
|
+
|
|
42
|
+
Every task must be the **smallest independently implementable, verifiable, and committable unit of
|
|
43
|
+
work**:
|
|
44
|
+
|
|
45
|
+
- **One observable outcome** — the task produces exactly one concrete artifact or behavioral
|
|
46
|
+
change. State it in `outcome` as a factual sentence describing what exists after the task is
|
|
47
|
+
done.
|
|
48
|
+
- **One domain** — exactly one of `BE`, `FE`, `DB`, `DevOps`, `INFRA`, `TEST`.
|
|
49
|
+
- **One agent type** — exactly one of `developer-backend`, `developer-frontend`,
|
|
50
|
+
`developer-testing`, `review-solution` (`developer-database` is deprecated — use
|
|
51
|
+
`developer-backend` for DB domain tasks).
|
|
52
|
+
- **One commit** — a single `commit.subject` describing the change.
|
|
53
|
+
- **Estimated ≤ 15 minutes of agent time** — the target. Up to 20 minutes is acceptable but above
|
|
54
|
+
target. Over 30 minutes is invalid — split the task instead.
|
|
55
|
+
|
|
56
|
+
**Anti-patterns to avoid (caught by semantic validation):**
|
|
57
|
+
- Titles or outcomes containing "N types", "all adapters", "complete CRUD", "implement and test" —
|
|
58
|
+
hidden multiplicity.
|
|
59
|
+
- Bundling two independently verifiable activities — split into separate tasks.
|
|
60
|
+
- Scope misalignment: a task that implements a behavior belonging to a different phase.
|
|
61
|
+
- **Duplicate implementation**: re-describing, as a new `BE`/`FE`/`DB` task, an outcome or file
|
|
62
|
+
already fully produced by a PRIOR phase's task (given to you in Input #4). If the behavior
|
|
63
|
+
already exists, this phase's task must be `domain: TEST` (`developer-testing`), verifying it via
|
|
64
|
+
`dependsOn` pointing at the task(s) that built it — never a second implementation task.
|
|
65
|
+
- **Domain mismatch on verification-only tasks**: a task whose outcome is a confirmation of
|
|
66
|
+
already-built behavior (title starting with "Verify", "Confirm", or similar) must be
|
|
67
|
+
`domain: TEST` / `agentType: developer-testing` — never an implementation agent type.
|
|
68
|
+
|
|
69
|
+
## Decomposition
|
|
70
|
+
|
|
71
|
+
Analyze this phase's own scoped Requirements excerpt and the Tech-Spec to identify all concrete
|
|
72
|
+
implementation tasks, following the Atomicity Contract.
|
|
73
|
+
|
|
74
|
+
| Domain | What to extract |
|
|
75
|
+
|--------|----------------|
|
|
76
|
+
| **DB** | Entity models, schema changes, migrations, seed data, indexes |
|
|
77
|
+
| **BE** | DTOs/models, validators, services, API endpoints, DI registration, mapping config |
|
|
78
|
+
| **FE** | Pages, components, route configuration, i18n keys, type definitions, API service calls |
|
|
79
|
+
| **INFRA** | Configuration, packages, manifest updates, auth/policy setup, agent definitions, scripts |
|
|
80
|
+
| **TEST** | Unit tests, integration tests, E2E tests, build verification |
|
|
81
|
+
| **DevOps** | CI/CD pipeline config, deployment scripts, infrastructure-as-code |
|
|
82
|
+
|
|
83
|
+
**Task ID format (mandatory):**
|
|
84
|
+
- If this is the INFRA phase: `INFRA-TASK-{DOMAIN}-{NN}`
|
|
85
|
+
- Otherwise: `{PHASE-ID}-TASK-{DOMAIN}-{NN}` (counter resets per phase)
|
|
86
|
+
|
|
87
|
+
`{DOMAIN}` in the task ID must match the `domain` field. `{NN}` is a two-digit zero-padded counter.
|
|
88
|
+
|
|
89
|
+
**Required task fields** — identical shape to the skeleton task entry this pipeline used before
|
|
90
|
+
FTR-033, MINUS `estimate` (produced later by `gaia-generate-work-breakdown-task`, unchanged since
|
|
91
|
+
FTR-032): `title`, `outcome`, `domain`, `agentType`, `dependsOn` (task IDs from THIS phase or any
|
|
92
|
+
PRIOR phase only — never a later one, and never a dangling reference), `acceptanceCriteria` (AC IDs
|
|
93
|
+
scoped to this phase's own `sourceUC`, never an AC owned by a different phase), `outputCount` (≥1),
|
|
94
|
+
`commit` (`{ "type": "...", "subject": "..." }`, subject with no `|`, CR, or LF).
|
|
95
|
+
|
|
96
|
+
**Domain → agentType mapping (default):** `DB`/`BE`/`INFRA`/`DevOps` → `developer-backend`;
|
|
97
|
+
`FE` → `developer-frontend`; `TEST` → `developer-testing`. Override when the Tech-Spec specifies a
|
|
98
|
+
different agent type for a task.
|
|
99
|
+
|
|
100
|
+
### Requesting Component Detail
|
|
101
|
+
|
|
102
|
+
Identical mechanism to the phase-enumeration agent's own sibling concern (and to
|
|
103
|
+
`gaia-validate-feature-docs`'s own established FTR-028 precedent): if a task decision genuinely
|
|
104
|
+
needs a specific component's own design body beyond Section 9's one-line summary, populate
|
|
105
|
+
`needsComponentDetail` with `{fileSlug, reason}` entries instead of guessing or exploring. The host
|
|
106
|
+
answers with a single, bounded second call; there is no third round. Leave it `[]` when you have
|
|
107
|
+
everything you need (the common case).
|
|
108
|
+
|
|
109
|
+
## Output
|
|
110
|
+
|
|
111
|
+
Return, as your final structured response, and nothing else:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"context": "2-4 sentences: why this phase exists, how its own tasks relate, any sequencing note. Never restate the title.",
|
|
116
|
+
"tasks": {
|
|
117
|
+
"US-01-TASK-BE-01": {
|
|
118
|
+
"title": "...", "outcome": "...", "domain": "BE", "agentType": "developer-backend",
|
|
119
|
+
"dependsOn": [], "acceptanceCriteria": ["AC-01"], "outputCount": 1,
|
|
120
|
+
"commit": { "type": "feat", "subject": "..." }
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"needsComponentDetail": []
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Every phase must have at least one task. `needsComponentDetail` is optional — omit or leave `[]`
|
|
128
|
+
in the common case.
|
|
129
|
+
|
|
130
|
+
## Guidelines
|
|
131
|
+
|
|
132
|
+
- Write in English. Derive content only from the inlined Requirements/Tech-Spec — never invent a
|
|
133
|
+
task not grounded in them.
|
|
134
|
+
- Never self-explore the filesystem for Requirements/Tech-Spec content — both are inlined.
|
|
135
|
+
- Atomicity is mandatory (see Atomicity Contract above).
|
|
136
|
+
- `dependsOn` may reference a task from this phase or any prior phase — never a later one, never a
|
|
137
|
+
dangling reference.
|
|
138
|
+
- Order tasks by layer dependency within the phase (DB → BE → FE → TEST); independent tasks in the
|
|
139
|
+
same layer may be listed in any order.
|
|
140
|
+
- `acceptanceCriteria` scoped to this phase's own UC(s) — never cite an AC owned by a different
|
|
141
|
+
phase, even for groundwork/prerequisite work; leave it empty `[]` instead.
|
|
142
|
+
- No pipes, CR, or LF in `task.title` or `commit.subject`.
|
|
@@ -1,383 +1,73 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gaia-generate-work-breakdown
|
|
3
|
-
description: "
|
|
3
|
+
description: "Enumerates the ordered phase list (no tasks) for a Work Breakdown, from validated and approved Requirements and Tech-Spec. Input: path to feature.md"
|
|
4
4
|
model: sonnet
|
|
5
|
-
tools: Read
|
|
5
|
+
tools: Read
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Generate Work Breakdown —
|
|
8
|
+
# Generate Work Breakdown — Phase Enumeration Pass
|
|
9
9
|
|
|
10
|
-
You are an **expert software architect
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
You are an **expert software architect**. Given a feature's functional requirements and technical
|
|
11
|
+
specification, decide ONLY the ordered list of phases a Work Breakdown will have — never any task.
|
|
12
|
+
A separate, per-phase agent (`gaia-generate-work-breakdown-phase`) is dispatched once per phase,
|
|
13
|
+
AFTER this call returns, to decide that phase's own tasks. You do **not** produce tasks, task
|
|
14
|
+
counts, or a phase's own narrative `context` — see that agent's own instructions for those.
|
|
15
15
|
|
|
16
16
|
## Input
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Your prompt directly inlines the content you need:
|
|
19
|
+
1. Requirements — full text, every UC's own flow detail included
|
|
20
|
+
2. Tech-Spec — SKELETON ONLY (Section 9's component index, feature-wide sections; never a
|
|
21
|
+
component's own design body)
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`{PREFIX}-Requirements.md`
|
|
23
|
-
2. Tech-Spec — `spec/index.md` (the split format, FTR-024; source of technical tasks,
|
|
24
|
-
implementation order, file inventory, architecture decisions) if it exists, otherwise the
|
|
25
|
-
legacy `{PREFIX}-Tech-Spec.md`
|
|
26
|
-
3. `{PREFIX}-Validation-Report.md` — confirms both documents passed coverage validation
|
|
27
|
-
4. `{PREFIX}-Approvals.md` — confirms user has approved the documents
|
|
23
|
+
Do NOT self-explore the filesystem for either document. The path to `feature.md` is given first;
|
|
24
|
+
Read it yourself for narrative context (Problem Statement, Core Flow) — it is small, not inlined.
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
**This agent runs ONLY after validation and human approval.** If Requirements/Tech-Spec exist in
|
|
33
|
-
neither shape, or (3)/(4) are missing, abort and report:
|
|
26
|
+
**This agent runs ONLY after validation and human approval.** If the inlined Requirements or
|
|
27
|
+
Tech-Spec text is empty or missing, abort and report:
|
|
34
28
|
```
|
|
35
|
-
Cannot generate work breakdown:
|
|
29
|
+
Cannot generate work breakdown: Requirements/Tech-Spec text was not provided.
|
|
36
30
|
The work breakdown requires validated and approved Requirements + Tech-Spec.
|
|
37
31
|
Run /implement-feature to orchestrate the full pipeline (including validation and approval gates).
|
|
38
32
|
```
|
|
39
33
|
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Step 0 — Read Project Conventions (MANDATORY)
|
|
43
|
-
|
|
44
|
-
Before generating the work breakdown, you MUST:
|
|
45
|
-
|
|
46
|
-
1. Read `AGENTS.md` from the current working directory — this defines:
|
|
47
|
-
- Tech stack and frameworks (determines domain classification)
|
|
48
|
-
- Directory structure (determines file paths in tasks)
|
|
49
|
-
- Build and verification commands
|
|
50
|
-
|
|
51
|
-
This ensures task descriptions reference the correct technologies, file paths, and verification commands.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
34
|
## Output
|
|
56
35
|
|
|
57
|
-
Extract the
|
|
58
|
-
|
|
59
|
-
- Folder: `FTR-042-Search-Engine` → prefix: `FTR-042`
|
|
60
|
-
|
|
61
|
-
The prefix is everything up to and including the second hyphen-separated segment (pattern: `[A-Z]+-[0-9]+`).
|
|
62
|
-
|
|
63
|
-
You do not have a Write tool. Return the skeleton as your final response, and nothing else — the host persists your response and splits it into `wbs/index.json` plus one `wbs/user-stories/{phaseId}.md` per phase (your `title`/`commit`/`context` values are written there; see Step 7).
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## Atomicity Contract
|
|
68
|
-
|
|
69
|
-
Every task must be the **smallest independently implementable, verifiable, and committable unit of work**. This means:
|
|
70
|
-
|
|
71
|
-
- **One observable outcome** — the task produces exactly one concrete artifact or behavioral change (one file, one endpoint, one migration, one test suite for one check). State it in the `outcome` field as a factual sentence describing what exists after the task is done.
|
|
72
|
-
- **One domain** — choose exactly one: `BE`, `FE`, `DB`, `DevOps`, `INFRA`, or `TEST`.
|
|
73
|
-
- **One agent type** — choose exactly one: `developer-backend`, `developer-frontend`, `developer-testing`, or `review-solution`. (`developer-database` is deprecated — use `developer-backend` for DB domain tasks.)
|
|
74
|
-
- **One commit** — supply a single `commit.subject` describing the change.
|
|
75
|
-
- **Estimated ≤ 15 minutes of agent time** — this is the target. If a task cannot be scoped to ≤ 15 minutes, split it further. Tasks up to 20 minutes are acceptable but above target. Tasks over 30 minutes are invalid and will be rejected by the validator.
|
|
76
|
-
|
|
77
|
-
**Anti-patterns to avoid (these will be caught by semantic validation):**
|
|
78
|
-
- Titles or outcomes containing "N types", "all adapters", "complete CRUD", "implement and test" — these indicate hidden multiplicity.
|
|
79
|
-
- Bundling two independently verifiable activities (e.g., "add endpoint and write tests") — split into separate tasks.
|
|
80
|
-
- Scope misalignment: a task in US-02 that implements a behavior belonging to US-03.
|
|
81
|
-
- **Duplicate implementation**: a later phase re-describing, as a new `BE`/`FE`/`DB` task, an outcome or file already fully produced by an earlier task (e.g., a controller task that already built audience-claim validation inline, followed by a later phase's task claiming to "implement" that same validation again). Check every earlier task's `outcome` before writing a new one for the same file or behavior. If the behavior already exists, the later phase's task must be `domain: TEST` (`developer-testing`), verifying it with `dependsOn` pointing at the task(s) that built it — never a second implementation task.
|
|
82
|
-
- **Domain mismatch on verification-only tasks**: a task whose outcome is a confirmation of already-built behavior (title starting with "Verify", "Confirm", or similar) must be `domain: TEST` / `agentType: developer-testing` — never `BE`/`FE`/`DB` with an implementation agent type.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Process
|
|
87
|
-
|
|
88
|
-
### Step 1 — Load and Cross-Reference
|
|
89
|
-
|
|
90
|
-
1. Check whether `req/index.md` exists (the split Requirements format, FTR-021). If it does:
|
|
91
|
-
- Read `req/index.md` fully — it already contains the full Use Cases index table, all Business
|
|
92
|
-
Rules, all Acceptance Criteria, and all NFRs (FTR-021 kept these feature-wide, not per-UC)
|
|
93
|
-
- For any UC whose own full flow description you need beyond the index's short Title/Actor
|
|
94
|
-
summary, Read `req/use-cases/{UC-ID}.md` directly
|
|
95
|
-
If `req/index.md` does not exist (a legacy feature), Read `{PREFIX}-Requirements.md` fully
|
|
96
|
-
instead — extract the same information from the monolithic file.
|
|
97
|
-
2. Check whether `spec/index.md` exists (the split Tech-Spec format, FTR-024). If it does:
|
|
98
|
-
- Read `spec/index.md` fully — it already contains Architecture, Section 9's complete File
|
|
99
|
-
Inventory/Components table (with Domain/Addresses routing), Implementation Order, and Risks
|
|
100
|
-
- For any component whose own Backend/Frontend/design detail you need beyond the Components
|
|
101
|
-
table's one-line Purpose/Addresses summary, Read `spec/components/{file-slug}.md` directly —
|
|
102
|
-
the `Spec` column in Section 9's table gives you the exact path
|
|
103
|
-
- If, after reading the index, you cannot determine from its own summary tables which per-item
|
|
104
|
-
files are relevant to a given phase/task decision, fall back to reading every file under
|
|
105
|
-
`spec/components/` rather than proceeding with incomplete context
|
|
106
|
-
If `spec/index.md` does not exist (a legacy feature), Read `{PREFIX}-Tech-Spec.md` fully
|
|
107
|
-
instead — extract architecture, file inventory, implementation order, data model, API
|
|
108
|
-
endpoints, frontend components from the monolithic file.
|
|
109
|
-
|
|
110
|
-
### Step 2 — Derive User Stories from Use Cases
|
|
111
|
-
|
|
112
|
-
Map each Use Case to a User Story using this transformation:
|
|
113
|
-
|
|
114
|
-
| Requirements (UC) | Work Breakdown (US) |
|
|
115
|
-
|---|---|
|
|
116
|
-
| UC-01: [Title] | US-01: [Title] |
|
|
117
|
-
| UC-02: [Title] | US-02: [Title] |
|
|
118
|
-
|
|
119
|
-
For each US, derive:
|
|
120
|
-
- **Phase id** — `US-NN` matching the UC (e.g., `US-01`)
|
|
121
|
-
- **Phase title** — the UC title
|
|
122
|
-
- **Phase type** — `"user-story"`
|
|
123
|
-
- **Phase commit** — a phase-level commit object: `{ "type": "feat", "subject": "implement US-NN title" }` — the subject must not contain `|`, CR, or LF characters; `wb-render.js` prepends the conventional prefix automatically
|
|
124
|
-
- **Phase `sourceUC`** — the UC-ID(s) this phase actually realizes (array). Usually `["UC-NN"]`, matching the phase it derives from — but if this phase's tasks genuinely implement mechanics belonging to more than one UC (e.g. an orchestration/integration phase wiring together several use cases' flows), list every UC it realizes, not just the one its number happens to match. Conversely, if one UC's mechanics are split across more than one phase (e.g. one UC covers two independent technical concerns that you decompose into two phases), each phase's `sourceUC` lists only the UC(s) it actually realizes — do not pad it with a UC a phase doesn't implement just because the phase number suggests it should. **Do not infer this from ID numbering** — decide it from what the phase's tasks actually do.
|
|
125
|
-
- **Acceptance Criteria** — the AC-XX IDs from the Requirements document that apply to this US
|
|
126
|
-
|
|
127
|
-
**Do not create an additional phase for end-to-end, integration, or overall verification.** Every phase traces to exactly one UC (plus the single `INFRA` phase for shared setup) — never a synthesized "Testing and verification", "Integration tests", or similarly feature-spanning phase. An integration/E2E test still belongs to the US phase of the UC it most directly verifies, as a `domain: TEST` task citing only that phase's own AC(s) — not a phase of its own, and not a grab-bag of ACs borrowed from across the feature.
|
|
128
|
-
|
|
129
|
-
### Step 3 — Decompose into Tasks
|
|
130
|
-
|
|
131
|
-
For each User Story (and for shared infrastructure), analyze the Tech-Spec to identify all concrete implementation tasks following the Atomicity Contract above.
|
|
132
|
-
|
|
133
|
-
Decomposition strategy by domain:
|
|
134
|
-
|
|
135
|
-
| Domain | What to extract |
|
|
136
|
-
|--------|----------------|
|
|
137
|
-
| **DB** | Entity models, schema changes, migrations, seed data, indexes |
|
|
138
|
-
| **BE** | DTOs/models, validators, services (interface + implementation), API endpoints, DI registration, mapping config |
|
|
139
|
-
| **FE** | Pages, components, route configuration, i18n keys, type definitions, API service calls |
|
|
140
|
-
| **INFRA** | Configuration (env vars, settings), packages, manifest updates, auth/policy setup, agent definitions, scripts |
|
|
141
|
-
| **TEST** | Unit tests, integration tests, E2E tests, build verification |
|
|
142
|
-
| **DevOps** | CI/CD pipeline config, deployment scripts, infrastructure-as-code |
|
|
143
|
-
|
|
144
|
-
**Task ID format (mandatory — wrong format is a validator error):**
|
|
145
|
-
- Infrastructure tasks: `INFRA-TASK-{DOMAIN}-{NN}` — globally unique at feature level (e.g., `INFRA-TASK-BE-01`, `INFRA-TASK-INFRA-02`)
|
|
146
|
-
- User Story tasks: `{US-ID}-TASK-{DOMAIN}-{NN}` — counter resets per US; US prefix disambiguates at feature level (e.g., `US-01-TASK-BE-01`, `US-02-TASK-DB-01`)
|
|
147
|
-
|
|
148
|
-
`{DOMAIN}` in the task ID must match the `domain` field. `{NN}` is a two-digit zero-padded counter.
|
|
149
|
-
|
|
150
|
-
**Required task fields (this pass — the skeleton):**
|
|
151
|
-
|
|
152
|
-
| Field | Type | Constraint |
|
|
153
|
-
|-------|------|-----------|
|
|
154
|
-
| `title` | string | Short descriptive title; must not contain `\|`, CR, or LF |
|
|
155
|
-
| `outcome` | string | Single observable outcome — what exists after this task is done |
|
|
156
|
-
| `domain` | string | One of: `BE`, `FE`, `DB`, `DevOps`, `INFRA`, `TEST` |
|
|
157
|
-
| `agentType` | string | One of: `developer-backend`, `developer-frontend`, `developer-testing`, `review-solution` (deprecated: `developer-database` — maps to `developer-backend`) |
|
|
158
|
-
| `dependsOn` | array of strings | Task IDs this task depends on; may be empty `[]`; all IDs must be defined within this same response |
|
|
159
|
-
| `acceptanceCriteria` | array of strings | AC IDs from Requirements scoped to this task's own phase that this task covers; may be empty `[]`. Never an AC owned by a different phase (see Guidelines) |
|
|
160
|
-
| `estimate` | object | `{ "agentMinutes": N, "tokens": N }` — target ≤ 15 minutes; positive integers |
|
|
161
|
-
| `outputCount` | integer | Number of distinct outputs; must be ≥ 1 |
|
|
162
|
-
| `commit` | object | `{ "type": "feat", "subject": "..." }` — subject must not contain `\|`, CR, or LF |
|
|
163
|
-
|
|
164
|
-
`verification.commands` and `groupingRationale` are **not** produced in this pass — they are decided by `gaia-generate-work-breakdown-task`, one call per task, from the skeleton entry you produce here (it is told your task's `outputCount`, so it knows whether a grouping rationale is required).
|
|
165
|
-
|
|
166
|
-
**Domain → agentType mapping (default):**
|
|
167
|
-
- `DB` → `developer-backend` (note: `developer-database` is a deprecated alias that still resolves — do NOT use it in new Work Breakdowns)
|
|
168
|
-
- `BE`, `INFRA`, `DevOps` → `developer-backend`
|
|
169
|
-
- `FE` → `developer-frontend`
|
|
170
|
-
- `TEST` → `developer-testing`
|
|
171
|
-
|
|
172
|
-
The mapping above is a default; override when the Tech-Spec specifies a different agent type for a task.
|
|
173
|
-
|
|
174
|
-
### Step 4 — Identify Shared Infrastructure Tasks
|
|
175
|
-
|
|
176
|
-
Some tasks are prerequisites for multiple User Stories. Extract these into a dedicated INFRA phase with:
|
|
177
|
-
- Phase `id`: `"INFRA"`
|
|
178
|
-
- Phase `type`: `"infrastructure"`
|
|
179
|
-
- Phase `title`: descriptive (e.g., `"Shared infrastructure setup"`)
|
|
180
|
-
- Phase `commit`: a phase-level commit (e.g., `{ "type": "feat", "subject": "shared infrastructure" }`)
|
|
181
|
-
- Phase `sourceUC`: `[]` — shared infrastructure has no single originating UC, by definition
|
|
182
|
-
- Task IDs: `INFRA-TASK-{DOMAIN}-{NN}`
|
|
183
|
-
|
|
184
|
-
Examples of infrastructure tasks:
|
|
185
|
-
- Database context/schema registration (needed by all DB tasks)
|
|
186
|
-
- Base model/validator infrastructure (needed by all BE tasks)
|
|
187
|
-
- Auth policy setup (needed by all endpoints)
|
|
188
|
-
- Route configuration (needed by all FE pages)
|
|
189
|
-
- Shared scripts, constants, or fixtures used across multiple USs
|
|
190
|
-
|
|
191
|
-
The INFRA phase, if present, must appear first in the `phases` array.
|
|
192
|
-
|
|
193
|
-
### Step 5 — Resolve Dependencies
|
|
194
|
-
|
|
195
|
-
For each task, determine `dependsOn` as a list of **task IDs** (not phase IDs):
|
|
196
|
-
- All referenced task IDs must be defined within this same response (no dangling references)
|
|
197
|
-
- A task may reference both INFRA tasks and tasks within its own phase or other US phases
|
|
198
|
-
- No self-references (a task cannot depend on itself)
|
|
199
|
-
- No cycles (A → B → A is invalid)
|
|
200
|
-
|
|
201
|
-
**Tip:** List only direct dependencies. Transitive dependencies are implied.
|
|
202
|
-
|
|
203
|
-
### Step 6 — Estimate
|
|
204
|
-
|
|
205
|
-
For each task, provide:
|
|
206
|
-
- `estimate.agentMinutes`: integer; **target ≤ 15**; above 30 is rejected by the validator
|
|
207
|
-
|
|
208
|
-
Duration guidance:
|
|
209
|
-
| Band | Range | Action |
|
|
210
|
-
|------|-------|--------|
|
|
211
|
-
| Target | ≤ 15 min | No action needed |
|
|
212
|
-
| Above target | 16–20 min | Acceptable |
|
|
213
|
-
| Warning | 21–30 min | Prefer to split |
|
|
214
|
-
| Split required | > 30 min | **Must split** — the validator will reject this |
|
|
215
|
-
|
|
216
|
-
- `estimate.tokens`: integer; rough estimate of token consumption (input + output) for the agent invocation; use project norms if available, otherwise estimate based on task complexity (small: 10 000–25 000, medium: 25 000–60 000)
|
|
217
|
-
|
|
218
|
-
### Step 7 — Return the Skeleton
|
|
219
|
-
|
|
220
|
-
Return the skeleton's content as your final response, and nothing else (no preamble, no explanatory prose, no Markdown code fence wrapping it) — you do not have a Write tool; the host persists your response. The content must be:
|
|
221
|
-
- Valid JSON
|
|
222
|
-
- UTF-8 encoded
|
|
223
|
-
- 2-space indentation
|
|
224
|
-
- Conform to the schema below
|
|
225
|
-
|
|
226
|
-
**Top-level structure:**
|
|
36
|
+
Extract the feature prefix from the folder name containing `feature.md` (pattern `[A-Z]+-[0-9]+`).
|
|
37
|
+
Return, as your final structured response, and nothing else:
|
|
227
38
|
|
|
228
39
|
```json
|
|
229
40
|
{
|
|
230
41
|
"schemaVersion": 3,
|
|
231
42
|
"feature": "{PREFIX}",
|
|
232
|
-
"phases": [ ... ],
|
|
233
|
-
"tasks": { ... }
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
- `schemaVersion` must be exactly `3` (integer)
|
|
238
|
-
- `feature` must be the feature prefix string (e.g., `"FTR-020"`)
|
|
239
|
-
- `phases` is an ordered array of phase objects; INFRA phase first (if present), then US phases in priority order
|
|
240
|
-
- `tasks` is a **map keyed by task ID** (not nested inside each phase) — every phase's `taskIds` array indexes into this map
|
|
241
|
-
|
|
242
|
-
**Phase object:**
|
|
243
|
-
|
|
244
|
-
```json
|
|
245
|
-
{
|
|
246
|
-
"id": "INFRA",
|
|
247
|
-
"type": "infrastructure",
|
|
248
|
-
"title": "Shared infrastructure setup",
|
|
249
|
-
"commit": { "type": "feat", "subject": "shared infrastructure" },
|
|
250
|
-
"sourceUC": [],
|
|
251
|
-
"context": "2-4 sentences: why this phase exists, how its own tasks relate to each other, and any dependency/sequencing reason other phases need to know before opening this phase's task files. Never restate the title.",
|
|
252
|
-
"taskIds": ["INFRA-TASK-BE-01"]
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
For user-story phases:
|
|
257
|
-
|
|
258
|
-
```json
|
|
259
|
-
{
|
|
260
|
-
"id": "US-01",
|
|
261
|
-
"type": "user-story",
|
|
262
|
-
"title": "As a... I want... so that...",
|
|
263
|
-
"commit": { "type": "feat", "subject": "implement US-01 user management" },
|
|
264
|
-
"sourceUC": ["UC-01"],
|
|
265
|
-
"context": "2-4 sentences: why this phase exists, how its own tasks relate to each other, and any dependency/sequencing reason other phases need to know before opening this phase's task files. Never restate the title.",
|
|
266
|
-
"taskIds": ["US-01-TASK-DB-01", "US-01-TASK-BE-01"]
|
|
267
|
-
}
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
- `phase.commit.subject` must not contain `|`, CR, or LF — `wb-render.js` constructs the full conventional message from it
|
|
271
|
-
- `phase.context` is persisted verbatim into this phase's own `wbs/user-stories/{id}.md` detail file (the host does not re-derive or summarize it) — it is the one piece of phase-detail content that genuinely needs your judgment; "Tasks in this phase" and "Depends on phases" are both derived mechanically by the host from `taskIds`/each task's own `title`/`dependsOn`, so do not restate those here
|
|
272
|
-
- Each phase must have at least one task
|
|
273
|
-
|
|
274
|
-
**Task entry (in the `tasks` map, keyed by its own ID):**
|
|
275
|
-
|
|
276
|
-
```json
|
|
277
|
-
{
|
|
278
|
-
"title": "Create base repository interface",
|
|
279
|
-
"outcome": "IRepository<T> interface exists at src/interfaces/IRepository.ts with CRUD method signatures",
|
|
280
|
-
"domain": "BE",
|
|
281
|
-
"agentType": "developer-backend",
|
|
282
|
-
"dependsOn": [],
|
|
283
|
-
"acceptanceCriteria": [],
|
|
284
|
-
"estimate": { "agentMinutes": 8, "tokens": 15000 },
|
|
285
|
-
"outputCount": 1,
|
|
286
|
-
"commit": { "type": "feat", "subject": "add IRepository base interface" }
|
|
287
|
-
}
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**Full example response:**
|
|
291
|
-
|
|
292
|
-
```json
|
|
293
|
-
{
|
|
294
|
-
"schemaVersion": 3,
|
|
295
|
-
"feature": "FTR-NNN",
|
|
296
43
|
"phases": [
|
|
297
|
-
{
|
|
298
|
-
"
|
|
299
|
-
|
|
300
|
-
"
|
|
301
|
-
|
|
302
|
-
"sourceUC": [],
|
|
303
|
-
"context": "Shared repository interface every other phase's data-access tasks depend on — opened first so downstream phases never block on it later.",
|
|
304
|
-
"taskIds": ["INFRA-TASK-BE-01"]
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
"id": "US-01",
|
|
308
|
-
"type": "user-story",
|
|
309
|
-
"title": "As an admin, I want to create a user, so that new members can access the system",
|
|
310
|
-
"commit": { "type": "feat", "subject": "implement US-01 user creation" },
|
|
311
|
-
"sourceUC": ["UC-01"],
|
|
312
|
-
"context": "Covers the full create-user path end to end: the entity/migration task establishes storage, the service task implements validation and persistence on top of it.",
|
|
313
|
-
"taskIds": ["US-01-TASK-DB-01", "US-01-TASK-BE-01"]
|
|
314
|
-
}
|
|
315
|
-
],
|
|
316
|
-
"tasks": {
|
|
317
|
-
"INFRA-TASK-BE-01": {
|
|
318
|
-
"title": "Create base repository interface",
|
|
319
|
-
"outcome": "IRepository<T> interface exists at src/interfaces/IRepository.ts with CRUD method signatures",
|
|
320
|
-
"domain": "BE",
|
|
321
|
-
"agentType": "developer-backend",
|
|
322
|
-
"dependsOn": [],
|
|
323
|
-
"acceptanceCriteria": [],
|
|
324
|
-
"estimate": { "agentMinutes": 8, "tokens": 15000 },
|
|
325
|
-
"outputCount": 1,
|
|
326
|
-
"commit": { "type": "feat", "subject": "add IRepository base interface" }
|
|
327
|
-
},
|
|
328
|
-
"US-01-TASK-DB-01": {
|
|
329
|
-
"title": "Create User entity and migration",
|
|
330
|
-
"outcome": "User entity class and initial migration exist; database table is created on migration run",
|
|
331
|
-
"domain": "DB",
|
|
332
|
-
"agentType": "developer-backend",
|
|
333
|
-
"dependsOn": ["INFRA-TASK-BE-01"],
|
|
334
|
-
"acceptanceCriteria": ["AC-01", "AC-03"],
|
|
335
|
-
"estimate": { "agentMinutes": 12, "tokens": 28000 },
|
|
336
|
-
"outputCount": 1,
|
|
337
|
-
"commit": { "type": "feat", "subject": "add User entity and migration" }
|
|
338
|
-
},
|
|
339
|
-
"US-01-TASK-BE-01": {
|
|
340
|
-
"title": "Implement CreateUserService",
|
|
341
|
-
"outcome": "CreateUserService class exists with createUser method; validates input, persists User, returns created entity",
|
|
342
|
-
"domain": "BE",
|
|
343
|
-
"agentType": "developer-backend",
|
|
344
|
-
"dependsOn": ["US-01-TASK-DB-01"],
|
|
345
|
-
"acceptanceCriteria": ["AC-02"],
|
|
346
|
-
"estimate": { "agentMinutes": 14, "tokens": 35000 },
|
|
347
|
-
"outputCount": 1,
|
|
348
|
-
"commit": { "type": "feat", "subject": "add CreateUserService" }
|
|
349
|
-
}
|
|
350
|
-
}
|
|
44
|
+
{ "id": "INFRA", "type": "infrastructure", "title": "Shared infrastructure setup",
|
|
45
|
+
"commit": { "type": "feat", "subject": "shared infrastructure" }, "sourceUC": [] },
|
|
46
|
+
{ "id": "US-01", "type": "user-story", "title": "As an admin, I want...",
|
|
47
|
+
"commit": { "type": "feat", "subject": "implement US-01 ..." }, "sourceUC": ["UC-01"] }
|
|
48
|
+
]
|
|
351
49
|
}
|
|
352
50
|
```
|
|
353
51
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
2. Concrete options (2–4) representing reasonable decomposition choices
|
|
362
|
-
3. **Always include** an option: "Leave as open point to discuss later"
|
|
363
|
-
|
|
364
|
-
Do NOT guess or invent task decompositions when the source is unclear. Ask first, then continue.
|
|
365
|
-
|
|
366
|
-
---
|
|
52
|
+
- Map each Use Case to a User Story phase (`US-NN` matching the UC by default; see Guidelines
|
|
53
|
+
below for when `sourceUC` legitimately diverges from the number).
|
|
54
|
+
- INFRA phase (if shared prerequisites exist across multiple User Stories) appears first, with
|
|
55
|
+
`sourceUC: []`.
|
|
56
|
+
- **Do not create an additional phase for end-to-end, integration, or overall verification** —
|
|
57
|
+
every phase traces to exactly one UC's worth of work (plus the single INFRA phase).
|
|
58
|
+
- `commit.subject` must not contain `|`, CR, or LF.
|
|
367
59
|
|
|
368
60
|
## Guidelines
|
|
369
61
|
|
|
370
|
-
-
|
|
371
|
-
|
|
372
|
-
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
-
|
|
378
|
-
|
|
379
|
-
-
|
|
380
|
-
-
|
|
381
|
-
|
|
382
|
-
- **No pipes, CR, or LF** in `phase.title`, `task.title`, or `commit.subject` — these characters break CSV generation
|
|
383
|
-
- **Traceability**: every UC must map to a US phase; every Must-priority AC must be covered by at least one task's `acceptanceCriteria` **within that AC's own owning US phase** (per its "Related UC" scope) — not by a task in an earlier or later phase, even one that contributes toward satisfying it eventually
|
|
62
|
+
- Derive every phase from the Requirements and Tech-Spec — do not invent a phase not grounded in
|
|
63
|
+
them.
|
|
64
|
+
- `sourceUC` must reflect what a phase's own (eventual) tasks will actually implement, not its
|
|
65
|
+
number — if a phase's work spans more than one UC, or a UC's own work is split across more than
|
|
66
|
+
one phase, decide `sourceUC` from the REAL decomposition, not ID numbering. This decision is
|
|
67
|
+
FINAL: `sourceUC` is handed to the per-phase agent as a fixed input (it scopes that phase's own
|
|
68
|
+
Requirements excerpt) and cannot be revised downstream — get it right here.
|
|
69
|
+
- INFRA phase first (if present), then US phases in priority order (Must before Should before
|
|
70
|
+
Could).
|
|
71
|
+
- `schemaVersion` must be exactly `3`.
|
|
72
|
+
- Write in English. No pipes, CR, or LF in `title` or `commit.subject` — these break CSV
|
|
73
|
+
generation downstream.
|
|
@@ -5,33 +5,40 @@ export const meta = {
|
|
|
5
5
|
phases: [{ title: 'Work Breakdown' }, { title: 'Effort Estimate' }],
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
// ──
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
|
|
8
|
+
// ── Phase-enumeration + per-phase JSON schemas (FTR-033) ─────────────────────
|
|
9
|
+
// FTR-033 splits the single monolithic skeleton call (deciding the ENTIRE feature's task graph in
|
|
10
|
+
// one turn — confirmed to fail reliably at real feature scale, independent of prompt size or
|
|
11
|
+
// dispatch mechanism) into two bounded tiers: enumeration (this schema) decides only the ordered
|
|
12
|
+
// phase list; PHASE_TASKS_SCHEMA below decides one phase's own tasks per call.
|
|
13
|
+
const PHASE_ENUMERATION_SCHEMA = {
|
|
13
14
|
type: 'object',
|
|
14
|
-
required: ['schemaVersion', 'feature', 'phases'
|
|
15
|
+
required: ['schemaVersion', 'feature', 'phases'],
|
|
15
16
|
properties: {
|
|
16
17
|
schemaVersion: { const: 3 },
|
|
17
18
|
feature: { type: 'string' },
|
|
18
19
|
phases: { type: 'array', items: {
|
|
19
20
|
type: 'object',
|
|
20
|
-
required: ['id', 'type', 'title', 'commit', 'sourceUC'
|
|
21
|
+
required: ['id', 'type', 'title', 'commit', 'sourceUC'],
|
|
21
22
|
properties: {
|
|
22
23
|
id: { type: 'string' }, type: { enum: ['infrastructure', 'user-story'] },
|
|
23
24
|
title: { type: 'string' },
|
|
24
25
|
commit: { type: 'object', required: ['type', 'subject'],
|
|
25
26
|
properties: { type: { type: 'string' }, subject: { type: 'string' } } },
|
|
26
27
|
sourceUC: { type: 'array', items: { type: 'string' } },
|
|
27
|
-
// 2-4 sentences: why this phase exists, how its tasks relate, any sequencing note other
|
|
28
|
-
// phases/tasks need before opening this phase's own task files — the one part of the
|
|
29
|
-
// FTR-020 phase-detail template that genuinely needs narrative judgment, not something
|
|
30
|
-
// the host can derive mechanically the way it does Source UC/Tasks-in-phase/Depends-on.
|
|
31
|
-
context: { type: 'string' },
|
|
32
|
-
taskIds: { type: 'array', items: { type: 'string' } },
|
|
33
28
|
},
|
|
34
29
|
} },
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const PHASE_TASKS_SCHEMA = {
|
|
34
|
+
type: 'object',
|
|
35
|
+
required: ['context', 'tasks'],
|
|
36
|
+
properties: {
|
|
37
|
+
// 2-4 sentences: why this phase exists, how its tasks relate, any sequencing note other
|
|
38
|
+
// phases/tasks need before opening this phase's own task files — the one part of the
|
|
39
|
+
// FTR-020 phase-detail template that genuinely needs narrative judgment, not something
|
|
40
|
+
// the host can derive mechanically the way it does Source UC/Tasks-in-phase/Depends-on.
|
|
41
|
+
context: { type: 'string' },
|
|
35
42
|
tasks: { type: 'object', additionalProperties: {
|
|
36
43
|
type: 'object',
|
|
37
44
|
required: ['title', 'outcome', 'domain', 'agentType', 'dependsOn',
|
|
@@ -56,22 +63,78 @@ const SKELETON_SCHEMA = {
|
|
|
56
63
|
properties: { type: { type: 'string' }, subject: { type: 'string' } } },
|
|
57
64
|
},
|
|
58
65
|
} },
|
|
66
|
+
// Bounded drill-down (mirrors pm-phase1.js's own needsComponentDetail precedent for the
|
|
67
|
+
// feature-doc validator, FTR-028) — declared in `properties` only, never `required`: the
|
|
68
|
+
// common case is an empty array, costing nothing extra. See
|
|
69
|
+
// gaia-generate-work-breakdown-phase.md's own "Requesting Component Detail" section for when
|
|
70
|
+
// the agent should populate this instead of self-exploring spec/components/* (the real,
|
|
71
|
+
// evidenced dominant cost driver on a large feature — confirmed against a real run: 1.18M of
|
|
72
|
+
// 1.38M total tokens on one failing attempt were cache_read_input_tokens, not the declared
|
|
73
|
+
// output schema size). FTR-033: available per-phase, not at the enumeration tier — phase-level
|
|
74
|
+
// decisions (id/type/title/sourceUC/commit) never need a component's own design body.
|
|
75
|
+
needsComponentDetail: { type: 'array', items: { type: 'object',
|
|
76
|
+
properties: { fileSlug: { type: 'string' }, reason: { type: 'string' } }, required: ['fileSlug'] } },
|
|
59
77
|
},
|
|
60
78
|
}
|
|
61
79
|
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
// Fixed, not externally configurable (same "no real evidence yet justifies external tuning"
|
|
81
|
+
// precedent as every other bounded retry/batch constant in this codebase) — a safety cap, not a
|
|
82
|
+
// typical case; the skeleton agent's own instructions already frame needsComponentDetail as the
|
|
83
|
+
// exception, reserved for a genuine per-task decision gap, not a substitute for broad exploration.
|
|
84
|
+
const SKELETON_DRILL_DOWN_MAX_COMPONENTS = 20
|
|
85
|
+
|
|
86
|
+
// Builds the phase-enumeration prompt: Requirements FULL text + Tech-Spec SKELETON ONLY
|
|
87
|
+
// (never per-component bodies) inlined directly, mirroring pm-phase1.js's own
|
|
88
|
+
// gaia-validate-feature-docs prompt shape exactly — the agent no longer self-reads either
|
|
89
|
+
// document or any per-item file via its own Read/Glob/Grep tool access. No drillDownText
|
|
90
|
+
// parameter — the enumeration call never declares needsComponentDetail (FTR-033: phase-level
|
|
91
|
+
// decisions never need a component's own design body; that mechanism now lives only at the
|
|
92
|
+
// per-phase tier, see buildPhaseTaskPrompt below).
|
|
93
|
+
function buildPhaseEnumerationPrompt(featurePath, requirementsText, techSpecSkeletonText) {
|
|
94
|
+
return [
|
|
95
|
+
featurePath,
|
|
96
|
+
'',
|
|
97
|
+
'Requirements:',
|
|
98
|
+
requirementsText,
|
|
99
|
+
'',
|
|
100
|
+
'Tech-Spec:',
|
|
101
|
+
techSpecSkeletonText,
|
|
102
|
+
].join('\n')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Validates each needsComponentDetail entry's fileSlug against the real component table (a
|
|
106
|
+
// hallucinated/mistyped reference is dropped, never dispatched — mirrors pm-phase1.js's own
|
|
107
|
+
// prepareDrillDownBatches), deduplicates by fileSlug, and caps the total at
|
|
108
|
+
// SKELETON_DRILL_DOWN_MAX_COMPONENTS. Returns the inlinable text block (or null if nothing valid
|
|
109
|
+
// remains) — this reads files directly (deterministic, free), never dispatches another agent.
|
|
110
|
+
function buildComponentDrillDownText(needsComponentDetail, specIndexContent, specDirArg) {
|
|
111
|
+
const components = parseComponentsTableLocal(specIndexContent)
|
|
112
|
+
const bySlug = new Map(components.map(c => [c.fileSlug, c]))
|
|
113
|
+
const uniqueSlugs = [...new Set((needsComponentDetail || [])
|
|
114
|
+
.map(e => e.fileSlug)
|
|
115
|
+
.filter(slug => bySlug.has(slug)))]
|
|
116
|
+
.slice(0, SKELETON_DRILL_DOWN_MAX_COMPONENTS)
|
|
117
|
+
if (uniqueSlugs.length === 0) return null
|
|
118
|
+
return uniqueSlugs.map(slug => {
|
|
119
|
+
const comp = bySlug.get(slug)
|
|
120
|
+
return `### ${comp.filePath} (${slug})\n\n${c.read(`${specDirArg}/components/${slug}`)}`
|
|
121
|
+
}).join('\n\n---\n\n')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Materializes the enumeration response into index.json's structural, map-keyed shape.
|
|
125
|
+
// FTR-033 (BR-09): title/commit ARE additively persisted here (unlike the old materializeIndex,
|
|
126
|
+
// which deliberately left them out, OQ-04) — a resumed run between phase-enumeration and the last
|
|
127
|
+
// phase's completion must be able to re-render any EARLIER-but-already-completed phase's own
|
|
128
|
+
// detail file (which needs title/commit) without re-calling the phase-enumeration agent.
|
|
129
|
+
// `context` is still NOT persisted here — it is only known once that phase's own per-phase call
|
|
130
|
+
// returns, and is rendered straight to the phase's detail file at that point (see the per-phase
|
|
131
|
+
// loop below), same "render immediately, don't round-trip through index.json" principle as before.
|
|
132
|
+
function materializeEnumeratedPhases(phaseList) {
|
|
133
|
+
const phases = phaseList.phases.map(p => ({
|
|
134
|
+
id: p.id, type: p.type, title: p.title, commit: p.commit, sourceUC: p.sourceUC,
|
|
135
|
+
detailFile: `user-stories/${p.id}.md`, taskIds: [],
|
|
73
136
|
}))
|
|
74
|
-
return { schemaVersion: 3, feature:
|
|
137
|
+
return { schemaVersion: 3, feature: phaseList.feature, phases, tasks: {} }
|
|
75
138
|
}
|
|
76
139
|
|
|
77
140
|
// Duplicated from src/claude/scripts/wbs-assembler.js's renderPhaseDetailBlock/template-engine
|
|
@@ -224,6 +287,50 @@ function parseComponentsTableLocal(specIndexContent) {
|
|
|
224
287
|
return entries
|
|
225
288
|
}
|
|
226
289
|
|
|
290
|
+
// FTR-033: local re-implementation of req-assembler.js's own parseUseCaseIndexTable, reusing the
|
|
291
|
+
// ALREADY-local _findSectionRange/_parseTableRows this file established for Tech-Spec's own
|
|
292
|
+
// Section 9 table (FTR-026) — same "sandboxed runtime has no require" reason.
|
|
293
|
+
function parseUseCaseIndexTableLocal(reqIndexContent) {
|
|
294
|
+
const { start, end, lines } = _findSectionRange(reqIndexContent, 2)
|
|
295
|
+
return _parseTableRows(lines, start, end).map(cells => {
|
|
296
|
+
const [id, title, actor, priority, fileCol] = cells
|
|
297
|
+
const m = fileCol && fileCol.match(/\(([^)]+)\)/)
|
|
298
|
+
if (!m) throw new Error(`malformed File column for UC "${id}" in req/index.md`)
|
|
299
|
+
return { id, file: m[1] }
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Scopes Requirements to one phase's own sourceUC: req/index.md's feature-wide content (Business
|
|
304
|
+
// Rules/AC table/NFRs, never per-UC) is ALWAYS included in full; only the per-UC flow detail is
|
|
305
|
+
// narrowed to this phase's own UC(s). Falls back to the raw text unchanged for a legacy
|
|
306
|
+
// (non-split) feature — hasReq is false, so sourceUC-based file lookups are meaningless anyway.
|
|
307
|
+
function buildPhaseRequirementsExcerpt(reqIndexContent, sourceUC, reqDirArg) {
|
|
308
|
+
const ucTable = parseUseCaseIndexTableLocal(reqIndexContent)
|
|
309
|
+
const matched = ucTable.filter(row => (sourceUC || []).includes(row.id))
|
|
310
|
+
if (matched.length === 0) return reqIndexContent
|
|
311
|
+
const ucBodies = matched.map(row => c.read(`${reqDirArg}/${row.file}`)).join('\n\n')
|
|
312
|
+
return `${reqIndexContent}\n\n${ucBodies}`
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Compact prompt for the per-phase task-generation worker: this phase's own skeleton entry, its
|
|
316
|
+
// scoped Requirements excerpt, the Tech-Spec skeleton, and every prior phase's own tasks as a
|
|
317
|
+
// lightweight id/title/outcome/domain projection (never a later phase's tasks, which do not exist
|
|
318
|
+
// yet) — mirrors buildTaskPrompt's own "siblings" list further below, same duplicate-
|
|
319
|
+
// implementation-awareness purpose, one tier up.
|
|
320
|
+
function buildPhaseTaskPrompt(phase, requirementsExcerpt, techSpecSkeletonText, priorTasks, drillDownText) {
|
|
321
|
+
const priorTasksList = priorTasks.length
|
|
322
|
+
? priorTasks.map(t => `- ${t.id}: ${t.title} — ${t.outcome} (domain: ${t.domain})`).join('\n')
|
|
323
|
+
: '(none — this is the first phase generated)'
|
|
324
|
+
const parts = [
|
|
325
|
+
`Phase:\n${JSON.stringify(phase, null, 2)}`,
|
|
326
|
+
`Requirements (scoped to this phase's own sourceUC, plus feature-wide sections):\n${requirementsExcerpt}`,
|
|
327
|
+
`Tech-Spec:\n${techSpecSkeletonText}`,
|
|
328
|
+
`Tasks already decided by prior phases:\n${priorTasksList}`,
|
|
329
|
+
]
|
|
330
|
+
if (drillDownText) parts.push(`Component detail you requested:\n${drillDownText}`)
|
|
331
|
+
return parts.join('\n\n')
|
|
332
|
+
}
|
|
333
|
+
|
|
227
334
|
// Matches a task's own acceptanceCriteria against each component's Addresses column (the same
|
|
228
335
|
// relation spec/index.md's own Section 9 table already expresses) to give the per-task worker
|
|
229
336
|
// only the Tech-Spec content relevant to its own task, instead of the entire assembled spec —
|
|
@@ -331,21 +438,81 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
331
438
|
const wbsDir = `${featureDir}/wbs`
|
|
332
439
|
const indexPath = `${wbsDir}/index.json`
|
|
333
440
|
|
|
334
|
-
// 1.
|
|
441
|
+
// 1. Phase enumeration (no declared worker() output — host writes every file itself). FTR-033:
|
|
442
|
+
// split from the old single monolithic skeleton call (which decided every phase AND every task
|
|
443
|
+
// in one turn — confirmed to fail reliably at real feature scale, independent of prompt size or
|
|
444
|
+
// dispatch mechanism) into this lightweight enumeration tier plus the bounded per-phase loop
|
|
445
|
+
// below.
|
|
335
446
|
let index
|
|
336
447
|
if (!c.exists(indexPath)) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
448
|
+
// Requirements FULL text + Tech-Spec SKELETON ONLY, inlined directly — same shape as
|
|
449
|
+
// pm-phase1.js's own validator prompt (FTR-028). Computed unconditionally here (not reused
|
|
450
|
+
// from the Gate-1 digest check above, which only runs when Approvals.md carries a digest
|
|
451
|
+
// line) so this prompt is always built the same way regardless of that check's own outcome.
|
|
452
|
+
const requirementsForSkeleton = hasReq
|
|
453
|
+
? c.command(['run-asset', 'scripts/req-assembler.js', '--project', c.root, '--', reqDir]).stdout
|
|
454
|
+
: c.read(file('Requirements.md'))
|
|
455
|
+
const techSpecSkeletonForSkeleton = hasSpec ? c.read(specIndexPath) : c.read(file('Tech-Spec.md'))
|
|
456
|
+
|
|
457
|
+
// No needsComponentDetail round here — the enumeration agent never declares or asks for it
|
|
458
|
+
// (PHASE_ENUMERATION_SCHEMA has no such property; gaia-generate-work-breakdown.md's own Output
|
|
459
|
+
// section doesn't mention it either). Phase-level decisions (id/type/title/sourceUC/commit)
|
|
460
|
+
// never need a component's own design body; the drill-down mechanism now lives ONLY at the
|
|
461
|
+
// per-phase tier below, where task-level decisions genuinely can need it.
|
|
462
|
+
const phaseList = await c.worker('gaia.agent.planner.work-breakdown',
|
|
463
|
+
buildPhaseEnumerationPrompt(featurePath, requirementsForSkeleton, techSpecSkeletonForSkeleton),
|
|
464
|
+
{ schema: PHASE_ENUMERATION_SCHEMA })
|
|
465
|
+
|
|
466
|
+
index = materializeEnumeratedPhases(phaseList)
|
|
346
467
|
c.writeOutput(indexPath, JSON.stringify(index, null, 2))
|
|
347
468
|
} else {
|
|
348
|
-
index = c.json(indexPath) // resume: reuse
|
|
469
|
+
index = c.json(indexPath) // resume: reuse already-enumerated phases / already-generated tasks as-is
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// 1b. Per-phase task generation (resume-by-phase: a phase whose taskIds is already non-empty is
|
|
473
|
+
// skipped entirely, never redispatched — BR-04/BR-05). Dispatched strictly in enumerated order:
|
|
474
|
+
// INFRA first (if present), then US phases in priority order (same order gaia-generate-
|
|
475
|
+
// work-breakdown.md's own Guidelines already produce for the phases array).
|
|
476
|
+
const reqIndexContentForPhases = c.read(reqIndexPath)
|
|
477
|
+
const techSpecSkeletonForPhases = hasSpec ? c.read(specIndexPath) : c.read(file('Tech-Spec.md'))
|
|
478
|
+
const taskIdToPhase = new Map()
|
|
479
|
+
for (const phase of index.phases) {
|
|
480
|
+
if (phase.taskIds.length > 0) {
|
|
481
|
+
for (const taskId of phase.taskIds) taskIdToPhase.set(taskId, phase.id)
|
|
482
|
+
continue
|
|
483
|
+
}
|
|
484
|
+
const reqExcerpt = hasReq
|
|
485
|
+
? buildPhaseRequirementsExcerpt(reqIndexContentForPhases, phase.sourceUC, reqDir)
|
|
486
|
+
: reqIndexContentForPhases
|
|
487
|
+
const priorTasks = Object.entries(index.tasks).map(([id, t]) => ({ id, title: t.title, outcome: t.outcome, domain: t.domain }))
|
|
488
|
+
|
|
489
|
+
let phaseResult = await c.worker('gaia.agent.planner.work-breakdown-phase',
|
|
490
|
+
buildPhaseTaskPrompt(phase, reqExcerpt, techSpecSkeletonForPhases, priorTasks),
|
|
491
|
+
{ schema: PHASE_TASKS_SCHEMA, label: `work-breakdown-phase:${phase.id}` })
|
|
492
|
+
|
|
493
|
+
// Bounded, single-round drill-down (FTR-028 precedent, reused unmodified from FTR-032's own
|
|
494
|
+
// whole-feature-skeleton mechanism) — scoped to this one phase's call now.
|
|
495
|
+
const phaseNeedsComponentDetail = phaseResult.needsComponentDetail || []
|
|
496
|
+
if (hasSpec && phaseNeedsComponentDetail.length > 0) {
|
|
497
|
+
const drillDownText = buildComponentDrillDownText(phaseNeedsComponentDetail, c.read(specIndexPath), specDir)
|
|
498
|
+
if (drillDownText) {
|
|
499
|
+
phaseResult = await c.worker('gaia.agent.planner.work-breakdown-phase',
|
|
500
|
+
buildPhaseTaskPrompt(phase, reqExcerpt, techSpecSkeletonForPhases, priorTasks, drillDownText),
|
|
501
|
+
{ schema: PHASE_TASKS_SCHEMA, label: `work-breakdown-phase:${phase.id}:with-drilldown` })
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
for (const [taskId, t] of Object.entries(phaseResult.tasks)) {
|
|
506
|
+
index.tasks[taskId] = { ...t, detailFile: `tasks/${taskId}.md`, status: 'pending' }
|
|
507
|
+
taskIdToPhase.set(taskId, phase.id)
|
|
508
|
+
}
|
|
509
|
+
phase.taskIds = Object.keys(phaseResult.tasks)
|
|
510
|
+
|
|
511
|
+
const taskTitles = phase.taskIds.map(taskId => ({ id: taskId, title: index.tasks[taskId].title }))
|
|
512
|
+
const dependsOnPhases = computeDependsOnPhases(index, phase.id, taskIdToPhase)
|
|
513
|
+
c.writeOutput(`${wbsDir}/${phase.detailFile}`,
|
|
514
|
+
renderPhaseDetailBlock({ ...phase, context: phaseResult.context }, taskTitles, dependsOnPhases))
|
|
515
|
+
c.writeOutput(indexPath, JSON.stringify(index, null, 2)) // persist BEFORE the next phase's call (BR-04)
|
|
349
516
|
}
|
|
350
517
|
|
|
351
518
|
// 2. Structural pre-checks (wb-skeleton-check.js, same wb-graph-checks.js functions
|