mandrel 2.36.0 → 2.38.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 +16 -16
- package/.agents/agents/plan-critic.md +1 -1
- package/.agents/docs/SDLC.md +40 -40
- package/.agents/docs/configuration.md +41 -16
- package/.agents/docs/execution-reference.md +3 -3
- package/.agents/docs/quality-gates.md +2 -2
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +5 -5
- package/.agents/rules/changelog-style.md +3 -3
- package/.agents/rules/ci-remediation.md +1 -1
- package/.agents/rules/git-conventions-reference.md +4 -4
- package/.agents/rules/testing-standards.md +56 -0
- package/.agents/schemas/agentrc.schema.json +9 -9
- package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +1 -1
- package/.agents/scripts/apply-quality-bootstrap.js +1 -1
- package/.agents/scripts/audit-to-stories.js +2 -2
- package/.agents/scripts/boot-sweep.js +7 -1
- package/.agents/scripts/check-context-budget.js +195 -103
- package/.agents/scripts/check-cyclomatic.js +112 -42
- package/.agents/scripts/check-doc-links.js +32 -4
- package/.agents/scripts/check-generated-validator.js +202 -0
- package/.agents/scripts/check-lifecycle-lint.js +2 -68
- package/.agents/scripts/check-schema-references.js +2 -28
- package/.agents/scripts/check-test-temp-hygiene.js +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +1 -1
- package/.agents/scripts/deliver-light.js +10 -10
- package/.agents/scripts/deliver-recover.js +1 -1
- package/.agents/scripts/drain-pending-cleanup.js +19 -2
- package/.agents/scripts/evidence-gate.js +1 -1
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +1 -1
- package/.agents/scripts/lib/baselines/components.js +32 -2
- package/.agents/scripts/lib/baselines/env-overrides.js +1 -1
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-budget.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bdd-step-index.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +2 -2
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/bootstrap/install-ledger.js +1 -1
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/prompt.js +1 -1
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +2 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +1 -1
- package/.agents/scripts/lib/checks/loop-health.js +1 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +1 -1
- package/.agents/scripts/lib/cli-args.js +1 -3
- package/.agents/scripts/lib/close-validation/gates.js +1 -1
- package/.agents/scripts/lib/close-validation/process.js +1 -1
- package/.agents/scripts/lib/command-header.js +1 -1
- package/.agents/scripts/lib/config/delivery-routing.js +1 -1
- package/.agents/scripts/lib/config/explain.js +1 -1
- package/.agents/scripts/lib/config/runners.js +2 -2
- package/.agents/scripts/lib/config/runtime.js +1 -1
- package/.agents/scripts/lib/config/sync-agentrc.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-delivery.js +3 -3
- package/.agents/scripts/lib/config-settings-schema-quality.js +6 -6
- package/.agents/scripts/lib/config-settings-schema.js +49 -9
- package/.agents/scripts/lib/coverage-baseline.js +2 -2
- package/.agents/scripts/lib/cpu-pool.js +90 -10
- package/.agents/scripts/lib/crap-utils.js +6 -2
- package/.agents/scripts/lib/cyclomatic-ceiling.js +28 -6
- package/.agents/scripts/lib/cyclomatic-scope.js +144 -0
- package/.agents/scripts/lib/dependency-version.js +86 -0
- package/.agents/scripts/lib/duplicate-search.js +2 -2
- package/.agents/scripts/lib/errors/index.js +1 -1
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +2 -2
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +5 -5
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +2 -2
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +12 -12
- package/.agents/scripts/lib/findings/route-finding.js +2 -2
- package/.agents/scripts/lib/generated/agentrc-validator.js +16 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/install-cmd-parser.js +1 -1
- package/.agents/scripts/lib/knip-entry-sync.js +1 -57
- package/.agents/scripts/lib/label-constants.js +2 -2
- package/.agents/scripts/lib/label-taxonomy.js +1 -1
- package/.agents/scripts/lib/maintainability-utils.js +108 -10
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- package/.agents/scripts/lib/onboard/init-tail.js +4 -4
- package/.agents/scripts/lib/onboard/scaffold-docs.js +2 -2
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
- package/.agents/scripts/lib/orchestration/code-review.js +4 -4
- package/.agents/scripts/lib/orchestration/complexity-gate.js +5 -5
- package/.agents/scripts/lib/orchestration/deliver-recover.js +3 -3
- package/.agents/scripts/lib/orchestration/docs-digest.js +3 -3
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +2 -2
- package/.agents/scripts/lib/orchestration/light-backstop.js +1 -1
- package/.agents/scripts/lib/orchestration/light-escalation.js +6 -6
- package/.agents/scripts/lib/orchestration/light-suitability.js +19 -19
- package/.agents/scripts/lib/orchestration/plan-context.js +4 -4
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-metrics.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +3 -3
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +6 -6
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +86 -25
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +3 -3
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +6 -6
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +7 -7
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -1
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +3 -3
- package/.agents/scripts/lib/orchestration/pr-watch.js +1 -30
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +2 -2
- package/.agents/scripts/lib/orchestration/remote-verifier.js +2 -2
- package/.agents/scripts/lib/orchestration/resolve-stories.js +4 -4
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +3 -3
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/native.js +9 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +3 -3
- package/.agents/scripts/lib/orchestration/run-epilogue.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +5 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +52 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +3 -3
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +2 -5
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +14 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-lease.js +34 -9
- package/.agents/scripts/lib/orchestration/ticket-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +6 -4
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +3 -3
- package/.agents/scripts/lib/qa/qa-session.js +1 -1
- package/.agents/scripts/lib/runtime-deps/manifest.js +1 -7
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +3 -58
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +284 -25
- package/.agents/scripts/lib/skills/walk-skill-files.js +1 -1
- package/.agents/scripts/lib/source-text/strip-js-comments.js +115 -0
- package/.agents/scripts/lib/story-adjacency.js +2 -2
- package/.agents/scripts/lib/templates/decomposer-prompts.js +1 -1
- package/.agents/scripts/lib/test-isolate/runner.js +3 -3
- package/.agents/scripts/lib/test-runner-contract.js +14 -6
- package/.agents/scripts/lib/test-tiers.js +135 -18
- package/.agents/scripts/lib/ticket-body-sections.js +1 -1
- package/.agents/scripts/lib/transpile.js +16 -3
- package/.agents/scripts/lib/util/concurrent-map.js +1 -1
- package/.agents/scripts/lib/util/parse-id-list.js +1 -1
- package/.agents/scripts/lib/wave-runner/live-probe.js +4 -4
- package/.agents/scripts/lib/wave-runner/ready-set.js +1 -1
- package/.agents/scripts/lib/workflow-closure.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +170 -32
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +2 -5
- package/.agents/scripts/lint-issue-body.js +3 -3
- package/.agents/scripts/plan-context.js +4 -4
- package/.agents/scripts/plan-critics.js +2 -2
- package/.agents/scripts/plan-persist.js +2 -2
- package/.agents/scripts/plan-run-epilogue.js +2 -2
- package/.agents/scripts/pr-watch-with-update.js +305 -137
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/tickets.js +114 -21
- package/.agents/scripts/quality-preview.js +162 -70
- package/.agents/scripts/resolve-stories.js +3 -3
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/run-lint.js +1 -1
- package/.agents/scripts/run-test-profile.js +8 -5
- package/.agents/scripts/run-tests.js +79 -14
- package/.agents/scripts/single-story-close.js +2 -4
- package/.agents/scripts/single-story-init.js +10 -6
- package/.agents/scripts/stories-wave-tick.js +8 -8
- package/.agents/skills/core/idea-refinement/SKILL.md +5 -5
- package/.agents/skills/core/scope-triage/SKILL.md +3 -3
- package/.agents/skills/skills.index.json +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -1
- package/.agents/workflows/audit-data-model.md +1 -1
- package/.agents/workflows/audit-documentation.md +2 -2
- package/.agents/workflows/audit-to-stories.md +11 -11
- package/.agents/workflows/git-deliver.md +4 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-review.md +4 -4
- package/.agents/workflows/helpers/deliver-light.md +26 -26
- package/.agents/workflows/helpers/deliver-reference.md +15 -7
- package/.agents/workflows/helpers/deliver-story-reference.md +9 -4
- package/.agents/workflows/helpers/deliver-story.md +6 -7
- package/.agents/workflows/helpers/diagnose.md +2 -2
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/plan-reference.md +9 -9
- package/.agents/workflows/helpers/qa-core.md +8 -8
- package/.agents/workflows/helpers/worktree-lifecycle.md +6 -6
- package/.agents/workflows/{deliver.md → mandrel-deliver.md} +15 -19
- package/.agents/workflows/{plan.md → mandrel-plan.md} +9 -9
- package/.agents/workflows/memory-consolidate.md +4 -4
- package/.agents/workflows/prototype.md +3 -3
- package/.agents/workflows/qa-assist.md +12 -12
- package/.agents/workflows/qa-explore.md +6 -6
- package/.agents/workflows/qa-run.md +1 -1
- package/README.md +7 -7
- package/docs/CHANGELOG.md +43 -0
- package/lib/cli/doctor.js +1 -1
- package/lib/cli/init.js +1 -1
- package/lib/cli/migrate.js +100 -94
- package/lib/migrations/helpers/retire-agentrc-key.js +200 -0
- package/lib/migrations/index.js +32 -33
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +21 -80
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +15 -87
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +13 -71
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +1 -1
- package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +13 -101
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +13 -100
- package/package.json +7 -3
- package/.agents/scripts/lib/audit-suite/frontmatter-lint.js +0 -32
- package/.agents/scripts/lib/baselines/maintainability-baseline-save.js +0 -37
- package/.agents/scripts/lib/cli/parse-numeric.js +0 -60
- package/.agents/scripts/lib/close-validation/telemetry.js +0 -79
- package/.agents/scripts/lib/orchestration/label-transitions.js +0 -44
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +0 -147
- package/.agents/scripts/lib/orchestration/phase-runner.js +0 -88
- package/.agents/scripts/lib/orchestration/recut.js +0 -56
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
* 3 below does the real enforcement against ground truth.
|
|
30
30
|
* 2. **Over-scope stops, never silently proceeds ({@link
|
|
31
31
|
* resolveLightGateOutcome}).** An over-ceiling prompt does **not**
|
|
32
|
-
* hard-fail — it STOPS and asks the operator to escalate to `/plan` or
|
|
32
|
+
* hard-fail — it STOPS and asks the operator to escalate to `/mandrel-plan` or
|
|
33
33
|
* proceed light. Both answers are executable: `proceed-light` is recorded
|
|
34
34
|
* through {@link resolveOperatorOverride}, which waives a *size
|
|
35
35
|
* prediction* only, never a risk rule, and only with a human present.
|
|
36
|
-
* Under `--yes` (unattended) it fails closed to recommending `/plan`.
|
|
36
|
+
* Under `--yes` (unattended) it fails closed to recommending `/mandrel-plan`.
|
|
37
37
|
* 3. **Diff-derived backstop ({@link checkLightDiffBackstop}).** After
|
|
38
38
|
* implementation the **actual** change set is re-checked with
|
|
39
39
|
* {@link module:lib/orchestration/review-depth.deriveChangeLevel} plus the
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
* the diff is the real scope signal — and an over-ceiling diff is blocked
|
|
42
42
|
* rather than landed silently. Story #4856 moved this from a `maxFiles: 4`
|
|
43
43
|
* cardinality ceiling to changed lines over implementation files, and made
|
|
44
|
-
* a block **recycle** its receipt Story through `/plan` tickets mode
|
|
44
|
+
* a block **recycle** its receipt Story through `/mandrel-plan` tickets mode
|
|
45
45
|
* instead of orphaning it.
|
|
46
46
|
* 4. **Minimal receipt Story ({@link buildReceiptStoryTicket}).** A
|
|
47
47
|
* `type::story` ticket is authored inline so `refs #`, history, telemetry,
|
|
@@ -131,7 +131,7 @@ function deriveUnwaivableRisk(decision) {
|
|
|
131
131
|
`class(es) ${classes.join(', ')} — this is risk, not size, so no ` +
|
|
132
132
|
`re-slicing, shrinking, or operator override satisfies it and the ` +
|
|
133
133
|
`diff backstop would refuse the same footprint after the work is ` +
|
|
134
|
-
`finished; take this to /plan now`,
|
|
134
|
+
`finished; take this to /mandrel-plan now`,
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
if (shape?.migrationSpan === true) {
|
|
@@ -142,7 +142,7 @@ function deriveUnwaivableRisk(decision) {
|
|
|
142
142
|
reason:
|
|
143
143
|
`un-waivable: the predicted footprint pairs a migration with its ` +
|
|
144
144
|
`consumers — this is risk, not size, so no re-slicing or operator ` +
|
|
145
|
-
`override satisfies it; take this to /plan now`,
|
|
145
|
+
`override satisfies it; take this to /mandrel-plan now`,
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
return { present: false, code: null, classes: [], reason: null };
|
|
@@ -237,7 +237,7 @@ export function resolveLedgeredVerdict({ route, reason } = {}) {
|
|
|
237
237
|
route: 'full',
|
|
238
238
|
reason: recordedReason || null,
|
|
239
239
|
recorded: recordedReason !== '',
|
|
240
|
-
note: 'model verdict is not lite — standard /plan route',
|
|
240
|
+
note: 'model verdict is not lite — standard /mandrel-plan route',
|
|
241
241
|
};
|
|
242
242
|
}
|
|
243
243
|
if (recordedReason === '') {
|
|
@@ -261,7 +261,7 @@ export function resolveLedgeredVerdict({ route, reason } = {}) {
|
|
|
261
261
|
* light path. The deterministic effort/risk derivation and the ledgered model
|
|
262
262
|
* verdict must **both** agree on `lite`; anything else — clearly-epic work, a
|
|
263
263
|
* sensitive-path footprint, an unledgered verdict — resolves to `full` (the
|
|
264
|
-
* conservative default that routes the operator to `/plan`).
|
|
264
|
+
* conservative default that routes the operator to `/mandrel-plan`).
|
|
265
265
|
*
|
|
266
266
|
* The predicted axes are declared by the caller: `predictedKinds` (the distinct
|
|
267
267
|
* kinds of change; absent, each entry's `assumption` is its kind, so N
|
|
@@ -394,7 +394,7 @@ export function resolveOperatorOverride({
|
|
|
394
394
|
}
|
|
395
395
|
if (yes === true) {
|
|
396
396
|
return refuse(
|
|
397
|
-
'operator override refused — it is attended-only, and --yes means nobody is at the keyboard; over-scope still fails closed to /plan',
|
|
397
|
+
'operator override refused — it is attended-only, and --yes means nobody is at the keyboard; over-scope still fails closed to /mandrel-plan',
|
|
398
398
|
);
|
|
399
399
|
}
|
|
400
400
|
|
|
@@ -412,7 +412,7 @@ export function resolveOperatorOverride({
|
|
|
412
412
|
? ` (${unwaivable.classes.join(', ')})`
|
|
413
413
|
: ''
|
|
414
414
|
}; waiving the size prediction cannot make this land light, and the ` +
|
|
415
|
-
`diff backstop would refuse the finished work. Escalate to /plan.`,
|
|
415
|
+
`diff backstop would refuse the finished work. Escalate to /mandrel-plan.`,
|
|
416
416
|
);
|
|
417
417
|
}
|
|
418
418
|
if (!OVERRIDABLE_SHAPE_CODES.includes(code)) {
|
|
@@ -441,7 +441,7 @@ export function resolveOperatorOverride({
|
|
|
441
441
|
* Resolve what the light gate does with a suitability decision (Story #4740
|
|
442
442
|
* AC-3). Over-scope never hard-fails: it STOPS and asks the operator to choose,
|
|
443
443
|
* unless the run is unattended (`--yes`), where it fails closed to recommending
|
|
444
|
-
* `/plan` rather than silently proceeding light.
|
|
444
|
+
* `/mandrel-plan` rather than silently proceeding light.
|
|
445
445
|
*
|
|
446
446
|
* - suitable → `proceed-light`
|
|
447
447
|
* - over-scope + attended (`yes:false`) → `ask-operator` (escalate | proceed)
|
|
@@ -498,7 +498,7 @@ export function resolveLightGateOutcome({
|
|
|
498
498
|
action: 'escalate-plan',
|
|
499
499
|
reasons: [
|
|
500
500
|
...reasons,
|
|
501
|
-
'--yes on over-scope fails closed to /plan (never silently proceeds light)',
|
|
501
|
+
'--yes on over-scope fails closed to /mandrel-plan (never silently proceeds light)',
|
|
502
502
|
],
|
|
503
503
|
};
|
|
504
504
|
}
|
|
@@ -519,7 +519,7 @@ export function resolveLightGateOutcome({
|
|
|
519
519
|
options: ['escalate-plan', 'proceed-light'],
|
|
520
520
|
reasons: [
|
|
521
521
|
...reasons,
|
|
522
|
-
'predicted scope exceeds the light ceilings — STOP and ask the operator to escalate to /plan or proceed light',
|
|
522
|
+
'predicted scope exceeds the light ceilings — STOP and ask the operator to escalate to /mandrel-plan or proceed light',
|
|
523
523
|
],
|
|
524
524
|
};
|
|
525
525
|
}
|
|
@@ -587,7 +587,7 @@ export function checkLightDiffBackstop({
|
|
|
587
587
|
magnitude: null,
|
|
588
588
|
ceilings: resolved,
|
|
589
589
|
reasons: [
|
|
590
|
-
'actual change set is unknown or empty — cannot verify the diff is light; escalate to /plan',
|
|
590
|
+
'actual change set is unknown or empty — cannot verify the diff is light; escalate to /mandrel-plan',
|
|
591
591
|
],
|
|
592
592
|
};
|
|
593
593
|
}
|
|
@@ -646,12 +646,12 @@ function normalizeMagnitude(magnitude) {
|
|
|
646
646
|
function describeSensitivity({ level, classes }) {
|
|
647
647
|
if (classes.length > 0) {
|
|
648
648
|
return [
|
|
649
|
-
`diff intersects sensitive-path class(es) ${classes.join(', ')} — escalate to /plan (do not land light)`,
|
|
649
|
+
`diff intersects sensitive-path class(es) ${classes.join(', ')} — escalate to /mandrel-plan (do not land light)`,
|
|
650
650
|
];
|
|
651
651
|
}
|
|
652
652
|
if (level !== 'low') {
|
|
653
653
|
return [
|
|
654
|
-
'sensitive-path classification unavailable — cannot verify the diff is non-sensitive; escalate to /plan',
|
|
654
|
+
'sensitive-path classification unavailable — cannot verify the diff is non-sensitive; escalate to /mandrel-plan',
|
|
655
655
|
];
|
|
656
656
|
}
|
|
657
657
|
return [];
|
|
@@ -667,18 +667,18 @@ function describeSensitivity({ level, classes }) {
|
|
|
667
667
|
function describeMagnitude(measured, ceilings) {
|
|
668
668
|
if (measured === null) {
|
|
669
669
|
return [
|
|
670
|
-
'change magnitude could not be measured (unreadable or unparseable numstat) — cannot verify the diff is light; escalate to /plan',
|
|
670
|
+
'change magnitude could not be measured (unreadable or unparseable numstat) — cannot verify the diff is light; escalate to /mandrel-plan',
|
|
671
671
|
];
|
|
672
672
|
}
|
|
673
673
|
const reasons = [];
|
|
674
674
|
if (measured.implLines > ceilings.maxImplLines) {
|
|
675
675
|
reasons.push(
|
|
676
|
-
`diff changes ${measured.implLines} implementation line(s) (> maxImplLines ${ceilings.maxImplLines}) — escalate to /plan (do not land light)`,
|
|
676
|
+
`diff changes ${measured.implLines} implementation line(s) (> maxImplLines ${ceilings.maxImplLines}) — escalate to /mandrel-plan (do not land light)`,
|
|
677
677
|
);
|
|
678
678
|
}
|
|
679
679
|
if (measured.implFiles > ceilings.maxImplFiles) {
|
|
680
680
|
reasons.push(
|
|
681
|
-
`diff spans ${measured.implFiles} implementation file(s) (> maxImplFiles ${ceilings.maxImplFiles}) — escalate to /plan (do not land light)`,
|
|
681
|
+
`diff spans ${measured.implFiles} implementation file(s) (> maxImplFiles ${ceilings.maxImplFiles}) — escalate to /mandrel-plan (do not land light)`,
|
|
682
682
|
);
|
|
683
683
|
}
|
|
684
684
|
return reasons;
|
|
@@ -832,7 +832,7 @@ export function buildReceiptStoryTicket({
|
|
|
832
832
|
goal: `${text}${amendNote}`,
|
|
833
833
|
spec:
|
|
834
834
|
`Delivered via /deliver-light as a validated single-session change — ` +
|
|
835
|
-
`the /plan session is removed for genuinely small work while every ` +
|
|
835
|
+
`the /mandrel-plan session is removed for genuinely small work while every ` +
|
|
836
836
|
`single-story-close gate runs byte-identical.${amendNote}` +
|
|
837
837
|
`${overrideNote} ` +
|
|
838
838
|
`Operator prompt: ${text}`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* plan-context.js — single planner-context envelope build for `/plan`.
|
|
2
|
+
* plan-context.js — single planner-context envelope build for `/mandrel-plan`.
|
|
3
3
|
*
|
|
4
4
|
* Folds the authoring-context builders plus the cross-Story dup search into
|
|
5
5
|
* ONE JSON envelope, so the authoring middle reads a single file instead of
|
|
@@ -481,7 +481,7 @@ export function buildDeliverLightSuggestion(complexitySignals) {
|
|
|
481
481
|
reasons: suggested
|
|
482
482
|
? [
|
|
483
483
|
'seed carries no risk signal (no risk-heuristic hits, no ' +
|
|
484
|
-
'sensitive-path classes) — the operator may prefer /deliver for ' +
|
|
484
|
+
'sensitive-path classes) — the operator may prefer /mandrel-deliver for ' +
|
|
485
485
|
"this scope; the light path's own gate and diff backstop decide size",
|
|
486
486
|
]
|
|
487
487
|
: reasons,
|
|
@@ -597,7 +597,7 @@ function uiSurfaceReason({
|
|
|
597
597
|
* derived from the consumer's own checkout, so a frontend-less project — this
|
|
598
598
|
* repository included — resolves falsey and the offer never fires.
|
|
599
599
|
*
|
|
600
|
-
* The signal carries **no routing authority** (`automatic: false`): `/plan`
|
|
600
|
+
* The signal carries **no routing authority** (`automatic: false`): `/mandrel-plan`
|
|
601
601
|
* may say that a plan touches UI and that `/prototype` exists, and must never
|
|
602
602
|
* invoke it. Pure over its inputs and total — a malformed signal bag or an
|
|
603
603
|
* unreadable manifest degrades, never throws.
|
|
@@ -911,7 +911,7 @@ async function gatherEnvelopeInputs({
|
|
|
911
911
|
(gather) => gather(),
|
|
912
912
|
// The per-mode envelope gathers (Story #4952): the duplicate search, the
|
|
913
913
|
// authoring-context fold and the docs digest have no data dependency on
|
|
914
|
-
// one another, so their serialization was incidental and `/plan` paid it
|
|
914
|
+
// one another, so their serialization was incidental and `/mandrel-plan` paid it
|
|
915
915
|
// with the operator waiting at Gate #1.
|
|
916
916
|
{ concurrency: FANOUT_CONCURRENCY },
|
|
917
917
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* plan-critic-conditions.js — size/heuristic-conditional dispatch decisions for
|
|
3
|
-
* the /plan author-step critics (Epic #4474 PR6, design §4).
|
|
3
|
+
* the /mandrel-plan author-step critics (Epic #4474 PR6, design §4).
|
|
4
4
|
*
|
|
5
5
|
* The collapsed plan flow keeps the consolidation and pre-mortem critics as
|
|
6
6
|
* fresh-context sub-agent dispatches, but makes each dispatch
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
* (`appendCriticSkip`) by the caller so under-firing is auditable.
|
|
45
45
|
*
|
|
46
46
|
* Pure, synchronous, no I/O. The single caller is `plan-critics-evaluate.js`,
|
|
47
|
-
* driven by the `plan-critics.js` CLI that `/plan` runs between Author and
|
|
47
|
+
* driven by the `plan-critics.js` CLI that `/mandrel-plan` runs between Author and
|
|
48
48
|
* Persist (Story #4592); the CLI owns reading the authored artifacts and the
|
|
49
49
|
* resolved config.
|
|
50
50
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* plan-critics-evaluate.js — shared critic-dispatch evaluation for the
|
|
3
|
-
* collapsed /plan flow (#4496 fix 6).
|
|
3
|
+
* collapsed /mandrel-plan flow (#4496 fix 6).
|
|
4
4
|
*
|
|
5
|
-
* One consumer: the `plan-critics.js` CLI, which `/plan` runs between its
|
|
5
|
+
* One consumer: the `plan-critics.js` CLI, which `/mandrel-plan` runs between its
|
|
6
6
|
* Author and Persist steps. The CLI loads the draft artifacts, calls this
|
|
7
7
|
* module, prints the verdict as JSON, and records every skip on the
|
|
8
8
|
* plan-metrics ledger; the workflow dispatches a fresh-context critic
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* plan-metrics.js — append-only plan-invocation ledger (Epic #4474, PR1).
|
|
3
3
|
*
|
|
4
|
-
* The `/plan` collapse (#4474) is measured, not asserted: before any pipeline
|
|
4
|
+
* The `/mandrel-plan` collapse (#4474) is measured, not asserted: before any pipeline
|
|
5
5
|
* phase is removed, every plan CLI invocation stamps an entry/exit record so
|
|
6
6
|
* the current 12-phase baseline is captured on disk. Each record is one
|
|
7
7
|
* newline-terminated JSON line appended to
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* plan-context-source.js — locate and read the `plan-context.js` envelope so
|
|
3
|
-
* persist can derive the `/plan --tickets` source ids from the run that
|
|
3
|
+
* persist can derive the `/mandrel-plan --tickets` source ids from the run that
|
|
4
4
|
* actually fetched them (Story #4554).
|
|
5
5
|
*
|
|
6
6
|
* This lives beside the persist ops rather than inside `plan-persist.js` so
|
|
@@ -17,7 +17,7 @@ import path from 'node:path';
|
|
|
17
17
|
import { Logger } from '../../Logger.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Filename the `/plan` interrogate step writes its envelope to inside
|
|
20
|
+
* Filename the `/mandrel-plan` interrogate step writes its envelope to inside
|
|
21
21
|
* `--plan-dir` (`plan-context.js --out <plan-dir>/plan-context.json`).
|
|
22
22
|
*/
|
|
23
23
|
export const PLAN_CONTEXT_FILENAME = 'plan-context.json';
|
|
@@ -81,7 +81,7 @@ export async function loadPlanContextEnvelope(planContext) {
|
|
|
81
81
|
if (!planContext) {
|
|
82
82
|
Logger.warn(
|
|
83
83
|
'[plan-persist] no --plan-dir or --plan-context given, so no ' +
|
|
84
|
-
'plan-context envelope was read. If this was a `/plan --tickets` ' +
|
|
84
|
+
'plan-context envelope was read. If this was a `/mandrel-plan --tickets` ' +
|
|
85
85
|
'run, its source tickets can only come from --source-tickets and ' +
|
|
86
86
|
`will NOT be closed otherwise. ${CAPTURE_HINT}`,
|
|
87
87
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* run-plan-persist.js — flat Story persist for the v2 `/plan` collapse
|
|
2
|
+
* run-plan-persist.js — flat Story persist for the v2 `/mandrel-plan` collapse
|
|
3
3
|
* (Stage 3 — `docs/roadmap.md`).
|
|
4
4
|
*
|
|
5
5
|
* Ordered, fail-closed pipeline:
|
|
@@ -293,7 +293,7 @@ async function renderRunScopedPlanMetricsLine({
|
|
|
293
293
|
* from the seed.
|
|
294
294
|
*
|
|
295
295
|
* The resolved route decides whether the created Stories carry the
|
|
296
|
-
* {@link LITE_ROUTE_LABEL} **hint** (never the control signal — `/deliver`
|
|
296
|
+
* {@link LITE_ROUTE_LABEL} **hint** (never the control signal — `/mandrel-deliver`
|
|
297
297
|
* re-derives the route from the Story body's shape) and the `route` block
|
|
298
298
|
* ledgered on their `story-plan-state` checkpoint, including the authored
|
|
299
299
|
* verdict, its recorded reason, and the per-Story shape evidence. A refused
|
|
@@ -531,7 +531,7 @@ async function enforceReachability(reachability, config) {
|
|
|
531
531
|
* concurrency, but the `await` on that whole fan-out is what keeps the
|
|
532
532
|
* Story #4541 invariant intact: *every* checkpoint is on its ticket before the
|
|
533
533
|
* first `agent::ready` flip is issued, so `ready` still means "fully
|
|
534
|
-
* persisted" and a `/deliver` that picks a Story up cannot read a null
|
|
534
|
+
* persisted" and a `/mandrel-deliver` that picks a Story up cannot read a null
|
|
535
535
|
* checkpoint. Concurrency inside the phase is safe; overlapping the phases is
|
|
536
536
|
* the race this ordering exists to close.
|
|
537
537
|
*
|
|
@@ -611,7 +611,7 @@ function logEffectiveRoute(route, isLiteRoute) {
|
|
|
611
611
|
Logger.info(
|
|
612
612
|
`[plan-persist] ceremony-lite route upheld by the shape backstop: ` +
|
|
613
613
|
`created Stories carry the ${LITE_ROUTE_LABEL} hint ` +
|
|
614
|
-
`(recorded reason: ${route.authored.reason}). /deliver re-derives ` +
|
|
614
|
+
`(recorded reason: ${route.authored.reason}). /mandrel-deliver re-derives ` +
|
|
615
615
|
'the route from each Story body — the label is never the control signal.',
|
|
616
616
|
);
|
|
617
617
|
return;
|
|
@@ -644,10 +644,10 @@ function logPersistEpilogue({ created, primary, planRunLabel }) {
|
|
|
644
644
|
`; primary #${primary.id} is agent::ready.`,
|
|
645
645
|
);
|
|
646
646
|
Logger.info(
|
|
647
|
-
`[plan-persist] Deliver with: /deliver ${created.map((s2) => s2.id).join(' ')}`,
|
|
647
|
+
`[plan-persist] Deliver with: /mandrel-deliver ${created.map((s2) => s2.id).join(' ')}`,
|
|
648
648
|
);
|
|
649
649
|
// Metadata only — a GitHub filter for the cohort this run authored, never
|
|
650
|
-
// a delivery-resolution input (/deliver stays ids-only, Story #4540).
|
|
650
|
+
// a delivery-resolution input (/mandrel-deliver stays ids-only, Story #4540).
|
|
651
651
|
Logger.info(
|
|
652
652
|
`[plan-persist] Cohort grouping label: ${planRunLabel} — filter with ` +
|
|
653
653
|
`label:${planRunLabel}`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* story-ops.js — flat Story creation for v2 plan-persist (Stage 3).
|
|
3
3
|
*
|
|
4
|
-
* Under the Story collapse (`docs/roadmap.md` § Stage 3), `/plan` persists
|
|
4
|
+
* Under the Story collapse (`docs/roadmap.md` § Stage 3), `/mandrel-plan` persists
|
|
5
5
|
* zero-or-more Story issues directly — no Epic parent, no reconciler tree,
|
|
6
6
|
* no `deliveryShape` mode matrix. Default is **one Story**; N>1 is gated by
|
|
7
7
|
* the Stage-1 split-policy validator (`assertAcceptancePartition`).
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
*
|
|
45
45
|
* Reintroduced (Story #4692) after Story #4540 retired it: #4540 was right
|
|
46
46
|
* that batch identity is the wrong axis for *ordering delivery across runs*
|
|
47
|
-
* (`/deliver` takes ids and resolves the graph from live state — that stays),
|
|
47
|
+
* (`/mandrel-deliver` takes ids and resolves the graph from live state — that stays),
|
|
48
48
|
* but it is the correct axis for *grouping the Stories one plan run created*
|
|
49
49
|
* so a cohort is filterable and traceable in the GitHub UI. The label is
|
|
50
50
|
* metadata only; nothing in persist or delivery reads it as a
|
|
@@ -57,7 +57,7 @@ const PLAN_RUN_LABEL_COLOR = '#C5DEF5';
|
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* Stable color for the `route::lite` ceremony-route hint (Story #4707;
|
|
60
|
-
* hint-only since Story #4722 — `/deliver` re-derives the route from the
|
|
60
|
+
* hint-only since Story #4722 — `/mandrel-deliver` re-derives the route from the
|
|
61
61
|
* Story body's shape).
|
|
62
62
|
*/
|
|
63
63
|
const LITE_ROUTE_LABEL_COLOR = '#D4C5F9';
|
|
@@ -197,6 +197,26 @@ function planFingerprintMarker(fingerprint) {
|
|
|
197
197
|
return `<!-- ${PLAN_FINGERPRINT_MARKER_PREFIX} ${fingerprint} -->`;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
/** The one parser for the marker {@link planFingerprintMarker} renders. */
|
|
201
|
+
const PLAN_FINGERPRINT_MARKER_RE = new RegExp(
|
|
202
|
+
`<!--\\s*${PLAN_FINGERPRINT_MARKER_PREFIX}\\s*([0-9a-f]+)\\s*-->`,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Recover the plan fingerprint an issue body was stamped with, or `null` when
|
|
207
|
+
* the body carries no marker. Module-private: both readers of the marker (the
|
|
208
|
+
* resume index and the create-retry adoption probe) go through it so they can
|
|
209
|
+
* never drift into recognising different Stories as "already created".
|
|
210
|
+
*
|
|
211
|
+
* @param {unknown} body
|
|
212
|
+
* @returns {string|null}
|
|
213
|
+
*/
|
|
214
|
+
function extractPlanFingerprint(body) {
|
|
215
|
+
if (typeof body !== 'string') return null;
|
|
216
|
+
const match = body.match(PLAN_FINGERPRINT_MARKER_RE);
|
|
217
|
+
return match ? match[1] : null;
|
|
218
|
+
}
|
|
219
|
+
|
|
200
220
|
/**
|
|
201
221
|
* Labels the authoring pass is never allowed to set. The `agent::*` axis is
|
|
202
222
|
* the runtime's lifecycle state (persist owns the terminal `agent::ready`
|
|
@@ -455,7 +475,7 @@ function assembleOnePlanStory(ticket, opts) {
|
|
|
455
475
|
const serialized = serializeStoryBody({ ...folded, depends_on });
|
|
456
476
|
// Carry audit dedup provenance into the persisted body (Story #4877). The
|
|
457
477
|
// audit sweep's Single-plan path stamps the `audit-fingerprints` /
|
|
458
|
-
// `audit-semantic-keys` footers into the seed it hands `/plan`; without this
|
|
478
|
+
// `audit-semantic-keys` footers into the seed it hands `/mandrel-plan`; without this
|
|
459
479
|
// the persisted Story carries no provenance and the next sweep re-files work
|
|
460
480
|
// it already planned. Mechanical on purpose — the authoring agent is not
|
|
461
481
|
// asked to notice HTML comments in a one-pager. A non-audit seed carries no
|
|
@@ -509,7 +529,7 @@ function assertSharedSpecAllowed(tickets, sharedSpec) {
|
|
|
509
529
|
* @param {object} [opts]
|
|
510
530
|
* @param {string|null} [opts.sharedSpec]
|
|
511
531
|
* @param {string[]} [opts.planAcceptance]
|
|
512
|
-
* @param {number[]} [opts.sourceTicketIds] Ids passed to `/plan --tickets`.
|
|
532
|
+
* @param {number[]} [opts.sourceTicketIds] Ids passed to `/mandrel-plan --tickets`.
|
|
513
533
|
* @returns {{ stories: Array<{ slug: string, title: string, body: string, acceptance: string[], depends_on: string[], supersedes: Array<{ id: number, note: string|null }> }> }}
|
|
514
534
|
*/
|
|
515
535
|
export function assemblePlanStories(tickets, opts = {}) {
|
|
@@ -617,14 +637,9 @@ async function indexExistingStories(provider) {
|
|
|
617
637
|
if (title !== '') {
|
|
618
638
|
idsByTitle.set(title, [...(idsByTitle.get(title) ?? []), id]);
|
|
619
639
|
}
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
`<!--\\s*${PLAN_FINGERPRINT_MARKER_PREFIX}\\s*([0-9a-f]+)\\s*-->`,
|
|
624
|
-
),
|
|
625
|
-
);
|
|
626
|
-
if (!match) continue;
|
|
627
|
-
byFingerprint.set(match[1], {
|
|
640
|
+
const fingerprint = extractPlanFingerprint(issue?.body);
|
|
641
|
+
if (!fingerprint) continue;
|
|
642
|
+
byFingerprint.set(fingerprint, {
|
|
628
643
|
id,
|
|
629
644
|
title,
|
|
630
645
|
url: issue.html_url ?? issue.url ?? undefined,
|
|
@@ -633,6 +648,42 @@ async function indexExistingStories(provider) {
|
|
|
633
648
|
return { byFingerprint, idsByTitle };
|
|
634
649
|
}
|
|
635
650
|
|
|
651
|
+
/**
|
|
652
|
+
* Re-run the resume lookup for a single fingerprint and return the **raw**
|
|
653
|
+
* issue, or `null`.
|
|
654
|
+
*
|
|
655
|
+
* This is the probe `createIssue` calls before any retry POST (Story #5112).
|
|
656
|
+
* A create whose response was lost has already filed the issue; retrying
|
|
657
|
+
* blind duplicates it. Because the body posted carries the fingerprint
|
|
658
|
+
* marker, the same content-keyed lookup the resume path uses answers "did
|
|
659
|
+
* attempt 1 land?" authoritatively — from the server's state, not from a
|
|
660
|
+
* client-side guess about where the connection broke.
|
|
661
|
+
*
|
|
662
|
+
* Best-effort like {@link indexExistingStories}: a provider without the
|
|
663
|
+
* listing surface, or a listing that throws, yields `null` and the retry
|
|
664
|
+
* proceeds exactly as it did before.
|
|
665
|
+
*
|
|
666
|
+
* @param {{ provider: object, fingerprint: string }} args
|
|
667
|
+
* @returns {Promise<object|null>}
|
|
668
|
+
*/
|
|
669
|
+
async function findOpenStoryByPlanFingerprint({ provider, fingerprint }) {
|
|
670
|
+
if (typeof provider?.listIssuesByLabel !== 'function') return null;
|
|
671
|
+
if (typeof fingerprint !== 'string' || fingerprint.length === 0) return null;
|
|
672
|
+
let issues;
|
|
673
|
+
try {
|
|
674
|
+
issues = await provider.listIssuesByLabel({
|
|
675
|
+
state: 'open',
|
|
676
|
+
labels: TYPE_LABELS.STORY,
|
|
677
|
+
});
|
|
678
|
+
} catch {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
for (const issue of Array.isArray(issues) ? issues : []) {
|
|
682
|
+
if (extractPlanFingerprint(issue?.body) === fingerprint) return issue;
|
|
683
|
+
}
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
|
|
636
687
|
/**
|
|
637
688
|
* Warn when a Story with this title is already open but did **not** match the
|
|
638
689
|
* fingerprint — i.e. its authored content differs from what this run is about
|
|
@@ -705,14 +756,14 @@ function renderStoryBodyForCreate(story, idBySlug) {
|
|
|
705
756
|
*
|
|
706
757
|
* Ordering is authored as slugs and, until now, survived persist only as
|
|
707
758
|
* `blocked by #N` prose in the body footer. That footer stays — it is what
|
|
708
|
-
* `/deliver`'s resolver falls back on — but a native edge is the durable,
|
|
759
|
+
* `/mandrel-deliver`'s resolver falls back on — but a native edge is the durable,
|
|
709
760
|
* machine-readable form: visible in the GitHub UI, readable without parsing
|
|
710
761
|
* markdown, and settable by an operator later for cross-run order.
|
|
711
762
|
*
|
|
712
763
|
* **Non-fatal by design, and deliberately asymmetric with the read path.** A
|
|
713
764
|
* missing native edge is cosmetic here: `renderStoryBodyForCreate` has already
|
|
714
765
|
* written the footer, so ordering is not lost when the dependencies API says
|
|
715
|
-
* no. `/deliver`'s *read* of these edges is a real dispatch gate, which is why
|
|
766
|
+
* no. `/mandrel-deliver`'s *read* of these edges is a real dispatch gate, which is why
|
|
716
767
|
* that side fails loud. Persist reports the failure and completes.
|
|
717
768
|
*
|
|
718
769
|
* Two shape hazards this crossing has to get right, both silent if missed:
|
|
@@ -788,7 +839,7 @@ async function mirrorNativeDependencyEdges({ provider, stories, idBySlug }) {
|
|
|
788
839
|
*
|
|
789
840
|
* **Non-fatal by design**, matching the native-blocked_by mirroring posture:
|
|
790
841
|
* neither label is load-bearing for correctness (grouping is cosmetic, and
|
|
791
|
-
* the route label is a human-visible hint only — `/deliver` re-derives the
|
|
842
|
+
* the route label is a human-visible hint only — `/mandrel-deliver` re-derives the
|
|
792
843
|
* route from the Story body's shape, Story #4722), so it is never a reason
|
|
793
844
|
* to fail persist. On an ensure
|
|
794
845
|
* failure (throw, or the label reported `missing` by the post-loop
|
|
@@ -869,7 +920,7 @@ async function ensurePersistLabel({
|
|
|
869
920
|
* create — no relabel call is needed on the resume path, and the cohort is
|
|
870
921
|
* never split across two labels. The label is ensured to exist before the
|
|
871
922
|
* first POST, **non-fatally**: grouping is cosmetic and never fails the run
|
|
872
|
-
* (see `ensureCohortLabel`). `/deliver` never reads it — delivery stays
|
|
923
|
+
* (see `ensureCohortLabel`). `/mandrel-deliver` never reads it — delivery stays
|
|
873
924
|
* ids-only over live state (Story #4540's actual point).
|
|
874
925
|
*
|
|
875
926
|
* **The create loop stays serial and dependency-ordered** — deliberately, and
|
|
@@ -889,7 +940,7 @@ async function ensurePersistLabel({
|
|
|
889
940
|
* effective complexity route to `lite` (the planner's recorded verdict,
|
|
890
941
|
* upheld by the shape backstop), it passes the label via `opts.routeLabel`
|
|
891
942
|
* and every created Story carries it — a **human-visible hint only**, never
|
|
892
|
-
* the control signal: `/deliver` re-derives the route from each Story body's
|
|
943
|
+
* the control signal: `/mandrel-deliver` re-derives the route from each Story body's
|
|
893
944
|
* own shape (`resolveStoryDispatchMode`), so a lost or failed label write
|
|
894
945
|
* cannot misroute delivery. A full-routed plan passes nothing and its
|
|
895
946
|
* Stories carry **no** route label. Like the cohort label, the ensure is
|
|
@@ -949,8 +1000,8 @@ export async function createStoryIssues({ provider, stories, opts = {} }) {
|
|
|
949
1000
|
label: cohortLabel,
|
|
950
1001
|
color: PLAN_RUN_LABEL_COLOR,
|
|
951
1002
|
description:
|
|
952
|
-
'Groups the Stories one /plan persist run authored (metadata ' +
|
|
953
|
-
'only — /deliver stays ids-only).',
|
|
1003
|
+
'Groups the Stories one /mandrel-plan persist run authored (metadata ' +
|
|
1004
|
+
'only — /mandrel-deliver stays ids-only).',
|
|
954
1005
|
role: 'cohort',
|
|
955
1006
|
});
|
|
956
1007
|
const applyRouteLabel =
|
|
@@ -960,7 +1011,7 @@ export async function createStoryIssues({ provider, stories, opts = {} }) {
|
|
|
960
1011
|
label: routeLabel,
|
|
961
1012
|
color: LITE_ROUTE_LABEL_COLOR,
|
|
962
1013
|
description:
|
|
963
|
-
'Ceremony-lite hint (human-visible only): /deliver re-derives the ' +
|
|
1014
|
+
'Ceremony-lite hint (human-visible only): /mandrel-deliver re-derives the ' +
|
|
964
1015
|
'route from the Story body shape; every close gate runs unchanged.',
|
|
965
1016
|
role: 'route-marker',
|
|
966
1017
|
}));
|
|
@@ -1000,6 +1051,14 @@ export async function createStoryIssues({ provider, stories, opts = {} }) {
|
|
|
1000
1051
|
...(applyCohortLabel ? [cohortLabel] : []),
|
|
1001
1052
|
...(applyRouteLabel ? [routeLabel] : []),
|
|
1002
1053
|
],
|
|
1054
|
+
// Story #5112 — hand the provider the same content-keyed lookup this
|
|
1055
|
+
// loop's resume path uses, so a retry after a lost response adopts the
|
|
1056
|
+
// issue attempt 1 already filed instead of creating a twin.
|
|
1057
|
+
findExisting: () =>
|
|
1058
|
+
findOpenStoryByPlanFingerprint({
|
|
1059
|
+
provider,
|
|
1060
|
+
fingerprint: story.fingerprint,
|
|
1061
|
+
}),
|
|
1003
1062
|
});
|
|
1004
1063
|
const id = result?.id ?? result?.number;
|
|
1005
1064
|
if (!Number.isInteger(id)) {
|
|
@@ -1012,7 +1071,9 @@ export async function createStoryIssues({ provider, stories, opts = {} }) {
|
|
|
1012
1071
|
id,
|
|
1013
1072
|
title: story.title,
|
|
1014
1073
|
url: result.url,
|
|
1015
|
-
adopted
|
|
1074
|
+
// True when the provider's retry probe adopted an issue a lost-response
|
|
1075
|
+
// first attempt had already filed — pre-existing either way.
|
|
1076
|
+
adopted: result.adopted === true,
|
|
1016
1077
|
});
|
|
1017
1078
|
idBySlug.set(story.slug, id);
|
|
1018
1079
|
}
|
|
@@ -1040,9 +1101,9 @@ export async function createStoryIssues({ provider, stories, opts = {} }) {
|
|
|
1040
1101
|
*
|
|
1041
1102
|
* This is what makes `agent::ready` *mean* "fully persisted": by the time it
|
|
1042
1103
|
* lands, the Story's `story-plan-state` checkpoint is already on the ticket, so
|
|
1043
|
-
* a `/deliver` that picks it up cannot read a null checkpoint.
|
|
1104
|
+
* a `/mandrel-deliver` that picks it up cannot read a null checkpoint.
|
|
1044
1105
|
*
|
|
1045
|
-
* Fails closed: an un-flipped Story is invisible to `/deliver`, which is the
|
|
1106
|
+
* Fails closed: an un-flipped Story is invisible to `/mandrel-deliver`, which is the
|
|
1046
1107
|
* safe direction — the operator is told exactly which ids need the label.
|
|
1047
1108
|
*
|
|
1048
1109
|
* **Collect failures, never fast-fail** (preserved verbatim under the
|
|
@@ -1098,7 +1159,7 @@ export async function markStoriesReady({ provider, created }) {
|
|
|
1098
1159
|
`[plan-persist] ${failed.length} Story(ies) were created with their ` +
|
|
1099
1160
|
'checkpoints but could not be flipped to agent::ready:\n' +
|
|
1100
1161
|
`${failed.map((f) => ` - ${f}`).join('\n')}\n` +
|
|
1101
|
-
'They are invisible to /deliver until the label lands. Re-run persist ' +
|
|
1162
|
+
'They are invisible to /mandrel-deliver until the label lands. Re-run persist ' +
|
|
1102
1163
|
'(it resumes rather than duplicating) or add the label by hand.',
|
|
1103
1164
|
);
|
|
1104
1165
|
}
|
|
@@ -163,8 +163,8 @@ export function buildPlanSummaryCommentBody({
|
|
|
163
163
|
// must name real ids, not a batch token that no longer exists.
|
|
164
164
|
const deliverCommand =
|
|
165
165
|
Array.isArray(stories) && stories.length > 0
|
|
166
|
-
? `/deliver ${stories.map((s) => s.id).join(' ')}`
|
|
167
|
-
: '/deliver <storyId> [<storyId> ...]';
|
|
166
|
+
? `/mandrel-deliver ${stories.map((s) => s.id).join(' ')}`
|
|
167
|
+
: '/mandrel-deliver <storyId> [<storyId> ...]';
|
|
168
168
|
|
|
169
169
|
return [
|
|
170
170
|
`### 📋 Plan Summary — Story #${epicId} is \`agent::ready\``,
|
|
@@ -182,6 +182,6 @@ export function buildPlanSummaryCommentBody({
|
|
|
182
182
|
...renderWaveTableLines(waveTable),
|
|
183
183
|
...renderSharedEditorLines(conflictFindings),
|
|
184
184
|
'',
|
|
185
|
-
`_Deliver with \`${deliverCommand}\` — \`/deliver\` resolves the dependency graph from live state, so edges may point at Stories from earlier plan runs._`,
|
|
185
|
+
`_Deliver with \`${deliverCommand}\` — \`/mandrel-deliver\` resolves the dependency graph from live state, so edges may point at Stories from earlier plan runs._`,
|
|
186
186
|
].join('\n');
|
|
187
187
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* supersede-ops.js — close the `/plan --tickets` source issues that the
|
|
2
|
+
* supersede-ops.js — close the `/mandrel-plan --tickets` source issues that the
|
|
3
3
|
* authored Stories supersede (Story #4535).
|
|
4
4
|
*
|
|
5
5
|
* `plan-context.js` fetches the source issues, emits `sourceTickets[]` on the
|
|
6
|
-
* `/plan` envelope, and (with `--out`) writes that envelope to disk.
|
|
6
|
+
* `/mandrel-plan` envelope, and (with `--out`) writes that envelope to disk.
|
|
7
7
|
* `resolveSourceTicketIds` below reads the id set back off it, so the normal
|
|
8
|
-
* `/plan --tickets` path needs no flag; an explicit `--source-tickets` still
|
|
8
|
+
* `/mandrel-plan --tickets` path needs no flag; an explicit `--source-tickets` still
|
|
9
9
|
* wins when passed, as the override for hand-driven runs (Story #4554).
|
|
10
10
|
* Before that thread existed the ids reached
|
|
11
11
|
* this module *solely* via the hand-passed flag, so a forgotten flag left
|
|
@@ -187,7 +187,7 @@ function sameIdSet(a, b) {
|
|
|
187
187
|
* loudly (the operator is overriding what the run actually fetched)
|
|
188
188
|
* but honoured.
|
|
189
189
|
* 2. otherwise the envelope's `sourceTickets[]` — so the common
|
|
190
|
-
* `/plan --tickets` path needs no flag at all.
|
|
190
|
+
* `/mandrel-plan --tickets` path needs no flag at all.
|
|
191
191
|
* 3. otherwise empty, reported as `origin: 'none'`.
|
|
192
192
|
*
|
|
193
193
|
* `origin` is surfaced on the persist envelope so a run that superseded
|
|
@@ -240,7 +240,7 @@ function describeStoryIds(entries) {
|
|
|
240
240
|
* live against an inconsistent tracker.
|
|
241
241
|
*
|
|
242
242
|
* @param {Array<{ slug: string, supersedes: Array<{ id: number }> }>} stories
|
|
243
|
-
* @param {number[]} sourceTicketIds Ids passed to `/plan --tickets`.
|
|
243
|
+
* @param {number[]} sourceTicketIds Ids passed to `/mandrel-plan --tickets`.
|
|
244
244
|
*/
|
|
245
245
|
export function assertSupersedePartition(stories, sourceTicketIds = []) {
|
|
246
246
|
const list = Array.isArray(stories) ? stories : [];
|
|
@@ -313,7 +313,7 @@ export function buildSupersedeCommentBody({
|
|
|
313
313
|
const lines = [
|
|
314
314
|
`**Superseded by #${story.id}** — *${story.title}* (${labels.join(', ')}).`,
|
|
315
315
|
'',
|
|
316
|
-
`Planned via \`/plan --tickets ${sourceTicketIds.join(',')}\`.`,
|
|
316
|
+
`Planned via \`/mandrel-plan --tickets ${sourceTicketIds.join(',')}\`.`,
|
|
317
317
|
];
|
|
318
318
|
if (note) {
|
|
319
319
|
lines.push('', note);
|