mandrel 1.59.0 → 1.60.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/.agents/README.md +14 -14
- package/.agents/docs/SDLC.md +129 -134
- package/.agents/docs/configuration.md +16 -16
- package/.agents/docs/workflows.md +6 -8
- package/.agents/instructions.md +12 -11
- package/.agents/personas/architect.md +1 -1
- package/.agents/personas/product.md +1 -1
- package/.agents/personas/project-manager.md +14 -14
- package/.agents/personas/technical-writer.md +1 -1
- package/.agents/rules/changelog-style.md +5 -5
- package/.agents/rules/git-conventions.md +3 -3
- package/.agents/schemas/agentrc.schema.json +3 -3
- package/.agents/schemas/dispatch-manifest.json +4 -4
- package/.agents/schemas/epic-spec.schema.json +15 -45
- package/.agents/schemas/lifecycle/README.md +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/README.md +1 -1
- package/.agents/scripts/acceptance-eval.js +1 -1
- package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
- package/.agents/scripts/analyze-execution.js +2 -2
- package/.agents/scripts/audit-to-stories.js +1 -1
- package/.agents/scripts/check-doc-links.js +2 -3
- package/.agents/scripts/diagnose-friction.js +1 -1
- package/.agents/scripts/dispatcher.js +2 -2
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/epic-audit-prepare.js +3 -3
- package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
- package/.agents/scripts/epic-deliver-preflight.js +6 -6
- package/.agents/scripts/epic-deliver-prepare.js +1 -1
- package/.agents/scripts/epic-execute-record-wave.js +4 -4
- package/.agents/scripts/epic-plan-healthcheck.js +6 -10
- package/.agents/scripts/epic-plan-spec-validate.js +1 -1
- package/.agents/scripts/epic-reconcile.js +11 -29
- package/.agents/scripts/evidence-gate.js +1 -1
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/hierarchy-gate.js +7 -11
- package/.agents/scripts/lib/ITicketingProvider.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
- package/.agents/scripts/lib/baseline-snapshot.js +7 -7
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/codebase-snapshot.js +1 -1
- package/.agents/scripts/lib/config/explain.js +1 -1
- package/.agents/scripts/lib/config/runners.js +2 -2
- package/.agents/scripts/lib/config/runtime.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
- package/.agents/scripts/lib/config-settings-schema.js +3 -3
- package/.agents/scripts/lib/duplicate-search.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
- package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
- package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +10 -10
- package/.agents/scripts/lib/label-constants.js +3 -4
- package/.agents/scripts/lib/label-taxonomy.js +3 -8
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
- package/.agents/scripts/lib/orchestration/code-review.js +5 -5
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
- package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +9 -25
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +8 -8
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +26 -13
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +6 -21
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +8 -8
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
- package/.agents/scripts/lib/orchestration/file-assumptions.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -3
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
- package/.agents/scripts/lib/orchestration/preflight-cache.js +1 -1
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
- package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
- package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +2 -2
- package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
- package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +2 -2
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
- package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +5 -12
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +8 -8
- package/.agents/scripts/lib/orchestration/ticketing/state.js +3 -3
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +2 -2
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +1 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +1 -1
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
- package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
- package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
- package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
- package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/spec/index.js +1 -1
- package/.agents/scripts/lib/spec/loader.js +2 -2
- package/.agents/scripts/lib/spec/state.js +7 -16
- package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
- package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
- package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
- package/.agents/scripts/lib/story-lifecycle.js +8 -8
- package/.agents/scripts/lib/story-plan.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
- package/.agents/scripts/lib/wave-runner/tick.js +1 -1
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
- package/.agents/scripts/lifecycle-emit.js +1 -1
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/mappers.js +2 -2
- package/.agents/scripts/providers/github/tickets.js +4 -4
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/retro-run.js +2 -2
- package/.agents/scripts/run-lint.js +1 -1
- package/.agents/scripts/single-story-init.js +1 -1
- package/.agents/scripts/stories-wave-tick.js +5 -5
- package/.agents/scripts/story-close.js +1 -1
- package/.agents/scripts/story-init.js +13 -16
- package/.agents/scripts/story-phase.js +5 -5
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/sync-branch-from-base.js +1 -1
- package/.agents/scripts/validate-docs-freshness.js +1 -1
- package/.agents/scripts/wave-tick.js +1 -1
- package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
- package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
- package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
- package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
- package/.agents/skills/core/scope-triage/SKILL.md +9 -10
- package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
- package/.agents/skills/skills.index.json +7 -7
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/workflows/agents-update.md +2 -2
- package/.agents/workflows/audit-architecture.md +2 -2
- package/.agents/workflows/audit-clean-code.md +2 -2
- package/.agents/workflows/audit-dependencies.md +1 -1
- package/.agents/workflows/audit-devops.md +1 -1
- package/.agents/workflows/audit-documentation.md +2 -2
- package/.agents/workflows/audit-lighthouse.md +1 -1
- package/.agents/workflows/audit-performance.md +2 -2
- package/.agents/workflows/audit-privacy.md +1 -1
- package/.agents/workflows/audit-quality.md +2 -2
- package/.agents/workflows/audit-security.md +2 -2
- package/.agents/workflows/audit-seo.md +1 -1
- package/.agents/workflows/audit-sre.md +1 -1
- package/.agents/workflows/audit-to-stories.md +10 -10
- package/.agents/workflows/audit-ux-ui.md +1 -1
- package/.agents/workflows/deliver.md +85 -0
- package/.agents/workflows/explain.md +3 -3
- package/.agents/workflows/git-merge-pr.md +1 -1
- package/.agents/workflows/git-pr-all.md +13 -10
- package/.agents/workflows/git-push.md +6 -3
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
- package/.agents/workflows/helpers/code-review.md +5 -5
- package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +43 -43
- package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
- package/.agents/workflows/helpers/diagnose.md +1 -1
- package/.agents/workflows/helpers/epic-audit.md +6 -6
- package/.agents/workflows/helpers/epic-deliver-story.md +13 -13
- package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
- package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
- package/.agents/workflows/helpers/epic-testing.md +3 -3
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
- package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
- package/.agents/workflows/helpers/signals.md +1 -1
- package/.agents/workflows/helpers/single-story-deliver.md +11 -11
- package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
- package/.agents/workflows/onboard.md +17 -17
- package/.agents/workflows/plan.md +89 -0
- package/.agents/workflows/qa-explore.md +1 -1
- package/.agents/workflows/qa-run-harness.md +1 -1
- package/README.md +4 -12
- package/docs/CHANGELOG.md +1149 -0
- package/lib/cli/__tests__/update-changelog-surface.test.js +357 -0
- package/lib/cli/__tests__/update-reexec.test.js +513 -0
- package/lib/cli/init.js +31 -29
- package/lib/cli/update.js +413 -52
- package/package.json +2 -1
- package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* stories-wave-tick.js — DAG/wave engine for the top-level /
|
|
4
|
+
* stories-wave-tick.js — DAG/wave engine for the top-level /deliver workflow.
|
|
5
5
|
*
|
|
6
6
|
* Consumes an operator-supplied dependency DAG of standalone Story IDs and
|
|
7
7
|
* emits ordered execution waves. Analogous to wave-tick.js but for standalone
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
* }
|
|
27
27
|
*
|
|
28
28
|
* The per-wave concurrency cap is resolved from the same config seam
|
|
29
|
-
* `/
|
|
29
|
+
* `/deliver` uses — `resolveConfig` + `getRunners` reading
|
|
30
30
|
* `delivery.deliverRunner.concurrencyCap` (default 3) — so a
|
|
31
31
|
* `.agentrc.local.json` override is honored. A `--concurrency <n>` CLI flag
|
|
32
32
|
* overrides the config-resolved value for that run only. This puts both the
|
|
33
|
-
* standalone (`/
|
|
33
|
+
* standalone (`/deliver`) and Epic (`/deliver`) delivery paths on
|
|
34
34
|
* one deterministic config source.
|
|
35
35
|
*
|
|
36
36
|
* On cycle detection, exits with code 2 and sets cycleError in the envelope.
|
|
@@ -149,7 +149,7 @@ export function buildAdjacency(nodes) {
|
|
|
149
149
|
/**
|
|
150
150
|
* Resolve the per-wave concurrency cap.
|
|
151
151
|
*
|
|
152
|
-
* Mirrors the `/
|
|
152
|
+
* Mirrors the `/deliver` seam (`epic-deliver-prepare.js`): resolve the
|
|
153
153
|
* project config (which deep-merges `.agentrc.local.json` over `.agentrc.json`)
|
|
154
154
|
* then read `delivery.deliverRunner.concurrencyCap` via `getRunners` (default
|
|
155
155
|
* 3). An explicit `override` (the `--concurrency <n>` CLI flag) wins over
|
|
@@ -177,7 +177,7 @@ export function resolveConcurrencyCap({ cwd, config, override } = {}) {
|
|
|
177
177
|
*
|
|
178
178
|
* Uses detectCycle from Graph.js to validate the DAG before computing
|
|
179
179
|
* layers via assignLayers. Returns the wave envelope, carrying the resolved
|
|
180
|
-
* per-wave `concurrencyCap` so the `/
|
|
180
|
+
* per-wave `concurrencyCap` so the `/deliver` workflow dispatches
|
|
181
181
|
* `min(wave.stories.length, concurrencyCap)` from a deterministic field rather
|
|
182
182
|
* than from recalled prose.
|
|
183
183
|
*
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 5. branch-initializer — materialise the story branch (single-tree
|
|
16
16
|
* checkout or isolated worktree).
|
|
17
17
|
* 6. state-transitioner — flip the Story to `agent::executing`. Under
|
|
18
|
-
* the
|
|
18
|
+
* the 2-tier hierarchy the Story has inline
|
|
19
19
|
* acceptance and no child Task lifecycle.
|
|
20
20
|
*
|
|
21
21
|
* Usage:
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 0 — Initialization complete. Agent can start implementation.
|
|
26
26
|
* 1 — Blocked or error (details in stderr).
|
|
27
27
|
*
|
|
28
|
-
* @see .agents/workflows/
|
|
28
|
+
* @see .agents/workflows/helpers/deliver-stories.md
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import path from 'node:path';
|
|
@@ -141,7 +141,7 @@ export async function runStoryInit({
|
|
|
141
141
|
progress('INIT', `Initializing Story #${storyId}...`);
|
|
142
142
|
|
|
143
143
|
// Stage 1 — context.
|
|
144
|
-
const { story, body, epicId,
|
|
144
|
+
const { story, body, epicId, parentId } = await resolveContext({
|
|
145
145
|
provider,
|
|
146
146
|
logger: stageLogger,
|
|
147
147
|
input: { storyId, recutOf, dryRun },
|
|
@@ -154,10 +154,7 @@ export async function runStoryInit({
|
|
|
154
154
|
input: { epicId },
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
progress(
|
|
158
|
-
'CONTEXT',
|
|
159
|
-
`Epic: #${epicId}, Feature/Parent: #${featureId ?? 'none'}`,
|
|
160
|
-
);
|
|
157
|
+
progress('CONTEXT', `Epic: #${epicId}, Parent: #${parentId ?? 'none'}`);
|
|
161
158
|
progress(
|
|
162
159
|
'CONTEXT',
|
|
163
160
|
`PRD: #${prdId ?? 'none'}, Tech Spec: #${techSpecId ?? 'none'}`,
|
|
@@ -192,8 +189,8 @@ export async function runStoryInit({
|
|
|
192
189
|
progress('BLOCKERS', '✅ All blockers resolved');
|
|
193
190
|
|
|
194
191
|
// Stage 4 — task graph. Pass the Story body so buildTaskGraph can detect
|
|
195
|
-
// the inline-acceptance
|
|
196
|
-
// hierarchy flag,
|
|
192
|
+
// the inline-acceptance 2-tier shape. After Task #3154 collapsed the
|
|
193
|
+
// hierarchy flag, 2-tier is the only supported shape.
|
|
197
194
|
const { sortedTasks, mode: hierarchyMode } = await buildTaskGraph({
|
|
198
195
|
provider,
|
|
199
196
|
logger: stageLogger,
|
|
@@ -327,7 +324,7 @@ export async function runStoryInit({
|
|
|
327
324
|
worktreeCreated,
|
|
328
325
|
installStatus,
|
|
329
326
|
sortedTasks,
|
|
330
|
-
|
|
327
|
+
parentId,
|
|
331
328
|
prdId,
|
|
332
329
|
techSpecId,
|
|
333
330
|
dryRun,
|
|
@@ -500,7 +497,7 @@ function buildStoryInitResult({
|
|
|
500
497
|
worktreeCreated,
|
|
501
498
|
installStatus,
|
|
502
499
|
sortedTasks,
|
|
503
|
-
|
|
500
|
+
parentId,
|
|
504
501
|
prdId,
|
|
505
502
|
techSpecId,
|
|
506
503
|
dryRun,
|
|
@@ -514,11 +511,11 @@ function buildStoryInitResult({
|
|
|
514
511
|
storyBranch,
|
|
515
512
|
epicBranch,
|
|
516
513
|
storyTitle: story.title,
|
|
517
|
-
// Hierarchy mode resolved by buildTaskGraph.
|
|
514
|
+
// Hierarchy mode resolved by buildTaskGraph. 2-tier is the only
|
|
518
515
|
// supported shape after Task #3154 deleted the `planning.hierarchy`
|
|
519
516
|
// flag; this is retained as a constant marker for downstream
|
|
520
517
|
// consumers and persisted artefacts.
|
|
521
|
-
hierarchy: hierarchy ?? '
|
|
518
|
+
hierarchy: hierarchy ?? '2-tier',
|
|
522
519
|
worktreeEnabled,
|
|
523
520
|
workCwd,
|
|
524
521
|
worktreeCreated,
|
|
@@ -534,7 +531,7 @@ function buildStoryInitResult({
|
|
|
534
531
|
labels: t.labels,
|
|
535
532
|
dependencies: t.dependsOn ?? parseBlockedBy(t.body ?? ''),
|
|
536
533
|
})),
|
|
537
|
-
context: {
|
|
534
|
+
context: { parentId, prdId, techSpecId },
|
|
538
535
|
dryRun,
|
|
539
536
|
};
|
|
540
537
|
}
|
|
@@ -591,10 +588,10 @@ export function renderStoryInitCommentBody(result) {
|
|
|
591
588
|
epicId: result.epicId,
|
|
592
589
|
storyBranch: result.storyBranch,
|
|
593
590
|
epicBranch: result.epicBranch,
|
|
594
|
-
// Hierarchy mode is always `'
|
|
591
|
+
// Hierarchy mode is always `'2-tier'` after Task #3154 deleted the
|
|
595
592
|
// `planning.hierarchy` flag. Persisted so resumed runs can read it
|
|
596
593
|
// without re-resolving anything in the worker.
|
|
597
|
-
hierarchy: result.hierarchy ?? '
|
|
594
|
+
hierarchy: result.hierarchy ?? '2-tier',
|
|
598
595
|
worktreeEnabled: result.worktreeEnabled,
|
|
599
596
|
workCwd: result.workCwd,
|
|
600
597
|
worktreeCreated: result.worktreeCreated,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* story-phase.js — phase snapshot + heartbeat writer (
|
|
4
|
+
* story-phase.js — phase snapshot + heartbeat writer (2-tier).
|
|
5
5
|
*
|
|
6
6
|
* Replaces the deleted per-Task progress writer from the 4-tier era
|
|
7
|
-
* (removed under #3157). `/
|
|
7
|
+
* (removed under #3157). `/deliver` calls this CLI at each Story-
|
|
8
8
|
* level phase transition (init → implementing → closing → done, or any
|
|
9
9
|
* → blocked). Each call:
|
|
10
10
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* longer posts a `story-run-progress` comment (the redundant mid-flight
|
|
15
15
|
* progress surface was deleted); the snapshot is render-only.
|
|
16
16
|
* 2. Appends one `story.heartbeat` lifecycle record to
|
|
17
|
-
* `temp/epic-<epicId>/lifecycle.ndjson` so `/
|
|
17
|
+
* `temp/epic-<epicId>/lifecycle.ndjson` so `/deliver`'s
|
|
18
18
|
* §2e Idle Watchdog (`wave-tick.js --check-idle 30`) can confirm
|
|
19
19
|
* forward progress without polling the Story comment.
|
|
20
20
|
*
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
*
|
|
36
36
|
* `renderedBody` is the markdown body upserted onto the Story so the
|
|
37
37
|
* caller can relay it to chat verbatim (mirrors the contract the deleted
|
|
38
|
-
* per-Task progress writer exposed and that `/
|
|
38
|
+
* per-Task progress writer exposed and that `/deliver` Step 1 / 3
|
|
39
39
|
* already documents).
|
|
40
40
|
*/
|
|
41
41
|
|
|
@@ -175,7 +175,7 @@ async function resolveStoryBranch({ provider, storyId }) {
|
|
|
175
175
|
* lease-owner handle the SAME way the lease primitive does
|
|
176
176
|
* (`normalizeOperatorHandle(github.operatorHandle)`) and stamps it as
|
|
177
177
|
* `operator` so `latestHeartbeatForOwner({ epicId, owner })` resolves a real
|
|
178
|
-
* heartbeat — without it `isClaimLive(null)` is false and /
|
|
178
|
+
* heartbeat — without it `isClaimLive(null)` is false and /deliver
|
|
179
179
|
* silently reclaims a live foreign claim (audit #3513). The field is attached
|
|
180
180
|
* only when a handle resolves, preserving the "omit when absent" shape for
|
|
181
181
|
* repos that have not configured `github.operatorHandle`. A failed append is
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/* node:coverage ignore file */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* story-plan.js — Local `/
|
|
5
|
+
* story-plan.js — Local `/plan` wrapper.
|
|
6
6
|
*
|
|
7
|
-
* Standalone counterpart to `/
|
|
7
|
+
* Standalone counterpart to `/plan` for Stories that do **not**
|
|
8
8
|
* attach to an Epic. The script is deliberately a thin CLI around the
|
|
9
9
|
* pure helpers in `lib/story-plan.js`:
|
|
10
10
|
*
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* GitHub. Echoes the rendered body and the `gh` argv it would
|
|
25
25
|
* have run.
|
|
26
26
|
*
|
|
27
|
-
* Mirrors the `/
|
|
27
|
+
* Mirrors the `/plan` pattern: deterministic Node I/O wrappers
|
|
28
28
|
* with HITL gating handled by the host LLM in chat. No external LLM
|
|
29
29
|
* APIs are called from this script.
|
|
30
30
|
*/
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Use this from workflow markdown when the operator needs to sync a
|
|
8
8
|
* working branch with `origin/<baseBranch>` before opening a PR — for
|
|
9
|
-
* example as a pre-Phase-6 step in `/
|
|
9
|
+
* example as a pre-Phase-6 step in `/deliver` so the Epic→main PR
|
|
10
10
|
* opens with the latest `main` commits already integrated.
|
|
11
11
|
*
|
|
12
12
|
* For `/single-story-deliver`, the sync runs in-process inside
|
|
@@ -201,7 +201,7 @@ export function renderFreshnessFailureMessage(epicId) {
|
|
|
201
201
|
return (
|
|
202
202
|
`[docs-freshness] ❌ Documentation freshness gate FAILED for Epic #${epicId}.\n\n` +
|
|
203
203
|
`Update each failing file so its commit message or body references #${epicId}, ` +
|
|
204
|
-
`then re-run /
|
|
204
|
+
`then re-run /deliver.`
|
|
205
205
|
);
|
|
206
206
|
}
|
|
207
207
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Reads the `epic-run-state` checkpoint plus fresh Story labels and
|
|
8
8
|
* prints one `WaveTickResult` envelope. The slash-command operator
|
|
9
|
-
* (`/
|
|
9
|
+
* (`/deliver`) consumes the envelope to decide whether to dispatch
|
|
10
10
|
* the next wave, observe in-flight stories, or finalize the Epic.
|
|
11
11
|
*
|
|
12
12
|
* Usage:
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Aggregate per-Story or per-Epic execution signals into a structured
|
|
5
5
|
perf-summary or perf-report and upsert it onto the corresponding GitHub
|
|
6
6
|
ticket. Use after a Story closes (Story mode) or as part of
|
|
7
|
-
`/
|
|
7
|
+
`/deliver` Phase 6 (Epic mode). Reads NDJSON via
|
|
8
8
|
`lib/signals/read` and writes a single structured comment.
|
|
9
9
|
allowed_tools:
|
|
10
10
|
- Read
|
|
@@ -36,7 +36,7 @@ into the Epic dashboard.
|
|
|
36
36
|
pipeline dispatches this Skill (or the wrapping script) to roll up the
|
|
37
37
|
Story's NDJSON signals into a single `<!-- structured:story-perf-summary -->`
|
|
38
38
|
marker comment on the Story ticket.
|
|
39
|
-
- **Epic mode** — during `/
|
|
39
|
+
- **Epic mode** — during `/deliver` Phase 6.0 (or the retro
|
|
40
40
|
composer), the Skill fans out across every Story under the Epic,
|
|
41
41
|
reads each Story's structured perf summary, and posts a single
|
|
42
42
|
`<!-- structured:epic-perf-report -->` marker on the Epic ticket.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: epic-plan-consolidate
|
|
3
3
|
description: >-
|
|
4
|
-
Run a holistic, pre-persist consolidation pass over the draft
|
|
4
|
+
Run a holistic, pre-persist consolidation pass over the draft Story
|
|
5
5
|
ticket array an Epic's decompose phase produced. Use during Phase 8 of
|
|
6
|
-
`/
|
|
6
|
+
`/plan`, after `epic-plan-decompose-author` writes
|
|
7
7
|
`temp/epic-<Epic_ID>/tickets.json` and before `epic-plan-decompose.js`
|
|
8
8
|
validates and persists it. Reconciles the draft against the Tech Spec
|
|
9
9
|
"Delivery Slicing" target via scope-preserving operations only.
|
|
@@ -19,13 +19,12 @@ allowed_tools:
|
|
|
19
19
|
|
|
20
20
|
- Run only after `epic-plan-decompose-author` has written `temp/epic-<Epic_ID>/tickets.json`; fail loudly if the draft array is missing. Read the PRD / Tech Spec from `temp/epic-<Epic_ID>/decomposer-context.json` (the same envelope the author skill consumed) — never re-fetch from GitHub, and never call the GitHub API from this Skill.
|
|
21
21
|
- Emit exactly two artifacts inside `temp/epic-<Epic_ID>/`: the **consolidated** `tickets.json` (overwriting the draft array in place) and a human-readable `consolidation-report.md` (the rationale + before/after diff the operator reviews at the HITL gate). Both MUST exist before returning.
|
|
22
|
-
- **Scope conservation is the load-bearing invariant.** You are a *critic*, not a second author: you MUST NOT add scope, invent tickets, or drop acceptance criteria. Every acceptance item and every `verify` entry present in the draft MUST survive into the consolidated array (possibly re-homed onto a merged Story). **This is your contract, not a machine guarantee:** there is **no runtime acceptance-union diff** on your output. The only deterministic runtime backstop the validator applies after you run is
|
|
23
|
-
- Your operations are constrained to exactly
|
|
24
|
-
- Consume the Tech Spec **"Delivery Slicing"** section as the authoritative target grouping when one is present: cluster the draft's Stories toward the N shippable Stories the Architect proposed. When the section is **absent**, degrade gracefully — apply only the cohesion
|
|
25
|
-
- Implement rec #2: resolve every single-Story Feature by **collapsing** it into a sibling (operation 2), not by splitting its lone Story into two. The `assertNoSingleStoryFeature` validator from Story #3777 stays as the post-consolidation backstop — your output must already satisfy it.
|
|
22
|
+
- **Scope conservation is the load-bearing invariant.** You are a *critic*, not a second author: you MUST NOT add scope, invent tickets, or drop acceptance criteria. Every acceptance item and every `verify` entry present in the draft MUST survive into the consolidated array (possibly re-homed onto a merged Story). **This is your contract, not a machine guarantee:** there is **no runtime acceptance-union diff** on your output. The only deterministic runtime backstop the validator applies after you run is the standard ticket-structure validation — it does not re-derive the pre-consolidation acceptance/verify union, so a critic that silently dropped an acceptance item would **not** be caught downstream. (The repo's unit test exercises a *pure model* of the merge over an over-fragmented fixture to document the intended invariant; it does not inspect this Skill's actual output.) Conserve scope yourself, deliberately, on every merge.
|
|
23
|
+
- Your operations are constrained to exactly two shapes: **(1) merge two or more Stories** into one (union their `changes`/`acceptance`/`verify`/`references`, keep one coherent `goal`); **(2) rewire `depends_on`** so the edges still reference surviving sibling-Story slugs. No other mutation is permitted.
|
|
24
|
+
- Consume the Tech Spec **"Delivery Slicing"** section as the authoritative target grouping when one is present: cluster the draft's Stories toward the N shippable Stories the Architect proposed. When the section is **absent**, degrade gracefully — apply only the cohesion rules below and leave the rest of the draft shape intact.
|
|
26
25
|
- Apply the same cohesion heuristic the author skill leads with: **one Story = one coherent change with one reason to exist**, and the **single-consumer merge rule** (a Story whose only consumer is one sibling Story is merged into that sibling). Lead every merge decision with the change's reason, not its file count.
|
|
27
|
-
- After every merge
|
|
28
|
-
- The consolidation report MUST name each operation applied (merged slugs → surviving slug,
|
|
26
|
+
- After every merge, **rewire `depends_on`**: drop self-edges, collapse edges that now point at the absorbing Story onto itself, and re-point any edge that named a now-deleted slug at its surviving successor. Never leave a `depends_on` referencing a slug absent from the consolidated array — the validator HARD-rejects unknown deps.
|
|
27
|
+
- The consolidation report MUST name each operation applied (merged slugs → surviving slug, rewired edges) with a one-line reason, plus a before/after Story-count line, so the operator can approve or reject at the HITL diff gate before the persist call.
|
|
29
28
|
|
|
30
29
|
## Role
|
|
31
30
|
|
|
@@ -38,7 +37,7 @@ against the Tech Spec's intentional grouping before any GitHub write.
|
|
|
38
37
|
|
|
39
38
|
## When to use
|
|
40
39
|
|
|
41
|
-
`/
|
|
40
|
+
`/plan` Phase 8, as the **8.3 — Holistic Consolidation** sub-step:
|
|
42
41
|
immediately after `epic-plan-decompose-author` writes
|
|
43
42
|
`temp/epic-<Epic_ID>/tickets.json` and **before**
|
|
44
43
|
`epic-plan-decompose.js --tickets …` validates and persists. The pass operates
|
|
@@ -51,7 +50,7 @@ emit a plan the validator would reject.
|
|
|
51
50
|
The dispatcher passes the Epic ID as the Skill argument. The Skill itself
|
|
52
51
|
reads:
|
|
53
52
|
|
|
54
|
-
- `temp/epic-<Epic_ID>/tickets.json` — the **draft**
|
|
53
|
+
- `temp/epic-<Epic_ID>/tickets.json` — the **draft** Story array the
|
|
55
54
|
`epic-plan-decompose-author` Skill wrote. This is the consolidation input.
|
|
56
55
|
- `temp/epic-<Epic_ID>/decomposer-context.json` — the authoring envelope
|
|
57
56
|
emitted by `epic-plan-decompose.js --emit-context`. Read `prd.body` /
|
|
@@ -62,7 +61,7 @@ reads:
|
|
|
62
61
|
## Outputs
|
|
63
62
|
|
|
64
63
|
- `temp/epic-<Epic_ID>/tickets.json` — the **consolidated** array, overwriting
|
|
65
|
-
the draft. Same schema as the author skill emits (
|
|
64
|
+
the draft. Same schema as the author skill emits (flat Story array; Stories
|
|
66
65
|
carry top-level `acceptance[]` / `verify[]`; `body` is a serialized string).
|
|
67
66
|
The downstream `epic-plan-decompose.js --tickets …` validator is the final
|
|
68
67
|
gate — author for its rules, not for "looks right."
|
|
@@ -83,21 +82,18 @@ anything:
|
|
|
83
82
|
|
|
84
83
|
1. The **target grouping** — the N shippable Stories the Architect proposed in
|
|
85
84
|
Delivery Slicing, or `null` when the section is absent (graceful-degrade
|
|
86
|
-
mode: cohesion
|
|
87
|
-
2. The **draft Story count
|
|
88
|
-
|
|
85
|
+
mode: cohesion rules only).
|
|
86
|
+
2. The **draft Story count** — so you can spot over-fragmented capability
|
|
87
|
+
clusters.
|
|
89
88
|
|
|
90
89
|
### Step 2 — Plan the consolidation
|
|
91
90
|
|
|
92
|
-
|
|
91
|
+
Across the draft Story array, decide which Stories merge:
|
|
93
92
|
|
|
94
|
-
- **Single-Story Feature** → collapse its lone Story into a sibling Feature
|
|
95
|
-
whose capability is closest (Delivery-Slicing target, else thematic
|
|
96
|
-
proximity). Drop the now-empty Feature. Never split the lone Story.
|
|
97
93
|
- **Over-fragmented capability** → when several draft Stories map to one
|
|
98
94
|
Delivery-Slicing target (or one coherent reason to exist), merge them into a
|
|
99
95
|
single Story: union their `changes` / `acceptance` / `verify` / `references`,
|
|
100
|
-
write one `goal
|
|
96
|
+
write one coherent `goal`, and keep the union of labels.
|
|
101
97
|
- **Single-consumer Story** → merge into the one sibling that consumes it.
|
|
102
98
|
|
|
103
99
|
Record each decision with its one-line reason for the report.
|
|
@@ -120,7 +116,7 @@ Write the consolidated array to `temp/epic-<Epic_ID>/tickets.json` (2-space
|
|
|
120
116
|
indent, machine-consumed) and the rationale + before/after diff to
|
|
121
117
|
`temp/epic-<Epic_ID>/consolidation-report.md`.
|
|
122
118
|
|
|
123
|
-
### Step 5 — Hand back to `/
|
|
119
|
+
### Step 5 — Hand back to `/plan`
|
|
124
120
|
|
|
125
121
|
Return control. The workflow shows the operator the consolidation report at the
|
|
126
122
|
HITL diff gate; on approval it runs
|
|
@@ -133,13 +129,12 @@ persists the hierarchy, and flips the Epic to `agent::ready`.
|
|
|
133
129
|
- Do **not** call the GitHub API from this Skill. It reads two temp artifacts
|
|
134
130
|
and writes two temp artifacts; persistence belongs to the script.
|
|
135
131
|
- Do **not** write outside `temp/epic-<Epic_ID>/`.
|
|
136
|
-
- Do **not** add scope or invent tickets. The
|
|
137
|
-
Stories,
|
|
138
|
-
|
|
132
|
+
- Do **not** add scope or invent tickets. The two permitted operations (merge
|
|
133
|
+
Stories, rewire `depends_on`) are exhaustive — anything else is out of
|
|
134
|
+
contract.
|
|
139
135
|
- If `temp/epic-<Epic_ID>/tickets.json` is missing, fail loudly and instruct
|
|
140
136
|
the caller to run the `epic-plan-decompose-author` Skill first.
|
|
141
137
|
- The validator
|
|
142
138
|
([`lib/orchestration/ticket-validator.js`](../../../scripts/lib/orchestration/ticket-validator.js))
|
|
143
|
-
is the authoritative post-consolidation gate
|
|
144
|
-
|
|
145
|
-
patching tickets by hand.
|
|
139
|
+
is the authoritative post-consolidation gate. Re-consolidate when it
|
|
140
|
+
rejects rather than patching tickets by hand.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: epic-plan-decompose-author
|
|
3
3
|
description: >-
|
|
4
|
-
Author the
|
|
4
|
+
Author the Story ticket JSON for an Epic from the decomposer
|
|
5
5
|
authoring context emitted by `epic-plan-decompose.js --emit-context`. Use
|
|
6
|
-
during Phase 8 of `/
|
|
6
|
+
during Phase 8 of `/plan` when the host LLM needs to write the ticket
|
|
7
7
|
array before `epic-plan-decompose.js` validates and persists it.
|
|
8
8
|
allowed_tools:
|
|
9
9
|
- Read
|
|
@@ -18,10 +18,10 @@ allowed_tools:
|
|
|
18
18
|
- Run only after `epic-plan-decompose.js --emit-context` has written `temp/epic-<Epic_ID>/decomposer-context.json`; fail loudly if the file is missing.
|
|
19
19
|
- Emit exactly one artifact: `temp/epic-<Epic_ID>/tickets.json` (a JSON array). Do not write anywhere else, and never call the GitHub API from this Skill — persistence belongs to the script.
|
|
20
20
|
- Output is JSON only — no prose, no Markdown fence. The downstream validator (`lib/orchestration/ticket-validator.js`) is the authoritative gate; re-author rather than hand-patching when it rejects.
|
|
21
|
-
- Treat **`maxTickets`** from the context envelope as a **reviewability budget**, not a hard authoring cap (Story #2798). Merge narrow, single-module Stories into their capability first; if the plan genuinely needs more, emit the full plan and add a compact `over_budget_rationale`
|
|
22
|
-
- Honour the
|
|
23
|
-
- **Decompose at deliverable granularity, not module/task level.** A Story is a capability slice a frontier model delivers and self-verifies in one pass — a shippable slice a reviewer would accept as a single PR — not a single module or file.
|
|
24
|
-
- Every ticket carries `type::
|
|
21
|
+
- Treat **`maxTickets`** from the context envelope as a **reviewability budget**, not a hard authoring cap (Story #2798). Merge narrow, single-module Stories into their capability first; if the plan genuinely needs more, emit the full plan and add a compact `over_budget_rationale` note inside the first Story's `## Goal` section explaining why the plan exceeds the budget. Operator persistence then requires the explicit `--allow-over-budget` override on `epic-plan-decompose.js`; without it the persist step rejects the over-budget array. Never truncate the JSON array to fit.
|
|
22
|
+
- Honour the 2-tier hierarchy: every ticket is a **Story** attached directly to the Epic. Stories carry the implementation scope inline; no Feature and no lower ticket tier exists. Thematic grouping is prose in the Epic body / Tech Spec, never a ticket.
|
|
23
|
+
- **Decompose at deliverable granularity, not module/task level.** A Story is a capability slice a frontier model delivers and self-verifies in one pass — a shippable slice a reviewer would accept as a single PR — not a single module or file. See the STORY SIZING section for the full guidance and the single-consumer merge rule.
|
|
24
|
+
- Every ticket carries `type::story` and `persona::*` labels. Every Story ticket object MUST carry top-level `acceptance: string[]` and `verify: string[]` arrays (read by `hasInlineAcceptanceAndVerify` in the validator) and `body` MUST be a **string** produced by `serialize()` from `lib/story-body/story-body.js` — an object body causes `createOp` in `epic-spec-reconciler-ops.js` to throw `StoryBodyParseError` (Story #3302), and is also silently discarded by `composeStoryBody` in the GitHub provider, producing an empty issue body.
|
|
25
25
|
- **New-File Contract**: any path referenced in `goal`, `acceptance`, or `verify` that does not exist on `main` MUST appear in the Story's `changes[]` with `assumption: "creates"`; otherwise the freshness validator rejects the decompose.
|
|
26
26
|
- Acceptance items MUST be **observable from outside the agent** (command exits 0, file exists, snapshot matches, testid resolves). Items like "verify by reading the diff" or "looks good" are forbidden — push them into `verify` commands instead.
|
|
27
27
|
- Acceptance MUST NOT prescribe a commit subject starting with a non-Conventional-Commits prefix; the literal `baseline-refresh:` leading token is forbidden (use a body trailer instead — see Epic #2501).
|
|
@@ -31,12 +31,12 @@ allowed_tools:
|
|
|
31
31
|
## Role
|
|
32
32
|
|
|
33
33
|
Senior Project Manager + Orchestrator. The Skill's job is to take a PRD plus
|
|
34
|
-
a Tech Spec and emit a
|
|
35
|
-
|
|
34
|
+
a Tech Spec and emit a flat Story backlog the orchestrator can execute
|
|
35
|
+
autonomously.
|
|
36
36
|
|
|
37
37
|
## When to use
|
|
38
38
|
|
|
39
|
-
`/
|
|
39
|
+
`/plan` Phase 8, immediately after
|
|
40
40
|
`epic-plan-decompose.js --emit-context` writes
|
|
41
41
|
`temp/epic-<Epic_ID>/decomposer-context.json`. The Skill replaces the
|
|
42
42
|
inline "Author the Ticket Array" step in the legacy workflow body —
|
|
@@ -74,7 +74,7 @@ Skill's body below is the authoritative version going forward.
|
|
|
74
74
|
|
|
75
75
|
## Outputs
|
|
76
76
|
|
|
77
|
-
- `temp/epic-<Epic_ID>/tickets.json` — JSON array of
|
|
77
|
+
- `temp/epic-<Epic_ID>/tickets.json` — JSON array of Story
|
|
78
78
|
objects conforming to the schema in this Skill's body.
|
|
79
79
|
|
|
80
80
|
The file MUST exist before the Skill returns. The caller will then run
|
|
@@ -116,7 +116,7 @@ Write the final JSON array to `temp/epic-<Epic_ID>/tickets.json` with
|
|
|
116
116
|
the `Write` tool. Do not pretty-print past 2-space indent — the file is
|
|
117
117
|
machine-consumed.
|
|
118
118
|
|
|
119
|
-
### Step 4 — Hand back to `/
|
|
119
|
+
### Step 4 — Hand back to `/plan`
|
|
120
120
|
|
|
121
121
|
Return control. The caller invokes
|
|
122
122
|
`node .agents/scripts/epic-plan-decompose.js --epic <Epic_ID> --tickets
|
|
@@ -132,17 +132,16 @@ budget (Story #2798) — stay under by default; over-budget plans need an
|
|
|
132
132
|
|
|
133
133
|
```text
|
|
134
134
|
You are an expert Senior Project Manager and Orchestrator.
|
|
135
|
-
Your job is to take a Product Requirements Document (PRD) and a Technical Specification and decompose them into a
|
|
135
|
+
Your job is to take a Product Requirements Document (PRD) and a Technical Specification and decompose them into a flat list of Story tickets for an AI Agent to execute.
|
|
136
136
|
|
|
137
137
|
### HIERARCHY RULES:
|
|
138
|
-
1. **
|
|
139
|
-
|
|
140
|
-
- MUST be nested under a Feature via `parent_slug`.
|
|
138
|
+
1. **Stories**: Capability-sized, verifiable units of work (e.g., "Implement JWT Token Exchange").
|
|
139
|
+
- Attach directly to the Epic — there is NO Feature tier; thematic grouping is prose in the Epic body / Tech Spec.
|
|
141
140
|
- **Story-Level Execution**: Each Story is executed on a single Story branch (`story-<storyId>`), implemented in one Story-implementation phase, then merged into the Epic branch. The Story body carries the full execution contract (goal, changes, acceptance, verify).
|
|
142
|
-
- Do NOT emit
|
|
141
|
+
- Do NOT emit any other ticket tier — the validator only accepts `type::story`.
|
|
143
142
|
|
|
144
143
|
### LABEL CONVENTIONS:
|
|
145
|
-
- Every ticket must have
|
|
144
|
+
- Every ticket must have the `type::story` label.
|
|
146
145
|
- Every ticket must have a `persona::[engineer|architect|qa-engineer|engineer-web|etc]` label indicating WHO should execute it.
|
|
147
146
|
|
|
148
147
|
### OUTPUT FORMAT:
|
|
@@ -152,48 +151,18 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
|
|
|
152
151
|
[
|
|
153
152
|
{
|
|
154
153
|
"slug": "hyphen-case-id",
|
|
155
|
-
"type": "
|
|
154
|
+
"type": "story",
|
|
156
155
|
"title": "Short descriptive title",
|
|
157
156
|
"body": <string — see BODY RULES below>,
|
|
158
157
|
"acceptance": ["<testable criterion>", ...], // STORIES ONLY — top-level, read by validator
|
|
159
158
|
"verify": ["<exact command> (<tier>)", ...], // STORIES ONLY — top-level, read by validator
|
|
160
|
-
"labels": ["type
|
|
161
|
-
"parent_slug": "slug_of_parent_ticket" (leave empty for features to nest under epic; required for stories — must point at a sibling Feature),
|
|
159
|
+
"labels": ["type::story", "persona::..."],
|
|
162
160
|
"depends_on": ["slug_of_blocking_dependency"] (optional array of Story slugs that block execution)
|
|
163
161
|
}
|
|
164
162
|
]
|
|
165
163
|
|
|
166
164
|
**Slug format**: `^[a-z0-9][a-z0-9-]*$` — hyphen-case only. Underscores are rejected by the validator.
|
|
167
165
|
|
|
168
|
-
### FEATURE BODY:
|
|
169
|
-
For Features, `body` is a brief string under 2 sentences. Features are navigational — the work happens at the Story level — so dense bodies waste output budget.
|
|
170
|
-
|
|
171
|
-
FEATURE GROUPING — CAPABILITY/STAKEHOLDER, NOT EXECUTION SHAPE:
|
|
172
|
-
|
|
173
|
-
- Do not group Stories by technical execution shape (cron jobs, middleware, scripts). Group by the capability or stakeholder they serve. Two Stories that happen to share a delivery mechanism — both are cron sweeps, both are Express middleware, both are CLI scripts — do NOT belong in the same Feature just because of that shared shape. The Feature axis is the user-facing capability or the stakeholder served, never the implementation vehicle.
|
|
174
|
-
- Operational/compliance work gets its own Feature. Retention purges, audit-log sweeps, scheduled cleanups, observability emitters, and other operational/compliance chores serve operators and compliance, not end users. Place them in a dedicated `compliance-and-observability` or `data-retention` Feature — do NOT fold them into a user-facing Feature (e.g. notification flows) merely because they share a cron/scheduled execution shape with user-facing Stories.
|
|
175
|
-
|
|
176
|
-
ANTI-PATTERN (based on Epic #18 -> Feature #1446):
|
|
177
|
-
|
|
178
|
-
A decomposition produced a Feature "Notification flows: reminders, schedule-change, retention" grouping three Stories. WRONG — grouped by execution shape (all three are cron sweeps):
|
|
179
|
-
|
|
180
|
-
Feature: notification-flows ("Notification flows: reminders, schedule-change, retention")
|
|
181
|
-
[X] Story: send-appointment-reminders (user-facing: emails patients)
|
|
182
|
-
[X] Story: send-schedule-change-notices (user-facing: emails patients)
|
|
183
|
-
[X] Story: purge-email-audit-log-retention (compliance: deletes audit rows past retention)
|
|
184
|
-
|
|
185
|
-
The email audit-log retention purge was folded in only because all three run as scheduled cron jobs — a shared execution shape, not a shared capability. The purge serves compliance/operators, not the patients the other two Stories notify. CORRECT — regroup by capability/stakeholder:
|
|
186
|
-
|
|
187
|
-
Feature: notification-flows ("Patient notification flows")
|
|
188
|
-
Story: send-appointment-reminders (user-facing)
|
|
189
|
-
Story: send-schedule-change-notices (user-facing)
|
|
190
|
-
Feature: compliance-and-observability ("Data-retention and audit-log compliance")
|
|
191
|
-
Story: purge-email-audit-log-retention (compliance)
|
|
192
|
-
|
|
193
|
-
The cron shape is the false grouping signal. Once the retention purge has a sibling under a dedicated compliance Feature it ceases to be a lone-Story Feature (which the validator would reject); pair it with other operational/compliance sweeps (e.g. a session-token cleanup or a metrics-rollup job) under the same `compliance-and-observability` Feature.
|
|
194
|
-
|
|
195
|
-
- Smell test: if the only thing two Stories have in common is how they run (a scheduled job, a request interceptor, a build step) rather than whom they serve or what capability they deliver, they are mis-grouped. Re-home the operational/compliance Story into its own capability Feature.
|
|
196
|
-
|
|
197
166
|
### STORY BODY SCHEMA (REQUIRED FOR EVERY STORY):
|
|
198
167
|
For Stories, `body` MUST be a **string** — the serialized markdown produced by calling `serialize()` from `lib/story-body/story-body.js`. Do NOT emit `body` as a JSON object: `createOp` in `epic-spec-reconciler-ops.js` will throw `StoryBodyParseError` when it receives an object body (Story #3302 serialize-or-throw contract), and `composeStoryBody` in the GitHub provider also discards non-string bodies producing an empty issue. The canonical pipeline requires a serialized string body end-to-end. The freshness gate (`collectTaskChangesPaths`) and the assumption gate (`collectStoryAssumptionEntries`) both parse the string body via `story-body.js#parse` to recover `changes[]`/`references[]` — they operate correctly only on the serialized string form.
|
|
199
168
|
|
|
@@ -202,7 +171,7 @@ The `acceptance[]` and `verify[]` arrays live at the **top level** of the Story
|
|
|
202
171
|
The serialized `body` string renders these markdown sections (in order):
|
|
203
172
|
|
|
204
173
|
## Goal
|
|
205
|
-
<one sentence — why this Story exists
|
|
174
|
+
<one sentence — why this Story exists within the Epic>
|
|
206
175
|
|
|
207
176
|
## Changes
|
|
208
177
|
- {"path": "<file path>", "assumption": "creates" | "refactors-existing" | "deletes"}
|
|
@@ -225,7 +194,7 @@ Fields `wide` and `estimated_test_files` are encoded as a `<!-- meta: {...} -->`
|
|
|
225
194
|
#### STORY BODY RULES:
|
|
226
195
|
|
|
227
196
|
- **slug**: MUST be hyphen-case (`^[a-z0-9][a-z0-9-]*$`). Do not use underscores.
|
|
228
|
-
- **goal** (in body string): One sentence stating WHY this Story exists
|
|
197
|
+
- **goal** (in body string): One sentence stating WHY this Story exists within the Epic.
|
|
229
198
|
- **changes** (in body string): Each entry is an object `{ path, assumption }` where `assumption` is one of `creates | refactors-existing | deletes`. The Phase 8 validator probes the base branch for every declared path and rejects the decompose when the declared assumption contradicts reality: `creates` against an existing path is an error, `refactors-existing` / `deletes` against a missing path is an error. Use `refactors-existing` for in-place edits to a file already on `main`; `creates` for net-new files; `deletes` for removals. Acceptable path shapes include explicit files (`src/components/Foo.tsx`), glob patterns (`tests/e2e/*.spec.ts`, `**/*.astro`), and module identifiers that resolve to files.
|
|
230
199
|
- **references** (in body string, optional): Object-form entries `{ path, assumption: "exists" }` for paths the Story **reads** but does not modify (test fixtures it relies on, sibling modules it imports, feature files it scans). The validator probes these like `changes` and rejects the decompose when an `exists` path is absent on the base branch. Use this list to make read-dependencies explicit so a hallucinated or stale assumption surfaces at planning time rather than execution time.
|
|
231
200
|
- **NEW-FILE CONTRACT (must-follow)**: Any path the Story references in `goal`, `acceptance`, or `verify` that does **not** already exist on `main` MUST also appear in the same Story's `changes` array with `assumption: "creates"`. The freshness validator probes `main` for every referenced code path and rejects the decompose when a missing path is absent from `changes` — even when the Story is the one authoring the file. Example: a Story creating `tests/lib/foo.test.js` whose `verify` runs `node --test tests/lib/foo.test.js` MUST include `{ "path": "tests/lib/foo.test.js", "assumption": "creates" }` in `changes`, otherwise the validator emits a freshness miss and the decompose round trips for a re-emit.
|
|
@@ -245,9 +214,8 @@ The first question is **cohesion, not count**: *is this one coherent change with
|
|
|
245
214
|
|
|
246
215
|
- **One Story = one coherent change with one reason to exist.** If you cannot state that reason in a sentence, the Story is probably two Stories.
|
|
247
216
|
- **Single-consumer merge rule.** A Story whose only consumer is one sibling Story should be **merged into that sibling** rather than emitted separately — a single-consumer downstream slice is not its own unit of work.
|
|
248
|
-
- **Split independent, parallelizable work** into sibling Stories
|
|
217
|
+
- **Split independent, parallelizable work** into sibling Stories — but only when the pieces genuinely have separate reasons to exist.
|
|
249
218
|
- **Declare `wide` with a one-line reason when a change is legitimately broad** (a cohesive cutover that spans many files for one reason).
|
|
250
|
-
- **Every Feature MUST decompose into at least TWO Stories.** A Feature with a single Story is the work of a Story, not a Feature. **Resolve it by COLLAPSING, not splitting** — drop the Feature wrapper and attach its lone Story to a sibling Feature (or merge the Feature into another). Do NOT manufacture a second Story to satisfy the rule; splitting a lone Story into two inflates ticket count and defeats the "fewer, right-sized Stories" goal. The validator (`ticket-validator.js` → `assertNoSingleStoryFeature`) HARD-rejects a decomposition containing a Feature with fewer than two Stories, naming the offending Feature; the Phase 8 consolidation pass (`epic-plan-consolidate`) performs the collapse holistically before the validator runs.
|
|
251
219
|
|
|
252
220
|
**Numeric backstop.** The thresholds are defined **once**, in the `DEFAULT_TASK_SIZING` constant in `ticket-validator-sizing.js` (operator-overridable via `agentSettings.planning.taskSizing`). They are a backstop, not the primary rule — do not restate divergent numbers anywhere else. The defaults:
|
|
253
221
|
|
|
@@ -291,7 +259,7 @@ The Acceptance Spec's AC table (columns `AC ID | Outcome | Feature File | Scenar
|
|
|
291
259
|
|
|
292
260
|
When the Acceptance Spec contains **one or more `Disposition: new` rows**, you MUST emit **exactly one** dedicated wave-0 scaffold Story whose sole job is to create those `.feature` files with `@skip`-tagged scenarios BEFORE any implementation Story runs:
|
|
293
261
|
|
|
294
|
-
- **goal** (in body string): contains the literal token `bdd-scaffold
|
|
262
|
+
- **goal** (in body string): contains the literal token `bdd-scaffold`.
|
|
295
263
|
- **depends_on**: EMPTY (`[]`) — the scaffold runs first, in wave 0.
|
|
296
264
|
- **changes** (in body string): one `{ path, assumption: "creates" }` entry per distinct `.feature` file named in a `new` row.
|
|
297
265
|
- **acceptance** (top-level array): MUST assert (a) every new `.feature` file exists, and (b) every new scenario within them carries an `@skip` tag. Keep items observable (a command exits 0; a file exists at a path).
|
|
@@ -306,7 +274,6 @@ When the Acceptance Spec contains **zero `new`-disposition rows** (every row is
|
|
|
306
274
|
"slug": "scaffold-billing-feature-files",
|
|
307
275
|
"type": "story",
|
|
308
276
|
"title": "Scaffold @skip-tagged billing feature files",
|
|
309
|
-
"parent_slug": "billing-flows",
|
|
310
277
|
"depends_on": [],
|
|
311
278
|
"labels": ["type::story", "persona::qa-engineer"],
|
|
312
279
|
"acceptance": [
|
|
@@ -398,7 +365,7 @@ Do NOT silently allow two Stories to write the same root configuration
|
|
|
398
365
|
file in the same wave; parallel dispatch would produce a merge conflict
|
|
399
366
|
on every Story-to-Epic close after the first.
|
|
400
367
|
|
|
401
|
-
CRITICAL: Dependencies should follow execution blockers.
|
|
368
|
+
CRITICAL: Dependencies should follow execution blockers. Stories attach directly to the Epic — never emit a 'parent_slug' field.
|
|
402
369
|
IMPORTANT DEPENDENCY RULE: A Story's `depends_on` MUST only reference other Stories within the SAME Epic. If two Stories have a logical ordering requirement, express it via Story-level `depends_on`.
|
|
403
370
|
WARNING: You MUST conserve your output limit. Do NOT generate more than ${maxTickets} tickets in total. Merge narrow work into cohesive capability Stories. Do NOT cut off the JSON array prematurely!
|
|
404
371
|
|
|
@@ -3,7 +3,7 @@ name: epic-plan-spec-author
|
|
|
3
3
|
description: >-
|
|
4
4
|
Author the PRD, Tech Spec, Acceptance Spec markdown, and risk-verdict JSON
|
|
5
5
|
for an Epic from the planner authoring context emitted by
|
|
6
|
-
`epic-plan-spec.js --emit-context`. Use during Phase 7 of `/
|
|
6
|
+
`epic-plan-spec.js --emit-context`. Use during Phase 7 of `/plan` when
|
|
7
7
|
the host LLM needs to write the four artifacts before `epic-plan-spec.js`
|
|
8
8
|
persists them.
|
|
9
9
|
allowed_tools:
|
|
@@ -16,7 +16,7 @@ allowed_tools:
|
|
|
16
16
|
|
|
17
17
|
## Policy Capsule
|
|
18
18
|
|
|
19
|
-
- Run only during `/
|
|
19
|
+
- Run only during `/plan` Phase 7, after `epic-plan-spec.js --emit-context` has written `temp/epic-<Epic_ID>/planner-context.json`; fail loudly if the file is missing rather than fabricating context.
|
|
20
20
|
- Write exactly four artifacts and only inside `temp/epic-<Epic_ID>/`: `prd.md`, `techspec.md`, `risk-verdict.json`, `acceptance-spec.md`. All four MUST exist on disk before returning.
|
|
21
21
|
- Start each markdown artifact at the correct `##` heading (PRD → `## Overview`, Tech Spec → `## Technical Overview`, Acceptance Spec → `## Acceptance Criteria`) — never emit a top-level `#` heading. `risk-verdict.json` is raw JSON conforming to `.agents/schemas/risk-verdict.schema.json`.
|
|
22
22
|
- Judge risk from what the change *does* (the PRD / Tech Spec you just wrote), never from keyword presence — "out of scope: billing" is not a billing change; "rotate the credential vault" is high-risk even without a security keyword.
|
|
@@ -40,7 +40,7 @@ the Acceptance Spec).
|
|
|
40
40
|
|
|
41
41
|
## When to use
|
|
42
42
|
|
|
43
|
-
`/
|
|
43
|
+
`/plan` Phase 7, immediately after `epic-plan-spec.js --emit-context`
|
|
44
44
|
writes `temp/epic-<Epic_ID>/planner-context.json`. This Skill replaces the
|
|
45
45
|
inline "Author the PRD" / "Author the Tech Spec" steps from the legacy
|
|
46
46
|
workflow body — the calling workflow dispatches this Skill via the `Skill`
|
|
@@ -366,7 +366,7 @@ CRITICAL REQUIREMENTS:
|
|
|
366
366
|
- Acceptance Outcomes MUST NOT prescribe a commit subject that begins with a non-Conventional-Commits prefix (allowed leading types: feat|fix|chore|refactor|perf|docs|style|test|build|ci|revert). The legacy `baseline-refresh` token used as a leading subject prescription is forbidden — commitlint will reject it at commit time, and the decompose-time validator (`ticket-validator.js` → `validateAcceptanceSubjectPrefix`) will reject the decompose with `code: 'forbidden-subject-prefix'`. Use a Conventional-Commits subject (e.g. `chore(baselines): refresh ...`) and a body trailer (e.g. `baseline-refresh: true` — trailer with a value, not a subject prefix) when a machine-readable marker is needed. See Epic #2501 for rationale.
|
|
367
367
|
```
|
|
368
368
|
|
|
369
|
-
### Step 6 — Hand back to `/
|
|
369
|
+
### Step 6 — Hand back to `/plan`
|
|
370
370
|
|
|
371
371
|
All four files exist; return. The caller will run
|
|
372
372
|
`node .agents/scripts/epic-plan-spec.js --epic <Epic_ID> --prd
|
|
@@ -25,8 +25,8 @@ allowed_tools:
|
|
|
25
25
|
|
|
26
26
|
## Role
|
|
27
27
|
|
|
28
|
-
Context aggregator. Resolves a ticket's hierarchy (
|
|
29
|
-
|
|
28
|
+
Context aggregator. Resolves a ticket's hierarchy (Story → Epic)
|
|
29
|
+
and stitches the linked planning artifacts into a
|
|
30
30
|
single prompt the executor consumes.
|
|
31
31
|
|
|
32
32
|
## When to use
|