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
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* mirrored this roster for an in-session runner was deleted with the
|
|
9
9
|
* dead epic-runner stratum in Story #3908; the host-LLM-drives-CLIs
|
|
10
10
|
* model reaches every close-tail listener through the `lifecycle-emit.js`
|
|
11
|
-
* CLI shells in `/
|
|
11
|
+
* CLI shells in `/deliver`'s Phase 6 / 7.5 / 8 markdown invocations,
|
|
12
12
|
* which call this builder.)
|
|
13
13
|
*
|
|
14
14
|
* Canonical roster (registration order):
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* `{ epicId, prNumber, mergeCommitSha, mergedAt, pollAttempts }`.
|
|
21
21
|
* 4. If the budget is exceeded without observing a merge, return
|
|
22
22
|
* a `failed` classification with reason `budget-exceeded` and
|
|
23
|
-
* do NOT emit `epic.merge.confirmed`. The /
|
|
23
|
+
* do NOT emit `epic.merge.confirmed`. The /deliver
|
|
24
24
|
* blocker-handler flow surfaces this via `agent::blocked`.
|
|
25
25
|
*
|
|
26
26
|
* Resume contract (AC of Task #2907): the ledger is the source of
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* webhookEvents entry lifecycle event
|
|
16
16
|
* -------------------- ---------------------
|
|
17
|
-
* `epic-started` (emitted at /
|
|
17
|
+
* `epic-started` (emitted at /deliver kickoff;
|
|
18
18
|
* this listener handles `epic.snapshot.start`)
|
|
19
19
|
* `epic-blocked` `epic.blocked`
|
|
20
20
|
* `epic-complete` `epic.complete`
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Idempotency contract (AC-10): per-instance `Set<string>` of
|
|
24
24
|
* `${event}:${seqId}` keys. A repeat `(event, seqId)` short-circuits
|
|
25
25
|
* without re-polling and emits nothing. Combined with the bus-level
|
|
26
|
-
* replay defence, this is sufficient — re-running `/
|
|
26
|
+
* replay defence, this is sufficient — re-running `/deliver` after
|
|
27
27
|
* a crash will produce a NEW seqId and the listener legitimately
|
|
28
28
|
* re-runs the poll loop (which is itself idempotent: the outcome map
|
|
29
29
|
* always reflects the live GitHub state).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/orchestration/manifest-builder.js — Manifest Building Logic
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 2-tier-only producer. Reads Story tickets from `allTickets` directly,
|
|
5
5
|
* computes Story-scoped waves, and emits the `waves[].stories[]` /
|
|
6
6
|
* Story-only `storyManifest` shape. The pre-Epic-#3163 Task-tier branch
|
|
7
7
|
* has been removed; the framework no longer carries a Task-tier
|
|
@@ -48,7 +48,7 @@ function extractSectionList(body, heading) {
|
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Project a Story ticket into the inline-acceptance/verify shape required by
|
|
51
|
-
* the
|
|
51
|
+
* the 2-tier waves[].stories[] schema. Reads `## Acceptance` /
|
|
52
52
|
* `## Acceptance Criteria` and `## Verify` sections from the body.
|
|
53
53
|
*
|
|
54
54
|
* @param {object} story
|
|
@@ -95,7 +95,7 @@ function projectStoryForWave(story, epicId) {
|
|
|
95
95
|
const AGENT_DONE_LABEL = STATE_LABELS.DONE;
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
* Build the Story-only manifest array used by the
|
|
98
|
+
* Build the Story-only manifest array used by the 2-tier hierarchy path.
|
|
99
99
|
* Reads Story tickets directly from `allTickets`; there is no Task tier
|
|
100
100
|
* to walk. Each entry exposes an empty `tasks: []` to keep downstream
|
|
101
101
|
* consumers (renderers, dispatch helpers) on a single per-Story shape
|
|
@@ -145,7 +145,7 @@ function buildStoryOnlyManifest(stories, epicId) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
|
-
* Build the wave records for a
|
|
148
|
+
* Build the wave records for a 2-tier manifest. Each wave entry exposes a
|
|
149
149
|
* `stories[]` projection (instead of the legacy `tasks[]`) so dispatch
|
|
150
150
|
* consumers can fan Story execution out wave-by-wave without ever seeing
|
|
151
151
|
* a `type::task` ticket.
|
|
@@ -200,7 +200,7 @@ export function buildManifest({
|
|
|
200
200
|
epicTitle: epic?.title ?? '',
|
|
201
201
|
executor: 'claude-code',
|
|
202
202
|
dryRun,
|
|
203
|
-
hierarchy: '
|
|
203
|
+
hierarchy: '2-tier',
|
|
204
204
|
summary: {
|
|
205
205
|
totalStories,
|
|
206
206
|
doneStories,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - "parked" — the Story is genuinely outside the manifest (carved off
|
|
10
10
|
* mid-sprint, no recut lineage). The operator should explicitly
|
|
11
11
|
* adopt it into the current Epic or defer it. Surfaced as a
|
|
12
|
-
* structured comment so `/
|
|
12
|
+
* structured comment so `/deliver` has a single checkpoint.
|
|
13
13
|
*
|
|
14
14
|
* Both categories are informational at the wave-completeness gate — they do
|
|
15
15
|
* not fail closure by themselves. The gate continues to enforce that every
|
|
@@ -81,7 +81,7 @@ export function renderParkedFollowOnsComment(epicId, classification) {
|
|
|
81
81
|
`## 🪝 Parked Follow-Ons & Recuts — Epic #${epicId}`,
|
|
82
82
|
'',
|
|
83
83
|
'Stories created under this Epic that are **not** in the frozen dispatch',
|
|
84
|
-
'manifest. Surfaced here so `/
|
|
84
|
+
'manifest. Surfaced here so `/deliver` can gate on them at the',
|
|
85
85
|
'completeness check.',
|
|
86
86
|
'',
|
|
87
87
|
`- **Recuts** (attributable to a manifest Story): ${recuts.length}`,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* plan-router — given an Epic's current labels, decide which plan-phase CLI
|
|
3
3
|
* should run next.
|
|
4
4
|
*
|
|
5
|
-
* Used by the local `/
|
|
5
|
+
* Used by the local `/plan` wrapper (chains spec → decompose).
|
|
6
6
|
*
|
|
7
7
|
* The router is intentionally stateless. Callers feed the current label set
|
|
8
8
|
* (a string array, usually from `provider.getEpic(id).labels`) and receive a
|
|
@@ -21,7 +21,7 @@ export const PLAN_PHASE_NAMES = Object.freeze({
|
|
|
21
21
|
* path used by the local wrapper; `command` is the slash-command invocation
|
|
22
22
|
* operators fire.
|
|
23
23
|
*
|
|
24
|
-
* Spec and Decompose are served by the unified `/
|
|
24
|
+
* Spec and Decompose are served by the unified `/plan` wrapper with a
|
|
25
25
|
* `--phase` flag — the phase workflows themselves live at
|
|
26
26
|
* `.agents/workflows/helpers/epic-plan-{spec,decompose}.md` and are not
|
|
27
27
|
* directly invokable slash commands.
|
|
@@ -33,20 +33,20 @@ export const PLAN_PHASE_DESCRIPTORS = Object.freeze({
|
|
|
33
33
|
[PLAN_PHASE_NAMES.SPEC]: {
|
|
34
34
|
phase: PLAN_PHASE_NAMES.SPEC,
|
|
35
35
|
script: '.agents/scripts/epic-plan-spec.js',
|
|
36
|
-
command: '/
|
|
36
|
+
command: '/plan --phase spec',
|
|
37
37
|
parkingLabel: AGENT_LABELS.REVIEW_SPEC,
|
|
38
38
|
},
|
|
39
39
|
[PLAN_PHASE_NAMES.DECOMPOSE]: {
|
|
40
40
|
phase: PLAN_PHASE_NAMES.DECOMPOSE,
|
|
41
41
|
script: '.agents/scripts/epic-plan-decompose.js',
|
|
42
|
-
command: '/
|
|
42
|
+
command: '/plan --phase decompose',
|
|
43
43
|
parkingLabel: AGENT_LABELS.READY,
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Given the Epic's current labels, pick the next plan phase to run in the
|
|
49
|
-
* local `/
|
|
49
|
+
* local `/plan` wrapper.
|
|
50
50
|
*
|
|
51
51
|
* Precedence:
|
|
52
52
|
* 1. If the Epic already carries `agent::ready`, there is nothing left to
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* phases/ticket-closure.js — post-merge ticket transition + cascade phase.
|
|
3
3
|
*
|
|
4
4
|
* Transitions the Story to `agent::done`, then runs cascade completion
|
|
5
|
-
* so any parent
|
|
5
|
+
* so any parent Epic-side rollup that is now fully resolved closes too.
|
|
6
6
|
*
|
|
7
|
-
* **
|
|
7
|
+
* **2-tier closure (Story #3127).** Under the 2-tier hierarchy a Story
|
|
8
8
|
* is the leaf unit of execution and has no child tickets — `tasks`
|
|
9
9
|
* arrives as an empty array. `batchTransitionTickets` handles the empty
|
|
10
10
|
* input cleanly (the loop trivially completes), the Story is
|
|
11
11
|
* transitioned alone, and cascade completion walks upward to
|
|
12
|
-
*
|
|
12
|
+
* parent. No branch on hierarchy mode is required here.
|
|
13
13
|
*
|
|
14
14
|
* Notifications are intentionally
|
|
15
15
|
* NOT routed through the per-ticket transitions here — `notificationPhase`
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Cache adapter for the snapshot/DAG envelope produced by
|
|
5
5
|
* `epic-deliver-preflight.js` so `epic-deliver-prepare.js` can skip the
|
|
6
|
-
* second walk of Epic →
|
|
6
|
+
* second walk of Epic → Story when the underlying Epic ticket
|
|
7
7
|
* has not drifted between the two operator invocations.
|
|
8
8
|
*
|
|
9
9
|
* Contract:
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `close-validate.end` `emitted` records and groups them by `failedGate`.
|
|
7
7
|
* Returns one finding per gate that appears in **two or more distinct
|
|
8
8
|
* Stories** within the same Epic. Findings are the substrate
|
|
9
|
-
* `/
|
|
9
|
+
* `/deliver` consumes when upserting the cross-Story
|
|
10
10
|
* `recurring-failure-class` structured comment on the Epic ticket.
|
|
11
11
|
*
|
|
12
12
|
* The helper is intentionally pure: no GitHub I/O, no global state. It
|
|
@@ -328,7 +328,7 @@ function followOnBody(s) {
|
|
|
328
328
|
``,
|
|
329
329
|
`Trigger: ${trigger}.`,
|
|
330
330
|
``,
|
|
331
|
-
`Apply the meta::framework-gap label so /
|
|
331
|
+
`Apply the meta::framework-gap label so /plan Phase 0 surfaces it on the next planning pass.`,
|
|
332
332
|
].join('\n');
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -130,8 +130,8 @@ async function warnIfEpicLooksPopulated({ epicId, provider, logger }) {
|
|
|
130
130
|
* `logger` so the silent failure becomes visible. Probe failure degrades
|
|
131
131
|
* gracefully — the function never throws on the guard alone.
|
|
132
132
|
*
|
|
133
|
-
* **
|
|
134
|
-
* hierarchy (Epic →
|
|
133
|
+
* **2-tier ledgers (Story #3151, Story #3200).** Under the 2-tier
|
|
134
|
+
* hierarchy (Epic → Story; no Task-tier children), `friction`
|
|
135
135
|
* / `parked` / `recuts` / `storyPerfSummaries` are all Story-scoped, so
|
|
136
136
|
* the function continues to produce a non-empty signals report. The
|
|
137
137
|
* empty-walk guard above is **not** triggered for this shape because
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Story #1155 (Epic #1142, 5.40.0) — extracts the helper-driven
|
|
5
5
|
* `epic-retro` invocation into a callable module so the
|
|
6
|
-
* `/
|
|
6
|
+
* `/deliver` runner can fire Phase E without a separate LLM
|
|
7
7
|
* helper turn. (Story #2259, Epic #2172: the legacy deliver-runner
|
|
8
8
|
* CLI was retired once delivery moved entirely into the slash
|
|
9
|
-
* command.) The retro fires before `/
|
|
9
|
+
* command.) The retro fires before `/deliver`'s finalize step
|
|
10
10
|
* opens the PR — the operator's PR-merge is the final human gate, not
|
|
11
11
|
* the retro itself.
|
|
12
12
|
*
|
|
@@ -56,7 +56,7 @@ export { gatherRetroSignals } from './retro/phases/gather-signals.js';
|
|
|
56
56
|
/**
|
|
57
57
|
* Public: compose and post the retro structured comment on the Epic.
|
|
58
58
|
*
|
|
59
|
-
* Story #1290 (Epic #1143) — at /
|
|
59
|
+
* Story #1290 (Epic #1143) — at /deliver Phase 5, the runner invokes
|
|
60
60
|
* the self-healing checks registry with `scope: 'retro'` and
|
|
61
61
|
* `autoFix: false`. The retro is **read-only by construction**: the
|
|
62
62
|
* registry runner enforces the invariant by throwing if any caller flips
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* is enumerated).
|
|
23
23
|
* - `standard` — everything else, including absent/malformed risk envelopes
|
|
24
24
|
* and a `medium` level. Fail toward the middle, never toward
|
|
25
|
-
* `light`: an Epic that skipped `/
|
|
25
|
+
* `light`: an Epic that skipped `/plan` has no risk
|
|
26
26
|
* verdict, and treating it as `light` would under-review
|
|
27
27
|
* unjudged work while `standard` preserves today's behaviour.
|
|
28
28
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* phases/wrong-tree-guard.js — detect worktree/main-checkout edit divergence.
|
|
3
3
|
*
|
|
4
|
-
* Story #3364 — `/single-story-deliver` (and `/
|
|
4
|
+
* Story #3364 — `/single-story-deliver` (and `/deliver`) materializes a
|
|
5
5
|
* per-Story worktree and instructs the agent to `cd` into it before editing.
|
|
6
6
|
* On Windows that guidance is silently insufficient: `cd <workCwd>` steers the
|
|
7
7
|
* Bash tool's working directory, but the path-based Edit/Write tools operate on
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* spec-freshness.js — Tech Spec post-author cross-validation against the
|
|
3
3
|
* current codebase.
|
|
4
4
|
*
|
|
5
|
-
* `/
|
|
5
|
+
* `/plan` Phase 7 authors PRD + Tech Spec from documentation alone.
|
|
6
6
|
* When `project.docsContextFiles` (architecture.md, etc.) drift from
|
|
7
7
|
* the real source tree, the Architect persona happily cites modules and
|
|
8
8
|
* paths that no longer exist. The mismatch only surfaces at delivery time,
|
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/orchestration/spec-renderer.js — tickets.json → epic-spec.yaml
|
|
3
|
-
* projection (
|
|
3
|
+
* projection (2-tier shape, Story #4041).
|
|
4
4
|
*
|
|
5
5
|
* The decomposer (`epic-plan-decompose-author`) produces a flat array
|
|
6
|
-
* of ticket objects
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `{ epic,
|
|
11
|
-
* `
|
|
6
|
+
* of Story ticket objects keyed by stable `slug`s and linked by
|
|
7
|
+
* `depends_on`. The spec reconciler consumes the declarative
|
|
8
|
+
* structural representation defined by
|
|
9
|
+
* `.agents/schemas/epic-spec.schema.json` — a flat
|
|
10
|
+
* `{ epic, stories: [...] }` shape with Story-level `wave`,
|
|
11
|
+
* `dependsOn`, and inline `acceptance[]` / `verify[]` arrays
|
|
12
12
|
* projected from the decomposer's edges.
|
|
13
13
|
*
|
|
14
|
-
* Under the
|
|
15
|
-
* children — acceptance and verify steps live
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* "Contract Cutovers — No Shim Layer").
|
|
20
|
-
* decomposer input is rejected at index time.
|
|
14
|
+
* Under the 2-tier hierarchy (Story #4041), Stories have no Feature
|
|
15
|
+
* parent and no Task children — acceptance and verify steps live
|
|
16
|
+
* inline on the Story, and Stories attach directly to the Epic. Any
|
|
17
|
+
* `feature` or `task` ticket in the decomposer input is rejected at
|
|
18
|
+
* index time (hard cutover; see `.agents/rules/git-conventions.md` §
|
|
19
|
+
* "Contract Cutovers — No Shim Layer").
|
|
21
20
|
*
|
|
22
21
|
* `renderSpec(tickets, opts)` is the pure projection between those
|
|
23
22
|
* two shapes. It:
|
|
24
23
|
*
|
|
25
|
-
* 1. Indexes the flat array by slug
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* 1. Indexes the flat array by slug. Any unrecognised type
|
|
25
|
+
* (including the historical `feature` / `task`) raises
|
|
26
|
+
* immediately.
|
|
28
27
|
* 2. Filters Story `depends_on` edges down to inter-Story
|
|
29
28
|
* references in the same Epic.
|
|
30
29
|
* 3. Layers Stories into waves via `Graph.assignLayers` (depth in
|
|
@@ -33,9 +32,9 @@
|
|
|
33
32
|
* convention (`build-wave-dag.js` produces the same layering at
|
|
34
33
|
* dispatch time from the live GH state, so the spec's waves are
|
|
35
34
|
* observationally identical to what dispatch will compute).
|
|
36
|
-
* 4. Walks the
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* 4. Walks the Stories in decomposer-declared order, preserving
|
|
36
|
+
* the order the LLM emitted so the reconciler's diff stays
|
|
37
|
+
* human-readable.
|
|
39
38
|
* 5. Strips `agent::*` labels from every entity. The decomposer
|
|
40
39
|
* doesn't normally write them, but they can leak via reverse-
|
|
41
40
|
* bootstrap from live GH state — and the schema forbids them
|
|
@@ -162,7 +161,7 @@ function sanitizeLabels(labels) {
|
|
|
162
161
|
* Convert a decomposer body value into a spec `body` string. The
|
|
163
162
|
* decomposer schema admits two shapes for a Story body:
|
|
164
163
|
*
|
|
165
|
-
* - A short string (preferred under the
|
|
164
|
+
* - A short string (preferred under the 2-tier hierarchy).
|
|
166
165
|
* - A structured object (`{ goal, changes[], acceptance[],
|
|
167
166
|
* verify[] }`) carried over from the legacy 4-tier Task body
|
|
168
167
|
* shape, when the decomposer chooses to inline the Story's
|
|
@@ -215,16 +214,12 @@ function assignNonEmpty(target, key, value) {
|
|
|
215
214
|
}
|
|
216
215
|
|
|
217
216
|
/**
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* (parents-before-children is guaranteed by the validator's
|
|
222
|
-
* topological sort, but we don't need that invariant here — we walk
|
|
223
|
-
* features in array order, then look up their children by parent_slug
|
|
224
|
-
* in the order the decomposer emitted them).
|
|
217
|
+
* Index the flat ticket array by slug. Returns the ordered Story slug
|
|
218
|
+
* list alongside the lookup map so the renderer can walk Stories in
|
|
219
|
+
* the decomposer's emit order.
|
|
225
220
|
*
|
|
226
|
-
* Under the
|
|
227
|
-
*
|
|
221
|
+
* Under the 2-tier hierarchy (Story #4041), only the `story` type is
|
|
222
|
+
* recognised. Any other type — including the historical `feature` /
|
|
228
223
|
* `task` — falls through to the unknown-type guard and raises
|
|
229
224
|
* immediately; there is no silent drop.
|
|
230
225
|
*
|
|
@@ -232,7 +227,6 @@ function assignNonEmpty(target, key, value) {
|
|
|
232
227
|
*/
|
|
233
228
|
function indexTickets(tickets) {
|
|
234
229
|
const bySlug = new Map();
|
|
235
|
-
const featureSlugs = [];
|
|
236
230
|
const storySlugs = [];
|
|
237
231
|
|
|
238
232
|
for (const t of tickets) {
|
|
@@ -247,15 +241,14 @@ function indexTickets(tickets) {
|
|
|
247
241
|
throw new Error(`[spec-renderer] duplicate slug "${slug}"`);
|
|
248
242
|
}
|
|
249
243
|
bySlug.set(slug, t);
|
|
250
|
-
if (t.type === '
|
|
251
|
-
else if (t.type === 'story') storySlugs.push(slug);
|
|
244
|
+
if (t.type === 'story') storySlugs.push(slug);
|
|
252
245
|
else {
|
|
253
246
|
throw new Error(
|
|
254
247
|
`[spec-renderer] ticket "${slug}" has unknown type "${t.type}"`,
|
|
255
248
|
);
|
|
256
249
|
}
|
|
257
250
|
}
|
|
258
|
-
return { bySlug,
|
|
251
|
+
return { bySlug, storySlugs };
|
|
259
252
|
}
|
|
260
253
|
|
|
261
254
|
/**
|
|
@@ -283,9 +276,8 @@ function layerStories(storySlugs, bySlug) {
|
|
|
283
276
|
* Project the decomposer ticket array into the structural spec object.
|
|
284
277
|
*
|
|
285
278
|
* @param {Array<object>} tickets — flat ticket array as emitted by the
|
|
286
|
-
* decomposer Skill (`type`
|
|
287
|
-
* `
|
|
288
|
-
* `acceptance`, `verify`).
|
|
279
|
+
* decomposer Skill (`type` = story, `slug`, `depends_on`, `title`,
|
|
280
|
+
* `body`, `labels`, `acceptance`, `verify`).
|
|
289
281
|
* @param {object} opts
|
|
290
282
|
* @param {{id: number, title: string, body?: string, labels?: string[]}} opts.epic
|
|
291
283
|
* — Epic descriptor (the decomposer doesn't emit the Epic row; it's
|
|
@@ -297,7 +289,7 @@ function layerStories(storySlugs, bySlug) {
|
|
|
297
289
|
* @param {boolean} [opts.validate=true] — when `false`, skip final
|
|
298
290
|
* schema validation (used by tests that intentionally craft invalid
|
|
299
291
|
* inputs).
|
|
300
|
-
* @returns {object} spec — `{ epic,
|
|
292
|
+
* @returns {object} spec — `{ epic, stories, gates? }` matching
|
|
301
293
|
* `.agents/schemas/epic-spec.schema.json`.
|
|
302
294
|
*/
|
|
303
295
|
function validateRenderSpecInputs(tickets, opts) {
|
|
@@ -318,18 +310,6 @@ function validateRenderSpecInputs(tickets, opts) {
|
|
|
318
310
|
}
|
|
319
311
|
}
|
|
320
312
|
|
|
321
|
-
function bucketStoriesByFeature({ storySlugs, bySlug }) {
|
|
322
|
-
const storiesByFeature = new Map();
|
|
323
|
-
for (const slug of storySlugs) {
|
|
324
|
-
const story = bySlug.get(slug);
|
|
325
|
-
const parent = story.parent_slug;
|
|
326
|
-
if (typeof parent !== 'string' || !bySlug.has(parent)) continue;
|
|
327
|
-
if (!storiesByFeature.has(parent)) storiesByFeature.set(parent, []);
|
|
328
|
-
storiesByFeature.get(parent).push(slug);
|
|
329
|
-
}
|
|
330
|
-
return storiesByFeature;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
313
|
function pickStringArray(primary, fallback) {
|
|
334
314
|
const src = Array.isArray(primary)
|
|
335
315
|
? primary
|
|
@@ -342,7 +322,7 @@ function pickStringArray(primary, fallback) {
|
|
|
342
322
|
}
|
|
343
323
|
|
|
344
324
|
function extractStoryAcceptanceVerify(story) {
|
|
345
|
-
//
|
|
325
|
+
// Stories carry inline
|
|
346
326
|
// acceptance[] / verify[] arrays directly on the ticket. The
|
|
347
327
|
// decomposer may emit these either at the top level of the ticket
|
|
348
328
|
// (preferred) or nested under a structured `body` object (legacy
|
|
@@ -380,20 +360,6 @@ function buildStoryOut({ story, layers, storySet }) {
|
|
|
380
360
|
return out;
|
|
381
361
|
}
|
|
382
362
|
|
|
383
|
-
function buildFeatureOut({ feature, storySlugs, bySlug, layers, storySet }) {
|
|
384
|
-
const stories = storySlugs.map((storySlug) =>
|
|
385
|
-
buildStoryOut({
|
|
386
|
-
story: bySlug.get(storySlug),
|
|
387
|
-
layers,
|
|
388
|
-
storySet,
|
|
389
|
-
}),
|
|
390
|
-
);
|
|
391
|
-
const out = { slug: feature.slug, title: feature.title, stories };
|
|
392
|
-
assignNonEmpty(out, 'body', renderBody(feature.body));
|
|
393
|
-
assignNonEmpty(out, 'labels', sanitizeLabels(feature.labels));
|
|
394
|
-
return out;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
363
|
function buildEpicOut(epic) {
|
|
398
364
|
const out = { id: epic.id, title: epic.title };
|
|
399
365
|
assignNonEmpty(out, 'body', renderBody(epic.body));
|
|
@@ -432,22 +398,19 @@ export function renderSpec(tickets, opts = {}) {
|
|
|
432
398
|
validateRenderSpecInputs(tickets, opts);
|
|
433
399
|
const { epic, gates, schemaPath, validate = true } = opts;
|
|
434
400
|
|
|
435
|
-
const { bySlug,
|
|
401
|
+
const { bySlug, storySlugs } = indexTickets(tickets);
|
|
436
402
|
const { layers } = layerStories(storySlugs, bySlug);
|
|
437
|
-
const storiesByFeature = bucketStoriesByFeature({ storySlugs, bySlug });
|
|
438
403
|
const storySet = new Set(storySlugs);
|
|
439
404
|
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
storySlugs: storiesByFeature.get(featureSlug) ?? [],
|
|
444
|
-
bySlug,
|
|
405
|
+
const stories = storySlugs.map((storySlug) =>
|
|
406
|
+
buildStoryOut({
|
|
407
|
+
story: bySlug.get(storySlug),
|
|
445
408
|
layers,
|
|
446
409
|
storySet,
|
|
447
410
|
}),
|
|
448
411
|
);
|
|
449
412
|
|
|
450
|
-
const spec = { epic: buildEpicOut(epic),
|
|
413
|
+
const spec = { epic: buildEpicOut(epic), stories };
|
|
451
414
|
const gatesOut = buildGatesOut(gates);
|
|
452
415
|
if (gatesOut) spec.gates = gatesOut;
|
|
453
416
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* spec-section-validator.js — Phase 7.5 Tech Spec post-authoring section gate.
|
|
3
3
|
*
|
|
4
|
-
* `/
|
|
4
|
+
* `/plan` Phase 7 authors a Tech Spec from documentation and the PRD.
|
|
5
5
|
* Phase 8.3 (Holistic Consolidation) then reconciles the draft ticket array
|
|
6
6
|
* against the Tech Spec's `## Delivery Slicing` section, which the
|
|
7
7
|
* decompose-author skill uses as the capability-boundary anchor. When the
|
|
@@ -100,7 +100,7 @@ export function renderBaselineFrictionBody({ rows, epicId, storyId } = {}) {
|
|
|
100
100
|
const triage = [
|
|
101
101
|
'**Triage:**',
|
|
102
102
|
`1. Open each suspect Story above and run \`npm run maintainability:update\` (or \`npm run crap:update\`) on **its** branch, then commit with a \`baseline-refresh:\` subject and re-close it.`,
|
|
103
|
-
`2. Re-run \`/
|
|
103
|
+
`2. Re-run \`/deliver ${storyId}\` once the suspect Story's refresh has merged into \`epic/${epicId}\`.`,
|
|
104
104
|
`3. If the suspect column reads \`_unknown_\`, the path has no commit on \`epic/${epicId}\` — investigate the baseline file directly before refreshing.`,
|
|
105
105
|
];
|
|
106
106
|
|
|
@@ -127,7 +127,7 @@ export async function runGatesAndRefresh(
|
|
|
127
127
|
* Read the parent Epic's judged `planningRisk` envelope off its
|
|
128
128
|
* `epic-plan-state` checkpoint so the Story-scope review can inherit the
|
|
129
129
|
* Epic's review depth (Story #3940). Best-effort and total — it reuses the
|
|
130
|
-
* shared `read` from `epic-plan-state-store.js` (the same reader `/
|
|
130
|
+
* shared `read` from `epic-plan-state-store.js` (the same reader `/plan
|
|
131
131
|
* --resume` and `epic-audit-prepare.js`'s `resolveRiskRoutedLenses` use, no
|
|
132
132
|
* third bespoke reader) and never fails the close:
|
|
133
133
|
*
|
|
@@ -137,7 +137,7 @@ export async function runGatesAndRefresh(
|
|
|
137
137
|
*
|
|
138
138
|
* A `null` result threads through `runStoryCodeReview` → `runCodeReview`
|
|
139
139
|
* unchanged, so depth resolves from diff width alone (`standard`), preserving
|
|
140
|
-
* today's behaviour for an Epic that skipped `/
|
|
140
|
+
* today's behaviour for an Epic that skipped `/plan`.
|
|
141
141
|
*
|
|
142
142
|
* @param {{ provider: object, epicId: number|null|undefined, readPlanStateFn?: typeof readPlanState }} args
|
|
143
143
|
* @returns {Promise<{ overallLevel?: string, axes?: Array<object> }|null>}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Story body schema validator (v5.33+).
|
|
3
3
|
*
|
|
4
|
-
* Enforces the four-section structured body shape on
|
|
4
|
+
* Enforces the four-section structured body shape on 2-tier Stories emitted
|
|
5
5
|
* by the decomposer. The canonical decomposition serializes every Story
|
|
6
6
|
* `body` to a **markdown string** via `serialize()` from
|
|
7
7
|
* `lib/story-body/story-body.js` (the decompose-author skill mandates this,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Only `type: 'story'` tickets are validated; Feature/Epic tickets and
|
|
19
19
|
* null/empty bodies pass through. There is no `type::task` ticket layer in
|
|
20
|
-
* the
|
|
20
|
+
* the 2-tier hierarchy (Epic → Story).
|
|
21
21
|
*
|
|
22
22
|
* Required after parse/normalize: a non-empty `goal`, and non-empty
|
|
23
23
|
* `changes`, `acceptance`, and `verify` arrays — and `changes` items must
|
|
@@ -110,7 +110,7 @@ function vagueVerbWithoutTarget(bullet) {
|
|
|
110
110
|
* - it has no body (null / undefined / empty-or-whitespace string — there
|
|
111
111
|
* is nothing to inspect).
|
|
112
112
|
*
|
|
113
|
-
* Under the
|
|
113
|
+
* Under the 2-tier hierarchy (Epic → Story), Stories carry the
|
|
114
114
|
* implementation scope inline. A canonical decomposition serializes the
|
|
115
115
|
* Story body to a markdown string, so a *string* body is NOT skipped here
|
|
116
116
|
* (Story #3906) — `validateTaskBodyShape` parses it back into structured
|
|
@@ -127,7 +127,7 @@ function vagueVerbWithoutTarget(bullet) {
|
|
|
127
127
|
*/
|
|
128
128
|
function shouldSkipTicket(ticket) {
|
|
129
129
|
if (!ticket) return true;
|
|
130
|
-
// Only Stories carry an inline implementation contract in the
|
|
130
|
+
// Only Stories carry an inline implementation contract in the 2-tier
|
|
131
131
|
// world. Features (and everything else) use narrative bodies.
|
|
132
132
|
if (ticket.type !== 'story') return true;
|
|
133
133
|
const body = ticket.body;
|
|
@@ -197,7 +197,7 @@ export function validateTaskBodyShape(ticket) {
|
|
|
197
197
|
}
|
|
198
198
|
errors.push(...collectChangesErrors(prefix, body.changes));
|
|
199
199
|
errors.push(...collectAcceptanceErrors(prefix, body.acceptance));
|
|
200
|
-
// Tier-suffix validation is always enforced on Story bodies (
|
|
200
|
+
// Tier-suffix validation is always enforced on Story bodies (2-tier world).
|
|
201
201
|
errors.push(...collectVerifyErrors(prefix, body.verify));
|
|
202
202
|
errors.push(...collectReferencesErrors(prefix, body.references));
|
|
203
203
|
return errors;
|
|
@@ -359,7 +359,7 @@ function collectVerifyErrors(prefix, rawVerify) {
|
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
/**
|
|
362
|
-
* Validate every
|
|
362
|
+
* Validate every 2-tier Story in `tickets` whose `body` is a structured
|
|
363
363
|
* object. Returns an array of error strings (one per offending slug); empty
|
|
364
364
|
* array means clean.
|
|
365
365
|
*
|
|
@@ -96,7 +96,7 @@ export function normalizeOperatorHandle(raw) {
|
|
|
96
96
|
* observability artifact never wedges the lease preflight.
|
|
97
97
|
*
|
|
98
98
|
* This is the shared liveness source the lease guards thread into
|
|
99
|
-
* `acquireLease` via `heartbeatAt`; `/
|
|
99
|
+
* `acquireLease` via `heartbeatAt`; `/plan` and `/deliver` both
|
|
100
100
|
* reuse it so a live foreign claim actually refuses.
|
|
101
101
|
*
|
|
102
102
|
* @param {object} args
|
|
@@ -170,7 +170,7 @@ function collectStoryProducerPaths(story) {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
|
-
* Resolve the Story-identifying slug for a
|
|
173
|
+
* Resolve the Story-identifying slug for a 2-tier Story. A Story is its
|
|
174
174
|
* own implementation unit (Epic #3238) — there is no parent Task — so the
|
|
175
175
|
* producer/consumer indices key on the Story's own `slug`.
|
|
176
176
|
*/
|
|
@@ -187,7 +187,7 @@ function storySlugOf(story) {
|
|
|
187
187
|
* producers.
|
|
188
188
|
*
|
|
189
189
|
* `taskSlug` is retained in the entry shape for finding/render
|
|
190
|
-
* compatibility; in the
|
|
190
|
+
* compatibility; in the 2-tier model it carries the Story's own slug since
|
|
191
191
|
* the Story is the implementation unit.
|
|
192
192
|
*/
|
|
193
193
|
function indexProducers(stories) {
|
|
@@ -39,15 +39,6 @@ export const DEFAULT_TASK_SIZING = Object.freeze({
|
|
|
39
39
|
maxAcceptance: 14,
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
/**
|
|
43
|
-
* Soft prose guidance for how many Stories a Feature typically decomposes
|
|
44
|
-
* into before the Feature scope smells like two Features. Rendered into the
|
|
45
|
-
* decomposer prompt's Feature-count sentence from this single constant so
|
|
46
|
-
* the prompt prose cannot drift from the SSOT module (Story #3874). Advisory
|
|
47
|
-
* only — no validator finding keys off it.
|
|
48
|
-
*/
|
|
49
|
-
export const SOFT_STORIES_PER_FEATURE = 7;
|
|
50
|
-
|
|
51
42
|
/**
|
|
52
43
|
* `DELIVERABLE_GRANULARITY_GUIDANCE` is the **single source of truth** for the
|
|
53
44
|
* deliverable-granularity definition of a Story (Story #3777). It is stated
|
|
@@ -339,7 +330,7 @@ function computeStorySizingFindings(story, sizing) {
|
|
|
339
330
|
* `findings`; the AC-visible `errors[]` channel is the rendered
|
|
340
331
|
* subset where `severity === 'hard'`.
|
|
341
332
|
*
|
|
342
|
-
*
|
|
333
|
+
* 2-tier (Epic #3238): each Story is its own implementation unit and
|
|
343
334
|
* carries the `body` (acceptance / changes / wide) that the sizing layers
|
|
344
335
|
* score. There is no Task tier, so findings are computed directly over
|
|
345
336
|
* `stories`.
|