mandrel 1.93.0 → 2.0.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 +59 -73
- package/.agents/agents/acceptance-critic.md +129 -0
- package/.agents/agents/story-worker.md +161 -0
- package/.agents/docs/SDLC.md +489 -1285
- package/.agents/docs/agentrc-reference.json +177 -67
- package/.agents/docs/configuration.md +108 -136
- package/.agents/docs/execution-reference.md +44 -22
- package/.agents/docs/quality-gates.md +13 -19
- package/.agents/docs/workflows.md +3 -3
- package/.agents/instructions.md +107 -108
- package/.agents/rules/ci-remediation.md +8 -12
- package/.agents/rules/git-conventions-reference.md +224 -0
- package/.agents/rules/git-conventions.md +42 -223
- package/.agents/rules/security-baseline.md +5 -0
- package/.agents/rules/testing-standards.md +106 -13
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +71 -201
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/risk-verdict.schema.json +0 -13
- package/.agents/scripts/acceptance-eval.js +62 -18
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/analyze-execution.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/check-context-budget.js +62 -5
- package/.agents/scripts/check-lifecycle-lint.js +6 -9
- package/.agents/scripts/check-prepush-recovery.js +1 -1
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/diagnose-friction.js +0 -6
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
- package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
- package/.agents/scripts/lib/checks/index.js +2 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +16 -7
- package/.agents/scripts/lib/close-validation/gates.js +160 -22
- package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +103 -0
- package/.agents/scripts/lib/config/explain.js +57 -36
- package/.agents/scripts/lib/config/limits.js +17 -58
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +1 -1
- package/.agents/scripts/lib/config/runners.js +17 -50
- package/.agents/scripts/lib/config/temp-paths.js +19 -14
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +3 -8
- package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
- package/.agents/scripts/lib/config-settings-schema.js +52 -38
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +39 -4
- package/.agents/scripts/lib/duplicate-search.js +211 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +5 -5
- package/.agents/scripts/lib/framework-version.js +2 -3
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
- package/.agents/scripts/lib/git-utils.js +32 -6
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/label-constants.js +10 -23
- package/.agents/scripts/lib/label-taxonomy.js +9 -43
- package/.agents/scripts/lib/observability/active-story-env.js +112 -3
- package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
- package/.agents/scripts/lib/observability/source-classifier.js +3 -3
- package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
- package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
- package/.agents/scripts/lib/orchestration/code-review.js +20 -268
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
- package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
- package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
- package/.agents/scripts/lib/planning-corpus.js +16 -11
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- package/.agents/scripts/lib/provider-factory.js +1 -1
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/story-adjacency.js +11 -14
- package/.agents/scripts/lib/story-body/story-body.js +124 -70
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
- package/.agents/scripts/lib/validation-evidence.js +1 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +64 -74
- package/.agents/scripts/plan-persist.js +121 -280
- package/.agents/scripts/plan-run-epilogue.js +97 -0
- package/.agents/scripts/post-structured-comment.js +38 -0
- package/.agents/scripts/providers/github/issues.js +17 -33
- package/.agents/scripts/providers/github/mappers.js +0 -12
- package/.agents/scripts/providers/github/tickets.js +2 -5
- package/.agents/scripts/resolve-plan-run.js +117 -0
- package/.agents/scripts/signals-view.js +24 -19
- package/.agents/scripts/single-story-close.js +11 -14
- package/.agents/scripts/single-story-confirm-merge.js +39 -23
- package/.agents/scripts/single-story-init.js +29 -20
- package/.agents/scripts/stories-wave-tick.js +6 -6
- package/.agents/scripts/story-plan.js +26 -47
- package/.agents/scripts/sync-claude-agents.js +165 -0
- package/.agents/scripts/update-ticket-state.js +37 -15
- package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
- package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
- package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
- package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
- package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
- package/.agents/skills/core/scope-triage/SKILL.md +28 -172
- package/.agents/skills/skills.index.json +8 -418
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +3 -3
- package/.agents/workflows/audit-clean-code.md +3 -3
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +5 -5
- package/.agents/workflows/audit-lighthouse.md +3 -3
- package/.agents/workflows/audit-navigability.md +3 -2
- package/.agents/workflows/audit-performance.md +3 -3
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +3 -3
- package/.agents/workflows/audit-security.md +3 -3
- package/.agents/workflows/audit-seo.md +3 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +3 -3
- package/.agents/workflows/deliver.md +122 -131
- package/.agents/workflows/git-cleanup.md +3 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
- package/.agents/workflows/helpers/code-review.md +70 -193
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
- package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
- package/.agents/workflows/mandrel-update.md +3 -2
- package/.agents/workflows/plan.md +112 -145
- package/.agents/workflows/qa-assist.md +24 -30
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -2
- package/README.md +9 -8
- package/docs/CHANGELOG.md +46 -0
- package/lib/cli/registry.js +95 -0
- package/lib/migrations/index.js +6 -5
- package/package.json +5 -3
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer-mobile.md +0 -120
- package/.agents/personas/engineer-web.md +0 -111
- package/.agents/personas/engineer.md +0 -119
- package/.agents/personas/product.md +0 -94
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/refactorer.md +0 -113
- package/.agents/personas/security-engineer.md +0 -112
- package/.agents/personas/sre.md +0 -86
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/personas/ux-designer.md +0 -95
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -590
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-decompose.js +0 -54
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-plan-spec.js +0 -64
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/plan-critics.js +0 -199
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -335
- package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
- package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
- package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
- package/.agents/skills/core/code-simplification/SKILL.md +0 -389
- package/.agents/skills/core/context-engineering/SKILL.md +0 -309
- package/.agents/skills/core/context-engineering/examples.md +0 -58
- package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
- package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
- package/.agents/skills/core/idea-refinement/examples.md +0 -437
- package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
- package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
- package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
- package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
- package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
- package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
- package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
- package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
- package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
- package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
- package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
- package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
- package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
- package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
- package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
- package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
- package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
- package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
- package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
- package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
- package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
- package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
- package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
- package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
- package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
- package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
- package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
- package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
- package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
- package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
- package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
- package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
- package/.agents/workflows/helpers/deliver-epic.md +0 -955
- package/.agents/workflows/helpers/deliver-stories.md +0 -440
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -351
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* ```js
|
|
12
12
|
* {
|
|
13
13
|
* goal: string, // one-sentence purpose
|
|
14
|
+
* slicing: string, // v2 intra-Story delivery slice plan (optional; '' when absent)
|
|
15
|
+
* spec: string, // folded Tech Spec text block (optional; '' when absent)
|
|
14
16
|
* changes: PathEntry[], // files/globs this Story touches
|
|
15
17
|
* acceptance: string[], // observable criteria
|
|
16
18
|
* verify: string[], // exact commands / tier annotation
|
|
@@ -23,10 +25,9 @@
|
|
|
23
25
|
* }
|
|
24
26
|
* ```
|
|
25
27
|
*
|
|
26
|
-
* Where `PathEntry` is
|
|
28
|
+
* Where `PathEntry` is:
|
|
27
29
|
* - `{ path: string, assumption: "creates"|"refactors-existing"|"exists"|"deletes" }`
|
|
28
|
-
* (canonical form)
|
|
29
|
-
* - `string` (legacy form — emits a `legacy-path-entry` warning)
|
|
30
|
+
* (canonical form — string bullets are rejected at parse time)
|
|
30
31
|
*
|
|
31
32
|
* ## Round-trip contract
|
|
32
33
|
*
|
|
@@ -61,16 +62,15 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
|
|
|
61
62
|
*/
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
|
-
* @typedef {PathEntry
|
|
65
|
-
* Canonical: PathEntry object.
|
|
66
|
-
* Legacy: bare string bullet (emits a `legacy-path-entry` warning via
|
|
67
|
-
* the `warnings` array on {@link ParseResult}).
|
|
65
|
+
* @typedef {PathEntry} ChangeEntry
|
|
68
66
|
*/
|
|
69
67
|
|
|
70
68
|
/**
|
|
71
69
|
* @typedef {object} StoryBody
|
|
72
70
|
* @property {string} goal - One-sentence purpose statement.
|
|
73
|
-
* @property {
|
|
71
|
+
* @property {string} slicing - Optional v2 intra-Story delivery slice plan text block; '' when absent.
|
|
72
|
+
* @property {string} spec - Optional folded Tech Spec text block; '' when absent.
|
|
73
|
+
* @property {PathEntry[]} changes - Files / globs this Story modifies.
|
|
74
74
|
* @property {string[]} acceptance - Observable acceptance criteria.
|
|
75
75
|
* @property {string[]} verify - Exact commands with tier annotation.
|
|
76
76
|
* @property {PathEntry[]} references - Read-only paths (may be empty).
|
|
@@ -86,7 +86,7 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
|
|
|
86
86
|
/**
|
|
87
87
|
* @typedef {object} ParseResult
|
|
88
88
|
* @property {StoryBody} body - The parsed structured body.
|
|
89
|
-
* @property {string[]} warnings - Non-fatal issues (e.g.
|
|
89
|
+
* @property {string[]} warnings - Non-fatal issues (e.g. unstructured-body).
|
|
90
90
|
* @property {ParseInfo} info - Metadata about the parse.
|
|
91
91
|
*/
|
|
92
92
|
|
|
@@ -98,7 +98,9 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
|
|
|
98
98
|
* @property {boolean} hasVerifySection - Whether a `## Verify` section was found.
|
|
99
99
|
* @property {boolean} hasReferencesSection - Whether a `## References` section was found.
|
|
100
100
|
* @property {boolean} hasNonGoalsSection - Whether a `## Non-Goals` section was found.
|
|
101
|
-
* @property {boolean}
|
|
101
|
+
* @property {boolean} hasSlicingSection - Whether a `## Slicing` section was found (v2 folded slice plan).
|
|
102
|
+
* @property {boolean} hasSpecSection - Whether a `## Spec` section was found (folded Tech Spec).
|
|
103
|
+
* @property {boolean} isUnstructuredBody - True when no structured sections were found.
|
|
102
104
|
*/
|
|
103
105
|
|
|
104
106
|
/**
|
|
@@ -139,12 +141,15 @@ export class StoryBodyParseError extends Error {
|
|
|
139
141
|
// maps to the `non_goals` field.
|
|
140
142
|
const HEADING_TO_FIELD = new Map([
|
|
141
143
|
['goal', 'goal'],
|
|
144
|
+
['slicing', 'slicing'],
|
|
145
|
+
['spec', 'spec'],
|
|
142
146
|
['changes', 'changes'],
|
|
143
147
|
['acceptance', 'acceptance'],
|
|
144
148
|
['verify', 'verify'],
|
|
145
149
|
['references', 'references'],
|
|
146
150
|
['non_goals', 'non_goals'],
|
|
147
151
|
]);
|
|
152
|
+
const TEXT_BLOCK_FIELDS = new Set(['slicing', 'spec']);
|
|
148
153
|
|
|
149
154
|
// ---------------------------------------------------------------------------
|
|
150
155
|
// Helpers
|
|
@@ -162,19 +167,16 @@ function stripListMarker(line) {
|
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
/**
|
|
165
|
-
* Parse a single `changes` / `references` bullet into a `PathEntry
|
|
166
|
-
* legacy string. Emits a `legacy-path-entry` warning for string form.
|
|
170
|
+
* Parse a single `changes` / `references` bullet into a `PathEntry`.
|
|
167
171
|
*
|
|
168
172
|
* Object form: `{ path: "...", assumption: "creates" }` (stored as
|
|
169
173
|
* `- { "path": "...", "assumption": "..." }` or just recognized from the
|
|
170
174
|
* structured body directly — when deserializing from a structured object
|
|
171
175
|
* that was never serialized to markdown, the entry arrives as-is).
|
|
172
176
|
*
|
|
173
|
-
* String form: `src/foo.js: create handleSubmit`
|
|
174
|
-
*
|
|
175
177
|
* @param {string|object} raw
|
|
176
178
|
* @param {string[]} warnings
|
|
177
|
-
* @returns {PathEntry
|
|
179
|
+
* @returns {PathEntry}
|
|
178
180
|
*/
|
|
179
181
|
function parsePathEntry(raw, warnings) {
|
|
180
182
|
// Already a structured object (from a parsed JSON body, not markdown).
|
|
@@ -218,15 +220,14 @@ function parsePathEntry(raw, warnings) {
|
|
|
218
220
|
} catch (err) {
|
|
219
221
|
// Re-throw StoryBodyParseError so it propagates.
|
|
220
222
|
if (err instanceof StoryBodyParseError) throw err;
|
|
221
|
-
// JSON parse failed — fall through to
|
|
223
|
+
// JSON parse failed — fall through to reject plain-string form.
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
226
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
throw new StoryBodyParseError(
|
|
228
|
+
`changes/references entry must be a { path, assumption } object; plain string bullets are no longer accepted: ${str.slice(0, 120)}`,
|
|
229
|
+
{ field: 'changes', raw: str },
|
|
228
230
|
);
|
|
229
|
-
return str;
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
/**
|
|
@@ -245,8 +246,11 @@ function extractBlockedBy(footerBlock) {
|
|
|
245
246
|
return deps;
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
// Matches
|
|
249
|
-
|
|
249
|
+
// Matches any trailing `<!-- meta: … -->` block. Object payloads are the
|
|
250
|
+
// canonical serialize() shape; non-object / malformed payloads are still
|
|
251
|
+
// recognized so section parsing can skip them and extractMeta can degrade.
|
|
252
|
+
const META_BLOCK_RE = /<!--\s*meta:\s*([\s\S]*?)\s*-->/;
|
|
253
|
+
const META_OBJECT_RE = /<!--\s*meta:\s*(\{[\s\S]*?\})\s*-->/;
|
|
250
254
|
|
|
251
255
|
/**
|
|
252
256
|
* Extract the `wide` / `estimated_test_files` fields from the trailing
|
|
@@ -275,7 +279,7 @@ function extractMeta(markdown) {
|
|
|
275
279
|
mandrel_version: null,
|
|
276
280
|
authored_at: null,
|
|
277
281
|
};
|
|
278
|
-
const match = markdown.match(META_BLOCK_RE);
|
|
282
|
+
const match = markdown.match(META_OBJECT_RE) ?? markdown.match(META_BLOCK_RE);
|
|
279
283
|
if (!match) return result;
|
|
280
284
|
|
|
281
285
|
let parsed;
|
|
@@ -285,7 +289,10 @@ function extractMeta(markdown) {
|
|
|
285
289
|
// Malformed meta comment — degrade to defaults rather than corrupt the body.
|
|
286
290
|
return result;
|
|
287
291
|
}
|
|
288
|
-
|
|
292
|
+
// Non-object JSON (array / scalar / null) is treated as absent meta.
|
|
293
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
289
296
|
|
|
290
297
|
result.wide = normalizeWide(parsed.wide);
|
|
291
298
|
result.reason_to_exist = normalizeReasonToExist(parsed.reason_to_exist);
|
|
@@ -385,27 +392,11 @@ function splitSections(markdown) {
|
|
|
385
392
|
// below, which closes the open section. The chosen canonical spelling is
|
|
386
393
|
// therefore the hyphenated single token `## Non-Goals`.
|
|
387
394
|
const fieldHeadingMatch = line.match(/^#{2,3}\s+([\w-]+)\s*$/i);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if (!sections.has(currentSection)) sections.set(currentSection, []);
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
// A heading that matches the canonical `## Word` shape but is not a
|
|
397
|
-
// recognized field name (e.g. a trailing free-form `## Notes`) closes
|
|
398
|
-
// the currently-open section. Without this reset, the unknown heading
|
|
399
|
-
// and its bullets bleed into the previously-recognized section,
|
|
400
|
-
// silently corrupting `verify[]` / `acceptance[]`. We do NOT re-enter
|
|
401
|
-
// the preamble (`inPreamble` stays false), so a later recognized
|
|
402
|
-
// heading still registers normally; we only stop appending to the
|
|
403
|
-
// closed section. The heading line and its body are dropped from all
|
|
404
|
-
// sections. (Multi-word free-form headings like `## Out of Scope` —
|
|
405
|
-
// with internal spaces — do not match the `[\w-]+` single-token shape
|
|
406
|
-
// and reach this branch too. The hyphenated single-token canonical
|
|
407
|
-
// negative-scope heading is `## Non-Goals`, which IS recognized above.)
|
|
408
|
-
currentSection = null;
|
|
395
|
+
const fieldName = fieldHeadingMatch?.[1]?.toLowerCase().replace(/-/g, '_');
|
|
396
|
+
if (HEADING_TO_FIELD.has(fieldName)) {
|
|
397
|
+
inPreamble = false;
|
|
398
|
+
currentSection = fieldName;
|
|
399
|
+
if (!sections.has(currentSection)) sections.set(currentSection, []);
|
|
409
400
|
continue;
|
|
410
401
|
}
|
|
411
402
|
|
|
@@ -418,7 +409,11 @@ function splitSections(markdown) {
|
|
|
418
409
|
// lines were silently absorbed into `verify[]` / `acceptance[]`. The
|
|
419
410
|
// heading and everything under it is dropped from structured parsing
|
|
420
411
|
// (it is extended, non-canonical markdown).
|
|
421
|
-
if (
|
|
412
|
+
if (
|
|
413
|
+
!inPreamble &&
|
|
414
|
+
/^#{1,6}\s+\S/.test(line) &&
|
|
415
|
+
!TEXT_BLOCK_FIELDS.has(currentSection)
|
|
416
|
+
) {
|
|
422
417
|
currentSection = null;
|
|
423
418
|
continue;
|
|
424
419
|
}
|
|
@@ -442,10 +437,7 @@ function splitSections(markdown) {
|
|
|
442
437
|
if (inPreamble) {
|
|
443
438
|
preambleLines.push(line);
|
|
444
439
|
} else if (currentSection !== null) {
|
|
445
|
-
|
|
446
|
-
if (trimmed.length > 0) {
|
|
447
|
-
sections.get(currentSection).push(line);
|
|
448
|
-
}
|
|
440
|
+
sections.get(currentSection).push(line);
|
|
449
441
|
}
|
|
450
442
|
}
|
|
451
443
|
|
|
@@ -460,7 +452,7 @@ function splitSections(markdown) {
|
|
|
460
452
|
// ---------------------------------------------------------------------------
|
|
461
453
|
|
|
462
454
|
/**
|
|
463
|
-
* Build the minimal {@link ParseResult} returned for
|
|
455
|
+
* Build the minimal {@link ParseResult} returned for an unstructured body —
|
|
464
456
|
* markdown that carries no recognised structured section. The goal falls
|
|
465
457
|
* back to the preamble text (or the whole trimmed input), `depends_on` is
|
|
466
458
|
* still recovered from the footer, and all section arrays are empty.
|
|
@@ -470,13 +462,15 @@ function splitSections(markdown) {
|
|
|
470
462
|
* @param {string} footer - Footer block text (from splitSections).
|
|
471
463
|
* @returns {ParseResult}
|
|
472
464
|
*/
|
|
473
|
-
function
|
|
465
|
+
function parseUnstructuredBody(input, preamble, footer) {
|
|
474
466
|
const warnings = [
|
|
475
|
-
'
|
|
467
|
+
'unstructured-body: no structured sections found; returning minimal body from preamble text.',
|
|
476
468
|
'test-surface-unestimated: estimated_test_files not present.',
|
|
477
469
|
];
|
|
478
470
|
const body = {
|
|
479
471
|
goal: preamble || input.trim(),
|
|
472
|
+
slicing: '',
|
|
473
|
+
spec: '',
|
|
480
474
|
changes: [],
|
|
481
475
|
acceptance: [],
|
|
482
476
|
verify: [],
|
|
@@ -499,7 +493,9 @@ function parseLegacyStringBody(input, preamble, footer) {
|
|
|
499
493
|
hasVerifySection: false,
|
|
500
494
|
hasReferencesSection: false,
|
|
501
495
|
hasNonGoalsSection: false,
|
|
502
|
-
|
|
496
|
+
hasSlicingSection: false,
|
|
497
|
+
hasSpecSection: false,
|
|
498
|
+
isUnstructuredBody: true,
|
|
503
499
|
},
|
|
504
500
|
};
|
|
505
501
|
}
|
|
@@ -518,15 +514,30 @@ function parseGoalSection(lines) {
|
|
|
518
514
|
.join(' ');
|
|
519
515
|
}
|
|
520
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Parse a verbatim text-block section (`## Slicing` or `## Spec`) into a
|
|
519
|
+
* newline-joined string. Unlike {@link parseGoalSection}, line breaks are
|
|
520
|
+
* preserved so a bullet list, compact table, or folded Tech Spec survives the
|
|
521
|
+
* round-trip; only blank lines and trailing whitespace are normalized.
|
|
522
|
+
*
|
|
523
|
+
* @param {string[]} lines
|
|
524
|
+
* @returns {string}
|
|
525
|
+
*/
|
|
526
|
+
function parseTextBlockSection(lines) {
|
|
527
|
+
return lines
|
|
528
|
+
.map((line) => line.replace(/\s+$/, ''))
|
|
529
|
+
.join('\n')
|
|
530
|
+
.replace(/^\n+|\n+$/g, '');
|
|
531
|
+
}
|
|
532
|
+
|
|
521
533
|
/**
|
|
522
534
|
* Parse a `## Changes` / `## References` section into a list of
|
|
523
|
-
* `PathEntry
|
|
524
|
-
* dropped, and each surviving entry is normalized via {@link parsePathEntry}
|
|
525
|
-
* (which appends `legacy-path-entry` warnings for bare-string bullets).
|
|
535
|
+
* `PathEntry` entries. List markers are stripped, blank entries are
|
|
536
|
+
* dropped, and each surviving entry is normalized via {@link parsePathEntry}.
|
|
526
537
|
*
|
|
527
538
|
* @param {string[]} lines - Raw content lines under the heading.
|
|
528
539
|
* @param {string[]} warnings - Mutable warnings sink.
|
|
529
|
-
* @returns {
|
|
540
|
+
* @returns {PathEntry[]}
|
|
530
541
|
*/
|
|
531
542
|
function parsePathEntrySection(lines, warnings) {
|
|
532
543
|
const entries = [];
|
|
@@ -601,19 +612,28 @@ export function parse(input) {
|
|
|
601
612
|
const hasVerifySection = sections.has('verify');
|
|
602
613
|
const hasReferencesSection = sections.has('references');
|
|
603
614
|
const hasNonGoalsSection = sections.has('non_goals');
|
|
615
|
+
const hasSlicingSection = sections.has('slicing');
|
|
616
|
+
const hasSpecSection = sections.has('spec');
|
|
604
617
|
|
|
605
|
-
// If no structured sections found, treat as
|
|
606
|
-
const
|
|
618
|
+
// If no structured sections found, treat as unstructured body.
|
|
619
|
+
const isUnstructuredBody =
|
|
607
620
|
!hasGoalSection &&
|
|
608
621
|
!hasChangesSection &&
|
|
609
622
|
!hasAcceptanceSection &&
|
|
610
623
|
!hasVerifySection;
|
|
611
624
|
|
|
612
|
-
if (
|
|
613
|
-
return
|
|
625
|
+
if (isUnstructuredBody) {
|
|
626
|
+
return parseUnstructuredBody(input, preamble, footer);
|
|
614
627
|
}
|
|
615
628
|
|
|
616
629
|
const goal = parseGoalSection(sections.get('goal') ?? []);
|
|
630
|
+
// Optional v2 intra-Story delivery slice plan (`## Slicing`). Preserved as
|
|
631
|
+
// a verbatim text block — a large Story (what v1 called an Epic) folds its
|
|
632
|
+
// Delivery Slicing here instead of fanning out into sibling Stories; a
|
|
633
|
+
// trivial Story omits it entirely. Parsed as a text block so a bullet list
|
|
634
|
+
// or compact table round-trips.
|
|
635
|
+
const slicing = parseTextBlockSection(sections.get('slicing') ?? []);
|
|
636
|
+
const spec = parseTextBlockSection(sections.get('spec') ?? []);
|
|
617
637
|
const changes = parsePathEntrySection(
|
|
618
638
|
sections.get('changes') ?? [],
|
|
619
639
|
warnings,
|
|
@@ -644,6 +664,8 @@ export function parse(input) {
|
|
|
644
664
|
|
|
645
665
|
const body = {
|
|
646
666
|
goal,
|
|
667
|
+
slicing,
|
|
668
|
+
spec,
|
|
647
669
|
changes,
|
|
648
670
|
acceptance,
|
|
649
671
|
verify,
|
|
@@ -667,7 +689,9 @@ export function parse(input) {
|
|
|
667
689
|
hasVerifySection,
|
|
668
690
|
hasReferencesSection,
|
|
669
691
|
hasNonGoalsSection,
|
|
670
|
-
|
|
692
|
+
hasSlicingSection,
|
|
693
|
+
hasSpecSection,
|
|
694
|
+
isUnstructuredBody: false,
|
|
671
695
|
},
|
|
672
696
|
};
|
|
673
697
|
}
|
|
@@ -685,6 +709,12 @@ function parseStructuredObject(obj) {
|
|
|
685
709
|
|
|
686
710
|
const goal = typeof obj.goal === 'string' ? obj.goal.trim() : '';
|
|
687
711
|
|
|
712
|
+
// slicing — optional v2 intra-Story delivery slice plan (verbatim text).
|
|
713
|
+
const slicing = typeof obj.slicing === 'string' ? obj.slicing.trim() : '';
|
|
714
|
+
|
|
715
|
+
// spec — optional folded Tech Spec (verbatim text).
|
|
716
|
+
const spec = typeof obj.spec === 'string' ? obj.spec.trim() : '';
|
|
717
|
+
|
|
688
718
|
// changes
|
|
689
719
|
const rawChanges = Array.isArray(obj.changes) ? obj.changes : [];
|
|
690
720
|
const changes = [];
|
|
@@ -747,6 +777,8 @@ function parseStructuredObject(obj) {
|
|
|
747
777
|
|
|
748
778
|
const body = {
|
|
749
779
|
goal,
|
|
780
|
+
slicing,
|
|
781
|
+
spec,
|
|
750
782
|
changes,
|
|
751
783
|
acceptance,
|
|
752
784
|
verify,
|
|
@@ -770,7 +802,9 @@ function parseStructuredObject(obj) {
|
|
|
770
802
|
hasVerifySection: 'verify' in obj,
|
|
771
803
|
hasReferencesSection: 'references' in obj,
|
|
772
804
|
hasNonGoalsSection: 'non_goals' in obj,
|
|
773
|
-
|
|
805
|
+
hasSlicingSection: 'slicing' in obj,
|
|
806
|
+
hasSpecSection: 'spec' in obj,
|
|
807
|
+
isUnstructuredBody: false,
|
|
774
808
|
},
|
|
775
809
|
};
|
|
776
810
|
}
|
|
@@ -793,10 +827,10 @@ function serializePathEntry(entry) {
|
|
|
793
827
|
|
|
794
828
|
/**
|
|
795
829
|
* Descriptor table for the human-readable Story-body sections, in canonical
|
|
796
|
-
* emit order (`## Goal`, `##
|
|
797
|
-
* `## References`, `## Non-Goals`). Each
|
|
798
|
-
*
|
|
799
|
-
* to omit the section.
|
|
830
|
+
* emit order (`## Goal`, `## Slicing`, `## Spec`, `## Changes`,
|
|
831
|
+
* `## Acceptance`, `## Verify`, `## References`, `## Non-Goals`). Each
|
|
832
|
+
* descriptor reads one body field and returns the section's markdown block
|
|
833
|
+
* when the field is present and non-empty, or `null` to omit the section.
|
|
800
834
|
*
|
|
801
835
|
* Standardising the section ladder as a single data table makes adding a new
|
|
802
836
|
* optional section a one-line edit here rather than a new control-flow branch
|
|
@@ -812,6 +846,26 @@ const SERIALIZE_SECTIONS = [
|
|
|
812
846
|
? `## Goal\n${goal.trim()}`
|
|
813
847
|
: null,
|
|
814
848
|
},
|
|
849
|
+
{
|
|
850
|
+
// Optional v2 intra-Story delivery slice plan. Single-token `## Slicing`
|
|
851
|
+
// heading (recognized by the `[\w-]+` field-heading regex). Verbatim text
|
|
852
|
+
// block. Render-when-non-empty: an absent/empty `slicing` emits nothing,
|
|
853
|
+
// so every pre-v2 body round-trips byte-identically.
|
|
854
|
+
field: 'slicing',
|
|
855
|
+
render: (slicing) =>
|
|
856
|
+
typeof slicing === 'string' && slicing.trim().length > 0
|
|
857
|
+
? `## Slicing\n${slicing.trim()}`
|
|
858
|
+
: null,
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
// Optional folded Tech Spec. Like `## Slicing`, this is a verbatim text
|
|
862
|
+
// block and emits nothing for absent/empty pre-v2 bodies.
|
|
863
|
+
field: 'spec',
|
|
864
|
+
render: (spec) =>
|
|
865
|
+
typeof spec === 'string' && spec.trim().length > 0
|
|
866
|
+
? `## Spec\n${spec.trim()}`
|
|
867
|
+
: null,
|
|
868
|
+
},
|
|
815
869
|
{
|
|
816
870
|
field: 'changes',
|
|
817
871
|
render: (changes) =>
|
|
@@ -938,8 +992,8 @@ function serializeFooter(body, opts) {
|
|
|
938
992
|
* format written to GitHub issue bodies.
|
|
939
993
|
*
|
|
940
994
|
* The output matches the section order the spec-renderer uses:
|
|
941
|
-
* `## Goal`, `##
|
|
942
|
-
* `## Non-Goals` (each omitted when empty).
|
|
995
|
+
* `## Goal`, `## Slicing`, `## Spec`, `## Changes`, `## Acceptance`,
|
|
996
|
+
* `## Verify`, `## References`, `## Non-Goals` (each omitted when empty).
|
|
943
997
|
*
|
|
944
998
|
* `wide`, `reason_to_exist`, and `estimated_test_files` are emitted as a
|
|
945
999
|
* fenced `<!-- meta -->` comment block so round-trips preserve them without
|
|
@@ -200,7 +200,6 @@ export async function loadBodyTemplate(projectRoot) {
|
|
|
200
200
|
export function buildContextEnvelope({
|
|
201
201
|
seed,
|
|
202
202
|
refine,
|
|
203
|
-
persona,
|
|
204
203
|
bodyTemplate,
|
|
205
204
|
duplicateCandidates,
|
|
206
205
|
techStack = null,
|
|
@@ -212,7 +211,6 @@ export function buildContextEnvelope({
|
|
|
212
211
|
version: 1,
|
|
213
212
|
seed,
|
|
214
213
|
refine,
|
|
215
|
-
persona,
|
|
216
214
|
bodyTemplate,
|
|
217
215
|
requiredSections: [...REQUIRED_SECTIONS],
|
|
218
216
|
duplicateCandidates: {
|
|
@@ -222,8 +220,8 @@ export function buildContextEnvelope({
|
|
|
222
220
|
techStack,
|
|
223
221
|
corpusContext,
|
|
224
222
|
deliverContract: {
|
|
225
|
-
workflow: '.agents/workflows/helpers/
|
|
226
|
-
requiredLabels: ['type::story'
|
|
223
|
+
workflow: '.agents/workflows/helpers/deliver-story.md',
|
|
224
|
+
requiredLabels: ['type::story'],
|
|
227
225
|
forbidden: ['Epic: #N references in the body'],
|
|
228
226
|
},
|
|
229
227
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { LIMITS_DEFAULTS } from '../config/limits.js';
|
|
2
2
|
import {
|
|
3
3
|
AUTHORING_ALTITUDE_GUIDANCE,
|
|
4
|
-
|
|
4
|
+
DEFAULT_MODEL_CAPACITY,
|
|
5
5
|
DELIVERABLE_GRANULARITY_GUIDANCE,
|
|
6
|
+
resolveCapacityCeilings,
|
|
6
7
|
} from '../orchestration/ticket-validator-sizing.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -18,27 +19,16 @@ import {
|
|
|
18
19
|
* asks the planner to carry acceptance/verify as top-level ticket arrays.
|
|
19
20
|
*
|
|
20
21
|
* **Single source of the prompt body (Story #4162).** This module is the sole
|
|
21
|
-
* carrier of the full decomposer system-prompt body
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* `epic-plan-decompose/phases/context.js`) instead, so the two surfaces cannot
|
|
26
|
-
* drift. A guard test (`tests/ticket-decomposer.test.js`) fails if the SKILL
|
|
27
|
-
* re-grows a full copy of the prompt preamble.
|
|
28
|
-
*
|
|
29
|
-
* **Token-budget sizing input (Story #4162).** `maxTokenBudget` is the real
|
|
30
|
-
* one-pass delivery envelope (the task-prompt hydration cap surfaced into the
|
|
31
|
-
* authoring envelope by `context.js`, Story #3875). It is threaded into the
|
|
32
|
-
* rendered prompt as a sizing input so the planner sizes Stories against the
|
|
33
|
-
* envelope a single agent can actually deliver in one pass, rather than leading
|
|
34
|
-
* with the file-count proxy alone.
|
|
22
|
+
* carrier of the full decomposer system-prompt body, delivered to the host
|
|
23
|
+
* LLM in the `systemPrompts.decompose` field of the `/plan` context envelope
|
|
24
|
+
* (via `lib/orchestration/planning/decomposer-context.js`), so no second
|
|
25
|
+
* verbatim copy can drift.
|
|
35
26
|
*/
|
|
36
27
|
export function renderDecomposerSystemPrompt({
|
|
37
28
|
maxTickets = LIMITS_DEFAULTS.maxTickets,
|
|
38
|
-
maxTokenBudget = LIMITS_DEFAULTS.maxTokenBudget,
|
|
39
29
|
epicId = null,
|
|
40
30
|
} = {}) {
|
|
41
|
-
return render2TierPrompt({ maxTickets,
|
|
31
|
+
return render2TierPrompt({ maxTickets, epicId });
|
|
42
32
|
}
|
|
43
33
|
|
|
44
34
|
/**
|
|
@@ -47,12 +37,16 @@ export function renderDecomposerSystemPrompt({
|
|
|
47
37
|
* on the Story body so the executing agent has everything it needs in one
|
|
48
38
|
* ticket. Thematic grouping lives as prose in the Epic body / Tech Spec.
|
|
49
39
|
*/
|
|
50
|
-
function render2TierPrompt({ maxTickets,
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
40
|
+
function render2TierPrompt({ maxTickets, epicId = null }) {
|
|
41
|
+
// v2 Stage 3: default-single — emit one Story unless the split policy clears.
|
|
42
|
+
// Capacity thresholds are sourced from the single DEFAULT_MODEL_CAPACITY
|
|
43
|
+
// constant (ticket-validator-sizing.js) so the prompt and the validator
|
|
44
|
+
// cannot drift.
|
|
45
|
+
const { softSessionTokens, hardSessionTokens } = resolveCapacityCeilings(
|
|
46
|
+
DEFAULT_MODEL_CAPACITY,
|
|
47
|
+
);
|
|
54
48
|
// Deliverable-granularity definition + single-consumer merge rule + the
|
|
55
|
-
//
|
|
49
|
+
// thin-dependent merge heuristic are sourced from the single
|
|
56
50
|
// DELIVERABLE_GRANULARITY_GUIDANCE constant (ticket-validator-sizing.js) so
|
|
57
51
|
// the prompt and the authoring SKILL cannot drift (Story #3777; the
|
|
58
52
|
// envelope-floor sentence added by Story #4313).
|
|
@@ -78,17 +72,18 @@ function render2TierPrompt({ maxTickets, maxTokenBudget, epicId = null }) {
|
|
|
78
72
|
? `@epic-${epicId}-ac-1`
|
|
79
73
|
: '@epic-<id>-ac-N';
|
|
80
74
|
return `You are an expert Senior Project Manager and Orchestrator.
|
|
81
|
-
Your job is to
|
|
75
|
+
Your job is to turn a plan seed / Tech Spec into a Story ticket array for an AI Agent to execute.
|
|
82
76
|
|
|
83
|
-
### HIERARCHY RULES:
|
|
84
|
-
1. **
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
77
|
+
### HIERARCHY RULES (v2 default-single):
|
|
78
|
+
1. **Emit exactly one Story by default.** Split into N>1 only when pieces have near-zero overlap or sit across an architectural seam. Coupled work stays one Story — put intra-session checkpoints in \`## Slicing\` and fold the Tech Spec into \`## Spec\`.
|
|
79
|
+
2. **Stories**: Specific user-facing or architectural capabilities (e.g., "Implement JWT Token Exchange").
|
|
80
|
+
- There is NO Epic parent ticket, NO Feature tier, and NO Task layer.
|
|
81
|
+
- **Story-Level Execution**: Each Story is executed end-to-end on a single branch by a single agent. Acceptance criteria and verification commands live as top-level \`acceptance[]\` / \`verify[]\` arrays on the Story ticket (see STORY BODY SCHEMA below).
|
|
82
|
+
- Thematic grouping is prose in the Story's folded \`## Spec\` / \`## Slicing\`, never sibling tickets for coupled work.
|
|
88
83
|
|
|
89
84
|
### LABEL CONVENTIONS:
|
|
90
85
|
- Every ticket must have the \`type::story\` label. No other type label is allowed — the retired Feature and Task tiers have no labels under this hierarchy.
|
|
91
|
-
-
|
|
86
|
+
- Do **not** emit \`persona::*\` labels — the behavioral persona concept (and its label axis) was removed in v2.
|
|
92
87
|
|
|
93
88
|
### OUTPUT FORMAT:
|
|
94
89
|
You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown blocks.
|
|
@@ -102,7 +97,7 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
|
|
|
102
97
|
"body": <string — see STORY BODY SCHEMA below>,
|
|
103
98
|
"acceptance": ["<testable, observable criterion>", ...],
|
|
104
99
|
"verify": ["<exact command or test path> (<tier>)", ...],
|
|
105
|
-
"labels": ["type::story"
|
|
100
|
+
"labels": ["type::story"],
|
|
106
101
|
"depends_on": ["slug-of-blocking-dependency"] (optional array of Story slugs that block execution)
|
|
107
102
|
}
|
|
108
103
|
]
|
|
@@ -112,12 +107,18 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
|
|
|
112
107
|
### STORY BODY SCHEMA (REQUIRED FOR EVERY STORY):
|
|
113
108
|
\`body\` MUST be a **string** — the serialized markdown produced by \`serialize()\` from \`lib/story-body/story-body.js\`. Do NOT emit \`body\` as a JSON object: an object body throws \`StoryBodyParseError\` in the reconciler (Story #3302) and is discarded by the GitHub provider, producing an empty issue body. Stories are consumed by non-interactive sub-agents that must self-verify from the Story ticket alone — so the ticket must carry everything an agent needs to execute and self-verify.
|
|
114
109
|
|
|
115
|
-
The \`acceptance[]\` and \`verify[]\` arrays live at the **top level** of the Story ticket object
|
|
110
|
+
The \`acceptance[]\` and \`verify[]\` arrays live at the **top level** of the Story ticket object — that is the machine contract the validator reads. Persist syncs those arrays into the body's \`## Acceptance\` / \`## Verify\` sections so the GitHub issue stays a complete executable document. Prefer authoring the lists **once at top-level** and omitting those sections from the authored \`body\` string (or mirroring the exact same items). Do **not** invent a second criteria list inside \`## Spec\`, and do not author a separate Acceptance Spec / PRD artifact.
|
|
116
111
|
|
|
117
112
|
The serialized \`body\` string renders these markdown sections (in order):
|
|
118
113
|
|
|
119
114
|
## Goal
|
|
120
|
-
<one sentence — why this Story exists
|
|
115
|
+
<one sentence — why this Story exists>
|
|
116
|
+
|
|
117
|
+
## Slicing
|
|
118
|
+
<optional ordered intra-session checkpoints — not a second Spec or AC table>
|
|
119
|
+
|
|
120
|
+
## Spec
|
|
121
|
+
<optional lean technical approach — do NOT restate Goal / Acceptance / Verify>
|
|
121
122
|
|
|
122
123
|
## Changes
|
|
123
124
|
- {"path": "<file path>", "assumption": "creates" | "refactors-existing" | "deletes"}
|
|
@@ -141,7 +142,9 @@ The serialized \`body\` string renders these markdown sections (in order):
|
|
|
141
142
|
|
|
142
143
|
#### STORY BODY RULES:
|
|
143
144
|
|
|
144
|
-
- **goal** (in body string): One sentence stating WHY this
|
|
145
|
+
- **goal** (in body string): One sentence stating WHY this Story exists.
|
|
146
|
+
- **spec** (optional, in body string as \`## Spec\`): Lean technical approach only. If the Spec is large enough to feel like its own document, the Story is probably too big — split it. Persist keeps Specs inline and rejects over-budget Specs (never writes them under \`docs/\`).
|
|
147
|
+
- **slicing** (optional): Ordered intra-session checkpoints for one Story. Not a fan-out table and not a duplicate of Acceptance.
|
|
145
148
|
- **changes** (in body string): Each entry is an object \`{ path, assumption }\` where \`assumption\` is one of \`creates | refactors-existing | deletes\`. Acceptable path shapes include explicit files (\`src/components/Foo.tsx\`), glob patterns (\`tests/e2e/*.spec.ts\`, \`**/*.astro\`), and module identifiers that resolve to files. Use \`refactors-existing\` for in-place edits to a file already on \`main\`; \`creates\` for net-new files; \`deletes\` for removals.
|
|
146
149
|
- **acceptance** (top-level array on the ticket object): Items MUST be observable from outside the agent. Acceptable shapes: a specific command exits 0, a file exists at a given path, a snapshot test matches, a \`data-testid\` resolves under a given selector, a row count in a fixture matches. UNACCEPTABLE: "verify by reading the diff", "looks good", "matches the spec" — push these down into a \`verify\` command instead.
|
|
147
150
|
- **verify** (top-level array on the ticket object): Each entry MUST name a testing tier in parentheses, drawn from \`unit\` / \`contract\` / \`e2e\` / \`validate\`. Example: \`npm run test -- src/x.test.ts (unit)\`, \`npm run validate (validate)\`. Stories with zero verify entries SHOULD fail validation; if a story is genuinely unverifiable in isolation (e.g., a copy edit auditor will eyeball), the literal entry \`manual:<reason>\` is allowed so the absence is intentional, not lazy. Manual entries without a reason are rejected.
|
|
@@ -157,37 +160,35 @@ ${newFileContract}
|
|
|
157
160
|
|
|
158
161
|
${advisoryCaveat}
|
|
159
162
|
|
|
160
|
-
#### STORY SIZING — COHESION FIRST (
|
|
163
|
+
#### STORY SIZING — COHESION FIRST (session capacity is only a backstop):
|
|
161
164
|
|
|
162
165
|
**Decompose at deliverable granularity, not module/task level.** ${granularityDefinition}
|
|
163
166
|
|
|
164
|
-
The primary question is **cohesion, not count**: *is this one coherent change with one reason to exist?* File count cannot tell a trivial
|
|
165
|
-
|
|
166
|
-
**Size against the real one-pass delivery envelope.** Each Story is delivered and self-verified by a single agent in one pass, whose context is capped by the delivery token budget \`maxTokenBudget = ${maxTokenBudget}\` tokens (the task-prompt hydration cap). Use that envelope — not the file count alone — as the leading sizing input: a Story is correctly sized when one agent can hold its full change, acceptance, and verification in a single pass within \`maxTokenBudget\`. The numeric file thresholds below are a coarse backstop on top of this envelope, not the primary signal.
|
|
167
|
+
The primary question is **cohesion, not count**: *is this one coherent change with one reason to exist?* File count cannot tell a trivial rename from a hard parser+caller+config change — so lead with the change's reason, not its size. Frontier models one-shot capability-sized work in a single pass — do not fragment a coherent capability into dependent slices just to stay "small."
|
|
167
168
|
|
|
168
169
|
${envelopeFloor}
|
|
169
170
|
|
|
170
171
|
- **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 — or two Stories that should be one. State that sentence explicitly in the Story's \`reason_to_exist\` meta field (see STORY BODY RULES) so the consolidate critic can check it.
|
|
171
172
|
- ${singleConsumerRule}
|
|
172
173
|
- **Split independent, parallelizable work** into sibling Stories — but only when the pieces genuinely have separate reasons to exist.
|
|
173
|
-
- **Declare \`wide\` with a one-line reason when a change is legitimately broad** (a cohesive cutover
|
|
174
|
+
- **Declare \`wide\` with a one-line reason when a change is legitimately broad** (a cohesive cutover whose authored ticket mass is high for one reason). Declaring \`wide\` lifts the hard session-mass ceiling — see below.
|
|
174
175
|
|
|
175
|
-
**
|
|
176
|
+
**Capacity backstop (validator-enforced).** Absolute authored-token ceilings from the single \`DEFAULT_MODEL_CAPACITY\` constant in \`ticket-validator-sizing.js\` — not operator-tunable. They catch Spec novels, not capability-sized Stories:
|
|
176
177
|
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
-
|
|
178
|
+
- Soft advisory (**${softSessionTokens} tokens**): authored session mass above this emits a nudge to check cohesion or declare \`wide\`.
|
|
179
|
+
- Hard ceiling (**${hardSessionTokens} tokens**): authored session mass above this is **rejected** unless the Story declares \`wide\` with a reason.
|
|
180
|
+
- Session mass = **authored tokens only** (goal / reason / Spec / acceptance / verify / slicing / change-path text). File count and AC count do **not** inflate mass — a long binding contract or a broad file footprint is never by itself a reason to fragment one coherent capability into dependent slices.
|
|
180
181
|
|
|
181
182
|
#### DELIVERY-SCHEDULE SIMULATION — the story count must earn itself:
|
|
182
183
|
|
|
183
184
|
Before emitting, simulate the delivery schedule your plan implies, and judge the plan by its schedule — not by how tidy the taxonomy looks:
|
|
184
185
|
|
|
185
186
|
1. **Build the wave schedule.** A Story runs only after every \`depends_on\` completes, and two Stories that name the same file in \`changes[]\` cannot run in the same wave (the scheduler serializes file-overlapping Stories even when no \`depends_on\` edge links them).
|
|
186
|
-
2. **Compute the parallelism yield**: story count ÷ critical-path length in waves. A yield near 1.0 means the plan is a serial chain — N Stories that deliver no faster than one Story while paying N delivery sessions (
|
|
187
|
+
2. **Compute the parallelism yield**: story count ÷ critical-path length in waves. A yield near 1.0 means the plan is a serial chain — N Stories that deliver no faster than one Story while paying N delivery sessions (branch, PR, review, CI).
|
|
187
188
|
3. **Every Story must earn its slot** by at least one of:
|
|
188
189
|
- **(a) parallelism** — it actually runs concurrently with a sibling in the schedule you just built ("logically independent" does not count; *schedule*-independent does);
|
|
189
190
|
- **(b) risk isolation** — it isolates a consumer-facing behavior change or high-risk cutover into its own reviewable, revertable unit;
|
|
190
|
-
- **(c)
|
|
191
|
+
- **(c) cohesion break** — merged into its neighbor it would no longer be one coherent change with one reason to exist.
|
|
191
192
|
4. **A dependent link with none of those justifications merges into its consumer.** This generalizes the single-consumer merge rule from pairs to chains.
|
|
192
193
|
5. **Hot-file rule.** When one file appears in the \`changes[]\` of more than a third of your Stories, the slicing axis cuts across a shared seam — merge the Stories that co-edit it, or re-slice along the seam so each Story owns its files.
|
|
193
194
|
|
|
@@ -201,7 +202,7 @@ A Story whose footprint is legitimately broad declares \`wide\` carrying a one-l
|
|
|
201
202
|
"wide": { "reason": "hard contract cutover: migrate every <X> call site in one PR" }
|
|
202
203
|
\`\`\`
|
|
203
204
|
|
|
204
|
-
Declaring \`wide\` with a non-empty reason **lifts the
|
|
205
|
+
Declaring \`wide\` with a non-empty reason **lifts the hard session-mass rejection** — no Story is rejected for width when it states why it is broad. Omit \`wide\` for ordinary Stories; a wide footprint with no \`wide\` declaration emits only an advisory nudge (check cohesion or declare \`wide\`), never a rejection on its own.
|
|
205
206
|
|
|
206
207
|
**Glob entries** in \`changes[]\` (bullets containing \`*\`) mark the Story footprint as \`unknown-width\`: the numeric ceiling cannot bound a glob, so it is skipped. A Story carrying glob changes with no \`wide\` declaration emits an advisory nudge.
|
|
207
208
|
|