mandrel 2.0.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 +59 -28
- package/.agents/agents/acceptance-critic.md +9 -7
- package/.agents/agents/story-worker.md +41 -46
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +51 -44
- package/.agents/docs/agentrc-reference.json +8 -13
- package/.agents/docs/configuration.md +32 -56
- package/.agents/docs/execution-reference.md +39 -10
- package/.agents/docs/quality-gates.md +14 -16
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +64 -79
- package/.agents/rules/ci-remediation.md +3 -3
- package/.agents/rules/git-conventions-reference.md +42 -51
- package/.agents/schemas/agentrc.schema.json +34 -45
- 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/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/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 +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- 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/audit-suite/selector.js +323 -23
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -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 +4 -1
- package/.agents/scripts/lib/checks/index.js +1 -1
- 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 +3 -3
- 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-args.js +23 -2
- package/.agents/scripts/lib/close-validation/gates.js +13 -13
- 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/delivery-routing.js +7 -6
- package/.agents/scripts/lib/config/explain.js +10 -16
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +15 -25
- package/.agents/scripts/lib/config/quality.js +11 -14
- package/.agents/scripts/lib/config/runners.js +8 -21
- package/.agents/scripts/lib/config/temp-paths.js +18 -56
- package/.agents/scripts/lib/config-settings-schema-delivery.js +31 -13
- package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
- package/.agents/scripts/lib/config-settings-schema.js +48 -22
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/duplicate-search.js +38 -7
- 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 -189
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
- package/.agents/scripts/lib/git-utils.js +0 -14
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +0 -15
- package/.agents/scripts/lib/label-taxonomy.js +1 -12
- package/.agents/scripts/lib/observability/active-story-env.js +42 -163
- 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 +2 -2
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- 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 +43 -45
- package/.agents/scripts/lib/orchestration/code-review.js +58 -168
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
- 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/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 +9 -11
- 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/listeners/README.md +7 -3
- 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/merge-block-class.js +76 -20
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +114 -24
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +3 -7
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -75
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
- package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
- package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
- 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/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 +374 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
- 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 +3 -12
- 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 +72 -30
- 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 +12 -8
- 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 +264 -43
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -32
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
- package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
- package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
- package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
- package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
- 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 -286
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- 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/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +8 -7
- package/.agents/scripts/lib/story-body/story-body.js +6 -5
- package/.agents/scripts/lib/templates/decomposer-prompts.js +7 -3
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/ticket-body-sections.js +0 -14
- package/.agents/scripts/lib/validation-evidence.js +31 -59
- package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/plan-context.js +38 -6
- package/.agents/scripts/plan-persist.js +145 -35
- package/.agents/scripts/plan-run-epilogue.js +83 -38
- 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 +1 -11
- package/.agents/scripts/providers/github/mappers.js +5 -0
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -153
- 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 +9 -10
- package/.agents/scripts/single-story-close.js +173 -18
- package/.agents/scripts/single-story-confirm-merge.js +288 -15
- package/.agents/scripts/single-story-init.js +6 -10
- package/.agents/scripts/stories-wave-tick.js +79 -4
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/update-ticket-state.js +8 -50
- 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 +3 -3
- package/.agents/skills/core/scope-triage/SKILL.md +3 -0
- 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 +2 -12
- 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/workflows/audit-architecture.md +3 -4
- package/.agents/workflows/audit-clean-code.md +4 -4
- package/.agents/workflows/audit-documentation.md +4 -5
- package/.agents/workflows/audit-lighthouse.md +8 -0
- package/.agents/workflows/audit-navigability.md +10 -0
- package/.agents/workflows/audit-performance.md +2 -3
- package/.agents/workflows/audit-quality.md +8 -9
- package/.agents/workflows/audit-security.md +1 -2
- package/.agents/workflows/audit-seo.md +10 -0
- package/.agents/workflows/audit-ux-ui.md +7 -0
- package/.agents/workflows/deliver.md +98 -45
- package/.agents/workflows/git-cleanup.md +2 -2
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +21 -13
- package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
- package/.agents/workflows/helpers/code-review.md +12 -10
- package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
- package/.agents/workflows/helpers/deliver-story.md +193 -118
- package/.agents/workflows/helpers/parallel-tooling.md +2 -2
- package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
- package/.agents/workflows/plan.md +184 -19
- package/.agents/workflows/qa-assist.md +6 -6
- package/.agents/workflows/qa-explore.md +3 -3
- package/.agents/workflows/qa-run.md +1 -5
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +40 -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 -9
- 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 +1 -1
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- 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/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -53
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- 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 -187
- 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/audit-lens-routing.js +0 -128
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- 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/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
- 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 -21
- 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 -397
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
- package/.agents/scripts/resolve-plan-run.js +0 -117
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* + `schema`; `buildSpanTree` was a throwing placeholder.
|
|
11
11
|
* - Epic #1181 / Story #1440 / Task #1461 — placeholder replaced by
|
|
12
12
|
* the real export from `./span-tree.js`.
|
|
13
|
-
* - Story #1476 — `appendSignal` / `appendTrace`
|
|
14
|
-
*
|
|
13
|
+
* - Story #1476 — `appendSignal` / `appendTrace` re-exported here
|
|
14
|
+
* via `./write.js` so the gate scripts (and any
|
|
15
15
|
* new code) converge on `lib/signals/` instead of importing the
|
|
16
16
|
* writer directly from `lib/observability/`.
|
|
17
17
|
*
|
|
@@ -21,19 +21,6 @@
|
|
|
21
21
|
import { read } from './read.js';
|
|
22
22
|
import * as schema from './schema.js';
|
|
23
23
|
import { buildSpanTree } from './span-tree.js';
|
|
24
|
-
import {
|
|
25
|
-
appendEpicSignal,
|
|
26
|
-
appendSignal,
|
|
27
|
-
appendTrace,
|
|
28
|
-
forEachLine,
|
|
29
|
-
} from './write.js';
|
|
24
|
+
import { appendSignal, appendTrace, forEachLine } from './write.js';
|
|
30
25
|
|
|
31
|
-
export {
|
|
32
|
-
appendEpicSignal,
|
|
33
|
-
appendSignal,
|
|
34
|
-
appendTrace,
|
|
35
|
-
buildSpanTree,
|
|
36
|
-
forEachLine,
|
|
37
|
-
read,
|
|
38
|
-
schema,
|
|
39
|
-
};
|
|
26
|
+
export { appendSignal, appendTrace, buildSpanTree, forEachLine, read, schema };
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Streaming signals reader (Epic #1181 / Story #1438 / Task #1459).
|
|
3
3
|
*
|
|
4
|
-
* Provides one async-iterator entry point — `read({
|
|
4
|
+
* Provides one async-iterator entry point — `read({ run, story?, kind?,
|
|
5
5
|
* config? })` — that consumers use instead of opening the NDJSON file
|
|
6
6
|
* themselves. The reader streams line-by-line so callers never load the
|
|
7
7
|
* full file into memory (50MB+ traces stay under file size in RSS).
|
|
8
8
|
*
|
|
9
9
|
* On-disk layout (resolved via `lib/config/temp-paths.js`):
|
|
10
10
|
*
|
|
11
|
-
* <tempRoot>/
|
|
11
|
+
* <tempRoot>/run-<run>/story-<story>/signals.ndjson
|
|
12
12
|
*
|
|
13
13
|
* When `story` is omitted, the reader fans out across every
|
|
14
|
-
* `story-<id>/signals.ndjson` under `<tempRoot>/
|
|
15
|
-
*
|
|
14
|
+
* `story-<id>/signals.ndjson` under `<tempRoot>/run-<run>/`. When the
|
|
15
|
+
* run directory is missing, the iterator yields nothing (consumers
|
|
16
16
|
* treat absence as "no signals yet").
|
|
17
17
|
*
|
|
18
18
|
* ## Filter semantics
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* argument are yielded. Filtering happens after the per-line JSON
|
|
22
22
|
* parse + envelope guard (see `lib/signals/schema.js`).
|
|
23
23
|
* - `story` — narrows to a single Story's stream; otherwise we walk
|
|
24
|
-
* every Story directory under the
|
|
24
|
+
* every Story directory under the run.
|
|
25
25
|
*
|
|
26
26
|
* ## Warn-once policy (AC #3)
|
|
27
27
|
*
|
|
@@ -46,8 +46,8 @@ import fs from 'node:fs/promises';
|
|
|
46
46
|
import path from 'node:path';
|
|
47
47
|
import { createInterface } from 'node:readline';
|
|
48
48
|
import {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
runArtifactPath,
|
|
50
|
+
runTempDir,
|
|
51
51
|
signalsFile,
|
|
52
52
|
storyTempDir,
|
|
53
53
|
} from '../config/temp-paths.js';
|
|
@@ -145,43 +145,43 @@ async function* streamFile(target, kindFilter) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
|
-
* List every `stories/story-<id>/signals.ndjson` path under the
|
|
149
|
-
* `<tempRoot>/
|
|
150
|
-
*
|
|
148
|
+
* List every `stories/story-<id>/signals.ndjson` path under the run's
|
|
149
|
+
* `<tempRoot>/run-<run>/` directory. Returns an empty array when the
|
|
150
|
+
* run directory is missing.
|
|
151
151
|
*
|
|
152
152
|
* The returned paths are sorted by Story ID ascending so the iterator's
|
|
153
153
|
* output is stable across runs.
|
|
154
154
|
*
|
|
155
155
|
* Story #2940 nested per-Story directories under a `stories/` segment.
|
|
156
|
-
*
|
|
156
|
+
* Run-level signals continue to live at the run root.
|
|
157
157
|
*
|
|
158
|
-
* @param {number}
|
|
158
|
+
* @param {number} run
|
|
159
159
|
* @param {object | undefined} config
|
|
160
160
|
* @returns {Promise<string[]>}
|
|
161
161
|
*/
|
|
162
|
-
async function
|
|
163
|
-
const
|
|
164
|
-
let
|
|
162
|
+
async function listRunStorySignalsFiles(run, config) {
|
|
163
|
+
const runDir = runTempDir(run, config);
|
|
164
|
+
let runEntries;
|
|
165
165
|
try {
|
|
166
|
-
|
|
166
|
+
runEntries = await fs.readdir(runDir, { withFileTypes: true });
|
|
167
167
|
} catch {
|
|
168
168
|
return [];
|
|
169
169
|
}
|
|
170
|
-
let
|
|
170
|
+
let hasRunLevelSignals = false;
|
|
171
171
|
let hasStoriesDir = false;
|
|
172
|
-
for (const ent of
|
|
172
|
+
for (const ent of runEntries) {
|
|
173
173
|
if (ent.isDirectory() && ent.name === 'stories') {
|
|
174
174
|
hasStoriesDir = true;
|
|
175
175
|
} else if (ent.isFile() && ent.name === 'signals.ndjson') {
|
|
176
176
|
// Story #1430 — wave-runner lifecycle signals land here.
|
|
177
|
-
|
|
177
|
+
hasRunLevelSignals = true;
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
const storyIds = [];
|
|
181
181
|
if (hasStoriesDir) {
|
|
182
182
|
let storyEntries;
|
|
183
183
|
try {
|
|
184
|
-
storyEntries = await fs.readdir(path.join(
|
|
184
|
+
storyEntries = await fs.readdir(path.join(runDir, 'stories'), {
|
|
185
185
|
withFileTypes: true,
|
|
186
186
|
});
|
|
187
187
|
} catch {
|
|
@@ -195,43 +195,43 @@ async function listEpicStorySignalsFiles(epic, config) {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
storyIds.sort((a, b) => a - b);
|
|
198
|
-
// Yield
|
|
198
|
+
// Yield run-level signals first (wave-start precedes per-Story friction),
|
|
199
199
|
// then walk the per-Story streams in ascending ID order.
|
|
200
|
-
const targets =
|
|
201
|
-
? [
|
|
200
|
+
const targets = hasRunLevelSignals
|
|
201
|
+
? [runArtifactPath(run, 'signals.ndjson', config)]
|
|
202
202
|
: [];
|
|
203
203
|
for (const sid of storyIds) {
|
|
204
|
-
targets.push(path.join(storyTempDir(
|
|
204
|
+
targets.push(path.join(storyTempDir(run, sid, config), 'signals.ndjson'));
|
|
205
205
|
}
|
|
206
206
|
return targets;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
210
|
-
* Stream every event matching `{
|
|
211
|
-
* configured `tempRoot`'s `
|
|
210
|
+
* Stream every event matching `{ run, story?, kind? }` from the
|
|
211
|
+
* configured `tempRoot`'s `run-<run>/[story-<story>/]signals.ndjson`
|
|
212
212
|
* file(s).
|
|
213
213
|
*
|
|
214
214
|
* Returns an async iterable so callers can `for await` over it without
|
|
215
215
|
* buffering. The reader is **streaming** — peak memory stays below the
|
|
216
216
|
* file size for any input.
|
|
217
217
|
*
|
|
218
|
-
* @param {{
|
|
218
|
+
* @param {{ run: number, story?: number, kind?: string, config?: object }} args
|
|
219
219
|
* @returns {AsyncGenerator<object>}
|
|
220
220
|
*
|
|
221
221
|
* @example
|
|
222
|
-
* for await (const evt of read({
|
|
223
|
-
* for await (const evt of read({
|
|
222
|
+
* for await (const evt of read({ run: 1181 })) { ... }
|
|
223
|
+
* for await (const evt of read({ run: 1181, story: 1438, kind: 'friction' })) { ... }
|
|
224
224
|
*/
|
|
225
225
|
export async function* read(args) {
|
|
226
226
|
if (args == null || typeof args !== 'object') {
|
|
227
227
|
throw new TypeError(
|
|
228
|
-
`signals/read: args must be an object with at minimum {
|
|
228
|
+
`signals/read: args must be an object with at minimum { run }; got ${args}`,
|
|
229
229
|
);
|
|
230
230
|
}
|
|
231
|
-
const {
|
|
232
|
-
if (!isPositiveInt(
|
|
231
|
+
const { run, story, kind, config } = args;
|
|
232
|
+
if (!isPositiveInt(run)) {
|
|
233
233
|
throw new RangeError(
|
|
234
|
-
`signals/read:
|
|
234
|
+
`signals/read: run must be a positive integer (got ${run})`,
|
|
235
235
|
);
|
|
236
236
|
}
|
|
237
237
|
if (story !== undefined && !isPositiveInt(story)) {
|
|
@@ -259,8 +259,8 @@ export async function* read(args) {
|
|
|
259
259
|
const kindFilter = kind ?? null;
|
|
260
260
|
const targets =
|
|
261
261
|
story !== undefined
|
|
262
|
-
? [signalsFile(
|
|
263
|
-
: await
|
|
262
|
+
? [signalsFile(run, story, config)]
|
|
263
|
+
: await listRunStorySignalsFiles(run, config);
|
|
264
264
|
|
|
265
265
|
for (const target of targets) {
|
|
266
266
|
yield* streamFile(target, kindFilter);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* shape guards (Epic #1181 / Story #1438 / Task #1458).
|
|
4
4
|
*
|
|
5
5
|
* Both writers (`lib/observability/signals-writer.js` callers) and
|
|
6
|
-
* readers (`lib/signals/read.js`,
|
|
6
|
+
* readers (`lib/signals/read.js`, the retro's gather-signals phase)
|
|
7
7
|
* import their field names from this module so the on-disk NDJSON shape
|
|
8
8
|
* stays under one schema.
|
|
9
9
|
*
|
|
@@ -19,15 +19,12 @@
|
|
|
19
19
|
*
|
|
20
20
|
* Signals-writer `appendSignal` call sites:
|
|
21
21
|
* - `friction` — quality-gate / runtime friction (diagnose-friction.js,
|
|
22
|
-
* lib/gates/friction.js
|
|
23
|
-
* worktree-reap.js, lifecycle-emit.js)
|
|
22
|
+
* lib/gates/friction.js)
|
|
24
23
|
* - `acceptance-eval` — acceptance-eval.js per-criterion terminus signal.
|
|
25
|
-
* - `wave-start` / `wave-complete` — `
|
|
26
|
-
*
|
|
27
|
-
* `wave-start` also anchors span-tree Story spans)
|
|
24
|
+
* - `wave-start` / `wave-complete` — wave-window anchors; `wave-start` also
|
|
25
|
+
* anchors span-tree Story spans
|
|
28
26
|
* - `wave-end` — span-tree pairing anchor (retained for span-tree)
|
|
29
|
-
* - `state-transition` — notification-derived window anchor
|
|
30
|
-
* waveParallelism bucketer.
|
|
27
|
+
* - `state-transition` — notification-derived window anchor.
|
|
31
28
|
*
|
|
32
29
|
* The `dispatched` kind was deleted in the Epic #4406 signal-contract
|
|
33
30
|
* cutover — it had no live emitter and no consumer.
|
|
@@ -80,9 +77,9 @@ export const EVENT_KINDS = Object.freeze({
|
|
|
80
77
|
FRICTION: 'friction',
|
|
81
78
|
TRACE: 'trace',
|
|
82
79
|
// Wave-window forensics signals: `wave-start` / `wave-end` anchor the
|
|
83
|
-
// span-tree's Story spans
|
|
84
|
-
//
|
|
85
|
-
//
|
|
80
|
+
// span-tree's Story spans. Story #4545 deleted the `waveParallelism`
|
|
81
|
+
// consumer (perf-aggregator) with the execution-analysis surface; these
|
|
82
|
+
// kinds stay as the span-tree's anchors.
|
|
86
83
|
WAVE_START: 'wave-start',
|
|
87
84
|
WAVE_END: 'wave-end',
|
|
88
85
|
WAVE_COMPLETE: 'wave-complete',
|
|
@@ -192,15 +192,15 @@ function bootstrapStoryWindow(storyNode, ts) {
|
|
|
192
192
|
* from `buildSpanTree` so the outer function's CRAP score stays under
|
|
193
193
|
* the new-method ceiling.
|
|
194
194
|
*
|
|
195
|
-
* @param {object} state — mutable accumulator (stories, tasksByStory,
|
|
195
|
+
* @param {object} state — mutable accumulator (stories, tasksByStory, run)
|
|
196
196
|
* @param {unknown} evt
|
|
197
197
|
* @returns {void}
|
|
198
198
|
*/
|
|
199
199
|
function ingestEvent(state, evt) {
|
|
200
200
|
if (evt == null || typeof evt !== 'object') return;
|
|
201
201
|
|
|
202
|
-
const
|
|
203
|
-
if (state.
|
|
202
|
+
const eRun = epicOf(evt);
|
|
203
|
+
if (state.run == null && eRun != null) state.run = eRun;
|
|
204
204
|
|
|
205
205
|
const ts = tsOf(evt);
|
|
206
206
|
const sid = storyOf(evt);
|
|
@@ -258,11 +258,11 @@ function finalizeStory(state, story) {
|
|
|
258
258
|
* Build the span tree from an async iterable of signal events.
|
|
259
259
|
*
|
|
260
260
|
* @param {AsyncIterable<object> | Iterable<object>} iter
|
|
261
|
-
* @returns {Promise<{
|
|
261
|
+
* @returns {Promise<{ run: number | null, stories: Array<object> }>}
|
|
262
262
|
*
|
|
263
263
|
* @example
|
|
264
264
|
* import { read, buildSpanTree } from './lib/signals/index.js';
|
|
265
|
-
* const tree = await buildSpanTree(read({
|
|
265
|
+
* const tree = await buildSpanTree(read({ run: 1181 }));
|
|
266
266
|
*/
|
|
267
267
|
export async function buildSpanTree(iter) {
|
|
268
268
|
if (iter == null || typeof iter !== 'object') {
|
|
@@ -274,7 +274,7 @@ export async function buildSpanTree(iter) {
|
|
|
274
274
|
// Accumulator state. `stories` keys are `storyKeyOf(sid)` strings;
|
|
275
275
|
// `tasksByStory` mirrors that and holds per-task sub-maps.
|
|
276
276
|
const state = {
|
|
277
|
-
|
|
277
|
+
run: null,
|
|
278
278
|
stories: new Map(),
|
|
279
279
|
tasksByStory: new Map(),
|
|
280
280
|
};
|
|
@@ -287,5 +287,5 @@ export async function buildSpanTree(iter) {
|
|
|
287
287
|
storyEntries.sort(compareNodeIds);
|
|
288
288
|
for (const story of storyEntries) finalizeStory(state, story);
|
|
289
289
|
|
|
290
|
-
return {
|
|
290
|
+
return { run: state.run, stories: storyEntries };
|
|
291
291
|
}
|
|
@@ -41,7 +41,13 @@ export async function flipLabelAndNotify({
|
|
|
41
41
|
config,
|
|
42
42
|
progress,
|
|
43
43
|
}) {
|
|
44
|
-
const labelFlipped = await flipLabel(
|
|
44
|
+
const labelFlipped = await flipLabel(
|
|
45
|
+
provider,
|
|
46
|
+
storyId,
|
|
47
|
+
story,
|
|
48
|
+
progress,
|
|
49
|
+
config,
|
|
50
|
+
);
|
|
45
51
|
if (!labelFlipped) return;
|
|
46
52
|
await fireStoryClosingNotify({
|
|
47
53
|
notifyFn: notifyFn ?? defaultNotify,
|
|
@@ -55,7 +61,7 @@ export async function flipLabelAndNotify({
|
|
|
55
61
|
});
|
|
56
62
|
}
|
|
57
63
|
|
|
58
|
-
async function flipLabel(provider, storyId, story, progress) {
|
|
64
|
+
async function flipLabel(provider, storyId, story, progress, config) {
|
|
59
65
|
try {
|
|
60
66
|
// Story #3385 — flip to `agent::closing`, NOT `agent::done`. The
|
|
61
67
|
// canonical mutator (`transitionTicketState`) only closes the GitHub
|
|
@@ -81,8 +87,13 @@ async function flipLabel(provider, storyId, story, progress) {
|
|
|
81
87
|
// notification that `transitionTicketState` would dispatch is
|
|
82
88
|
// redundant with the typed `story-closing` event that
|
|
83
89
|
// `fireStoryClosingNotify` emits immediately afterwards.
|
|
90
|
+
//
|
|
91
|
+
// `config` is threaded so the on-disk board-metadata cache (issue #4555)
|
|
92
|
+
// lands under the project's configured `tempRoot` rather than the
|
|
93
|
+
// framework default, matching every other transition call site.
|
|
84
94
|
await transitionTicketState(provider, storyId, STATE_LABELS.CLOSING, {
|
|
85
95
|
ticketSnapshot: story,
|
|
96
|
+
config,
|
|
86
97
|
});
|
|
87
98
|
progress?.('LABELS', `🏷️ Story #${storyId} → agent::closing`);
|
|
88
99
|
return true;
|
|
@@ -30,6 +30,8 @@ const FRONTMATTER_DELIMITER = '---';
|
|
|
30
30
|
const POLICY_HEADING_RE = /^## Policy Capsule\s*$/;
|
|
31
31
|
const ANY_H2_RE = /^## /;
|
|
32
32
|
const BULLET_RE = /^- /;
|
|
33
|
+
/** An indented (wrapped) continuation of the bullet above it. */
|
|
34
|
+
const CONTINUATION_RE = /^\s+\S/;
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* Repo root resolver. Walks up from the SKILL.md path until we find a
|
|
@@ -85,8 +87,14 @@ function extractFrontmatterBlock(lines, skillPath) {
|
|
|
85
87
|
/**
|
|
86
88
|
* Scan the body for the '## Policy Capsule' heading and count contiguous
|
|
87
89
|
* top-level '- ' bullets that follow it, stopping at the next '## ' heading
|
|
88
|
-
* or end-of-file. Blank lines inside the bullet run do not reset the count
|
|
89
|
-
*
|
|
90
|
+
* or end-of-file. Blank lines inside the bullet run do not reset the count.
|
|
91
|
+
*
|
|
92
|
+
* An **indented** continuation line belongs to the bullet above it — capsule
|
|
93
|
+
* bullets routinely wrap at the document's prose width — so it neither counts
|
|
94
|
+
* as a new bullet nor terminates the run. Only a **flush-left**, non-blank,
|
|
95
|
+
* non-bullet line after the run terminates it (Story #4546: treating any
|
|
96
|
+
* non-bullet line as a terminator counted a wrapped 5-bullet capsule as 1 and
|
|
97
|
+
* tripped the floor in validate-skills.js).
|
|
90
98
|
*/
|
|
91
99
|
function findPolicyCapsule(lines, bodyStart) {
|
|
92
100
|
let headingIndex = -1;
|
|
@@ -114,8 +122,13 @@ function findPolicyCapsule(lines, bodyStart) {
|
|
|
114
122
|
// Blank lines inside or before the bullet run are tolerated.
|
|
115
123
|
continue;
|
|
116
124
|
}
|
|
125
|
+
if (sawBulletRun && CONTINUATION_RE.test(line)) {
|
|
126
|
+
// Indented continuation of the bullet above — same bullet, not a
|
|
127
|
+
// terminator. Wrapped capsule bullets are the norm, not an error.
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
117
130
|
if (sawBulletRun) {
|
|
118
|
-
//
|
|
131
|
+
// Flush-left, non-blank, non-bullet line after the run terminates it.
|
|
119
132
|
break;
|
|
120
133
|
}
|
|
121
134
|
// Leading prose between heading and the first bullet is allowed.
|
|
@@ -42,16 +42,17 @@ import { parseBlockedBy } from './dependency-parser.js';
|
|
|
42
42
|
* Story records (live ticket payloads, fixture tickets, or operator
|
|
43
43
|
* DAG nodes).
|
|
44
44
|
* @param {object} [opts]
|
|
45
|
-
* @param {boolean} [opts.dropForeign=
|
|
46
|
-
* matching
|
|
45
|
+
* @param {boolean} [opts.dropForeign=false] When `false` (the v2 default,
|
|
46
|
+
* matching the `/deliver` path — `stories-wave-tick.js` and the
|
|
47
|
+
* `selectReadySet` core), the operator-DAG contract is preserved: a
|
|
48
|
+
* dependency on an id absent from the input is treated as not-yet-done
|
|
49
|
+
* and withholds the dependent until it completes. When `true` (the
|
|
50
|
+
* pre-v2 Epic-scoped-wrapper semantics), edges pointing at ids outside
|
|
47
51
|
* the supplied story set are dropped so the DAG stays closed over the
|
|
48
|
-
* scheduled set.
|
|
49
|
-
* `selectReadySet` core) passes `false` to preserve the operator-DAG
|
|
50
|
-
* contract, where a dependency on an id absent from the input is treated
|
|
51
|
-
* as not-yet-done and withholds the dependent until it completes.
|
|
52
|
+
* scheduled set.
|
|
52
53
|
* @returns {Map<number, number[]>}
|
|
53
54
|
*/
|
|
54
|
-
export function buildStoryAdjacency(stories, { dropForeign =
|
|
55
|
+
export function buildStoryAdjacency(stories, { dropForeign = false } = {}) {
|
|
55
56
|
const records = Array.isArray(stories) ? stories : [];
|
|
56
57
|
const storyIds = new Set(records.map((s) => Number(s?.id ?? s?.number)));
|
|
57
58
|
const adjacency = new Map();
|
|
@@ -105,10 +105,9 @@ import { FILE_ASSUMPTION_VALUES } from '../orchestration/file-assumption-enum.js
|
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* @typedef {object} SerializeOptions
|
|
108
|
-
* @property {boolean} [includeFooter=false] - Include `---\nparent/
|
|
108
|
+
* @property {boolean} [includeFooter=false] - Include `---\nparent/blocked-by` footer.
|
|
109
109
|
* @property {object} [footer] - Footer fields when `includeFooter` is true.
|
|
110
110
|
* @property {number} [footer.parent] - Parent feature issue number.
|
|
111
|
-
* @property {number} [footer.epic] - Epic issue number.
|
|
112
111
|
*/
|
|
113
112
|
|
|
114
113
|
// ---------------------------------------------------------------------------
|
|
@@ -967,8 +966,8 @@ function serializeAuthoredMarker(body) {
|
|
|
967
966
|
}
|
|
968
967
|
|
|
969
968
|
/**
|
|
970
|
-
* Build the optional `---` footer block (`parent` / `
|
|
971
|
-
*
|
|
969
|
+
* Build the optional `---` footer block (`parent` / `blocked by` lines).
|
|
970
|
+
* Returns the empty string when `opts.includeFooter` is falsy.
|
|
972
971
|
*
|
|
973
972
|
* @param {StoryBody} body
|
|
974
973
|
* @param {SerializeOptions} opts
|
|
@@ -978,7 +977,9 @@ function serializeFooter(body, opts) {
|
|
|
978
977
|
if (!opts.includeFooter) return '';
|
|
979
978
|
const footerLines = ['---'];
|
|
980
979
|
if (opts.footer?.parent) footerLines.push(`parent: #${opts.footer.parent}`);
|
|
981
|
-
|
|
980
|
+
// Story #4545 — no `Epic: #N` branch. `pr-base-guard.js` hard-refuses a
|
|
981
|
+
// Story body carrying that footer, so composing one here would let the
|
|
982
|
+
// framework generate work it would then reject at delivery.
|
|
982
983
|
if (Array.isArray(body.depends_on)) {
|
|
983
984
|
for (const dep of body.depends_on) {
|
|
984
985
|
footerLines.push(`blocked by ${dep}`);
|
|
@@ -82,7 +82,9 @@ Your job is to turn a plan seed / Tech Spec into a Story ticket array for an AI
|
|
|
82
82
|
- Thematic grouping is prose in the Story's folded \`## Spec\` / \`## Slicing\`, never sibling tickets for coupled work.
|
|
83
83
|
|
|
84
84
|
### LABEL CONVENTIONS:
|
|
85
|
-
-
|
|
85
|
+
- \`type::story\` is applied automatically by persist — you do not need to emit it, and no other type label is allowed (the retired Feature and Task tiers have no labels under this hierarchy).
|
|
86
|
+
- \`labels[]\` is **optional**. Emit it only to request an *additional* label; persist sanitizes the list before applying it.
|
|
87
|
+
- Do **not** emit \`agent::*\` labels — lifecycle state is runtime-owned, and persist applies \`agent::ready\` itself once every checkpoint is on the ticket.
|
|
86
88
|
- Do **not** emit \`persona::*\` labels — the behavioral persona concept (and its label axis) was removed in v2.
|
|
87
89
|
|
|
88
90
|
### OUTPUT FORMAT:
|
|
@@ -97,7 +99,7 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
|
|
|
97
99
|
"body": <string — see STORY BODY SCHEMA below>,
|
|
98
100
|
"acceptance": ["<testable, observable criterion>", ...],
|
|
99
101
|
"verify": ["<exact command or test path> (<tier>)", ...],
|
|
100
|
-
"labels": ["type::story
|
|
102
|
+
"labels": ["<extra-label>"] (optional — type::story is applied automatically; omit this field unless you need an additional label),
|
|
101
103
|
"depends_on": ["slug-of-blocking-dependency"] (optional array of Story slugs that block execution)
|
|
102
104
|
}
|
|
103
105
|
]
|
|
@@ -107,7 +109,9 @@ You MUST respond ONLY with a valid JSON array of objects. No prose, no markdown
|
|
|
107
109
|
### STORY BODY SCHEMA (REQUIRED FOR EVERY STORY):
|
|
108
110
|
\`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.
|
|
109
111
|
|
|
110
|
-
The \`acceptance[]\` and \`verify[]\` arrays live at the **top level** of the Story ticket object — that is the machine contract the validator reads.
|
|
112
|
+
The \`acceptance[]\` and \`verify[]\` arrays live at the **top level** of the Story ticket object — that is the machine contract the validator reads. Author each list **once, at top level**, and **omit** the \`## Acceptance\` / \`## Verify\` sections from the authored \`body\` string: persist syncs the top-level arrays into those sections so the GitHub issue stays a complete executable document. The validator resolves both fields from the top level, so an omitted section is the expected shape, not a violation.
|
|
113
|
+
|
|
114
|
+
If you do write those sections into the \`body\` string anyway, they must mirror the top-level arrays **item for item** — persist fails closed on a disagreement rather than guessing which list is authoritative. Do **not** invent a second criteria list inside \`## Spec\`, and do not author a separate Acceptance Spec / PRD artifact.
|
|
111
115
|
|
|
112
116
|
The serialized \`body\` string renders these markdown sections (in order):
|
|
113
117
|
|
|
@@ -17,12 +17,25 @@
|
|
|
17
17
|
* the NODE_ENV band-aid was removed in Story #3342. Tests that need to
|
|
18
18
|
* exercise the webhook POST inject `opts.fetchImpl` instead, so the
|
|
19
19
|
* request never reaches the real network even if a URL resolves.)
|
|
20
|
+
* - Every `GIT_*` variable is dropped. When the suite runs inside a git
|
|
21
|
+
* hook (husky pre-push via the coverage-capture path), the parent git
|
|
22
|
+
* invocation exports `GIT_DIR` — from a linked worktree, the absolute
|
|
23
|
+
* `<main>/.git/worktrees/<name>` path. A test fixture's `git init`
|
|
24
|
+
* under that env re-initializes the shared gitdir and writes
|
|
25
|
+
* `core.bare=true` into the MAIN checkout's `.git/config`, breaking
|
|
26
|
+
* every worktree at once (#4580). Production git call sites are
|
|
27
|
+
* covered by `cleanGitEnv` in `git-utils.js`; this is the same scrub
|
|
28
|
+
* for test child processes, which may spawn git directly. Tests that
|
|
29
|
+
* need a `GIT_*` variable set it explicitly on their own spawn.
|
|
20
30
|
*
|
|
21
31
|
* @param {NodeJS.ProcessEnv} baseEnv
|
|
22
32
|
* @returns {NodeJS.ProcessEnv}
|
|
23
33
|
*/
|
|
24
34
|
export function buildWebhookSafeTestEnv(baseEnv = process.env) {
|
|
25
|
-
const env =
|
|
35
|
+
const env = Object.fromEntries(
|
|
36
|
+
Object.entries(baseEnv).filter(([k]) => !k.startsWith('GIT_')),
|
|
37
|
+
);
|
|
38
|
+
env.NODE_ENV = baseEnv.NODE_ENV ?? 'test';
|
|
26
39
|
if (env.MANDREL_ALLOW_TEST_WEBHOOKS !== '1') {
|
|
27
40
|
delete env.NOTIFICATION_WEBHOOK_URL;
|
|
28
41
|
}
|
|
@@ -12,13 +12,10 @@ import picomatch from 'picomatch';
|
|
|
12
12
|
*/
|
|
13
13
|
export const INTEGRATION_INCLUDE = [
|
|
14
14
|
'tests/**/*.integration.test.js',
|
|
15
|
-
'tests/epic-execute/epic-execute-record-wave.test.js',
|
|
16
15
|
'tests/hook-chain-reflog-invariant.test.js',
|
|
17
|
-
'tests/push-epic-retry.test.js',
|
|
18
16
|
'tests/contract/check-baselines-regression.test.js',
|
|
19
17
|
'tests/contract/check-baselines-kernel-mismatch.test.js',
|
|
20
18
|
'tests/integration-prime-after-sweep.test.js',
|
|
21
|
-
'tests/concurrency-wiring.test.js',
|
|
22
19
|
'tests/scripts/git-cleanup.test.js',
|
|
23
20
|
'tests/lib/checks/runner-integration.test.js',
|
|
24
21
|
'tests/single-story-close-sync.test.js',
|
|
@@ -107,20 +107,6 @@ export function hasTicketSection(body, kind) {
|
|
|
107
107
|
return locate(body, kind) !== null;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/**
|
|
111
|
-
* Extract a managed region's content (between the markers, trimmed).
|
|
112
|
-
* Returns `null` when the region is absent.
|
|
113
|
-
*
|
|
114
|
-
* @param {string} body
|
|
115
|
-
* @param {'techSpec'|'acceptanceTable'} kind
|
|
116
|
-
* @returns {string|null}
|
|
117
|
-
*/
|
|
118
|
-
export function extractTicketSection(body, kind) {
|
|
119
|
-
const loc = locate(body, kind);
|
|
120
|
-
if (!loc) return null;
|
|
121
|
-
return body.slice(loc.contentStart, loc.contentEnd).trim();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
110
|
/**
|
|
125
111
|
* Insert or replace a managed region, preserving every byte outside it.
|
|
126
112
|
*
|