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
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* context-envelope.js — typed ContextEnvelope SDK for the hydration pipeline
|
|
3
|
-
* (Epic #2648, Story #2762).
|
|
4
|
-
*
|
|
5
|
-
* Pure functions with no I/O. Downstream Stories assemble sections from ticket
|
|
6
|
-
* fetches and file reads, then serialize via {@link envelopeToPrompt}.
|
|
7
|
-
*
|
|
8
|
-
* @module lib/orchestration/context-envelope
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** @typedef {'protocolPolicy' | 'skillCapsules' | 'hierarchy' | 'acceptanceCriteria' | 'verificationCommands' | 'taskInstructions'} SectionName */
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {object} SectionSource
|
|
15
|
-
* @property {'file' | 'ticket' | 'derived'} kind
|
|
16
|
-
* @property {string} ref
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {object} Section
|
|
21
|
-
* @property {SectionName} name
|
|
22
|
-
* @property {number} priority Lower numbers are elided first.
|
|
23
|
-
* @property {'drop' | 'summarize'} elideWhenOverBudget
|
|
24
|
-
* @property {string} content
|
|
25
|
-
* @property {number} estimatedTokens
|
|
26
|
-
* @property {SectionSource} [source]
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {object} TicketSnapshot
|
|
31
|
-
* @property {number} id
|
|
32
|
-
* @property {string} version ISO 8601 ticket updatedAt
|
|
33
|
-
* @property {string} hash sha256(body) truncated to 12 hex chars
|
|
34
|
-
* @property {string} retrievedAt ISO 8601 at fetch time
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @typedef {object} ContextEnvelope
|
|
39
|
-
* @property {'1'} schemaVersion
|
|
40
|
-
* @property {{ id: number, title: string, skills?: string[], protocolVersion?: string }} task
|
|
41
|
-
* @property {Section[]} sections
|
|
42
|
-
* @property {TicketSnapshot[]} provenance
|
|
43
|
-
* @property {{ maxTokens: number, used: number, elided: string[] }} budget
|
|
44
|
-
* @property {string[]} warnings
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
/** Separator between rendered sections — matches legacy hydrateContext join. */
|
|
48
|
-
export const PROMPT_SECTION_SEPARATOR =
|
|
49
|
-
'\n\n========================================================================\n\n';
|
|
50
|
-
|
|
51
|
-
/** Rendering order for {@link envelopeToPrompt} (not elision priority). */
|
|
52
|
-
export const SECTION_RENDER_ORDER = Object.freeze([
|
|
53
|
-
'protocolPolicy',
|
|
54
|
-
'skillCapsules',
|
|
55
|
-
'hierarchy',
|
|
56
|
-
'acceptanceCriteria',
|
|
57
|
-
'verificationCommands',
|
|
58
|
-
'taskInstructions',
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
|
-
/** Default elision priority per section name (lower drops first). */
|
|
62
|
-
export const DEFAULT_SECTION_PRIORITIES = Object.freeze({
|
|
63
|
-
skillCapsules: 10,
|
|
64
|
-
hierarchy: 20,
|
|
65
|
-
acceptanceCriteria: 30,
|
|
66
|
-
verificationCommands: 40,
|
|
67
|
-
protocolPolicy: 80,
|
|
68
|
-
taskInstructions: 100,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
/** Default elide policy per section name. */
|
|
72
|
-
export const DEFAULT_ELIDE_POLICIES = Object.freeze({
|
|
73
|
-
skillCapsules: 'summarize',
|
|
74
|
-
hierarchy: 'summarize',
|
|
75
|
-
acceptanceCriteria: 'summarize',
|
|
76
|
-
verificationCommands: 'drop',
|
|
77
|
-
protocolPolicy: 'drop',
|
|
78
|
-
taskInstructions: 'drop',
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const SUMMARIZE_HEAD_CHARS = 200;
|
|
82
|
-
const TASK_INSTRUCTIONS = 'taskInstructions';
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Rough token estimate matching legacy {@link truncateToTokenBudget}.
|
|
86
|
-
*
|
|
87
|
-
* @param {string} text
|
|
88
|
-
* @returns {number}
|
|
89
|
-
*/
|
|
90
|
-
export function estimateTokens(text) {
|
|
91
|
-
return Math.ceil(String(text ?? '').length / 4);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Normalize a section: stamp estimatedTokens when absent.
|
|
96
|
-
*
|
|
97
|
-
* @param {Section} section
|
|
98
|
-
* @returns {Section}
|
|
99
|
-
*/
|
|
100
|
-
function normalizeSection(section) {
|
|
101
|
-
const content = String(section.content ?? '');
|
|
102
|
-
return {
|
|
103
|
-
...section,
|
|
104
|
-
content,
|
|
105
|
-
estimatedTokens:
|
|
106
|
-
typeof section.estimatedTokens === 'number'
|
|
107
|
-
? section.estimatedTokens
|
|
108
|
-
: estimateTokens(content),
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Sum estimatedTokens across sections.
|
|
114
|
-
*
|
|
115
|
-
* @param {Section[]} sections
|
|
116
|
-
* @returns {number}
|
|
117
|
-
*/
|
|
118
|
-
function totalSectionTokens(sections) {
|
|
119
|
-
return sections.reduce((sum, s) => sum + s.estimatedTokens, 0);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Build a {@link ContextEnvelope} from assembled parts.
|
|
124
|
-
*
|
|
125
|
-
* @param {{
|
|
126
|
-
* task: ContextEnvelope['task'],
|
|
127
|
-
* sections: Section[],
|
|
128
|
-
* provenance?: TicketSnapshot[],
|
|
129
|
-
* warnings?: string[],
|
|
130
|
-
* maxTokens?: number,
|
|
131
|
-
* }} parts
|
|
132
|
-
* @returns {ContextEnvelope}
|
|
133
|
-
*/
|
|
134
|
-
export function buildEnvelope(parts) {
|
|
135
|
-
const sections = (parts.sections ?? []).map(normalizeSection);
|
|
136
|
-
const used = totalSectionTokens(sections);
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
schemaVersion: '1',
|
|
140
|
-
task: parts.task,
|
|
141
|
-
sections,
|
|
142
|
-
provenance: parts.provenance ?? [],
|
|
143
|
-
budget: {
|
|
144
|
-
maxTokens: parts.maxTokens ?? used,
|
|
145
|
-
used,
|
|
146
|
-
elided: [],
|
|
147
|
-
},
|
|
148
|
-
warnings: parts.warnings ?? [],
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Deterministic summary for over-budget sections.
|
|
154
|
-
*
|
|
155
|
-
* @param {string} content
|
|
156
|
-
* @returns {{ content: string, estimatedTokens: number, droppedTokens: number }}
|
|
157
|
-
*/
|
|
158
|
-
function summarizeSectionContent(content) {
|
|
159
|
-
const originalTokens = estimateTokens(content);
|
|
160
|
-
if (content.length <= SUMMARIZE_HEAD_CHARS) {
|
|
161
|
-
return { content, estimatedTokens: originalTokens, droppedTokens: 0 };
|
|
162
|
-
}
|
|
163
|
-
const head = content.slice(0, SUMMARIZE_HEAD_CHARS);
|
|
164
|
-
const droppedTokens = originalTokens - estimateTokens(head);
|
|
165
|
-
const summary = `${head}…[elided, ${droppedTokens} tokens dropped]`;
|
|
166
|
-
return {
|
|
167
|
-
content: summary,
|
|
168
|
-
estimatedTokens: estimateTokens(summary),
|
|
169
|
-
droppedTokens,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Apply section-aware elision against a token budget.
|
|
175
|
-
*
|
|
176
|
-
* Sections iterate in ascending priority order. `taskInstructions` is never
|
|
177
|
-
* dropped or summarized. When still over budget after all eligible sections
|
|
178
|
-
* are elided, a warning is appended and task instructions remain intact.
|
|
179
|
-
*
|
|
180
|
-
* @param {ContextEnvelope} envelope
|
|
181
|
-
* @param {number} maxTokens
|
|
182
|
-
* @returns {ContextEnvelope}
|
|
183
|
-
*/
|
|
184
|
-
export function elideEnvelope(envelope, maxTokens) {
|
|
185
|
-
const sections = envelope.sections.map((s) => ({ ...s }));
|
|
186
|
-
let used = totalSectionTokens(sections);
|
|
187
|
-
|
|
188
|
-
if (used <= maxTokens) {
|
|
189
|
-
return {
|
|
190
|
-
...envelope,
|
|
191
|
-
budget: { maxTokens, used, elided: [] },
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const elided = [];
|
|
196
|
-
const byPriority = [...sections].sort((a, b) => a.priority - b.priority);
|
|
197
|
-
|
|
198
|
-
for (const template of byPriority) {
|
|
199
|
-
if (used <= maxTokens) break;
|
|
200
|
-
if (template.name === TASK_INSTRUCTIONS) continue;
|
|
201
|
-
|
|
202
|
-
const idx = sections.findIndex((s) => s.name === template.name);
|
|
203
|
-
if (idx === -1) continue;
|
|
204
|
-
|
|
205
|
-
const current = sections[idx];
|
|
206
|
-
if (!current.content) continue;
|
|
207
|
-
|
|
208
|
-
if (current.elideWhenOverBudget === 'summarize') {
|
|
209
|
-
const { content, estimatedTokens } = summarizeSectionContent(
|
|
210
|
-
current.content,
|
|
211
|
-
);
|
|
212
|
-
sections[idx] = { ...current, content, estimatedTokens };
|
|
213
|
-
} else {
|
|
214
|
-
sections[idx] = { ...current, content: '', estimatedTokens: 0 };
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (!elided.includes(template.name)) {
|
|
218
|
-
elided.push(template.name);
|
|
219
|
-
}
|
|
220
|
-
used = totalSectionTokens(sections);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const warnings = [...envelope.warnings];
|
|
224
|
-
if (used > maxTokens) {
|
|
225
|
-
warnings.push(
|
|
226
|
-
`⚠️ Context envelope still over token budget after elision (${used}/${maxTokens} tokens). Task instructions preserved intact.`,
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return {
|
|
231
|
-
...envelope,
|
|
232
|
-
sections,
|
|
233
|
-
warnings,
|
|
234
|
-
budget: { maxTokens, used, elided },
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Serialize a {@link ContextEnvelope} to the legacy prose prompt form.
|
|
240
|
-
*
|
|
241
|
-
* Warnings are prepended, then non-empty sections are joined in
|
|
242
|
-
* {@link SECTION_RENDER_ORDER} with {@link PROMPT_SECTION_SEPARATOR}.
|
|
243
|
-
* Identical envelope input yields byte-identical output.
|
|
244
|
-
*
|
|
245
|
-
* @param {ContextEnvelope} envelope
|
|
246
|
-
* @returns {string}
|
|
247
|
-
*/
|
|
248
|
-
export function envelopeToPrompt(envelope) {
|
|
249
|
-
const sectionByName = new Map(
|
|
250
|
-
envelope.sections.map((section) => [section.name, section]),
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
const parts = [];
|
|
254
|
-
|
|
255
|
-
const warningsText = (envelope.warnings ?? [])
|
|
256
|
-
.map((w) => String(w).trim())
|
|
257
|
-
.filter(Boolean)
|
|
258
|
-
.join('\n\n');
|
|
259
|
-
if (warningsText) {
|
|
260
|
-
parts.push(warningsText);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
for (const name of SECTION_RENDER_ORDER) {
|
|
264
|
-
const section = sectionByName.get(name);
|
|
265
|
-
if (section?.content) {
|
|
266
|
-
parts.push(section.content);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
for (const section of envelope.sections) {
|
|
271
|
-
if (!SECTION_RENDER_ORDER.includes(section.name) && section.content) {
|
|
272
|
-
parts.push(section.content);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return parts.join(PROMPT_SECTION_SEPARATOR);
|
|
277
|
-
}
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* detectors-phase.js — pure phase that runs the per-Story signal detectors
|
|
3
|
-
* (rework + retry) over the local NDJSON stream.
|
|
4
|
-
*
|
|
5
|
-
* Story #4545 — this phase has no production caller. Its sequencer
|
|
6
|
-
* (`post-merge-pipeline.js`) went in the v2.0.0 cutover, and the
|
|
7
|
-
* `analyze-execution.js` consumer it fed was deleted with the
|
|
8
|
-
* execution-analysis surface. Kept alive only by its own test — the
|
|
9
|
-
* test-importer blind spot the dead-exports ratchet cannot see.
|
|
10
|
-
*
|
|
11
|
-
* Extracted from `post-merge-pipeline.js` (Story #1770 / Task #1779) to
|
|
12
|
-
* keep the parent sequencer's maintainability score above its baseline
|
|
13
|
-
* after the new wiring layer landed. The phase contract is identical to
|
|
14
|
-
* every other entry in `DEFAULT_POST_MERGE_PHASES`: take a context bag,
|
|
15
|
-
* return a value the runner stitches under a `stateKey`.
|
|
16
|
-
*
|
|
17
|
-
* ### Contract
|
|
18
|
-
*
|
|
19
|
-
* - **Pure detectors.** Both `detectRework` and `detectRetry` are pure
|
|
20
|
-
* modules under `lib/signals/detectors/` — they read the per-Story
|
|
21
|
-
* `traces.ndjson` and return SignalEvent arrays. This phase resolves
|
|
22
|
-
* the operator-tunable thresholds via `getSignals(config)` (Epic
|
|
23
|
-
* #1720 — `delivery.signals.*`), invokes each detector, and persists
|
|
24
|
-
* each event through `appendSignal` so the per-Story `signals.ndjson`
|
|
25
|
-
* stream covers both kinds before the analyzer reads it.
|
|
26
|
-
*
|
|
27
|
-
* - **Failure isolation.** A failing detector or a per-event append
|
|
28
|
-
* MUST NOT block Task close. Each call is wrapped in try/catch;
|
|
29
|
-
* failures degrade to a warn and contribute 0 to the offending
|
|
30
|
-
* detector's count. The phase always resolves with a stable
|
|
31
|
-
* `{ rework: N, retry: N }` shape.
|
|
32
|
-
*
|
|
33
|
-
* - **One info line per close.** The summary log
|
|
34
|
-
* (`detectors: rework=N retry=M`) is the only stdout signal — one
|
|
35
|
-
* line per Story rather than two per detector + N per event.
|
|
36
|
-
*
|
|
37
|
-
* - **2-tier (Storyless) closure (Story #3127).** When `tasks` is
|
|
38
|
-
* empty (the 2-tier hierarchy shape), `resolveLastTaskId` returns
|
|
39
|
-
* `null` and both detectors run with `taskId: null`. The detector
|
|
40
|
-
* modules already accept a nullable `taskId` (see
|
|
41
|
-
* `lib/signals/detectors/{rework,retry}.js`), so no branching on
|
|
42
|
-
* hierarchy mode is required here.
|
|
43
|
-
*
|
|
44
|
-
* @module lib/orchestration/detectors-phase
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
import path from 'node:path';
|
|
48
|
-
import { getSignals } from '../config/limits.js';
|
|
49
|
-
import { storyTempDir } from '../config/temp-paths.js';
|
|
50
|
-
import { Logger } from '../Logger.js';
|
|
51
|
-
import { appendSignal } from '../observability/signals-writer.js';
|
|
52
|
-
import { detectRetry, detectRework } from '../signals/detectors/index.js';
|
|
53
|
-
|
|
54
|
-
function reapPhaseLogger(progress) {
|
|
55
|
-
return progress ?? (() => {});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function resolveLastTaskId(tasks) {
|
|
59
|
-
if (!Array.isArray(tasks) || tasks.length === 0) return null;
|
|
60
|
-
const last = tasks[tasks.length - 1];
|
|
61
|
-
const id = Number(last?.id ?? last);
|
|
62
|
-
return Number.isInteger(id) && id > 0 ? id : null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async function persistDetectorEvents({
|
|
66
|
-
events,
|
|
67
|
-
epicId,
|
|
68
|
-
storyId,
|
|
69
|
-
config,
|
|
70
|
-
appendSignalFn,
|
|
71
|
-
logger,
|
|
72
|
-
kind,
|
|
73
|
-
}) {
|
|
74
|
-
let count = 0;
|
|
75
|
-
for (const evt of events) {
|
|
76
|
-
try {
|
|
77
|
-
await appendSignalFn({ epicId, storyId, signal: evt, config });
|
|
78
|
-
count += 1;
|
|
79
|
-
} catch (err) {
|
|
80
|
-
logger?.warn?.(
|
|
81
|
-
`[detectors-phase] ${kind} appendSignal failed (${err?.message ?? err})`,
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return count;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function runOneDetector({
|
|
89
|
-
detectorFn,
|
|
90
|
-
args,
|
|
91
|
-
epicId,
|
|
92
|
-
storyId,
|
|
93
|
-
config,
|
|
94
|
-
appendSignalFn,
|
|
95
|
-
logger,
|
|
96
|
-
kind,
|
|
97
|
-
}) {
|
|
98
|
-
try {
|
|
99
|
-
const events = await detectorFn(args);
|
|
100
|
-
return await persistDetectorEvents({
|
|
101
|
-
events,
|
|
102
|
-
epicId,
|
|
103
|
-
storyId,
|
|
104
|
-
config,
|
|
105
|
-
appendSignalFn,
|
|
106
|
-
logger,
|
|
107
|
-
kind,
|
|
108
|
-
});
|
|
109
|
-
} catch (err) {
|
|
110
|
-
logger?.warn?.(
|
|
111
|
-
`[detectors-phase] ${kind} detector threw (${err?.message ?? err})`,
|
|
112
|
-
);
|
|
113
|
-
return 0;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function isValidIdPair(eid, sid) {
|
|
118
|
-
return Number.isInteger(eid) && eid > 0 && Number.isInteger(sid) && sid > 0;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Run the rework + retry detectors for one Story and persist every
|
|
123
|
-
* emission to `temp/run-<id>/stories/story-<sid>/signals.ndjson`.
|
|
124
|
-
*
|
|
125
|
-
* @param {{
|
|
126
|
-
* epicId: number|string,
|
|
127
|
-
* storyId: number|string,
|
|
128
|
-
* tasks?: Array<{ id?: number|string }>,
|
|
129
|
-
* config?: object,
|
|
130
|
-
* progress?: Function,
|
|
131
|
-
* logger?: object,
|
|
132
|
-
* detectorsImpl?: { detectRework?: typeof detectRework, detectRetry?: typeof detectRetry },
|
|
133
|
-
* appendSignalFn?: typeof appendSignal,
|
|
134
|
-
* }} ctx
|
|
135
|
-
* @returns {Promise<{ rework: number, retry: number }>}
|
|
136
|
-
*/
|
|
137
|
-
export async function detectorsPhase(ctx) {
|
|
138
|
-
const {
|
|
139
|
-
epicId,
|
|
140
|
-
storyId,
|
|
141
|
-
tasks,
|
|
142
|
-
config,
|
|
143
|
-
progress,
|
|
144
|
-
logger = Logger,
|
|
145
|
-
detectorsImpl,
|
|
146
|
-
appendSignalFn = appendSignal,
|
|
147
|
-
} = ctx;
|
|
148
|
-
const log = reapPhaseLogger(progress);
|
|
149
|
-
const eid = Number(epicId);
|
|
150
|
-
const sid = Number(storyId);
|
|
151
|
-
if (!isValidIdPair(eid, sid)) {
|
|
152
|
-
logger?.warn?.(
|
|
153
|
-
`[detectors-phase] skipped: invalid epicId=${epicId} / storyId=${storyId}`,
|
|
154
|
-
);
|
|
155
|
-
return { rework: 0, retry: 0 };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
let signalsCfg;
|
|
159
|
-
try {
|
|
160
|
-
signalsCfg = getSignals(config);
|
|
161
|
-
} catch (err) {
|
|
162
|
-
logger?.warn?.(
|
|
163
|
-
`[detectors-phase] getSignals failed (${err?.message ?? err}); using zero counts`,
|
|
164
|
-
);
|
|
165
|
-
return { rework: 0, retry: 0 };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const tracesPath = path.join(storyTempDir(eid, sid, config), 'traces.ndjson');
|
|
169
|
-
const taskId = resolveLastTaskId(tasks);
|
|
170
|
-
const baseArgs = { tracesPath, epicId: eid, storyId: sid, taskId };
|
|
171
|
-
const common = {
|
|
172
|
-
epicId: eid,
|
|
173
|
-
storyId: sid,
|
|
174
|
-
config,
|
|
175
|
-
appendSignalFn,
|
|
176
|
-
logger,
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const rework = await runOneDetector({
|
|
180
|
-
...common,
|
|
181
|
-
detectorFn: detectorsImpl?.detectRework ?? detectRework,
|
|
182
|
-
args: { ...baseArgs, threshold: signalsCfg.rework.editsPerFile },
|
|
183
|
-
kind: 'rework',
|
|
184
|
-
});
|
|
185
|
-
const retry = await runOneDetector({
|
|
186
|
-
...common,
|
|
187
|
-
detectorFn: detectorsImpl?.detectRetry ?? detectRetry,
|
|
188
|
-
args: { ...baseArgs, threshold: signalsCfg.retry.repeatCount },
|
|
189
|
-
kind: 'retry',
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
log('DETECTORS', `detectors: rework=${rework} retry=${retry}`);
|
|
193
|
-
return { rework, retry };
|
|
194
|
-
}
|