mandrel 1.94.0 → 2.1.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 +116 -99
- package/.agents/agents/acceptance-critic.md +9 -7
- package/.agents/agents/story-worker.md +45 -51
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +498 -1287
- package/.agents/docs/agentrc-reference.json +185 -80
- package/.agents/docs/configuration.md +132 -190
- package/.agents/docs/execution-reference.md +51 -25
- package/.agents/docs/quality-gates.md +25 -33
- package/.agents/docs/workflows.md +8 -8
- package/.agents/instructions.md +113 -139
- package/.agents/rules/ci-remediation.md +11 -15
- package/.agents/rules/git-conventions-reference.md +48 -58
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +83 -254
- package/.agents/schemas/audit-rules.json +59 -1
- package/.agents/schemas/audit-rules.schema.json +33 -1
- package/.agents/schemas/lifecycle/README.md +1 -2
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
- package/.agents/schemas/signal-event.schema.json +3 -3
- package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +22 -66
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/bootstrap.js +3 -3
- package/.agents/scripts/check-dead-exports.js +43 -104
- package/.agents/scripts/check-doc-links.js +2 -2
- package/.agents/scripts/check-lifecycle-lint.js +7 -10
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/deliver-recover.js +122 -0
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +20 -50
- package/.agents/scripts/generate-skills-index.js +17 -1
- package/.agents/scripts/generate-workflows-doc.js +4 -4
- package/.agents/scripts/lib/ITicketingProvider.js +1 -19
- 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 +328 -28
- 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 -15
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
- package/.agents/scripts/lib/checks/index.js +3 -2
- package/.agents/scripts/lib/checks/loop-health.js +12 -11
- package/.agents/scripts/lib/checks/state.js +17 -248
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +39 -9
- package/.agents/scripts/lib/close-validation/gates.js +15 -15
- package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
- package/.agents/scripts/lib/close-validation/runner.js +13 -21
- package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +52 -35
- package/.agents/scripts/lib/config/explain.js +61 -48
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +29 -80
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +12 -15
- package/.agents/scripts/lib/config/runners.js +20 -66
- package/.agents/scripts/lib/config/temp-paths.js +30 -63
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
- package/.agents/scripts/lib/config-settings-schema.js +100 -60
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +2 -2
- package/.agents/scripts/lib/duplicate-search.js +242 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +23 -14
- package/.agents/scripts/lib/format-generated-json.js +97 -0
- package/.agents/scripts/lib/framework-version.js +19 -190
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
- package/.agents/scripts/lib/git-utils.js +32 -20
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +10 -38
- package/.agents/scripts/lib/label-taxonomy.js +10 -55
- package/.agents/scripts/lib/observability/active-story-env.js +44 -165
- package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
- package/.agents/scripts/lib/observability/signal-validator.js +4 -4
- package/.agents/scripts/lib/observability/signals-writer.js +6 -82
- package/.agents/scripts/lib/observability/source-classifier.js +5 -5
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
- package/.agents/scripts/lib/orchestration/code-review.js +78 -436
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
- 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/git-cleanup/phases/fast-forward.js +34 -0
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- 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 +52 -51
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
- package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
- package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- 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/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
- package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
- package/.agents/scripts/lib/planning-corpus.js +12 -281
- package/.agents/scripts/lib/preflight-runner.js +4 -4
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
- package/.agents/scripts/lib/signals/index.js +4 -17
- package/.agents/scripts/lib/signals/read.js +35 -35
- package/.agents/scripts/lib/signals/schema.js +8 -11
- package/.agents/scripts/lib/signals/span-tree.js +7 -7
- package/.agents/scripts/lib/signals/write.js +0 -1
- package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +17 -19
- package/.agents/scripts/lib/story-body/story-body.js +130 -75
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
- package/.agents/scripts/lib/validation-evidence.js +32 -60
- package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- 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 +102 -80
- package/.agents/scripts/plan-persist.js +230 -279
- package/.agents/scripts/plan-run-epilogue.js +142 -0
- package/.agents/scripts/post-structured-comment.js +0 -38
- package/.agents/scripts/pr-watch-with-update.js +43 -22
- package/.agents/scripts/providers/github/compose.js +0 -1
- package/.agents/scripts/providers/github/errors.js +0 -19
- package/.agents/scripts/providers/github/issues.js +13 -39
- package/.agents/scripts/providers/github/mappers.js +5 -12
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -156
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/resolve-stories.js +236 -0
- package/.agents/scripts/run-coverage.js +4 -1
- package/.agents/scripts/run-lint.js +2 -2
- package/.agents/scripts/run-verify.js +31 -2
- package/.agents/scripts/signals-view.js +25 -21
- package/.agents/scripts/single-story-close.js +178 -26
- package/.agents/scripts/single-story-confirm-merge.js +313 -24
- package/.agents/scripts/single-story-init.js +35 -30
- package/.agents/scripts/stories-wave-tick.js +85 -10
- package/.agents/scripts/story-plan.js +28 -49
- package/.agents/scripts/update-ticket-state.js +14 -65
- package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
- package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
- package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
- package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
- package/.agents/skills/core/scope-triage/SKILL.md +31 -172
- package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
- package/.agents/skills/core/security-and-hardening/reference.md +375 -0
- package/.agents/skills/skills.index.json +3 -53
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +6 -7
- package/.agents/workflows/audit-clean-code.md +7 -7
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +9 -10
- package/.agents/workflows/audit-lighthouse.md +11 -3
- package/.agents/workflows/audit-navigability.md +13 -2
- package/.agents/workflows/audit-performance.md +5 -6
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +11 -12
- package/.agents/workflows/audit-security.md +4 -5
- package/.agents/workflows/audit-seo.md +13 -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 +10 -3
- package/.agents/workflows/deliver.md +177 -176
- package/.agents/workflows/git-cleanup.md +5 -6
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
- package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
- package/.agents/workflows/helpers/code-review.md +75 -196
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
- package/.agents/workflows/helpers/deliver-story.md +606 -0
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/parallel-tooling.md +3 -3
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
- package/.agents/workflows/mandrel-update.md +2 -1
- package/.agents/workflows/plan.md +277 -145
- package/.agents/workflows/qa-assist.md +27 -33
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -6
- package/README.md +9 -8
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +70 -0
- package/lib/cli/registry.js +262 -19
- package/lib/cli/sync-agents.js +157 -0
- package/lib/cli/sync-commands.js +115 -6
- package/lib/cli/sync.js +168 -6
- package/lib/cli/update.js +105 -8
- package/lib/cli/version-helpers.js +131 -0
- package/lib/migrations/README.md +7 -5
- package/lib/migrations/index.js +12 -8
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
- package/package.json +2 -2
- package/.agents/agents/retro.md +0 -42
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer.md +0 -33
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/security-engineer.md +0 -111
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
- package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
- package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
- package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -66
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- 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 -852
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- 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/git-merge-orchestrator.js +0 -261
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
- package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
- package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
- package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
- package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
- package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
- 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/risk-verdict.js +0 -105
- 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 -621
- 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/story-run-progress-writer.js +0 -400
- 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/error-journal.js +0 -139
- 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-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
- 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 -284
- 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/merge-watcher.js +0 -665
- 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/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
- package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- 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-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- 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 -302
- 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/retro-run.js +0 -218
- package/.agents/scripts/slice-phase.js +0 -361
- 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 -464
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
- 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 -383
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
- package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
- package/.agents/workflows/helpers/deliver-epic.md +0 -998
- package/.agents/workflows/helpers/deliver-stories.md +0 -450
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
- 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 -353
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- package/.agents/workflows/helpers/single-story-deliver.md +0 -557
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* node:coverage ignore file */
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* wave-tick.js — thin CLI shim around `lib/wave-runner/tick.js`.
|
|
6
|
-
*
|
|
7
|
-
* Reads the `epic-run-state` checkpoint plus fresh Story labels and
|
|
8
|
-
* prints one `WaveTickResult` envelope. The slash-command operator
|
|
9
|
-
* (`/deliver`) consumes the envelope to decide whether to dispatch
|
|
10
|
-
* the next wave, observe in-flight stories, or finalize the Epic.
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
|
|
14
|
-
*
|
|
15
|
-
* The tick is stateless — "loop until terminal" is the caller's job
|
|
16
|
-
* (today: the markdown's wave loop).
|
|
17
|
-
*
|
|
18
|
-
* Output: one JSON object on stdout. Schema in `lib/wave-runner/tick.js`.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { execFileSync } from 'node:child_process';
|
|
22
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
23
|
-
import { parseArgs } from 'node:util';
|
|
24
|
-
|
|
25
|
-
import { runAsCli } from './lib/cli-utils.js';
|
|
26
|
-
import { epicLedgerPath } from './lib/config/temp-paths.js';
|
|
27
|
-
import { resolveConfig } from './lib/config-resolver.js';
|
|
28
|
-
import { Logger } from './lib/Logger.js';
|
|
29
|
-
import { createProvider } from './lib/provider-factory.js';
|
|
30
|
-
import { tick } from './lib/wave-runner/tick.js';
|
|
31
|
-
|
|
32
|
-
const HELP = `Usage: node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
|
|
33
|
-
|
|
34
|
-
Stateless wave-loop planner. Reads the epic-run-state checkpoint on
|
|
35
|
-
Epic #<id>, evaluates the live story-label state, and prints one
|
|
36
|
-
WaveTickResult envelope describing the next dispatchable action.
|
|
37
|
-
|
|
38
|
-
When --check-idle <minutes> is supplied, the planner skips the normal
|
|
39
|
-
WaveTickResult emit and instead scans the per-Epic lifecycle ledger
|
|
40
|
-
(temp/epic-<id>/lifecycle.ndjson) for in-flight Stories whose most
|
|
41
|
-
recent lifecycle event is older than the threshold. Emits a single
|
|
42
|
-
JSON envelope on stdout and exits non-zero when at least one stalled
|
|
43
|
-
Story is detected. The envelope shape mirrors the wave-stall
|
|
44
|
-
structured-comment payload so the slash-command host can post it
|
|
45
|
-
verbatim.
|
|
46
|
-
`;
|
|
47
|
-
|
|
48
|
-
export async function runWaveTickCli({
|
|
49
|
-
epicId,
|
|
50
|
-
cwd,
|
|
51
|
-
injectedProvider,
|
|
52
|
-
injectedConfig,
|
|
53
|
-
} = {}) {
|
|
54
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
55
|
-
throw new TypeError('runWaveTickCli: --epic must be a positive integer');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const config = injectedConfig ?? resolveConfig({ cwd });
|
|
59
|
-
const provider = injectedProvider ?? createProvider(config);
|
|
60
|
-
|
|
61
|
-
const result = await tick({
|
|
62
|
-
epic: epicId,
|
|
63
|
-
collaborators: { provider },
|
|
64
|
-
ctx: { config },
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Scan the per-Epic lifecycle ledger and compute, per in-flight Story,
|
|
72
|
-
* the timestamp of its most recent lifecycle event. A Story is
|
|
73
|
-
* "in-flight" when the ledger carries a `story.dispatch.start` record
|
|
74
|
-
* without a matching `story.dispatch.end`. Any other `story.*` event
|
|
75
|
-
* (notably `story.heartbeat` from Story #3057) refreshes the Story's
|
|
76
|
-
* last-event timestamp.
|
|
77
|
-
*
|
|
78
|
-
* Pure helper — exported for unit tests.
|
|
79
|
-
*
|
|
80
|
-
* @param {string} ledgerPath Absolute path to `lifecycle.ndjson`.
|
|
81
|
-
* @returns {Map<number, string>} `storyId → ISO-8601 timestamp`. Empty
|
|
82
|
-
* when the ledger is missing, unreadable, or carries no in-flight
|
|
83
|
-
* Stories.
|
|
84
|
-
*/
|
|
85
|
-
export function readLedgerLastEvents(ledgerPath) {
|
|
86
|
-
if (!ledgerPath || !existsSync(ledgerPath)) return new Map();
|
|
87
|
-
let raw;
|
|
88
|
-
try {
|
|
89
|
-
raw = readFileSync(ledgerPath, 'utf8');
|
|
90
|
-
} catch {
|
|
91
|
-
return new Map();
|
|
92
|
-
}
|
|
93
|
-
if (!raw) return new Map();
|
|
94
|
-
const started = new Set();
|
|
95
|
-
const ended = new Set();
|
|
96
|
-
const lastTs = new Map();
|
|
97
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
98
|
-
if (!line) continue;
|
|
99
|
-
let record;
|
|
100
|
-
try {
|
|
101
|
-
record = JSON.parse(line);
|
|
102
|
-
} catch {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (!record || record.kind !== 'emitted') continue;
|
|
106
|
-
const event = typeof record.event === 'string' ? record.event : '';
|
|
107
|
-
if (!event.startsWith('story.')) continue;
|
|
108
|
-
const storyId = record.payload?.storyId;
|
|
109
|
-
if (!Number.isInteger(storyId) || storyId <= 0) continue;
|
|
110
|
-
if (event === 'story.dispatch.start') started.add(storyId);
|
|
111
|
-
else if (event === 'story.dispatch.end') ended.add(storyId);
|
|
112
|
-
const ts = typeof record.ts === 'string' ? record.ts : null;
|
|
113
|
-
if (ts) {
|
|
114
|
-
const prior = lastTs.get(storyId);
|
|
115
|
-
if (!prior || prior < ts) lastTs.set(storyId, ts);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const out = new Map();
|
|
119
|
-
for (const id of started) {
|
|
120
|
-
if (ended.has(id)) continue;
|
|
121
|
-
const ts = lastTs.get(id);
|
|
122
|
-
if (ts) out.set(id, ts);
|
|
123
|
-
}
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Single-delivery analogue of {@link readLedgerLastEvents} (Epic #4476, M5).
|
|
129
|
-
* A single-delivery run has no Story fan-out; the whole Epic is one long
|
|
130
|
-
* guarded session walking the Delivery Slicing table, and its liveness signal
|
|
131
|
-
* is `slice.heartbeat` (emitted off the token stream by the PostToolUse hook).
|
|
132
|
-
* This scans the ledger for `slice.*` events, treats a slice carrying a
|
|
133
|
-
* `slice.start` without a matching `slice.end` as in-flight, and returns each
|
|
134
|
-
* in-flight slice's most recent event timestamp — the same
|
|
135
|
-
* started-without-ended shape the Story reader uses, keyed by the string
|
|
136
|
-
* `sliceId`. Any `slice.*` event (notably `slice.heartbeat`) refreshes the
|
|
137
|
-
* timestamp.
|
|
138
|
-
*
|
|
139
|
-
* Pure helper — exported for unit tests.
|
|
140
|
-
*
|
|
141
|
-
* @param {string} ledgerPath Absolute path to `lifecycle.ndjson`.
|
|
142
|
-
* @returns {Map<string, string>} `sliceId → ISO-8601 timestamp`. Empty when
|
|
143
|
-
* the ledger is missing, unreadable, or carries no in-flight slices.
|
|
144
|
-
*/
|
|
145
|
-
export function readLedgerSliceEvents(ledgerPath) {
|
|
146
|
-
if (!ledgerPath || !existsSync(ledgerPath)) return new Map();
|
|
147
|
-
let raw;
|
|
148
|
-
try {
|
|
149
|
-
raw = readFileSync(ledgerPath, 'utf8');
|
|
150
|
-
} catch {
|
|
151
|
-
return new Map();
|
|
152
|
-
}
|
|
153
|
-
if (!raw) return new Map();
|
|
154
|
-
const started = new Set();
|
|
155
|
-
const ended = new Set();
|
|
156
|
-
const lastTs = new Map();
|
|
157
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
158
|
-
if (!line) continue;
|
|
159
|
-
let record;
|
|
160
|
-
try {
|
|
161
|
-
record = JSON.parse(line);
|
|
162
|
-
} catch {
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
if (!record || record.kind !== 'emitted') continue;
|
|
166
|
-
const event = typeof record.event === 'string' ? record.event : '';
|
|
167
|
-
if (!event.startsWith('slice.')) continue;
|
|
168
|
-
const sliceId = record.payload?.sliceId;
|
|
169
|
-
if (typeof sliceId !== 'string' || sliceId.length === 0) continue;
|
|
170
|
-
if (event === 'slice.start') started.add(sliceId);
|
|
171
|
-
else if (event === 'slice.end') ended.add(sliceId);
|
|
172
|
-
const ts = typeof record.ts === 'string' ? record.ts : null;
|
|
173
|
-
if (ts) {
|
|
174
|
-
const prior = lastTs.get(sliceId);
|
|
175
|
-
if (!prior || prior < ts) lastTs.set(sliceId, ts);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
const out = new Map();
|
|
179
|
-
for (const id of started) {
|
|
180
|
-
if (ended.has(id)) continue;
|
|
181
|
-
const ts = lastTs.get(id);
|
|
182
|
-
if (ts) out.set(id, ts);
|
|
183
|
-
}
|
|
184
|
-
return out;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Deterministic branch-activity resolver (Story #3900). Returns the epoch-ms
|
|
189
|
-
* timestamp of the most recent commit on `story-<storyId>` via
|
|
190
|
-
* `git log -1 --format=%cI`, or `null` when the branch does not exist, has no
|
|
191
|
-
* commits, or git is unavailable.
|
|
192
|
-
*
|
|
193
|
-
* This is the secondary liveness signal the idle watchdog consults before
|
|
194
|
-
* flagging a Story as stalled: a healthy long-running Story routinely exceeds
|
|
195
|
-
* the heartbeat threshold during `implementing → closing` (heartbeats fire
|
|
196
|
-
* only at phase transitions), but its branch keeps gaining commits. A recent
|
|
197
|
-
* commit is hard, deterministic evidence of forward progress that does not
|
|
198
|
-
* depend on a heartbeat landing in the ledger. Pure-ish (shells out to git)
|
|
199
|
-
* and injectable so unit tests never spawn a subprocess.
|
|
200
|
-
*
|
|
201
|
-
* @param {number} storyId
|
|
202
|
-
* @param {{ cwd?: string, exec?: typeof execFileSync, branch?: string }} [deps]
|
|
203
|
-
* `branch` overrides the default `story-<storyId>` ref — the single-delivery
|
|
204
|
-
* watchdog passes `epic-<id>` (Epic #4476, M5) to consult the one
|
|
205
|
-
* integration branch instead of a per-Story branch.
|
|
206
|
-
* @returns {number|null} epoch-ms of the last commit, or null.
|
|
207
|
-
*/
|
|
208
|
-
export function branchLastCommitMs(storyId, deps = {}) {
|
|
209
|
-
const exec = deps.exec ?? execFileSync;
|
|
210
|
-
const cwd = deps.cwd ?? process.cwd();
|
|
211
|
-
const branch =
|
|
212
|
-
typeof deps.branch === 'string' && deps.branch
|
|
213
|
-
? deps.branch
|
|
214
|
-
: `story-${storyId}`;
|
|
215
|
-
try {
|
|
216
|
-
const out = exec('git', ['log', '-1', '--format=%cI', branch, '--'], {
|
|
217
|
-
cwd,
|
|
218
|
-
encoding: 'utf8',
|
|
219
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
220
|
-
}).trim();
|
|
221
|
-
if (!out) return null;
|
|
222
|
-
const ms = Date.parse(out);
|
|
223
|
-
return Number.isFinite(ms) ? ms : null;
|
|
224
|
-
} catch {
|
|
225
|
-
// Branch absent / git unavailable — no deterministic signal.
|
|
226
|
-
return null;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Build the wave-stall envelope. Pure helper — exported for unit tests.
|
|
232
|
-
*
|
|
233
|
-
* A Story whose latest ledger event is older than the threshold is *not*
|
|
234
|
-
* flagged as stalled when its `story-<id>` branch carries a commit newer
|
|
235
|
-
* than the threshold (Story #3900). Branch commits are deterministic
|
|
236
|
-
* forward-progress evidence that survives the heartbeat-cadence gap during
|
|
237
|
-
* `implementing → closing`, so consulting them eliminates the false-positive
|
|
238
|
-
* re-dispatch hazard (two agents on one branch) the watchdog otherwise
|
|
239
|
-
* manufactures for every healthy long-running Story.
|
|
240
|
-
*
|
|
241
|
-
* @param {object} args
|
|
242
|
-
* @param {number} args.epicId
|
|
243
|
-
* @param {number} args.thresholdMinutes
|
|
244
|
-
* @param {Map<number, string>} args.lastEvents `storyId → ISO-8601 ts`
|
|
245
|
-
* from {@link readLedgerLastEvents}.
|
|
246
|
-
* @param {Date} args.now Reference clock for the staleness comparison.
|
|
247
|
-
* @param {(storyId: number) => (number|null)} [args.branchActivity]
|
|
248
|
-
* Resolver for the last commit epoch-ms on `story-<id>`. Defaults to
|
|
249
|
-
* {@link branchLastCommitMs}. Injected for tests.
|
|
250
|
-
* @param {Map<string, string>} [args.sliceEvents] `sliceId → ISO-8601 ts`
|
|
251
|
-
* from {@link readLedgerSliceEvents} (Epic #4476, M5). Single-delivery has
|
|
252
|
-
* no Story fan-out; its liveness signal is `slice.heartbeat`. When
|
|
253
|
-
* non-empty, in-flight slices are surfaced under the additive
|
|
254
|
-
* `inFlightSlices` / `stalledSlices` fields — the story fields are
|
|
255
|
-
* untouched, so a fan-out run's envelope is byte-for-byte unchanged.
|
|
256
|
-
* @param {(epicId: number) => (number|null)} [args.epicBranchActivity]
|
|
257
|
-
* Resolver for the last commit epoch-ms on the single-delivery integration
|
|
258
|
-
* branch `epic-<id>` — the deterministic forward-progress signal for the
|
|
259
|
-
* one long session, mirroring the per-Story branch check. Injected for
|
|
260
|
-
* tests.
|
|
261
|
-
* @returns {{
|
|
262
|
-
* kind: 'wave-stall',
|
|
263
|
-
* epicId: number,
|
|
264
|
-
* thresholdMinutes: number,
|
|
265
|
-
* checkedAt: string,
|
|
266
|
-
* stalled: Array<{storyId: number, lastEventAt: string, idleMinutes: number}>,
|
|
267
|
-
* inFlight: number[],
|
|
268
|
-
* stalledSlices: Array<{sliceId: string, lastEventAt: string, idleMinutes: number}>,
|
|
269
|
-
* inFlightSlices: string[]
|
|
270
|
-
* }}
|
|
271
|
-
*/
|
|
272
|
-
export function buildWaveStallEnvelope({
|
|
273
|
-
epicId,
|
|
274
|
-
thresholdMinutes,
|
|
275
|
-
lastEvents,
|
|
276
|
-
now,
|
|
277
|
-
branchActivity = branchLastCommitMs,
|
|
278
|
-
sliceEvents = new Map(),
|
|
279
|
-
epicBranchActivity = (eid) =>
|
|
280
|
-
branchLastCommitMs(0, { branch: `epic-${eid}` }),
|
|
281
|
-
}) {
|
|
282
|
-
const checkedAt = now.toISOString();
|
|
283
|
-
const thresholdMs = thresholdMinutes * 60 * 1000;
|
|
284
|
-
const stalled = [];
|
|
285
|
-
const inFlight = [];
|
|
286
|
-
for (const [storyId, ts] of lastEvents) {
|
|
287
|
-
inFlight.push(storyId);
|
|
288
|
-
const eventMs = Date.parse(ts);
|
|
289
|
-
if (!Number.isFinite(eventMs)) continue;
|
|
290
|
-
const idleMs = now.getTime() - eventMs;
|
|
291
|
-
if (idleMs < thresholdMs) continue;
|
|
292
|
-
|
|
293
|
-
// Ledger says idle — consult the branch as a deterministic liveness
|
|
294
|
-
// signal before declaring a stall. A recent commit means the Story is
|
|
295
|
-
// making progress despite the heartbeat-cadence gap.
|
|
296
|
-
const commitMs = branchActivity(storyId);
|
|
297
|
-
if (
|
|
298
|
-
typeof commitMs === 'number' &&
|
|
299
|
-
Number.isFinite(commitMs) &&
|
|
300
|
-
now.getTime() - commitMs < thresholdMs
|
|
301
|
-
) {
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
stalled.push({
|
|
306
|
-
storyId,
|
|
307
|
-
lastEventAt: ts,
|
|
308
|
-
idleMinutes: Math.floor(idleMs / 60000),
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
inFlight.sort((a, b) => a - b);
|
|
312
|
-
stalled.sort((a, b) => a.storyId - b.storyId);
|
|
313
|
-
|
|
314
|
-
// Single-delivery slice liveness (additive). A slice that has gone silent
|
|
315
|
-
// past the threshold is a stall UNLESS the `epic-<id>` branch carries a
|
|
316
|
-
// recent commit — the same forward-progress carve-out the Story path uses.
|
|
317
|
-
const stalledSlices = [];
|
|
318
|
-
const inFlightSlices = [];
|
|
319
|
-
for (const [sliceId, ts] of sliceEvents) {
|
|
320
|
-
inFlightSlices.push(sliceId);
|
|
321
|
-
const eventMs = Date.parse(ts);
|
|
322
|
-
if (!Number.isFinite(eventMs)) continue;
|
|
323
|
-
const idleMs = now.getTime() - eventMs;
|
|
324
|
-
if (idleMs < thresholdMs) continue;
|
|
325
|
-
|
|
326
|
-
const commitMs = epicBranchActivity(epicId);
|
|
327
|
-
if (
|
|
328
|
-
typeof commitMs === 'number' &&
|
|
329
|
-
Number.isFinite(commitMs) &&
|
|
330
|
-
now.getTime() - commitMs < thresholdMs
|
|
331
|
-
) {
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
stalledSlices.push({
|
|
336
|
-
sliceId,
|
|
337
|
-
lastEventAt: ts,
|
|
338
|
-
idleMinutes: Math.floor(idleMs / 60000),
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
inFlightSlices.sort();
|
|
342
|
-
stalledSlices.sort((a, b) => a.sliceId.localeCompare(b.sliceId));
|
|
343
|
-
|
|
344
|
-
return {
|
|
345
|
-
kind: 'wave-stall',
|
|
346
|
-
epicId,
|
|
347
|
-
thresholdMinutes,
|
|
348
|
-
checkedAt,
|
|
349
|
-
stalled,
|
|
350
|
-
inFlight,
|
|
351
|
-
stalledSlices,
|
|
352
|
-
inFlightSlices,
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Run the `--check-idle` path. Exported so unit tests can drive the
|
|
358
|
-
* branch without spawning the CLI subprocess.
|
|
359
|
-
*
|
|
360
|
-
* @param {object} args
|
|
361
|
-
* @param {number} args.epicId
|
|
362
|
-
* @param {number} args.thresholdMinutes
|
|
363
|
-
* @param {string} [args.ledgerPath] Override for tests; defaults to the
|
|
364
|
-
* canonical `temp/epic-<id>/lifecycle.ndjson`.
|
|
365
|
-
* @param {Date} [args.now] Override for tests; defaults to wall clock.
|
|
366
|
-
* @param {object} [args.config] Optional resolved config for tempRoot.
|
|
367
|
-
* @param {(storyId: number) => (number|null)} [args.branchActivity]
|
|
368
|
-
* Branch-liveness resolver; defaults to {@link branchLastCommitMs}.
|
|
369
|
-
* Injected for tests so the watchdog never spawns git.
|
|
370
|
-
* @param {(epicId: number) => (number|null)} [args.epicBranchActivity]
|
|
371
|
-
* Single-delivery integration-branch (`epic-<id>`) liveness resolver;
|
|
372
|
-
* injected for tests. Defaults to {@link branchLastCommitMs} with the
|
|
373
|
-
* `epic-<id>` ref.
|
|
374
|
-
* @returns {{envelope: object, stalledCount: number}} `stalledCount` counts
|
|
375
|
-
* both stalled Stories (fan-out) and stalled slices (single delivery), so a
|
|
376
|
-
* dead single-delivery session still exits the CLI non-zero.
|
|
377
|
-
*/
|
|
378
|
-
export function runCheckIdle({
|
|
379
|
-
epicId,
|
|
380
|
-
thresholdMinutes,
|
|
381
|
-
ledgerPath,
|
|
382
|
-
now = new Date(),
|
|
383
|
-
config,
|
|
384
|
-
branchActivity = branchLastCommitMs,
|
|
385
|
-
epicBranchActivity,
|
|
386
|
-
}) {
|
|
387
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
388
|
-
throw new TypeError('runCheckIdle: epicId must be a positive integer');
|
|
389
|
-
}
|
|
390
|
-
if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
|
|
391
|
-
throw new TypeError(
|
|
392
|
-
'runCheckIdle: thresholdMinutes must be a positive integer',
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
const resolvedPath = ledgerPath ?? epicLedgerPath(epicId, config);
|
|
396
|
-
const lastEvents = readLedgerLastEvents(resolvedPath);
|
|
397
|
-
const sliceEvents = readLedgerSliceEvents(resolvedPath);
|
|
398
|
-
const envelope = buildWaveStallEnvelope({
|
|
399
|
-
epicId,
|
|
400
|
-
thresholdMinutes,
|
|
401
|
-
lastEvents,
|
|
402
|
-
now,
|
|
403
|
-
branchActivity,
|
|
404
|
-
sliceEvents,
|
|
405
|
-
...(epicBranchActivity ? { epicBranchActivity } : {}),
|
|
406
|
-
});
|
|
407
|
-
return {
|
|
408
|
-
envelope,
|
|
409
|
-
stalledCount: envelope.stalled.length + envelope.stalledSlices.length,
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
async function main(argv) {
|
|
414
|
-
const { values } = parseArgs({
|
|
415
|
-
args: argv,
|
|
416
|
-
options: {
|
|
417
|
-
epic: { type: 'string' },
|
|
418
|
-
'check-idle': { type: 'string' },
|
|
419
|
-
help: { type: 'boolean', short: 'h' },
|
|
420
|
-
},
|
|
421
|
-
strict: false,
|
|
422
|
-
allowPositionals: true,
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
if (values.help) {
|
|
426
|
-
process.stdout.write(`${HELP}\n`);
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const epicId = Number.parseInt(
|
|
431
|
-
String(values.epic ?? '').replace(/^#/, ''),
|
|
432
|
-
10,
|
|
433
|
-
);
|
|
434
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
435
|
-
Logger.error('wave-tick: --epic <id> is required (positive integer)');
|
|
436
|
-
process.exitCode = 2;
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (values['check-idle'] !== undefined) {
|
|
441
|
-
const thresholdMinutes = Number.parseInt(String(values['check-idle']), 10);
|
|
442
|
-
if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
|
|
443
|
-
Logger.error(
|
|
444
|
-
'wave-tick: --check-idle <minutes> must be a positive integer',
|
|
445
|
-
);
|
|
446
|
-
process.exitCode = 2;
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
const { envelope, stalledCount } = runCheckIdle({
|
|
450
|
-
epicId,
|
|
451
|
-
thresholdMinutes,
|
|
452
|
-
});
|
|
453
|
-
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
454
|
-
process.exitCode = stalledCount > 0 ? 1 : 0;
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
const result = await runWaveTickCli({ epicId });
|
|
459
|
-
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
runAsCli(import.meta.url, () => main(process.argv.slice(2)), {
|
|
463
|
-
source: 'wave-tick',
|
|
464
|
-
});
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: analyze-execution
|
|
3
|
-
description: >-
|
|
4
|
-
Aggregate per-Story or per-Epic execution signals into a structured
|
|
5
|
-
perf-summary or perf-report and upsert it onto the corresponding GitHub
|
|
6
|
-
ticket. Use after a Story closes (Story mode) or as part of
|
|
7
|
-
`/deliver` Phase 6 (Epic mode). Reads NDJSON via
|
|
8
|
-
`lib/signals/read` and writes a single structured comment.
|
|
9
|
-
allowed_tools:
|
|
10
|
-
- Read
|
|
11
|
-
- Bash
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# analyze-execution
|
|
15
|
-
|
|
16
|
-
## Policy Capsule
|
|
17
|
-
|
|
18
|
-
- Invoke via the wrapping CLI `node .agents/scripts/analyze-execution.js`; do not duplicate the read/write logic from this Skill body.
|
|
19
|
-
- Resolve mode strictly by flags: `--story <sid> --epic <eid>` → Story mode; `--epic <eid>` alone → Epic mode.
|
|
20
|
-
- Read NDJSON signals only through `lib/signals/read` (the async-iterator entry point). Never open `<tempRoot>/epic-<eid>/story-<sid>/signals.ndjson` directly — the reader owns the warn-once malformed-JSON policy.
|
|
21
|
-
- Emit a single structured GitHub comment per ticket (`<!-- structured:story-perf-summary -->` or `<!-- structured:epic-perf-report -->`); rely on `upsertStructuredComment` for idempotence — never post duplicates.
|
|
22
|
-
- Never rename or alter the structured-marker IDs; the retro composer and Epic dashboard grep them verbatim.
|
|
23
|
-
- Validate the structured payload against `docs/data-dictionary.md §StoryPerfSummary` or `§EpicPerfReport` before posting. Schema violations exit non-zero.
|
|
24
|
-
- Soft-fail (exit 0 with a warning) when NDJSON is missing for a Story or an Epic has no children — observability output MUST NOT block the close pipeline.
|
|
25
|
-
- Do not write to disk. Persistence is GitHub; the Skill is read-NDJSON + post-comment only.
|
|
26
|
-
|
|
27
|
-
## Role
|
|
28
|
-
|
|
29
|
-
Observability writer. Composes the structured `story-perf-summary` /
|
|
30
|
-
`epic-perf-report` comment bodies the retro composer downstream renders
|
|
31
|
-
into the Epic dashboard.
|
|
32
|
-
|
|
33
|
-
## When to use
|
|
34
|
-
|
|
35
|
-
- **Story mode** — after `story-close.js` finishes, the post-merge
|
|
36
|
-
pipeline dispatches this Skill (or the wrapping script) to roll up the
|
|
37
|
-
Story's NDJSON signals into a single `<!-- structured:story-perf-summary -->`
|
|
38
|
-
marker comment on the Story ticket.
|
|
39
|
-
- **Epic mode** — during `/deliver` Phase 6.0 (or the retro
|
|
40
|
-
composer), the Skill fans out across every Story under the Epic,
|
|
41
|
-
reads each Story's structured perf summary, and posts a single
|
|
42
|
-
`<!-- structured:epic-perf-report -->` marker on the Epic ticket.
|
|
43
|
-
|
|
44
|
-
## Inputs
|
|
45
|
-
|
|
46
|
-
The Skill reads (never writes) the NDJSON signal stream at:
|
|
47
|
-
|
|
48
|
-
```text
|
|
49
|
-
<tempRoot>/epic-<eid>/story-<sid>/signals.ndjson
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Use the `lib/signals/read` async-iterator entry point — never open the
|
|
53
|
-
file directly. Story mode also reads `phase-timings.json` written by
|
|
54
|
-
`post-merge-close.js`.
|
|
55
|
-
|
|
56
|
-
## Outputs
|
|
57
|
-
|
|
58
|
-
A single upserted GitHub comment per ticket. The Skill writes nothing to
|
|
59
|
-
disk — the persist path is GitHub. Idempotence: the underlying script's
|
|
60
|
-
`upsertStructuredComment` helper deletes any prior marker before posting
|
|
61
|
-
the new one.
|
|
62
|
-
|
|
63
|
-
## Procedure
|
|
64
|
-
|
|
65
|
-
### Step 1 — Resolve mode
|
|
66
|
-
|
|
67
|
-
If both `--story <sid>` and `--epic <eid>` are supplied → Story mode.
|
|
68
|
-
If only `--epic <eid>` is supplied → Epic mode. The script
|
|
69
|
-
`analyze-execution.js` is the dispatcher today; this Skill documents the
|
|
70
|
-
contract the dispatcher implements.
|
|
71
|
-
|
|
72
|
-
### Step 2 — Read signals via lib/signals/read
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
node .agents/scripts/analyze-execution.js --story <sid> --epic <eid>
|
|
76
|
-
# or
|
|
77
|
-
node .agents/scripts/analyze-execution.js --epic <eid>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Step 3 — Validate the structured payload before posting
|
|
81
|
-
|
|
82
|
-
The payload must conform to `docs/data-dictionary.md §StoryPerfSummary`
|
|
83
|
-
or §EpicPerfReport. Schema violations exit non-zero — the close
|
|
84
|
-
pipeline treats that as a non-fatal warning, but the smoke spec pins
|
|
85
|
-
the contract so we never silently emit malformed comments.
|
|
86
|
-
|
|
87
|
-
## Constraints
|
|
88
|
-
|
|
89
|
-
- Do **not** open `signals.ndjson` outside `lib/signals/read` — the
|
|
90
|
-
reader handles the warn-once policy for malformed JSON lines and
|
|
91
|
-
the streaming-iteration contract.
|
|
92
|
-
- Do **not** rename the structured-marker IDs
|
|
93
|
-
(`<!-- structured:story-perf-summary -->`,
|
|
94
|
-
`<!-- structured:epic-perf-report -->`); the retro composer and the
|
|
95
|
-
Epic dashboard both grep for them verbatim.
|
|
96
|
-
- Soft-failure mode is intentional: missing NDJSON for a Story or no
|
|
97
|
-
children for an Epic returns exit 0 with a warning so close pipelines
|
|
98
|
-
never block on observability output.
|