mandrel 2.24.0 → 2.26.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/agents/acceptance-critic.md +19 -21
- package/.agents/agents/auditor.md +16 -19
- package/.agents/agents/story-worker.md +41 -54
- package/.agents/audit-checklists/architecture.md +5 -1
- package/.agents/audit-checklists/baselines.md +21 -0
- package/.agents/audit-checklists/quality.md +3 -0
- package/.agents/docs/agentrc-reference.json +2 -1
- package/.agents/docs/configuration.md +2 -1
- package/.agents/docs/quality-gates.md +80 -18
- package/.agents/docs/workflows.md +4 -2
- package/.agents/instructions.md +1 -1
- package/.agents/rules/ci-remediation.md +68 -3
- package/.agents/schemas/agentrc.schema.json +6 -1
- package/.agents/schemas/audit-rules.json +15 -0
- package/.agents/schemas/baselines/audit-baselines-envelope.schema.json +242 -0
- package/.agents/schemas/baselines/baseline-envelope.schema.json +8 -0
- package/.agents/schemas/baselines/crap.schema.json +13 -1
- package/.agents/schemas/crap-report.schema.json +37 -0
- package/.agents/schemas/model-attribution.schema.json +4 -0
- package/.agents/scripts/acceptance-eval.js +124 -15
- package/.agents/scripts/audit-baselines.js +136 -0
- package/.agents/scripts/audit-labels-bootstrap.js +16 -95
- package/.agents/scripts/audit-to-stories.js +33 -3
- package/.agents/scripts/check-arch-cycles.js +12 -93
- package/.agents/scripts/check-baseline-drift.js +16 -3
- package/.agents/scripts/check-baselines.js +19 -3
- package/.agents/scripts/check-context-budget.js +95 -14
- package/.agents/scripts/check-cyclomatic.js +214 -0
- package/.agents/scripts/check-schema-references.js +392 -0
- package/.agents/scripts/check-test-temp-hygiene.js +121 -1
- package/.agents/scripts/check-workflow-timeouts.js +291 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +7 -5
- package/.agents/scripts/deliver-light.js +3 -4
- package/.agents/scripts/deliver-recover.js +13 -0
- package/.agents/scripts/diagnose-friction.js +85 -19
- package/.agents/scripts/lib/audit-baselines/engine.js +177 -0
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +63 -0
- package/.agents/scripts/lib/audit-baselines/headroom.js +72 -0
- package/.agents/scripts/lib/audit-baselines/hotspots.js +69 -0
- package/.agents/scripts/lib/audit-baselines/kinds.js +313 -0
- package/.agents/scripts/lib/audit-baselines/outliers.js +100 -0
- package/.agents/scripts/lib/audit-baselines/read.js +87 -0
- package/.agents/scripts/lib/audit-baselines/staleness.js +123 -0
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +106 -0
- package/.agents/scripts/lib/audit-baselines/trend.js +125 -0
- package/.agents/scripts/lib/audit-baselines/weights.js +193 -0
- package/.agents/scripts/lib/audit-suite/index.js +0 -5
- package/.agents/scripts/lib/audit-suite/selector.js +9 -62
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +177 -0
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +1 -0
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +35 -3
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +20 -11
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +23 -9
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +9 -2
- package/.agents/scripts/lib/baseline-loader.js +0 -0
- package/.agents/scripts/lib/baseline-schema-registry.js +13 -1
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +22 -160
- package/.agents/scripts/lib/baselines/duplication-scanner.js +27 -0
- package/.agents/scripts/lib/baselines/git-base.js +0 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +499 -57
- package/.agents/scripts/lib/baselines/preview-gates.js +58 -15
- package/.agents/scripts/lib/baselines/reader.js +10 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +69 -11
- package/.agents/scripts/lib/baselines/scope.js +39 -90
- package/.agents/scripts/lib/baselines/writer.js +16 -7
- package/.agents/scripts/lib/changed-files.js +8 -1
- package/.agents/scripts/lib/cli-args.js +115 -1
- package/.agents/scripts/lib/close-validation/runner.js +70 -25
- package/.agents/scripts/lib/config-settings-schema-delivery.js +5 -0
- package/.agents/scripts/lib/crap-engine.js +124 -27
- package/.agents/scripts/lib/crap-method-identity.js +153 -0
- package/.agents/scripts/lib/crap-utils.js +86 -13
- package/.agents/scripts/lib/cyclomatic-ceiling.js +265 -0
- package/.agents/scripts/lib/env-loader.js +46 -16
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -2
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +0 -2
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +0 -2
- package/.agents/scripts/lib/findings/route-finding.js +123 -17
- package/.agents/scripts/lib/findings/severity.js +80 -2
- package/.agents/scripts/lib/git/cached-fetch.js +0 -0
- package/.agents/scripts/lib/git-utils.js +136 -80
- package/.agents/scripts/lib/import-graph.js +156 -0
- package/.agents/scripts/lib/label-constants.js +17 -0
- package/.agents/scripts/lib/observability/runtime-friction.js +17 -2
- package/.agents/scripts/lib/observability/source-classifier.js +175 -2
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +110 -17
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +17 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +36 -6
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +5 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +12 -1
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +8 -1
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +548 -0
- package/.agents/scripts/lib/orchestration/deliver-recover.js +2 -2
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +10 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +39 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +71 -20
- package/.agents/scripts/lib/orchestration/light-backstop.js +20 -3
- package/.agents/scripts/lib/orchestration/light-escalation.js +82 -3
- package/.agents/scripts/lib/orchestration/light-suitability.js +103 -5
- package/.agents/scripts/lib/orchestration/plan-context.js +119 -66
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +31 -5
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +216 -109
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +61 -13
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +79 -22
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +51 -20
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +70 -74
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +231 -0
- package/.agents/scripts/lib/orchestration/resolve-stories.js +18 -17
- package/.agents/scripts/lib/orchestration/retro-proposals.js +0 -0
- package/.agents/scripts/lib/orchestration/run-epilogue.js +12 -0
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +276 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +41 -10
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +125 -37
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +6 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +42 -38
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +129 -21
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -1
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +267 -125
- package/.agents/scripts/lib/orchestration/spec-budget.js +16 -5
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +182 -95
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +22 -0
- package/.agents/scripts/lib/orchestration/ticket-validator.js +5 -11
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +4 -4
- package/.agents/scripts/lib/reserved-test-ids.js +77 -0
- package/.agents/scripts/lib/story-adjacency.js +3 -3
- package/.agents/scripts/lib/story-plan.js +137 -42
- package/.agents/scripts/lib/templates/decomposer-prompts.js +4 -4
- package/.agents/scripts/lib/test-runner-contract.js +134 -0
- package/.agents/scripts/lib/test-tiers.js +11 -2
- package/.agents/scripts/lib/ticket-body-sections.js +1 -1
- package/.agents/scripts/lib/util/concurrent-map.js +17 -0
- package/.agents/scripts/lib/util/parse-id-list.js +103 -0
- package/.agents/scripts/lib/util/poll-loop.js +18 -2
- package/.agents/scripts/lib/wave-runner/live-probe.js +29 -13
- package/.agents/scripts/lib/wave-runner/ready-set.js +254 -43
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +10 -13
- package/.agents/scripts/lib/workers/crap-worker.js +8 -13
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +4 -10
- package/.agents/scripts/lib/workers/maintainability-worker.js +4 -10
- package/.agents/scripts/lib/workers/serve-worker-messages.js +35 -0
- package/.agents/scripts/lib/worktree/git-hooks.js +206 -0
- package/.agents/scripts/lib/worktree/lifecycle/creation.js +6 -0
- package/.agents/scripts/lib/worktree-manager.js +14 -0
- package/.agents/scripts/plan-run-epilogue.js +17 -5
- package/.agents/scripts/pr-watch-with-update.js +568 -213
- package/.agents/scripts/providers/github/tickets.js +33 -10
- package/.agents/scripts/provision-git-hooks.js +85 -0
- package/.agents/scripts/quality-preview.js +137 -28
- package/.agents/scripts/resolve-stories.js +4 -1
- package/.agents/scripts/run-coverage.js +86 -35
- package/.agents/scripts/run-lint.js +20 -0
- package/.agents/scripts/run-tests.js +36 -36
- package/.agents/scripts/single-story-close.js +34 -2
- package/.agents/scripts/single-story-confirm-merge.js +22 -6
- package/.agents/scripts/single-story-init.js +7 -0
- package/.agents/scripts/stories-wave-tick.js +308 -47
- package/.agents/scripts/story-plan.js +65 -9
- package/.agents/scripts/update-coverage-baseline.js +34 -4
- package/.agents/scripts/update-crap-baseline.js +42 -4
- package/.agents/scripts/update-duplication-baseline.js +209 -83
- package/.agents/scripts/update-maintainability-baseline.js +31 -4
- package/.agents/scripts/validate-docs-freshness.js +1 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +4 -1
- package/.agents/skills/core/gates-and-baselines/SKILL.md +17 -11
- package/.agents/skills/skills.index.json +2 -2
- package/.agents/templates/single-story-body.md +16 -8
- package/.agents/workflows/audit-architecture.md +69 -13
- package/.agents/workflows/audit-baselines.md +289 -0
- package/.agents/workflows/audit-navigability.md +5 -4
- package/.agents/workflows/audit-quality.md +26 -0
- package/.agents/workflows/audit-to-stories.md +30 -4
- package/.agents/workflows/deliver.md +92 -97
- package/.agents/workflows/helpers/acceptance-self-eval.md +47 -10
- package/.agents/workflows/helpers/audit-lens-core.md +25 -4
- package/.agents/workflows/helpers/code-quality-guardrails.md +9 -2
- package/.agents/workflows/helpers/deliver-digest.md +41 -21
- package/.agents/workflows/helpers/deliver-reference.md +95 -4
- package/.agents/workflows/helpers/deliver-story-reference.md +174 -52
- package/.agents/workflows/helpers/deliver-story.md +104 -119
- package/.agents/workflows/helpers/plan-reference.md +49 -5
- package/.agents/workflows/memory-consolidate.md +116 -0
- package/.agents/workflows/plan.md +62 -75
- package/README.md +13 -6
- package/docs/CHANGELOG.md +93 -0
- package/lib/cli/update.js +14 -11
- package/lib/cli/version-check.js +9 -1
- package/package.json +9 -4
- package/.agents/schemas/friction-event.schema.json +0 -56
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +0 -707
|
@@ -31,15 +31,13 @@ import {
|
|
|
31
31
|
renderAcceptanceSpecSystemPrompt,
|
|
32
32
|
renderTechSpecSystemPrompt,
|
|
33
33
|
} from '../templates/spec-author-prompts.js';
|
|
34
|
-
import { concurrentMap } from '../util/concurrent-map.js';
|
|
34
|
+
import { concurrentMap, FANOUT_CONCURRENCY } from '../util/concurrent-map.js';
|
|
35
35
|
import { buildComplexitySignals } from './complexity-gate.js';
|
|
36
36
|
import { parseDeliverySlicingTable } from './consolidation-precondition.js';
|
|
37
37
|
import { buildDocsDigest } from './docs-digest.js';
|
|
38
38
|
import { buildAuthoringContext } from './planning/authoring-context.js';
|
|
39
39
|
import { buildDecomposerSystemPrompt } from './planning/decomposer-context.js';
|
|
40
40
|
|
|
41
|
-
/** Bounded concurrency for `--tickets` source-ticket hydration. */
|
|
42
|
-
const SOURCE_TICKET_FETCH_CONCURRENCY = 4;
|
|
43
41
|
/**
|
|
44
42
|
* Envelope byte ceiling (regression guard for the design's named PR2 risk:
|
|
45
43
|
* two envelopes → one bigger one). This is the **only** live bound on
|
|
@@ -229,7 +227,8 @@ export function renderStoriesTemplate({ complexitySignals = null } = {}) {
|
|
|
229
227
|
'codes, security invariants, and load-bearing constraints with ' +
|
|
230
228
|
'their why. Implementation choices belong to the deliverer unless ' +
|
|
231
229
|
'load-bearing. No per-file behavior paragraphs, no current-state ' +
|
|
232
|
-
'narration.
|
|
230
|
+
'narration. Aim for ~250 words; an advisory warning fires past 350, ' +
|
|
231
|
+
'and it never fails the persist. ' +
|
|
233
232
|
'Delete this field when acceptance[] carries the whole contract.',
|
|
234
233
|
changes: buildTemplateChanges(complexitySignals),
|
|
235
234
|
non_goals: [],
|
|
@@ -813,6 +812,84 @@ async function searchStoryDuplicates({
|
|
|
813
812
|
}
|
|
814
813
|
}
|
|
815
814
|
|
|
815
|
+
/**
|
|
816
|
+
* Gather the three independent envelope inputs — the open-Story duplicate
|
|
817
|
+
* search, the folded authoring context, and the inline docs digest — under
|
|
818
|
+
* bounded concurrency (Story #4952).
|
|
819
|
+
*
|
|
820
|
+
* None of the three reads a value the others produce, so the result is a pure
|
|
821
|
+
* function of `seed` and the injected config: the assembled envelope is
|
|
822
|
+
* **byte-identical** to the serial build for the same inputs, whichever order
|
|
823
|
+
* the three happen to settle in. `concurrentMap` preserves input order, so the
|
|
824
|
+
* destructuring below is positional and stable.
|
|
825
|
+
*
|
|
826
|
+
* `docsContextFiles` is emptied for the `buildAuthoringContext` call: the
|
|
827
|
+
* per-plan digest-file path needs a plan id that does not exist yet — the
|
|
828
|
+
* inline digest gathered alongside it replaces that pointer.
|
|
829
|
+
*
|
|
830
|
+
* @param {{
|
|
831
|
+
* seed: string,
|
|
832
|
+
* epicTitle: string,
|
|
833
|
+
* excludeIds?: Iterable<number|string>,
|
|
834
|
+
* provider: object,
|
|
835
|
+
* config: object,
|
|
836
|
+
* settings: object,
|
|
837
|
+
* cwd?: string,
|
|
838
|
+
* }} args
|
|
839
|
+
* @returns {Promise<{
|
|
840
|
+
* duplicates: Array<object>,
|
|
841
|
+
* authoring: object,
|
|
842
|
+
* docsContext: { mode: 'digest-inline', digest: string }|null,
|
|
843
|
+
* }>}
|
|
844
|
+
*/
|
|
845
|
+
async function gatherEnvelopeInputs({
|
|
846
|
+
seed,
|
|
847
|
+
epicTitle,
|
|
848
|
+
excludeIds = [],
|
|
849
|
+
provider,
|
|
850
|
+
config,
|
|
851
|
+
settings,
|
|
852
|
+
cwd,
|
|
853
|
+
}) {
|
|
854
|
+
const paths = settings?.paths ?? {};
|
|
855
|
+
const [duplicates, authoring, inlineDigest] = await concurrentMap(
|
|
856
|
+
[
|
|
857
|
+
() => searchStoryDuplicates({ seed, provider, config, excludeIds }),
|
|
858
|
+
() =>
|
|
859
|
+
buildAuthoringContext(
|
|
860
|
+
0,
|
|
861
|
+
/* provider (unused behind the prefetch seam) */ {},
|
|
862
|
+
{ ...settings, docsContextFiles: [] },
|
|
863
|
+
{
|
|
864
|
+
epic: { id: 0, title: epicTitle, body: seed },
|
|
865
|
+
github: config.github ?? null,
|
|
866
|
+
cwd,
|
|
867
|
+
},
|
|
868
|
+
),
|
|
869
|
+
() =>
|
|
870
|
+
buildDocsDigest({
|
|
871
|
+
docsContextFiles: settings?.docsContextFiles,
|
|
872
|
+
docsRoot: paths.docsRoot,
|
|
873
|
+
}),
|
|
874
|
+
],
|
|
875
|
+
(gather) => gather(),
|
|
876
|
+
// The per-mode envelope gathers (Story #4952): the duplicate search, the
|
|
877
|
+
// authoring-context fold and the docs digest have no data dependency on
|
|
878
|
+
// one another, so their serialization was incidental and `/plan` paid it
|
|
879
|
+
// with the operator waiting at Gate #1.
|
|
880
|
+
{ concurrency: FANOUT_CONCURRENCY },
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
return {
|
|
884
|
+
duplicates,
|
|
885
|
+
authoring,
|
|
886
|
+
docsContext:
|
|
887
|
+
inlineDigest == null
|
|
888
|
+
? null
|
|
889
|
+
: { mode: 'digest-inline', digest: inlineDigest },
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
816
893
|
/**
|
|
817
894
|
* Build the seed-file (ideation) envelope. No parent ticket
|
|
818
895
|
* exists yet — creation moves to the persist half — so the open-Story
|
|
@@ -836,37 +913,17 @@ async function buildSeedFileModeEnvelope({
|
|
|
836
913
|
);
|
|
837
914
|
}
|
|
838
915
|
|
|
839
|
-
|
|
916
|
+
// Dup search, the authoring-context fold grounded in the seed prose, and the
|
|
917
|
+
// inline docs digest are independent — gathered concurrently (Story #4952).
|
|
918
|
+
const { duplicates, authoring, docsContext } = await gatherEnvelopeInputs({
|
|
840
919
|
seed: content,
|
|
920
|
+
epicTitle: seedFilePath ?? 'seed',
|
|
841
921
|
provider,
|
|
842
922
|
config,
|
|
923
|
+
settings,
|
|
924
|
+
cwd,
|
|
843
925
|
});
|
|
844
926
|
|
|
845
|
-
// Fold the authoring-context builders grounded in the seed prose.
|
|
846
|
-
// `docsContextFiles` is emptied for this call: the per-plan digest-file
|
|
847
|
-
// path needs a plan id that does not exist yet — the inline digest
|
|
848
|
-
// below replaces it.
|
|
849
|
-
const authoring = await buildAuthoringContext(
|
|
850
|
-
0,
|
|
851
|
-
/* provider (unused behind the prefetch seam) */ {},
|
|
852
|
-
{ ...settings, docsContextFiles: [] },
|
|
853
|
-
{
|
|
854
|
-
epic: { id: 0, title: seedFilePath ?? 'seed', body: content },
|
|
855
|
-
github: config.github ?? null,
|
|
856
|
-
cwd,
|
|
857
|
-
},
|
|
858
|
-
);
|
|
859
|
-
|
|
860
|
-
const paths = settings?.paths ?? {};
|
|
861
|
-
const inlineDigest = await buildDocsDigest({
|
|
862
|
-
docsContextFiles: settings?.docsContextFiles,
|
|
863
|
-
docsRoot: paths.docsRoot,
|
|
864
|
-
});
|
|
865
|
-
const docsContext =
|
|
866
|
-
inlineDigest == null
|
|
867
|
-
? null
|
|
868
|
-
: { mode: 'digest-inline', digest: inlineDigest };
|
|
869
|
-
|
|
870
927
|
const limits = getLimits(config);
|
|
871
928
|
const heuristics = resolveRiskHeuristics(config);
|
|
872
929
|
|
|
@@ -892,7 +949,7 @@ async function buildSeedFileModeEnvelope({
|
|
|
892
949
|
docsContext,
|
|
893
950
|
bddRunner: authoring.bddRunner,
|
|
894
951
|
bddScenarios: authoring.bddScenarios,
|
|
895
|
-
|
|
952
|
+
memoryPoolAdvisory: authoring.memoryPoolAdvisory,
|
|
896
953
|
priorFeedback: authoring.priorFeedback,
|
|
897
954
|
ticketSchema: TICKET_SCHEMA_DESCRIPTOR,
|
|
898
955
|
maxTickets: limits.maxTickets,
|
|
@@ -975,7 +1032,8 @@ async function fetchSourceTickets(ticketIds, provider) {
|
|
|
975
1032
|
state: ticket.state ?? undefined,
|
|
976
1033
|
};
|
|
977
1034
|
},
|
|
978
|
-
|
|
1035
|
+
// `--tickets` source-ticket hydration: one independent read per id.
|
|
1036
|
+
{ concurrency: FANOUT_CONCURRENCY },
|
|
979
1037
|
);
|
|
980
1038
|
}
|
|
981
1039
|
|
|
@@ -1001,37 +1059,18 @@ async function buildTicketsModeEnvelope({
|
|
|
1001
1059
|
.map((t) => `# ${t.title}\n\n${t.body}`)
|
|
1002
1060
|
.join('\n\n---\n\n');
|
|
1003
1061
|
|
|
1004
|
-
|
|
1062
|
+
// Same three independent gathers as seed-file mode, concurrent under the
|
|
1063
|
+
// same bound (Story #4952); only the source-ticket hydration above is a
|
|
1064
|
+
// genuine data dependency, because `seed` is derived from it.
|
|
1065
|
+
const { duplicates, authoring, docsContext } = await gatherEnvelopeInputs({
|
|
1005
1066
|
seed,
|
|
1067
|
+
epicTitle: sourceTickets[0]?.title ?? 'tickets',
|
|
1068
|
+
excludeIds: ticketIds,
|
|
1006
1069
|
provider,
|
|
1007
1070
|
config,
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
const authoring = await buildAuthoringContext(
|
|
1012
|
-
0,
|
|
1013
|
-
{},
|
|
1014
|
-
{ ...settings, docsContextFiles: [] },
|
|
1015
|
-
{
|
|
1016
|
-
epic: {
|
|
1017
|
-
id: 0,
|
|
1018
|
-
title: sourceTickets[0]?.title ?? 'tickets',
|
|
1019
|
-
body: seed,
|
|
1020
|
-
},
|
|
1021
|
-
github: config.github ?? null,
|
|
1022
|
-
cwd,
|
|
1023
|
-
},
|
|
1024
|
-
);
|
|
1025
|
-
|
|
1026
|
-
const paths = settings?.paths ?? {};
|
|
1027
|
-
const inlineDigest = await buildDocsDigest({
|
|
1028
|
-
docsContextFiles: settings?.docsContextFiles,
|
|
1029
|
-
docsRoot: paths.docsRoot,
|
|
1071
|
+
settings,
|
|
1072
|
+
cwd,
|
|
1030
1073
|
});
|
|
1031
|
-
const docsContext =
|
|
1032
|
-
inlineDigest == null
|
|
1033
|
-
? null
|
|
1034
|
-
: { mode: 'digest-inline', digest: inlineDigest };
|
|
1035
1074
|
|
|
1036
1075
|
const limits = getLimits(config);
|
|
1037
1076
|
const heuristics = resolveRiskHeuristics(config);
|
|
@@ -1053,7 +1092,7 @@ async function buildTicketsModeEnvelope({
|
|
|
1053
1092
|
docsContext,
|
|
1054
1093
|
bddRunner: authoring.bddRunner,
|
|
1055
1094
|
bddScenarios: authoring.bddScenarios,
|
|
1056
|
-
|
|
1095
|
+
memoryPoolAdvisory: authoring.memoryPoolAdvisory,
|
|
1057
1096
|
priorFeedback: authoring.priorFeedback,
|
|
1058
1097
|
ticketSchema: TICKET_SCHEMA_DESCRIPTOR,
|
|
1059
1098
|
maxTickets: limits.maxTickets,
|
|
@@ -1147,12 +1186,26 @@ async function buildAmendmentModeEnvelope({
|
|
|
1147
1186
|
|
|
1148
1187
|
const heuristics = resolveRiskHeuristics(config);
|
|
1149
1188
|
const limits = getLimits(config);
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1189
|
+
// Story #4952 — this builder's independent-gather set has exactly one
|
|
1190
|
+
// member. `provider.getTicket` above is a hard data dependency (the prior
|
|
1191
|
+
// body IS the seed), and the mode deliberately carries no authoring-context
|
|
1192
|
+
// fold and no docs digest — the prior artifacts are the grounding. It still
|
|
1193
|
+
// goes through the same bounded gather as the other two builders so one file
|
|
1194
|
+
// does not carry two ways of gathering independent envelope inputs.
|
|
1195
|
+
const [duplicates] = await concurrentMap(
|
|
1196
|
+
[
|
|
1197
|
+
() =>
|
|
1198
|
+
searchStoryDuplicates({
|
|
1199
|
+
seed: priorBody,
|
|
1200
|
+
provider,
|
|
1201
|
+
config,
|
|
1202
|
+
excludeIds: [amendsId],
|
|
1203
|
+
}),
|
|
1204
|
+
],
|
|
1205
|
+
(gather) => gather(),
|
|
1206
|
+
// Same independent-gather fan-out as the seed-mode envelope above.
|
|
1207
|
+
{ concurrency: FANOUT_CONCURRENCY },
|
|
1208
|
+
);
|
|
1156
1209
|
|
|
1157
1210
|
return {
|
|
1158
1211
|
mode: 'amends',
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Logger } from '../../Logger.js';
|
|
9
9
|
import {
|
|
10
|
+
CONFLICT_KINDS,
|
|
10
11
|
renderFanOutEvidence,
|
|
11
12
|
renderFanOutRemedy,
|
|
12
13
|
renderHardConflictError,
|
|
@@ -54,6 +55,15 @@ export function enforceFanOutGate(
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
58
|
+
* Report every soft finding the validator produced, each under its own kind.
|
|
59
|
+
*
|
|
60
|
+
* Only the {@link CONFLICT_KINDS} are cross-Story conflicts. The advisory
|
|
61
|
+
* kinds — `spec-word-budget` and the sizing findings — are single-Story
|
|
62
|
+
* nudges, and announcing them as conflicts overstated them and taught readers
|
|
63
|
+
* to discount the whole channel (Story #4907). `fan-out-warning` is excluded
|
|
64
|
+
* throughout: {@link enforceFanOutGate} owns it and has already either thrown
|
|
65
|
+
* or logged the override.
|
|
66
|
+
*
|
|
57
67
|
* @param {object[]} findings
|
|
58
68
|
* @param {string} [tag]
|
|
59
69
|
*/
|
|
@@ -62,10 +72,26 @@ export function surfaceSoftConflictFindings(findings, tag = 'plan-persist') {
|
|
|
62
72
|
(f) => f?.severity === 'soft' && f?.kind !== 'fan-out-warning',
|
|
63
73
|
);
|
|
64
74
|
if (soft.length === 0) return;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
const conflicts = soft.filter((f) => CONFLICT_KINDS.has(f?.kind));
|
|
76
|
+
const advisories = soft.filter((f) => !CONFLICT_KINDS.has(f?.kind));
|
|
77
|
+
if (conflicts.length > 0) {
|
|
78
|
+
Logger.warn(
|
|
79
|
+
`[${tag}] ${conflicts.length} soft cross-Story conflict finding(s) — review before approving the plan:`,
|
|
80
|
+
);
|
|
81
|
+
for (const finding of conflicts) {
|
|
82
|
+
Logger.warn(
|
|
83
|
+
`[${tag}] soft conflict: ${renderHardConflictError(finding)}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (advisories.length > 0) {
|
|
88
|
+
Logger.warn(
|
|
89
|
+
`[${tag}] ${advisories.length} advisory finding(s) — the persist proceeds:`,
|
|
90
|
+
);
|
|
91
|
+
for (const finding of advisories) {
|
|
92
|
+
Logger.warn(
|
|
93
|
+
`[${tag}] advisory (${finding.kind}): ${renderHardConflictError(finding)}`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
70
96
|
}
|
|
71
97
|
}
|