scene-capability-engine 3.6.32 → 3.6.37
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/CHANGELOG.md +109 -11
- package/README.md +119 -122
- package/README.zh.md +123 -121
- package/bin/scene-capability-engine.js +12 -1
- package/docs/331-poc-adaptation-roadmap.md +3 -3
- package/docs/README.md +21 -32
- package/docs/auto-refactor-index.md +384 -0
- package/docs/command-reference.md +99 -7
- package/docs/faq.md +1 -1
- package/docs/interactive-customization/331-poc-sce-integration-checklist.md +3 -3
- package/docs/interactive-customization/moqui-interactive-template-playbook.md +4 -4
- package/docs/interactive-customization/phase-acceptance-evidence.md +2 -2
- package/docs/magicball-adaptation-task-checklist-v1.md +385 -0
- package/docs/magicball-app-bundle-sqlite-and-command-draft.md +539 -0
- package/docs/magicball-capability-iteration-api.md +2 -0
- package/docs/magicball-capability-iteration-ui.md +2 -0
- package/docs/magicball-capability-library.md +2 -0
- package/docs/magicball-cli-invocation-examples.md +336 -0
- package/docs/magicball-frontend-state-and-command-mapping.md +244 -0
- package/docs/magicball-integration-doc-index.md +137 -0
- package/docs/magicball-integration-issue-tracker.md +218 -0
- package/docs/magicball-mode-home-and-ontology-empty-state-playbook.md +249 -0
- package/docs/magicball-sce-adaptation-guide.md +203 -0
- package/docs/magicball-three-mode-alignment-plan.md +551 -0
- package/docs/magicball-ui-surface-checklist.md +126 -0
- package/docs/magicball-write-auth-adaptation-guide.md +328 -0
- package/docs/moqui-standard-rebuild-guide.md +6 -6
- package/docs/moqui-template-core-library-playbook.md +1 -1
- package/docs/refactor-completion-roadmap.md +116 -0
- package/docs/release-checklist.md +50 -27
- package/docs/releases/README.md +1 -0
- package/docs/releases/v3.6.37.md +22 -0
- package/docs/steering-strategy-guide.md +7 -7
- package/docs/troubleshooting.md +1 -1
- package/docs/zh/README.md +27 -30
- package/docs/zh/refactor-completion-roadmap.md +116 -0
- package/docs/zh/release-checklist.md +40 -17
- package/docs/zh/releases/README.md +1 -0
- package/docs/zh/releases/v3.6.37.md +22 -0
- package/lib/app/registry-config.js +73 -0
- package/lib/app/registry-sync-service.js +228 -0
- package/lib/auto/archive-schema-service.js +276 -0
- package/lib/auto/archive-summary.js +60 -0
- package/lib/auto/batch-goal-input-service.js +543 -0
- package/lib/auto/batch-output.js +201 -0
- package/lib/auto/batch-summary-storage-service.js +110 -0
- package/lib/auto/close-loop-batch-service.js +116 -0
- package/lib/auto/close-loop-controller-service.js +287 -0
- package/lib/auto/close-loop-program-service.js +283 -0
- package/lib/auto/close-loop-recovery-service.js +191 -0
- package/lib/auto/close-loop-session-storage-service.js +50 -0
- package/lib/auto/controller-lock-service.js +55 -0
- package/lib/auto/controller-output.js +32 -0
- package/lib/auto/controller-queue-service.js +127 -0
- package/lib/auto/controller-session-storage-service.js +105 -0
- package/lib/auto/governance-advisory-service.js +208 -0
- package/lib/auto/governance-close-loop-service.js +411 -0
- package/lib/auto/governance-maintenance-presenter.js +162 -0
- package/lib/auto/governance-maintenance-service.js +112 -0
- package/lib/auto/governance-session-presenter.js +70 -0
- package/lib/auto/governance-session-storage-service.js +198 -0
- package/lib/auto/governance-signals.js +139 -0
- package/lib/auto/governance-stats-presenter.js +337 -0
- package/lib/auto/governance-stats-service.js +115 -0
- package/lib/auto/governance-summary.js +703 -0
- package/lib/auto/handoff-capability-matrix-service.js +281 -0
- package/lib/auto/handoff-evidence-review-service.js +251 -0
- package/lib/auto/handoff-release-evidence-service.js +190 -0
- package/lib/auto/handoff-release-gate-history-loaders-service.js +502 -0
- package/lib/auto/handoff-release-gate-history-service.js +257 -0
- package/lib/auto/handoff-reporting-service.js +1407 -0
- package/lib/auto/handoff-run-service.js +486 -0
- package/lib/auto/handoff-snapshots-service.js +645 -0
- package/lib/auto/observability-service.js +132 -0
- package/lib/auto/output-writer.js +34 -0
- package/lib/auto/program-auto-remediation-service.js +130 -0
- package/lib/auto/program-diagnostics.js +138 -0
- package/lib/auto/program-governance-helpers.js +306 -0
- package/lib/auto/program-governance-loop-service.js +413 -0
- package/lib/auto/program-output.js +106 -0
- package/lib/auto/program-summary.js +183 -0
- package/lib/auto/recovery-memory-service.js +684 -0
- package/lib/auto/recovery-selection-service.js +52 -0
- package/lib/auto/retention-policy.js +98 -0
- package/lib/auto/session-persistence-service.js +106 -0
- package/lib/auto/session-presenter.js +105 -0
- package/lib/auto/session-prune-service.js +190 -0
- package/lib/auto/session-query-service.js +249 -0
- package/lib/auto/spec-protection.js +141 -0
- package/lib/commands/adopt.js +4 -4
- package/lib/commands/app.js +911 -0
- package/lib/commands/assurance.js +212 -0
- package/lib/commands/auto.js +1093 -11065
- package/lib/commands/mode.js +321 -0
- package/lib/commands/ontology.js +415 -0
- package/lib/commands/pm.js +422 -0
- package/lib/ontology/seed-profiles.js +160 -0
- package/lib/spec/bootstrap/context-collector.js +1 -1
- package/lib/state/sce-state-store.js +3369 -1200
- package/lib/steering/adoption-config.js +2 -2
- package/lib/steering/compliance-cache.js +2 -2
- package/lib/steering/steering-manager.js +4 -4
- package/lib/task/task-claimer.js +1 -2
- package/lib/workspace/multi/workspace-context-resolver.js +3 -3
- package/lib/workspace/multi/workspace-state-manager.js +0 -164
- package/lib/workspace/sce-tracking-audit.js +1 -1
- package/lib/workspace/takeover-baseline.js +1 -1
- package/package.json +1 -1
- package/template/.sce/README.md +1 -1
- package/template/.sce/steering/CORE_PRINCIPLES.md +1 -1
- package/bin/kse.js +0 -3
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
function hasRecoverableProgramGoals(summary, dependencies = {}) {
|
|
2
|
+
const getBatchFailureStatusSet = dependencies.getBatchFailureStatusSet;
|
|
3
|
+
const failedStatuses = getBatchFailureStatusSet();
|
|
4
|
+
const results = Array.isArray(summary && summary.results) ? summary.results : [];
|
|
5
|
+
return results.some(item => failedStatuses.has(`${item && item.status ? item.status : ''}`.trim().toLowerCase()));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function applyProgramGovernancePatch(baseOptions, patch) {
|
|
9
|
+
const merged = { ...baseOptions };
|
|
10
|
+
const sourcePatch = patch && typeof patch === 'object' ? patch : {};
|
|
11
|
+
for (const [key, value] of Object.entries(sourcePatch)) {
|
|
12
|
+
if (value === undefined) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
merged[key] = value;
|
|
16
|
+
}
|
|
17
|
+
return merged;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function buildProgramGovernanceReplayGoalsResult(baseGoalsResult, round, summary) {
|
|
21
|
+
const source = baseGoalsResult && typeof baseGoalsResult === 'object'
|
|
22
|
+
? baseGoalsResult
|
|
23
|
+
: { file: '(generated-from-goal)', goals: [] };
|
|
24
|
+
const sourceSummary = summary && typeof summary === 'object' ? summary : {};
|
|
25
|
+
return {
|
|
26
|
+
...source,
|
|
27
|
+
file: source.file || '(generated-from-goal)',
|
|
28
|
+
resumedFromSummary: {
|
|
29
|
+
file: sourceSummary.batch_session && sourceSummary.batch_session.file
|
|
30
|
+
? sourceSummary.batch_session.file
|
|
31
|
+
: '(program-governance-replay)',
|
|
32
|
+
strategy: 'program-governance-replay',
|
|
33
|
+
round,
|
|
34
|
+
previous_status: sourceSummary.status || null,
|
|
35
|
+
previous_total_goals: Number(sourceSummary.total_goals) || null,
|
|
36
|
+
previous_processed_goals: Number(sourceSummary.processed_goals) || null
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function runProgramGovernanceLoop(context = {}, dependencies = {}) {
|
|
42
|
+
const {
|
|
43
|
+
normalizeProgramGovernMaxRounds,
|
|
44
|
+
normalizeProgramGovernMaxMinutes,
|
|
45
|
+
normalizeProgramGovernAnomalyWeeks,
|
|
46
|
+
normalizeAutoKpiTrendPeriod,
|
|
47
|
+
normalizeProgramGovernUseAction,
|
|
48
|
+
resolveProgramGatePolicy,
|
|
49
|
+
normalizeRecoveryMemoryToken,
|
|
50
|
+
normalizeResumeStrategy,
|
|
51
|
+
normalizeRecoverMaxRounds,
|
|
52
|
+
normalizeRecoverMaxMinutes,
|
|
53
|
+
isSpecSessionBudgetHardFailure,
|
|
54
|
+
isSpecSessionGrowthGuardHardFailure,
|
|
55
|
+
buildAutoKpiTrend,
|
|
56
|
+
buildProgramAnomalyGovernancePatch,
|
|
57
|
+
loadCloseLoopRecoveryMemory,
|
|
58
|
+
buildRecoveryMemorySignature,
|
|
59
|
+
getRecoveryMemoryEntry,
|
|
60
|
+
resolveRecoveryActionSelection,
|
|
61
|
+
loadCloseLoopBatchSummaryPayload,
|
|
62
|
+
executeCloseLoopRecoveryCycle,
|
|
63
|
+
mergeProgramRecoveryIntoProgramSummary,
|
|
64
|
+
executeCloseLoopBatch,
|
|
65
|
+
buildProgramKpiSnapshot,
|
|
66
|
+
buildProgramDiagnostics,
|
|
67
|
+
buildProgramCoordinationSnapshot,
|
|
68
|
+
applyProgramGateOutcome,
|
|
69
|
+
getBatchFailureStatusSet,
|
|
70
|
+
now = () => Date.now(),
|
|
71
|
+
cwd = () => process.cwd()
|
|
72
|
+
} = dependencies;
|
|
73
|
+
|
|
74
|
+
let summary = context.summary && typeof context.summary === 'object' ? context.summary : {};
|
|
75
|
+
const projectPath = context.projectPath || cwd();
|
|
76
|
+
const baseProgramOptions = context.programOptions && typeof context.programOptions === 'object'
|
|
77
|
+
? context.programOptions
|
|
78
|
+
: {};
|
|
79
|
+
const baseGoalsResult = context.baseGoalsResult && typeof context.baseGoalsResult === 'object'
|
|
80
|
+
? context.baseGoalsResult
|
|
81
|
+
: { file: '(generated-from-goal)', goals: [] };
|
|
82
|
+
const enabled = Boolean(context.enabled);
|
|
83
|
+
const maxRounds = normalizeProgramGovernMaxRounds(context.maxRounds);
|
|
84
|
+
const maxDurationMinutes = normalizeProgramGovernMaxMinutes(context.maxMinutes);
|
|
85
|
+
const maxDurationMs = maxDurationMinutes * 60 * 1000;
|
|
86
|
+
const anomalyEnabled = context.anomalyEnabled !== false;
|
|
87
|
+
const anomalyWeeks = normalizeProgramGovernAnomalyWeeks(context.anomalyWeeks);
|
|
88
|
+
const anomalyPeriod = normalizeAutoKpiTrendPeriod(context.anomalyPeriod);
|
|
89
|
+
const governUseAction = normalizeProgramGovernUseAction(context.governUseAction);
|
|
90
|
+
const governAutoActionEnabled = context.governAutoActionEnabled !== false;
|
|
91
|
+
const governActionEnabled = governAutoActionEnabled || governUseAction !== null;
|
|
92
|
+
const programGatePolicy = resolveProgramGatePolicy(context.programGatePolicy || {});
|
|
93
|
+
const gateFallbackChain = Array.isArray(context.gateFallbackChain) ? context.gateFallbackChain : [];
|
|
94
|
+
const recoveryMemoryScope = context.recoveryMemoryScope || null;
|
|
95
|
+
const normalizedRecoveryScope = normalizeRecoveryMemoryToken(recoveryMemoryScope || '') || 'default-scope';
|
|
96
|
+
const recoverResumeStrategy = normalizeResumeStrategy(context.recoverResumeStrategy || 'pending');
|
|
97
|
+
const recoverMaxRounds = normalizeRecoverMaxRounds(context.recoverMaxRounds);
|
|
98
|
+
const recoverMaxMinutes = normalizeRecoverMaxMinutes(
|
|
99
|
+
context.recoverMaxMinutes,
|
|
100
|
+
'--program-recover-max-minutes'
|
|
101
|
+
);
|
|
102
|
+
const recoverMaxDurationMs = recoverMaxMinutes === null ? null : recoverMaxMinutes * 60 * 1000;
|
|
103
|
+
const governanceStartedAt = now();
|
|
104
|
+
const history = [];
|
|
105
|
+
let exhausted = false;
|
|
106
|
+
let stopReason = enabled ? 'stable' : 'disabled';
|
|
107
|
+
let settled = false;
|
|
108
|
+
|
|
109
|
+
if (!enabled) {
|
|
110
|
+
return {
|
|
111
|
+
summary,
|
|
112
|
+
governance: {
|
|
113
|
+
enabled: false,
|
|
114
|
+
anomaly_enabled: anomalyEnabled,
|
|
115
|
+
anomaly_weeks: anomalyWeeks,
|
|
116
|
+
anomaly_period: anomalyPeriod,
|
|
117
|
+
auto_action_enabled: governAutoActionEnabled,
|
|
118
|
+
action_selection_enabled: false,
|
|
119
|
+
pinned_action_index: governUseAction,
|
|
120
|
+
max_rounds: maxRounds,
|
|
121
|
+
max_minutes: maxDurationMinutes,
|
|
122
|
+
performed_rounds: 0,
|
|
123
|
+
converged: Boolean(
|
|
124
|
+
summary &&
|
|
125
|
+
summary.program_gate_effective &&
|
|
126
|
+
summary.program_gate_effective.passed &&
|
|
127
|
+
!isSpecSessionBudgetHardFailure(summary) &&
|
|
128
|
+
!isSpecSessionGrowthGuardHardFailure(summary)
|
|
129
|
+
),
|
|
130
|
+
exhausted: false,
|
|
131
|
+
stop_reason: 'disabled',
|
|
132
|
+
history: []
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (let round = 1; round <= maxRounds; round += 1) {
|
|
138
|
+
const elapsedBeforeRound = now() - governanceStartedAt;
|
|
139
|
+
if (elapsedBeforeRound >= maxDurationMs) {
|
|
140
|
+
exhausted = true;
|
|
141
|
+
stopReason = 'time-budget-exhausted';
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let trendResult = null;
|
|
146
|
+
let anomalies = [];
|
|
147
|
+
if (anomalyEnabled) {
|
|
148
|
+
trendResult = await buildAutoKpiTrend(projectPath, {
|
|
149
|
+
weeks: anomalyWeeks,
|
|
150
|
+
mode: 'program',
|
|
151
|
+
period: anomalyPeriod
|
|
152
|
+
});
|
|
153
|
+
anomalies = Array.isArray(trendResult.anomalies) ? trendResult.anomalies : [];
|
|
154
|
+
summary.program_kpi_trend = {
|
|
155
|
+
generated_at: trendResult.generated_at,
|
|
156
|
+
weeks: trendResult.weeks,
|
|
157
|
+
period_unit: trendResult.period_unit,
|
|
158
|
+
total_runs: trendResult.total_runs,
|
|
159
|
+
overall: trendResult.overall,
|
|
160
|
+
anomaly_detection: trendResult.anomaly_detection || null
|
|
161
|
+
};
|
|
162
|
+
summary.program_kpi_anomalies = anomalies;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const gateFailed = Boolean(
|
|
166
|
+
!summary.program_gate_effective ||
|
|
167
|
+
!summary.program_gate_effective.passed ||
|
|
168
|
+
isSpecSessionBudgetHardFailure(summary) ||
|
|
169
|
+
isSpecSessionGrowthGuardHardFailure(summary)
|
|
170
|
+
);
|
|
171
|
+
const highSeverityAnomalies = anomalies.filter(item => `${item && item.severity ? item.severity : ''}`.trim().toLowerCase() === 'high');
|
|
172
|
+
const anomalyFailed = anomalyEnabled && highSeverityAnomalies.length > 0;
|
|
173
|
+
if (!gateFailed && !anomalyFailed) {
|
|
174
|
+
stopReason = 'stable';
|
|
175
|
+
settled = true;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const gatePatch = summary && summary.program_gate_auto_remediation && summary.program_gate_auto_remediation.next_run_patch
|
|
180
|
+
? summary.program_gate_auto_remediation.next_run_patch
|
|
181
|
+
: {};
|
|
182
|
+
const anomalyPatch = buildProgramAnomalyGovernancePatch(summary, highSeverityAnomalies, baseProgramOptions);
|
|
183
|
+
let governanceActionSelection = null;
|
|
184
|
+
let governanceActionPatch = {};
|
|
185
|
+
if (governActionEnabled) {
|
|
186
|
+
const recoveryMemory = await loadCloseLoopRecoveryMemory(projectPath);
|
|
187
|
+
const recoverySignature = buildRecoveryMemorySignature(summary, {
|
|
188
|
+
scope: normalizedRecoveryScope
|
|
189
|
+
});
|
|
190
|
+
const recoveryMemoryEntry = getRecoveryMemoryEntry(recoveryMemory.payload, recoverySignature);
|
|
191
|
+
governanceActionSelection = resolveRecoveryActionSelection(summary, governUseAction, {
|
|
192
|
+
recoveryMemoryEntry,
|
|
193
|
+
optionLabel: '--program-govern-use-action'
|
|
194
|
+
});
|
|
195
|
+
governanceActionPatch = governanceActionSelection &&
|
|
196
|
+
governanceActionSelection.appliedPatch &&
|
|
197
|
+
typeof governanceActionSelection.appliedPatch === 'object'
|
|
198
|
+
? governanceActionSelection.appliedPatch
|
|
199
|
+
: {};
|
|
200
|
+
}
|
|
201
|
+
const roundPatch = {
|
|
202
|
+
...(governanceActionPatch && typeof governanceActionPatch === 'object' ? governanceActionPatch : {}),
|
|
203
|
+
...(anomalyPatch.patch || {}),
|
|
204
|
+
...(gatePatch && typeof gatePatch === 'object' ? gatePatch : {})
|
|
205
|
+
};
|
|
206
|
+
if (Object.keys(roundPatch).length === 0) {
|
|
207
|
+
stopReason = 'no-actionable-patch';
|
|
208
|
+
history.push({
|
|
209
|
+
round,
|
|
210
|
+
status_before: summary.status,
|
|
211
|
+
status_after: summary.status,
|
|
212
|
+
trigger: {
|
|
213
|
+
gate_failed: gateFailed,
|
|
214
|
+
anomaly_failed: anomalyFailed,
|
|
215
|
+
anomaly_count: highSeverityAnomalies.length
|
|
216
|
+
},
|
|
217
|
+
selected_action_index: governanceActionSelection ? governanceActionSelection.selectedIndex : null,
|
|
218
|
+
selected_action: governanceActionSelection && governanceActionSelection.selectedAction
|
|
219
|
+
? governanceActionSelection.selectedAction.action
|
|
220
|
+
: null,
|
|
221
|
+
selected_action_priority: governanceActionSelection && governanceActionSelection.selectedAction
|
|
222
|
+
? governanceActionSelection.selectedAction.priority
|
|
223
|
+
: null,
|
|
224
|
+
action_selection_source: governanceActionSelection ? governanceActionSelection.selectionSource : null,
|
|
225
|
+
action_selection_explain: governanceActionSelection ? governanceActionSelection.selectionExplain || null : null,
|
|
226
|
+
execution_mode: 'none',
|
|
227
|
+
applied_patch: null,
|
|
228
|
+
notes: [
|
|
229
|
+
'No actionable governance patch generated.'
|
|
230
|
+
]
|
|
231
|
+
});
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const roundOptions = applyProgramGovernancePatch(baseProgramOptions, roundPatch);
|
|
236
|
+
roundOptions.out = null;
|
|
237
|
+
roundOptions.programKpiOut = null;
|
|
238
|
+
roundOptions.programAuditOut = null;
|
|
239
|
+
|
|
240
|
+
const statusBefore = summary.status;
|
|
241
|
+
const failedGoalsBefore = Number(summary.failed_goals) || 0;
|
|
242
|
+
const selectedGovernanceActionIndex = governanceActionSelection ? governanceActionSelection.selectedIndex : null;
|
|
243
|
+
let executionMode = 'program-replay';
|
|
244
|
+
let roundSummary = null;
|
|
245
|
+
if (hasRecoverableProgramGoals(summary, { getBatchFailureStatusSet })) {
|
|
246
|
+
executionMode = 'recover-cycle';
|
|
247
|
+
const roundSourceSummary = summary.batch_session && summary.batch_session.file
|
|
248
|
+
? await loadCloseLoopBatchSummaryPayload(projectPath, summary.batch_session.file)
|
|
249
|
+
: {
|
|
250
|
+
file: '(program-governance-derived-summary)',
|
|
251
|
+
payload: summary
|
|
252
|
+
};
|
|
253
|
+
const recoveryResult = await executeCloseLoopRecoveryCycle({
|
|
254
|
+
projectPath,
|
|
255
|
+
sourceSummary: roundSourceSummary,
|
|
256
|
+
baseOptions: {
|
|
257
|
+
...roundOptions,
|
|
258
|
+
useAction: selectedGovernanceActionIndex || context.programRecoverUseAction
|
|
259
|
+
},
|
|
260
|
+
recoverAutonomousEnabled: true,
|
|
261
|
+
resumeStrategy: recoverResumeStrategy,
|
|
262
|
+
recoverUntilComplete: true,
|
|
263
|
+
recoverMaxRounds,
|
|
264
|
+
recoverMaxDurationMs,
|
|
265
|
+
recoveryMemoryScope,
|
|
266
|
+
actionCandidate: selectedGovernanceActionIndex || context.programRecoverUseAction
|
|
267
|
+
});
|
|
268
|
+
roundSummary = mergeProgramRecoveryIntoProgramSummary(summary, recoveryResult.summary, {
|
|
269
|
+
enabled: true,
|
|
270
|
+
triggered: true,
|
|
271
|
+
governance_round: round,
|
|
272
|
+
recover_until_complete: true,
|
|
273
|
+
source: 'governance-recover-cycle'
|
|
274
|
+
});
|
|
275
|
+
roundSummary.resource_plan = recoveryResult.summary && recoveryResult.summary.resource_plan
|
|
276
|
+
? recoveryResult.summary.resource_plan
|
|
277
|
+
: roundSummary.resource_plan;
|
|
278
|
+
roundSummary.batch_parallel = Number(recoveryResult.summary && recoveryResult.summary.batch_parallel) || roundSummary.batch_parallel;
|
|
279
|
+
} else {
|
|
280
|
+
const replayGoalsResult = buildProgramGovernanceReplayGoalsResult(baseGoalsResult, round, summary);
|
|
281
|
+
const replaySummary = await executeCloseLoopBatch(
|
|
282
|
+
replayGoalsResult,
|
|
283
|
+
roundOptions,
|
|
284
|
+
projectPath,
|
|
285
|
+
'auto-close-loop-program'
|
|
286
|
+
);
|
|
287
|
+
roundSummary = {
|
|
288
|
+
...replaySummary,
|
|
289
|
+
auto_recovery: summary && summary.auto_recovery ? summary.auto_recovery : null
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
roundSummary.program_kpi = buildProgramKpiSnapshot(roundSummary);
|
|
294
|
+
roundSummary.program_diagnostics = buildProgramDiagnostics(roundSummary);
|
|
295
|
+
roundSummary.program_coordination = buildProgramCoordinationSnapshot(roundSummary);
|
|
296
|
+
await applyProgramGateOutcome(roundSummary, {
|
|
297
|
+
projectPath,
|
|
298
|
+
options: roundOptions,
|
|
299
|
+
programGatePolicy,
|
|
300
|
+
gateFallbackChain,
|
|
301
|
+
enableAutoRemediation: context.programGateAutoRemediate !== false
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const failedGoalsAfter = Number(roundSummary.failed_goals) || 0;
|
|
305
|
+
history.push({
|
|
306
|
+
round,
|
|
307
|
+
status_before: statusBefore,
|
|
308
|
+
status_after: roundSummary.status,
|
|
309
|
+
trigger: {
|
|
310
|
+
gate_failed: gateFailed,
|
|
311
|
+
anomaly_failed: anomalyFailed,
|
|
312
|
+
anomaly_count: highSeverityAnomalies.length
|
|
313
|
+
},
|
|
314
|
+
selected_action_index: selectedGovernanceActionIndex,
|
|
315
|
+
selected_action: governanceActionSelection && governanceActionSelection.selectedAction
|
|
316
|
+
? governanceActionSelection.selectedAction.action
|
|
317
|
+
: null,
|
|
318
|
+
selected_action_priority: governanceActionSelection && governanceActionSelection.selectedAction
|
|
319
|
+
? governanceActionSelection.selectedAction.priority
|
|
320
|
+
: null,
|
|
321
|
+
action_selection_source: governanceActionSelection ? governanceActionSelection.selectionSource : null,
|
|
322
|
+
action_selection_explain: governanceActionSelection ? governanceActionSelection.selectionExplain || null : null,
|
|
323
|
+
execution_mode: executionMode,
|
|
324
|
+
applied_patch: roundPatch,
|
|
325
|
+
patch_reasons: [
|
|
326
|
+
...(governanceActionSelection && governanceActionSelection.selectionExplain
|
|
327
|
+
? [`governance-action: ${governanceActionSelection.selectionExplain.reason}`]
|
|
328
|
+
: []),
|
|
329
|
+
...(Array.isArray(anomalyPatch.reasons) ? anomalyPatch.reasons : []),
|
|
330
|
+
...(summary.program_gate_auto_remediation && Array.isArray(summary.program_gate_auto_remediation.reasons)
|
|
331
|
+
? summary.program_gate_auto_remediation.reasons
|
|
332
|
+
: [])
|
|
333
|
+
],
|
|
334
|
+
failed_goals_before: failedGoalsBefore,
|
|
335
|
+
failed_goals_after: failedGoalsAfter
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
summary = roundSummary;
|
|
339
|
+
if (
|
|
340
|
+
summary.program_gate_effective &&
|
|
341
|
+
summary.program_gate_effective.passed &&
|
|
342
|
+
!isSpecSessionBudgetHardFailure(summary) &&
|
|
343
|
+
!isSpecSessionGrowthGuardHardFailure(summary)
|
|
344
|
+
) {
|
|
345
|
+
if (!anomalyEnabled) {
|
|
346
|
+
stopReason = 'gate-stable';
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
const postTrend = await buildAutoKpiTrend(projectPath, {
|
|
350
|
+
weeks: anomalyWeeks,
|
|
351
|
+
mode: 'program',
|
|
352
|
+
period: anomalyPeriod
|
|
353
|
+
});
|
|
354
|
+
const postAnomalies = Array.isArray(postTrend.anomalies) ? postTrend.anomalies : [];
|
|
355
|
+
summary.program_kpi_trend = {
|
|
356
|
+
generated_at: postTrend.generated_at,
|
|
357
|
+
weeks: postTrend.weeks,
|
|
358
|
+
period_unit: postTrend.period_unit,
|
|
359
|
+
total_runs: postTrend.total_runs,
|
|
360
|
+
overall: postTrend.overall,
|
|
361
|
+
anomaly_detection: postTrend.anomaly_detection || null
|
|
362
|
+
};
|
|
363
|
+
summary.program_kpi_anomalies = postAnomalies;
|
|
364
|
+
const hasHighPostAnomaly = postAnomalies.some(item => `${item && item.severity ? item.severity : ''}`.trim().toLowerCase() === 'high');
|
|
365
|
+
if (!hasHighPostAnomaly) {
|
|
366
|
+
stopReason = 'stable';
|
|
367
|
+
settled = true;
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!settled && history.length >= maxRounds && stopReason === 'stable') {
|
|
374
|
+
stopReason = 'round-limit-reached';
|
|
375
|
+
exhausted = true;
|
|
376
|
+
}
|
|
377
|
+
if (!settled && history.length >= maxRounds && stopReason !== 'stable') {
|
|
378
|
+
exhausted = true;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
summary,
|
|
383
|
+
governance: {
|
|
384
|
+
enabled: true,
|
|
385
|
+
anomaly_enabled: anomalyEnabled,
|
|
386
|
+
anomaly_weeks: anomalyWeeks,
|
|
387
|
+
anomaly_period: anomalyPeriod,
|
|
388
|
+
auto_action_enabled: governAutoActionEnabled,
|
|
389
|
+
action_selection_enabled: governActionEnabled,
|
|
390
|
+
pinned_action_index: governUseAction,
|
|
391
|
+
max_rounds: maxRounds,
|
|
392
|
+
max_minutes: maxDurationMinutes,
|
|
393
|
+
performed_rounds: history.length,
|
|
394
|
+
converged: Boolean(
|
|
395
|
+
summary &&
|
|
396
|
+
summary.program_gate_effective &&
|
|
397
|
+
summary.program_gate_effective.passed &&
|
|
398
|
+
!isSpecSessionBudgetHardFailure(summary) &&
|
|
399
|
+
!isSpecSessionGrowthGuardHardFailure(summary)
|
|
400
|
+
),
|
|
401
|
+
exhausted,
|
|
402
|
+
stop_reason: stopReason,
|
|
403
|
+
history
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
module.exports = {
|
|
409
|
+
hasRecoverableProgramGoals,
|
|
410
|
+
applyProgramGovernancePatch,
|
|
411
|
+
buildProgramGovernanceReplayGoalsResult,
|
|
412
|
+
runProgramGovernanceLoop
|
|
413
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
async function maybeWriteProgramKpi(summary, outCandidate, projectPath, dependencies = {}) {
|
|
2
|
+
const pathModule = dependencies.pathModule;
|
|
3
|
+
const fs = dependencies.fs;
|
|
4
|
+
if (!outCandidate) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const outputPath = pathModule.isAbsolute(outCandidate)
|
|
9
|
+
? outCandidate
|
|
10
|
+
: pathModule.join(projectPath, outCandidate);
|
|
11
|
+
await fs.ensureDir(pathModule.dirname(outputPath));
|
|
12
|
+
await fs.writeJson(outputPath, {
|
|
13
|
+
mode: summary.mode === 'auto-close-loop-recover'
|
|
14
|
+
? 'auto-close-loop-recover-kpi'
|
|
15
|
+
: 'auto-close-loop-program-kpi',
|
|
16
|
+
program_mode: summary.mode,
|
|
17
|
+
status: summary.status,
|
|
18
|
+
program_started_at: summary.program_started_at || null,
|
|
19
|
+
program_completed_at: summary.program_completed_at || null,
|
|
20
|
+
program_elapsed_ms: Number.isFinite(Number(summary.program_elapsed_ms))
|
|
21
|
+
? Number(summary.program_elapsed_ms)
|
|
22
|
+
: null,
|
|
23
|
+
total_goals: summary.total_goals,
|
|
24
|
+
processed_goals: summary.processed_goals,
|
|
25
|
+
completed_goals: summary.completed_goals,
|
|
26
|
+
failed_goals: summary.failed_goals,
|
|
27
|
+
metrics: summary.metrics,
|
|
28
|
+
program_kpi: summary.program_kpi,
|
|
29
|
+
program_diagnostics: summary.program_diagnostics,
|
|
30
|
+
program_coordination: summary.program_coordination || null,
|
|
31
|
+
auto_recovery: summary.auto_recovery || null,
|
|
32
|
+
program_governance: summary.program_governance || null,
|
|
33
|
+
program_kpi_trend: summary.program_kpi_trend || null,
|
|
34
|
+
program_kpi_anomalies: Array.isArray(summary.program_kpi_anomalies) ? summary.program_kpi_anomalies : [],
|
|
35
|
+
goal_input_guard: summary.goal_input_guard || null,
|
|
36
|
+
spec_session_budget: summary.spec_session_budget || null,
|
|
37
|
+
spec_session_growth_guard: summary.spec_session_growth_guard || null,
|
|
38
|
+
spec_session_auto_prune: summary.spec_session_auto_prune || null,
|
|
39
|
+
program_gate_auto_remediation: summary.program_gate_auto_remediation || null,
|
|
40
|
+
program_gate: summary.program_gate || null,
|
|
41
|
+
program_gate_fallback: summary.program_gate_fallback || null,
|
|
42
|
+
program_gate_fallbacks: summary.program_gate_fallbacks || [],
|
|
43
|
+
program_gate_effective: summary.program_gate_effective || null
|
|
44
|
+
}, { spaces: 2 });
|
|
45
|
+
summary.program_kpi_file = outputPath;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function maybeWriteProgramAudit(summary, outCandidate, projectPath, dependencies = {}) {
|
|
49
|
+
const pathModule = dependencies.pathModule;
|
|
50
|
+
const fs = dependencies.fs;
|
|
51
|
+
const now = dependencies.now || (() => new Date().toISOString());
|
|
52
|
+
if (!outCandidate) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const outputPath = pathModule.isAbsolute(outCandidate)
|
|
56
|
+
? outCandidate
|
|
57
|
+
: pathModule.join(projectPath, outCandidate);
|
|
58
|
+
await fs.ensureDir(pathModule.dirname(outputPath));
|
|
59
|
+
await fs.writeJson(outputPath, {
|
|
60
|
+
mode: 'auto-close-loop-program-audit',
|
|
61
|
+
generated_at: now(),
|
|
62
|
+
summary_mode: summary && summary.mode ? summary.mode : null,
|
|
63
|
+
status: summary && summary.status ? summary.status : null,
|
|
64
|
+
program_started_at: summary && summary.program_started_at ? summary.program_started_at : null,
|
|
65
|
+
program_completed_at: summary && summary.program_completed_at ? summary.program_completed_at : null,
|
|
66
|
+
program_elapsed_ms: Number.isFinite(Number(summary && summary.program_elapsed_ms))
|
|
67
|
+
? Number(summary && summary.program_elapsed_ms)
|
|
68
|
+
: null,
|
|
69
|
+
totals: {
|
|
70
|
+
total_goals: Number(summary && summary.total_goals) || 0,
|
|
71
|
+
processed_goals: Number(summary && summary.processed_goals) || 0,
|
|
72
|
+
completed_goals: Number(summary && summary.completed_goals) || 0,
|
|
73
|
+
failed_goals: Number(summary && summary.failed_goals) || 0
|
|
74
|
+
},
|
|
75
|
+
metrics: summary && summary.metrics ? summary.metrics : null,
|
|
76
|
+
batch_retry: summary && summary.batch_retry ? summary.batch_retry : null,
|
|
77
|
+
program_kpi: summary && summary.program_kpi ? summary.program_kpi : null,
|
|
78
|
+
program_diagnostics: summary && summary.program_diagnostics ? summary.program_diagnostics : null,
|
|
79
|
+
program_coordination: summary && summary.program_coordination ? summary.program_coordination : null,
|
|
80
|
+
program_gate: summary && summary.program_gate ? summary.program_gate : null,
|
|
81
|
+
program_gate_fallback: summary && summary.program_gate_fallback ? summary.program_gate_fallback : null,
|
|
82
|
+
program_gate_fallbacks: Array.isArray(summary && summary.program_gate_fallbacks) ? summary.program_gate_fallbacks : [],
|
|
83
|
+
program_gate_effective: summary && summary.program_gate_effective ? summary.program_gate_effective : null,
|
|
84
|
+
auto_recovery: summary && summary.auto_recovery ? summary.auto_recovery : null,
|
|
85
|
+
program_governance: summary && summary.program_governance ? summary.program_governance : null,
|
|
86
|
+
program_kpi_trend: summary && summary.program_kpi_trend ? summary.program_kpi_trend : null,
|
|
87
|
+
program_kpi_anomalies: Array.isArray(summary && summary.program_kpi_anomalies) ? summary.program_kpi_anomalies : [],
|
|
88
|
+
recovery_cycle: summary && summary.recovery_cycle ? summary.recovery_cycle : null,
|
|
89
|
+
recovery_plan: summary && summary.recovery_plan ? summary.recovery_plan : null,
|
|
90
|
+
recovery_memory: summary && summary.recovery_memory ? summary.recovery_memory : null,
|
|
91
|
+
goal_input_guard: summary && summary.goal_input_guard ? summary.goal_input_guard : null,
|
|
92
|
+
spec_session_prune: summary && summary.spec_session_prune ? summary.spec_session_prune : null,
|
|
93
|
+
spec_session_budget: summary && summary.spec_session_budget ? summary.spec_session_budget : null,
|
|
94
|
+
spec_session_growth_guard: summary && summary.spec_session_growth_guard ? summary.spec_session_growth_guard : null,
|
|
95
|
+
spec_session_auto_prune: summary && summary.spec_session_auto_prune ? summary.spec_session_auto_prune : null,
|
|
96
|
+
program_gate_auto_remediation: summary && summary.program_gate_auto_remediation ? summary.program_gate_auto_remediation : null,
|
|
97
|
+
resource_plan: summary && summary.resource_plan ? summary.resource_plan : null,
|
|
98
|
+
results: Array.isArray(summary && summary.results) ? summary.results : []
|
|
99
|
+
}, { spaces: 2 });
|
|
100
|
+
summary.program_audit_file = outputPath;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = {
|
|
104
|
+
maybeWriteProgramKpi,
|
|
105
|
+
maybeWriteProgramAudit
|
|
106
|
+
};
|