mandrel 2.30.0 → 2.32.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 +13 -17
- package/.agents/agents/acceptance-critic.md +1 -2
- package/.agents/docs/SDLC.md +4 -4
- package/.agents/docs/agentrc-reference.json +61 -57
- package/.agents/docs/configuration.md +274 -227
- package/.agents/docs/execution-reference.md +13 -14
- package/.agents/docs/quality-gates.md +195 -23
- package/.agents/instructions.md +2 -5
- package/.agents/rules/ci-remediation.md +44 -1
- package/.agents/rules/git-conventions-reference.md +27 -27
- package/.agents/rules/git-conventions.md +4 -2
- package/.agents/rules/known-tooling-behavior.md +66 -30
- package/.agents/rules/testing-standards.md +35 -71
- package/.agents/runtime-deps.json +0 -1
- package/.agents/schemas/agentrc.schema.json +1939 -1400
- package/.agents/schemas/lifecycle/README.md +21 -14
- package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
- package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
- package/.agents/scripts/README.md +7 -29
- package/.agents/scripts/apply-quality-bootstrap.js +27 -34
- package/.agents/scripts/bootstrap.js +28 -26
- package/.agents/scripts/check-baseline-drift.js +73 -13
- package/.agents/scripts/check-baseline-scope.js +362 -0
- package/.agents/scripts/check-dead-exports.js +9 -1
- package/.agents/scripts/check-gherkin-corpus.js +508 -0
- package/.agents/scripts/check-knip-entries.js +136 -0
- package/.agents/scripts/check-lifecycle-lint.js +36 -112
- package/.agents/scripts/check-schema-references.js +1 -1
- package/.agents/scripts/diagnose-friction.js +7 -4
- package/.agents/scripts/generate-config-docs.js +263 -171
- package/.agents/scripts/install-matrix-assert.js +0 -1
- package/.agents/scripts/lib/ITicketingProvider.js +0 -58
- package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
- package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +0 -1
- package/.agents/scripts/lib/baselines/envelope.js +41 -60
- package/.agents/scripts/lib/baselines/git-base.js +30 -37
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
- package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
- package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
- package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
- package/.agents/scripts/lib/bdd-step-index.js +326 -0
- package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
- package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
- package/.agents/scripts/lib/checks/loop-health.js +9 -37
- package/.agents/scripts/lib/child-exec.js +193 -0
- package/.agents/scripts/lib/cli/standard-args.js +1 -1
- package/.agents/scripts/lib/cli-args.js +64 -0
- package/.agents/scripts/lib/close-validation/gates.js +2 -2
- package/.agents/scripts/lib/close-validation/runner.js +3 -3
- package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
- package/.agents/scripts/lib/config/commands.js +3 -5
- package/.agents/scripts/lib/config/explain.js +5 -7
- package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
- package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
- package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
- package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
- package/.agents/scripts/lib/config/gates/index.js +5 -2
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
- package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
- package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
- package/.agents/scripts/lib/config/gates/shared.js +58 -9
- package/.agents/scripts/lib/config/github.js +0 -1
- package/.agents/scripts/lib/config/limits.js +3 -48
- package/.agents/scripts/lib/config/qa.js +105 -0
- package/.agents/scripts/lib/config/temp-paths.js +6 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +237 -56
- package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
- package/.agents/scripts/lib/config-settings-schema.js +386 -39
- package/.agents/scripts/lib/crap-baseline-join.js +126 -9
- package/.agents/scripts/lib/crap-utils.js +84 -520
- package/.agents/scripts/lib/dead-exports-knip.js +79 -10
- package/.agents/scripts/lib/degraded-mode.js +2 -2
- package/.agents/scripts/lib/doc-tiers.js +3 -3
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
- package/.agents/scripts/lib/fs-walk.js +52 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/git-utils.js +16 -36
- package/.agents/scripts/lib/knip-entry-sync.js +469 -0
- package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
- package/.agents/scripts/lib/observability/signal-validator.js +5 -85
- package/.agents/scripts/lib/observability/signals-writer.js +19 -62
- package/.agents/scripts/lib/observability/source-classifier.js +5 -7
- package/.agents/scripts/lib/observability/terse-result.js +3 -3
- package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
- package/.agents/scripts/lib/orchestration/code-review.js +2 -2
- package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
- package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
- package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +6 -0
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +0 -1
- package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
- package/.agents/scripts/lib/orchestration/resolve-stories.js +5 -15
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +17 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +65 -25
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
- package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
- package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
- package/.agents/scripts/lib/signals/detectors/common.js +1 -1
- package/.agents/scripts/lib/signals/index.js +8 -6
- package/.agents/scripts/lib/signals/schema.js +20 -25
- package/.agents/scripts/lib/signals/write.js +8 -8
- package/.agents/scripts/lib/story-body/story-body.js +12 -59
- package/.agents/scripts/lib/temp-retention.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
- package/.agents/scripts/lib/ticket-body-sections.js +4 -5
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
- package/.agents/scripts/lib/worktree-manager.js +2 -3
- package/.agents/scripts/lint-label-vocabulary.js +2 -24
- package/.agents/scripts/pr-watch-with-update.js +7 -5
- package/.agents/scripts/providers/github/cache.js +2 -2
- package/.agents/scripts/providers/github/comments.js +6 -28
- package/.agents/scripts/providers/github/compose.js +0 -15
- package/.agents/scripts/providers/github/errors.js +10 -27
- package/.agents/scripts/providers/github/request-helpers.js +1 -2
- package/.agents/scripts/providers/github/sub-issues.js +10 -218
- package/.agents/scripts/providers/github.js +4 -7
- package/.agents/scripts/prune-baseline-orphans.js +181 -0
- package/.agents/scripts/resolve-stories.js +0 -2
- package/.agents/scripts/run-lint.js +61 -61
- package/.agents/scripts/run-test-profile.js +6 -6
- package/.agents/scripts/run-verify.js +48 -30
- package/.agents/scripts/single-story-close.js +20 -0
- package/.agents/scripts/single-story-init.js +12 -35
- package/.agents/scripts/update-dead-exports-baseline.js +321 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
- package/.agents/skills/skills.index.json +2 -12
- package/.agents/skills/stack/qa/playwright/SKILL.md +48 -0
- package/.agents/workflows/audit-documentation.md +5 -6
- package/.agents/workflows/audit-to-stories.md +2 -2
- package/.agents/workflows/helpers/audit-lens-core.md +11 -12
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
- package/.agents/workflows/helpers/code-review.md +3 -8
- package/.agents/workflows/helpers/deliver-reference.md +2 -1
- package/.agents/workflows/helpers/deliver-story-reference.md +27 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
- package/.agents/workflows/mandrel-update.md +10 -10
- package/.agents/workflows/qa-assist.md +15 -20
- package/.agents/workflows/qa-explore.md +9 -8
- package/README.md +1 -1
- package/docs/CHANGELOG.md +49 -0
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
- package/package.json +12 -3
- package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
- package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
- package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
- package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
- package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
- package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
- package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
- package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
- package/.agents/scripts/check-gherkin-placeholders.js +0 -663
- package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
- package/.agents/scripts/lib/audit-suite/cli.js +0 -64
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
- package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
- package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
- package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
- package/.agents/scripts/lib/crap-baseline-index.js +0 -46
- package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
- package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
- package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
- package/.agents/scripts/lib/mutation/config-detector.js +0 -119
- package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
- package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
- package/.agents/scripts/lib/observability/active-story-env.js +0 -170
- package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
- package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
- package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
- package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
- package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
- package/.agents/scripts/lib/planning-corpus.js +0 -37
- package/.agents/scripts/lib/qa/coverage-report.js +0 -181
- package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
- package/.agents/scripts/lib/signals/detectors/index.js +0 -14
- package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
- package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
- package/.agents/scripts/lib/signals/read.js +0 -268
- package/.agents/scripts/lib/signals/span-tree.js +0 -291
- package/.agents/scripts/lib/story-lifecycle.js +0 -194
- package/.agents/scripts/lib/story-plan.js +0 -379
- package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
- package/.agents/scripts/lib/util/phase-timer.js +0 -163
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
- package/.agents/scripts/lint-baseline.js +0 -507
- package/.agents/scripts/providers/github/prs.js +0 -103
- package/.agents/scripts/signals-view.js +0 -309
- package/.agents/scripts/story-plan.js +0 -370
- package/.agents/scripts/sync-branch-from-base.js +0 -149
- package/.agents/scripts/validate-docs-freshness.js +0 -314
- package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
- package/.agents/workflows/helpers/signals.md +0 -112
|
@@ -29,18 +29,17 @@
|
|
|
29
29
|
* against {@link STORY_SHAPE_CEILINGS}. A `lite` claim whose work exceeds
|
|
30
30
|
* them **fails closed to `full`** (`run-plan-persist.js`). Artifact
|
|
31
31
|
* cardinality is deliberately not an axis (Story #4764).
|
|
32
|
-
* 4. **Deliver
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* unchanged.
|
|
32
|
+
* 4. **Deliver dispatches on topology alone.** The dispatch *mode*
|
|
33
|
+
* ({@link resolveStoryDispatchMode}) answers a different question from
|
|
34
|
+
* the route: may the engine run in the router's own session? Only a
|
|
35
|
+
* **single-Story run** may (Story #4736) — sub-agent isolation buys
|
|
36
|
+
* nothing when there is no concurrent sibling to isolate from. Shape
|
|
37
|
+
* cannot grant that session (Story #4829): a lite body makes work cheap,
|
|
38
|
+
* it does not conjure a second session for a sibling to run in. Story
|
|
39
|
+
* #5006 removed the shape derivation that survived there for reporting,
|
|
40
|
+
* since no consumer read it. The `route::lite` label is a
|
|
41
|
+
* **human-visible hint only**, never the control signal. Either way every
|
|
42
|
+
* `single-story-close.js` gate runs unchanged.
|
|
44
43
|
*
|
|
45
44
|
* The shape taxonomy is deliberately the one `review-depth.js` already
|
|
46
45
|
* applies to the landed diff at close (`deriveChangeLevel` over the
|
|
@@ -77,10 +76,7 @@
|
|
|
77
76
|
|
|
78
77
|
import { existsSync } from 'node:fs';
|
|
79
78
|
import path from 'node:path';
|
|
80
|
-
import {
|
|
81
|
-
extractChangePaths,
|
|
82
|
-
parse as parseStoryBody,
|
|
83
|
-
} from '../story-body/story-body.js';
|
|
79
|
+
import { extractChangePaths } from '../story-body/story-body.js';
|
|
84
80
|
import { deriveChangeLevel } from './review-depth.js';
|
|
85
81
|
|
|
86
82
|
/**
|
|
@@ -97,11 +93,10 @@ const DEFAULT_COMPLEXITY_GATE = Object.freeze({
|
|
|
97
93
|
* The persisted route marker for a lite-routed Story.
|
|
98
94
|
*
|
|
99
95
|
* **A human-visible hint only (Story #4722)** — never the control signal.
|
|
100
|
-
* Persist
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* label absent (or its write failed) still executes inline.
|
|
96
|
+
* Persist applies it so a lite cohort is filterable in the GitHub UI, and
|
|
97
|
+
* `deliver-light` reads the Story's own shape ({@link deriveStoryShape}) when
|
|
98
|
+
* it needs one. Nothing routes on the label: a lost label or an unread marker
|
|
99
|
+
* cannot misroute delivery.
|
|
105
100
|
*/
|
|
106
101
|
export const LITE_ROUTE_LABEL = 'route::lite';
|
|
107
102
|
|
|
@@ -279,8 +274,8 @@ function spansMigrationAndConsumers(paths) {
|
|
|
279
274
|
* against ground truth by the diff backstop.
|
|
280
275
|
* - **Absolute rules** — `migration-span`, `sensitive-path`. Risk, not size.
|
|
281
276
|
* - **Unknown-footprint rejections** — `no-changes`, `unreadable-changes`,
|
|
282
|
-
* `glob-footprint`, `no-acceptance`, `classification-unavailable
|
|
283
|
-
*
|
|
277
|
+
* `glob-footprint`, `no-acceptance`, `classification-unavailable`.
|
|
278
|
+
* Nothing was judged, so there is nothing to waive.
|
|
284
279
|
*
|
|
285
280
|
* A `lite` route carries `code: null`.
|
|
286
281
|
*/
|
|
@@ -296,7 +291,6 @@ export const SHAPE_CODES = Object.freeze({
|
|
|
296
291
|
GLOB_FOOTPRINT: 'glob-footprint',
|
|
297
292
|
NO_ACCEPTANCE: 'no-acceptance',
|
|
298
293
|
CLASSIFICATION_UNAVAILABLE: 'classification-unavailable',
|
|
299
|
-
UNPARSEABLE_BODY: 'unparseable-body',
|
|
300
294
|
});
|
|
301
295
|
|
|
302
296
|
/**
|
|
@@ -409,9 +403,9 @@ function normalizeCeiling(value, fallback) {
|
|
|
409
403
|
*
|
|
410
404
|
* Exported for persist (`run-plan-persist.js#resolveEffectiveRoute`), which
|
|
411
405
|
* consults `enabled` to refuse a planner lite claim when the gate is off —
|
|
412
|
-
* the schema's documented contract
|
|
413
|
-
* {@link resolveStoryDispatchMode},
|
|
414
|
-
*
|
|
406
|
+
* the schema's documented contract. It is the only read point: Story #5006
|
|
407
|
+
* removed the second one in {@link resolveStoryDispatchMode}, where the switch
|
|
408
|
+
* gated a shape derivation whose result no consumer read.
|
|
415
409
|
*
|
|
416
410
|
* @param {object | null | undefined} config
|
|
417
411
|
* @returns {{ enabled: boolean, maxArtifacts: number }}
|
|
@@ -810,60 +804,7 @@ export function deriveStoryShape({
|
|
|
810
804
|
}
|
|
811
805
|
|
|
812
806
|
/**
|
|
813
|
-
*
|
|
814
|
-
* the deliver-side entry to {@link deriveStoryShape} (`/deliver` already
|
|
815
|
-
* fetches the body; the route is computed from it, never from a label). An
|
|
816
|
-
* unparseable body degrades to `full`: unknown shape is not trivial shape.
|
|
817
|
-
*
|
|
818
|
-
* Module-private, reachable end to end through
|
|
819
|
-
* {@link resolveStoryDispatchMode} (which returns the derived route) — so
|
|
820
|
-
* there is no test-only export to leave production-dead.
|
|
821
|
-
*
|
|
822
|
-
* @param {string} body Serialized Story-body markdown.
|
|
823
|
-
* @param {{ injectedRules?: object, selectSensitivePathClassesFn?: Function }} [opts]
|
|
824
|
-
* @returns {ReturnType<typeof deriveStoryShape>}
|
|
825
|
-
*/
|
|
826
|
-
function deriveStoryRouteFromBody(body, opts = {}) {
|
|
827
|
-
let parsed;
|
|
828
|
-
try {
|
|
829
|
-
parsed = parseStoryBody(String(body ?? '')).body;
|
|
830
|
-
} catch (err) {
|
|
831
|
-
return {
|
|
832
|
-
route: 'full',
|
|
833
|
-
reasons: [
|
|
834
|
-
`Story body is unparseable (${err?.message ?? err}) — shape unknown; conservative full route`,
|
|
835
|
-
],
|
|
836
|
-
code: SHAPE_CODES.UNPARSEABLE_BODY,
|
|
837
|
-
shape: null,
|
|
838
|
-
ceilings: STORY_SHAPE_CEILINGS,
|
|
839
|
-
preserves: LITE_PATH_INVARIANTS,
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
return deriveStoryShape({
|
|
843
|
-
changes: parsed?.changes,
|
|
844
|
-
acceptance: parsed?.acceptance,
|
|
845
|
-
injectedRules: opts.injectedRules,
|
|
846
|
-
selectSensitivePathClassesFn: opts.selectSensitivePathClassesFn,
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
/**
|
|
851
|
-
* Best-effort route derivation for reporting, when the *mode* is already
|
|
852
|
-
* pinned by run topology and only `route` remains to be filled in. A body
|
|
853
|
-
* that will not parse yields `null` rather than throwing — the caller is not
|
|
854
|
-
* asking the shape to decide anything.
|
|
855
|
-
*
|
|
856
|
-
* @param {unknown} body
|
|
857
|
-
* @param {{ injectedRules?: object, selectSensitivePathClassesFn?: Function }} opts
|
|
858
|
-
* @returns {ReturnType<typeof deriveStoryShape>|null}
|
|
859
|
-
*/
|
|
860
|
-
function routeForReporting(body, opts) {
|
|
861
|
-
if (typeof body !== 'string' || body.trim() === '') return null;
|
|
862
|
-
return deriveStoryRouteFromBody(body, opts);
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
/**
|
|
866
|
-
* Decide how `/deliver` executes a Story.
|
|
807
|
+
* Decide how `/deliver` executes a Story: **run topology, and nothing else.**
|
|
867
808
|
*
|
|
868
809
|
* **`inline` names one indivisible resource: the router's own session.** Two
|
|
869
810
|
* Stories cannot both own it, so exactly one premise can grant it —
|
|
@@ -873,9 +814,7 @@ function routeForReporting(body, opts) {
|
|
|
873
814
|
* branch refs) and a one-Story run has no sibling to race. It therefore pays
|
|
874
815
|
* the spawn premium (a boot is a cache WRITE at full rate, where an inline
|
|
875
816
|
* continuation is a cache read at ~10%; ~$1.43/M vs ~$1.07/M on comparable
|
|
876
|
-
* bench work) for nothing.
|
|
877
|
-
* the shape gate's `enabled` switch — which governs *shape derivation* — does
|
|
878
|
-
* not reach it.
|
|
817
|
+
* bench work) for nothing.
|
|
879
818
|
*
|
|
880
819
|
* **Shape cannot grant it (Story #4829).** The shape read used to return
|
|
881
820
|
* `inline` for any lite-shaped body in a multi-Story run, inheriting no
|
|
@@ -883,16 +822,15 @@ function routeForReporting(body, opts) {
|
|
|
883
822
|
* run came back `inline` for *every* Story while `stories-wave-tick.js`
|
|
884
823
|
* reported the whole set ready under a concurrency cap of five — a router
|
|
885
824
|
* following both signals literally runs several engines over one session and
|
|
886
|
-
* one checkout, the precise hazard the sub-agent path exists to prevent.
|
|
887
|
-
* runs were completed only by an operator overriding the verdict by hand, which
|
|
888
|
-
* is an invariant held by judgment rather than by code. So this function has
|
|
889
|
-
* exactly **one** `inline` exit, guarded by the topology premise; every path
|
|
890
|
-
* below it returns `subagent`, and the derived shape is carried on `route` for
|
|
891
|
-
* reporting only. A lite shape makes the work cheap — it does not conjure a
|
|
892
|
-
* second session for a sibling to run in.
|
|
825
|
+
* one checkout, the precise hazard the sub-agent path exists to prevent.
|
|
893
826
|
*
|
|
894
|
-
*
|
|
895
|
-
*
|
|
827
|
+
* **So this function reads only `storyCount` (Story #5006).** #4829 left the
|
|
828
|
+
* body parse, the shape derivation, the `route::lite` hint note and the
|
|
829
|
+
* `planning.complexityGate.enabled` branch in place to populate a `route`
|
|
830
|
+
* field for reporting — but the sole consumer, `resolve-stories.js`, reads
|
|
831
|
+
* `.mode` and discards the rest, so every one of those inputs was a parse
|
|
832
|
+
* whose result nothing could act on. A caller that wants the shape calls
|
|
833
|
+
* {@link deriveStoryShape} directly, as the light path and plan-persist do.
|
|
896
834
|
*
|
|
897
835
|
* Inline execution removes model-side fan-out only — it changes **where** the
|
|
898
836
|
* engine runs, never **what** runs. Every deterministic
|
|
@@ -900,35 +838,13 @@ function routeForReporting(body, opts) {
|
|
|
900
838
|
* `story-deliver-terminal` envelope are identical in both modes; see the
|
|
901
839
|
* module header's non-negotiables.
|
|
902
840
|
*
|
|
903
|
-
* @param {{
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
* injectedRules?: object,
|
|
909
|
-
* selectSensitivePathClassesFn?: Function,
|
|
910
|
-
* }} [args] `storyCount` is the number of Stories the invoking `/deliver` run
|
|
911
|
-
* resolved. Omitted (or not a positive integer) means "unknown run size",
|
|
912
|
-
* which cannot be shown sibling-free and therefore dispatches as a sub-agent
|
|
913
|
-
* — never an assumed 1.
|
|
914
|
-
* @returns {{ mode: 'inline'|'subagent', reasons: string[], route: ReturnType<typeof deriveStoryShape>|null }}
|
|
841
|
+
* @param {{ storyCount?: unknown }} [args] `storyCount` is the number of
|
|
842
|
+
* Stories the invoking `/deliver` run resolved. Omitted (or not exactly 1)
|
|
843
|
+
* means the run cannot be shown sibling-free and therefore dispatches as a
|
|
844
|
+
* sub-agent — never an assumed 1.
|
|
845
|
+
* @returns {{ mode: 'inline'|'subagent', reasons: string[] }}
|
|
915
846
|
*/
|
|
916
|
-
export function resolveStoryDispatchMode({
|
|
917
|
-
body,
|
|
918
|
-
labels,
|
|
919
|
-
config,
|
|
920
|
-
storyCount,
|
|
921
|
-
injectedRules,
|
|
922
|
-
selectSensitivePathClassesFn,
|
|
923
|
-
} = {}) {
|
|
924
|
-
const labelList = Array.isArray(labels)
|
|
925
|
-
? labels.filter((l) => typeof l === 'string')
|
|
926
|
-
: [];
|
|
927
|
-
const hasHint = labelList.includes(LITE_ROUTE_LABEL);
|
|
928
|
-
const hintNote = hasHint
|
|
929
|
-
? `the ${LITE_ROUTE_LABEL} label is present (hint only — the derived shape is the control signal)`
|
|
930
|
-
: `the ${LITE_ROUTE_LABEL} label is absent (hint only — the derived shape is the control signal)`;
|
|
931
|
-
|
|
847
|
+
export function resolveStoryDispatchMode({ storyCount } = {}) {
|
|
932
848
|
// The ONLY `inline` exit in this function, and the guard is the whole
|
|
933
849
|
// contract: an inline verdict must mean the engine can actually run inline.
|
|
934
850
|
if (storyCount === 1) {
|
|
@@ -936,48 +852,14 @@ export function resolveStoryDispatchMode({
|
|
|
936
852
|
mode: 'inline',
|
|
937
853
|
reasons: [
|
|
938
854
|
'single-Story run — execute deliver-story inline; sub-agent isolation is load-bearing only for concurrent dispatch, and a one-Story run has no sibling to race (close gates, PR, and terminal envelope unchanged)',
|
|
939
|
-
hintNote,
|
|
940
|
-
],
|
|
941
|
-
route: routeForReporting(body, {
|
|
942
|
-
injectedRules,
|
|
943
|
-
selectSensitivePathClassesFn,
|
|
944
|
-
}),
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
const gate = resolveComplexityGate(config);
|
|
949
|
-
if (!gate.enabled) {
|
|
950
|
-
return {
|
|
951
|
-
mode: 'subagent',
|
|
952
|
-
reasons: [
|
|
953
|
-
'complexity routing disabled (planning.complexityGate.enabled=false) — standard sub-agent dispatch',
|
|
954
855
|
],
|
|
955
|
-
route: null,
|
|
956
856
|
};
|
|
957
857
|
}
|
|
958
858
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
],
|
|
966
|
-
route: null,
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
// Past the topology guard a sibling may be dispatched concurrently, so the
|
|
971
|
-
// router's session is not available to anyone. The shape is still derived and
|
|
972
|
-
// returned on `route` — ceremony and reporting read it — but it decides
|
|
973
|
-
// nothing here: both shapes dispatch as a sub-agent.
|
|
974
|
-
const route = deriveStoryRouteFromBody(body, {
|
|
975
|
-
injectedRules,
|
|
976
|
-
selectSensitivePathClassesFn,
|
|
977
|
-
});
|
|
978
|
-
const shapeNote =
|
|
979
|
-
route.route === 'lite'
|
|
980
|
-
? `lite-shaped Story in a multi-Story run — the shape is inline-eligible but the router's session is not: a concurrent sibling would have to share it, racing worktrees and branch refs; sub-agent dispatch (${route.reasons[0]})`
|
|
981
|
-
: `full-shaped Story — ${route.reasons[0]}`;
|
|
982
|
-
return { mode: 'subagent', reasons: [shapeNote, hintNote], route };
|
|
859
|
+
return {
|
|
860
|
+
mode: 'subagent',
|
|
861
|
+
reasons: [
|
|
862
|
+
"multi-Story (or unknown-size) run — a concurrent sibling would have to share the router's session, racing worktrees and branch refs; sub-agent dispatch",
|
|
863
|
+
],
|
|
864
|
+
};
|
|
983
865
|
}
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
*
|
|
19
19
|
* So the axis is **changed lines over implementation files**, and the companion
|
|
20
20
|
* classes the framework itself mandates are exempt from the count: obeying
|
|
21
|
-
* `rules/testing-standards.md` (test-first), the
|
|
22
|
-
* and the baseline ratchets must not inflate
|
|
23
|
-
* change. Re-counting those same 33 merges on implementation files alone moves
|
|
21
|
+
* `rules/testing-standards.md` (test-first), the documentation a change of
|
|
22
|
+
* consequence is expected to touch, and the baseline ratchets must not inflate
|
|
23
|
+
* the number that then rejects the change. Re-counting those same 33 merges on implementation files alone moves
|
|
24
24
|
* the four-file pass rate from 21% to 58%.
|
|
25
25
|
*
|
|
26
26
|
* ## Three contracts worth not rediscovering
|
|
@@ -88,7 +88,7 @@ const COMPANION_PATH_GLOBS = Object.freeze([
|
|
|
88
88
|
'**/*.test.tsx',
|
|
89
89
|
'tests/**',
|
|
90
90
|
'features/**',
|
|
91
|
-
// Documentation —
|
|
91
|
+
// Documentation — the prose a change of consequence is expected to refresh.
|
|
92
92
|
'docs/**',
|
|
93
93
|
'**/*.md',
|
|
94
94
|
// Generated baseline data — written by the ratchets, not hand-authored.
|
|
@@ -26,8 +26,9 @@ export function toExecuting(provider, ticketId, opts) {
|
|
|
26
26
|
/**
|
|
27
27
|
* Transition an array of tickets to `agent::done`, in order. Each call
|
|
28
28
|
* triggers its own cascade (via `transitionTicketState`). Failures for
|
|
29
|
-
* individual tickets propagate —
|
|
30
|
-
*
|
|
29
|
+
* individual tickets propagate — the loop aborts on the first error, so
|
|
30
|
+
* callers that need per-ticket tolerance must catch around each id
|
|
31
|
+
* themselves.
|
|
31
32
|
*
|
|
32
33
|
* @param {object} provider
|
|
33
34
|
* @param {number[]} ticketIds
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* historically also the retired Epic-tier deliver/plan guards —
|
|
7
7
|
* each carried their own copy of
|
|
8
8
|
* the operator-handle resolution and the fail-closed acquire wrapper around
|
|
9
|
-
* `ticket-lease.acquireLease` (
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* `ticket-lease.acquireLease` (refuse any foreign assignee, throwing an
|
|
10
|
+
* operator-facing message naming the current owner unless `--steal`). The
|
|
11
|
+
* three copies had
|
|
12
12
|
* already diverged — different `resolveOperator` signatures and different
|
|
13
13
|
* missing-handle behaviour (`null` vs `throw`) — and were synchronised only
|
|
14
14
|
* by docstring promise ("This mirrors the sibling lease guards…").
|
|
@@ -30,16 +30,15 @@
|
|
|
30
30
|
* handle must degrade to a `no-operator` no-op rather than throw.
|
|
31
31
|
* - **Refusal wording** — each surface renders its own operator-facing
|
|
32
32
|
* message via `renderRefusal(result, ticketId)`.
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* anchoring.
|
|
33
|
+
*
|
|
34
|
+
* A third axis, **liveness anchoring**, is gone: Story #5006 deleted the
|
|
35
|
+
* lease TTL, so every foreign claim refuses unconditionally and there is no
|
|
36
|
+
* heartbeat to anchor.
|
|
38
37
|
*
|
|
39
38
|
* The unclaimed / already-held / foreign-claim decision table itself (and
|
|
40
39
|
* the steal transfer) lives in `ticket-lease.acquireLease`; this kernel owns
|
|
41
|
-
* the
|
|
42
|
-
*
|
|
40
|
+
* the refuse-by-throw boundary that the three guards previously each
|
|
41
|
+
* re-implemented.
|
|
43
42
|
*
|
|
44
43
|
* Per `.agents/rules/orchestration-error-handling.md`, failures surface via
|
|
45
44
|
* `throw new Error(...)`, never `Logger.fatal`.
|
|
@@ -85,27 +84,16 @@ export function resolveOperatorFromCandidates({
|
|
|
85
84
|
|
|
86
85
|
/**
|
|
87
86
|
* Acquire a ticket lease, failing closed by throwing the surface's refusal
|
|
88
|
-
* message when the claim is refused (
|
|
87
|
+
* message when the claim is refused (foreign owner, no `steal`).
|
|
89
88
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* same resolved clock value so `isClaimLive` returns true for ANY foreign
|
|
93
|
-
* owner — `acquireLease` then refuses a foreign assignee unless `steal` is
|
|
94
|
-
* set, while unclaimed and self-held tickets still proceed without a write.
|
|
95
|
-
* When unset (`/deliver`), the caller-supplied `heartbeatAt` / `now`
|
|
96
|
-
* pass through untouched.
|
|
89
|
+
* Unclaimed and self-held tickets proceed — the self-held case without a
|
|
90
|
+
* write. A foreign assignee always refuses unless `steal` is set.
|
|
97
91
|
*
|
|
98
92
|
* @param {object} opts
|
|
99
93
|
* @param {object} opts.provider Ticketing provider.
|
|
100
94
|
* @param {number} opts.ticketId Ticket to claim.
|
|
101
95
|
* @param {string} opts.operator Resolved operator handle.
|
|
102
|
-
* @param {number|null} [opts.heartbeatAt=null] Current owner's last
|
|
103
|
-
* heartbeat (epoch ms). Ignored when `anchorHeartbeatToNow` is set.
|
|
104
96
|
* @param {boolean} [opts.steal=false] Forcibly transfer a foreign claim.
|
|
105
|
-
* @param {object} [opts.config] Resolved config (TTL default).
|
|
106
|
-
* @param {number} [opts.now] Injectable clock (epoch ms; tests).
|
|
107
|
-
* @param {boolean} [opts.anchorHeartbeatToNow=false] Fail-closed liveness
|
|
108
|
-
* anchoring for surfaces with no heartbeat source.
|
|
109
97
|
* @param {(result: object, ticketId: number) => string} opts.renderRefusal
|
|
110
98
|
* Renders the operator-facing refusal message for a refused claim.
|
|
111
99
|
* @returns {Promise<{ acquired: boolean, owner: string, previousOwner: string|null, reason: string }>}
|
|
@@ -115,28 +103,14 @@ export async function acquireLeaseFailClosed({
|
|
|
115
103
|
provider,
|
|
116
104
|
ticketId,
|
|
117
105
|
operator,
|
|
118
|
-
heartbeatAt = null,
|
|
119
106
|
steal = false,
|
|
120
|
-
config,
|
|
121
|
-
now,
|
|
122
|
-
anchorHeartbeatToNow = false,
|
|
123
107
|
renderRefusal,
|
|
124
108
|
}) {
|
|
125
|
-
let resolvedHeartbeatAt = heartbeatAt;
|
|
126
|
-
let resolvedNow = now;
|
|
127
|
-
if (anchorHeartbeatToNow) {
|
|
128
|
-
resolvedNow =
|
|
129
|
-
typeof now === 'number' && Number.isFinite(now) ? now : Date.now();
|
|
130
|
-
resolvedHeartbeatAt = resolvedNow;
|
|
131
|
-
}
|
|
132
109
|
const result = await acquireLease({
|
|
133
110
|
provider,
|
|
134
111
|
ticketId,
|
|
135
112
|
operator,
|
|
136
|
-
heartbeatAt: resolvedHeartbeatAt,
|
|
137
113
|
steal,
|
|
138
|
-
config,
|
|
139
|
-
now: resolvedNow,
|
|
140
114
|
});
|
|
141
115
|
if (!result.acquired) {
|
|
142
116
|
throw new Error(renderRefusal(result, ticketId));
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Programmatic helper that appends a single `merge.unlanded` NDJSON
|
|
5
5
|
* record to the lifecycle ledger whenever a headless delivery run
|
|
6
|
-
* finishes its work without a confirmed merge.
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* the call site simple and dependency-free.
|
|
6
|
+
* finishes its work without a confirmed merge. Direct schema validation via
|
|
7
|
+
* Ajv followed by a synchronous `appendFileSync`: it fires from the standalone
|
|
8
|
+
* `single-story-close` flow, and a bare append keeps the call site simple and
|
|
9
|
+
* dependency-free. This was the shape that outlived the lifecycle bus — Story
|
|
10
|
+
* #5024 retired the bus, leaving this path the only lifecycle-ledger writer.
|
|
12
11
|
*
|
|
13
12
|
* Ledger destination (Story #4426 AC4): `storyLedgerPath(null, ticketId)`
|
|
14
13
|
* — the standalone story-scope destination
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* the current 12-phase baseline is captured on disk. Each record is one
|
|
7
7
|
* newline-terminated JSON line appended to
|
|
8
8
|
* `temp/run-<id>/plan-metrics.json` (per-Epic plan CLIs) or
|
|
9
|
-
* `temp/standalone/plan-metrics.json` (
|
|
10
|
-
*
|
|
11
|
-
* ledger uses).
|
|
9
|
+
* `temp/standalone/plan-metrics.json` (Epic-less plan and healthcheck runs —
|
|
10
|
+
* same standalone routing the friction ledger uses).
|
|
12
11
|
*
|
|
13
12
|
* Record shape (v1):
|
|
14
13
|
*
|
|
@@ -20,6 +20,7 @@ import { gitSpawn } from '../../git-utils.js';
|
|
|
20
20
|
import { validateTaskBodies } from '../task-body-validator.js';
|
|
21
21
|
import { validateAndNormalizeTickets } from '../ticket-validator.js';
|
|
22
22
|
import { DEFAULT_REGISTRY_PATTERNS } from '../ticket-validator-conflicts.js';
|
|
23
|
+
import { normalizeVerifyTiers } from '../verify-tier-repair.js';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Extensions an import specifier may elide. Probed longest-path-first when
|
|
@@ -240,6 +241,11 @@ export function validateTickets(tickets, config, opts = {}) {
|
|
|
240
241
|
// process.cwd(), which is only the repo root by coincidence.
|
|
241
242
|
cwd: opts.cwd,
|
|
242
243
|
});
|
|
244
|
+
// Repair before judging (Story #5005): a `verify[]` entry whose tier the
|
|
245
|
+
// validator can already infer is auto-corrected rather than rejected, so a
|
|
246
|
+
// mechanically-fixable formality no longer costs a re-authoring round. An
|
|
247
|
+
// uninferable entry survives untouched and still hard-errors below.
|
|
248
|
+
normalizeVerifyTiers(validated);
|
|
243
249
|
validateTaskBodies(validated);
|
|
244
250
|
return validated;
|
|
245
251
|
}
|