scene-capability-engine 3.6.32 → 3.6.36
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 +86 -1
- package/README.md +119 -122
- package/README.zh.md +123 -121
- package/bin/scene-capability-engine.js +11 -0
- package/docs/README.md +21 -32
- package/docs/auto-refactor-index.md +384 -0
- package/docs/command-reference.md +94 -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/refactor-completion-roadmap.md +116 -0
- package/docs/zh/README.md +27 -30
- package/docs/zh/refactor-completion-roadmap.md +116 -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/app.js +911 -0
- package/lib/commands/assurance.js +212 -0
- package/lib/commands/auto.js +1091 -11063
- 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/state/sce-state-store.js +3369 -1200
- package/package.json +1 -1
|
@@ -0,0 +1,1407 @@
|
|
|
1
|
+
const { buildMoquiRegressionRecoverySequenceLines } = require('./moqui-recovery-sequence');
|
|
2
|
+
|
|
3
|
+
function quoteCliArg(value) {
|
|
4
|
+
const text = `${value || ''}`;
|
|
5
|
+
if (/^[A-Za-z0-9_./:-]+$/.test(text)) {
|
|
6
|
+
return text;
|
|
7
|
+
}
|
|
8
|
+
return JSON.stringify(text);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function buildAutoHandoffRegressionSnapshot(report, dependencies = {}) {
|
|
12
|
+
const { normalizeHandoffText, normalizeRiskRank } = dependencies;
|
|
13
|
+
const payload = report && report.payload ? report.payload : report;
|
|
14
|
+
const specStatus = payload && payload.spec_status ? payload.spec_status : {};
|
|
15
|
+
const gates = payload && payload.gates ? payload.gates : {};
|
|
16
|
+
const gateActual = gates && gates.actual ? gates.actual : {};
|
|
17
|
+
const batchSummary = payload && payload.batch_summary ? payload.batch_summary : {};
|
|
18
|
+
const ontology = payload && payload.ontology_validation ? payload.ontology_validation : {};
|
|
19
|
+
const ontologyMetrics = ontology && ontology.metrics ? ontology.metrics : {};
|
|
20
|
+
const scenePackageBatch = payload && payload.scene_package_batch ? payload.scene_package_batch : {};
|
|
21
|
+
const scenePackageBatchSummary = scenePackageBatch && scenePackageBatch.summary
|
|
22
|
+
? scenePackageBatch.summary
|
|
23
|
+
: {};
|
|
24
|
+
|
|
25
|
+
const riskLevel = gateActual.risk_level
|
|
26
|
+
|| (payload && payload.observability_snapshot && payload.observability_snapshot.highlights
|
|
27
|
+
? payload.observability_snapshot.highlights.governance_risk_level
|
|
28
|
+
: 'high');
|
|
29
|
+
const successRate = Number(specStatus.success_rate_percent);
|
|
30
|
+
const failedGoals = Number(batchSummary.failed_goals);
|
|
31
|
+
const elapsedMs = Number(payload && payload.elapsed_ms);
|
|
32
|
+
const ontologyQualityScore = Number(
|
|
33
|
+
gateActual.ontology_quality_score !== undefined
|
|
34
|
+
? gateActual.ontology_quality_score
|
|
35
|
+
: ontology.quality_score
|
|
36
|
+
);
|
|
37
|
+
const ontologyUnmappedRules = Number(
|
|
38
|
+
gateActual.ontology_business_rule_unmapped !== undefined
|
|
39
|
+
? gateActual.ontology_business_rule_unmapped
|
|
40
|
+
: ontologyMetrics.business_rule_unmapped
|
|
41
|
+
);
|
|
42
|
+
const ontologyUndecidedDecisions = Number(
|
|
43
|
+
gateActual.ontology_decision_undecided !== undefined
|
|
44
|
+
? gateActual.ontology_decision_undecided
|
|
45
|
+
: ontologyMetrics.decision_undecided
|
|
46
|
+
);
|
|
47
|
+
const businessRulePassRate = Number(
|
|
48
|
+
gateActual.ontology_business_rule_pass_rate_percent !== undefined
|
|
49
|
+
? gateActual.ontology_business_rule_pass_rate_percent
|
|
50
|
+
: ontologyMetrics.business_rule_pass_rate_percent
|
|
51
|
+
);
|
|
52
|
+
const decisionResolvedRate = Number(
|
|
53
|
+
gateActual.ontology_decision_resolved_rate_percent !== undefined
|
|
54
|
+
? gateActual.ontology_decision_resolved_rate_percent
|
|
55
|
+
: ontologyMetrics.decision_resolved_rate_percent
|
|
56
|
+
);
|
|
57
|
+
const sceneBatchFailureCount = Number(
|
|
58
|
+
scenePackageBatchSummary.batch_gate_failure_count !== undefined
|
|
59
|
+
? scenePackageBatchSummary.batch_gate_failure_count
|
|
60
|
+
: scenePackageBatchSummary.failed
|
|
61
|
+
);
|
|
62
|
+
const sceneBatchStatus = normalizeHandoffText(
|
|
63
|
+
scenePackageBatch.status !== undefined
|
|
64
|
+
? scenePackageBatch.status
|
|
65
|
+
: gateActual.scene_package_batch_status
|
|
66
|
+
);
|
|
67
|
+
const moquiBaseline = payload && payload.moqui_baseline ? payload.moqui_baseline : {};
|
|
68
|
+
const moquiCompare = moquiBaseline && moquiBaseline.compare ? moquiBaseline.compare : {};
|
|
69
|
+
const moquiMatrixRegressionCount = Number(
|
|
70
|
+
gateActual.moqui_matrix_regression_count !== undefined
|
|
71
|
+
? gateActual.moqui_matrix_regression_count
|
|
72
|
+
: buildAutoHandoffMoquiCoverageRegressions(moquiCompare, { normalizeHandoffText }).length
|
|
73
|
+
);
|
|
74
|
+
let sceneBatchPassed = null;
|
|
75
|
+
if (sceneBatchStatus && sceneBatchStatus !== 'skipped') {
|
|
76
|
+
sceneBatchPassed = sceneBatchStatus === 'passed';
|
|
77
|
+
}
|
|
78
|
+
if (gateActual.scene_package_batch_passed === true) {
|
|
79
|
+
sceneBatchPassed = true;
|
|
80
|
+
} else if (gateActual.scene_package_batch_passed === false) {
|
|
81
|
+
sceneBatchPassed = false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
session_id: payload && payload.session_id ? payload.session_id : null,
|
|
86
|
+
status: payload && payload.status ? payload.status : null,
|
|
87
|
+
spec_success_rate_percent: Number.isFinite(successRate) ? successRate : null,
|
|
88
|
+
risk_level: `${riskLevel || 'high'}`.trim().toLowerCase(),
|
|
89
|
+
risk_level_rank: normalizeRiskRank(riskLevel),
|
|
90
|
+
failed_goals: Number.isFinite(failedGoals) ? failedGoals : null,
|
|
91
|
+
elapsed_ms: Number.isFinite(elapsedMs) ? elapsedMs : null,
|
|
92
|
+
ontology_quality_score: Number.isFinite(ontologyQualityScore) ? ontologyQualityScore : null,
|
|
93
|
+
ontology_unmapped_rules: Number.isFinite(ontologyUnmappedRules) ? ontologyUnmappedRules : null,
|
|
94
|
+
ontology_undecided_decisions: Number.isFinite(ontologyUndecidedDecisions) ? ontologyUndecidedDecisions : null,
|
|
95
|
+
ontology_business_rule_pass_rate_percent: Number.isFinite(businessRulePassRate) ? businessRulePassRate : null,
|
|
96
|
+
ontology_decision_resolved_rate_percent: Number.isFinite(decisionResolvedRate) ? decisionResolvedRate : null,
|
|
97
|
+
moqui_matrix_regression_count: Number.isFinite(moquiMatrixRegressionCount) ? moquiMatrixRegressionCount : null,
|
|
98
|
+
scene_package_batch_status: sceneBatchStatus || null,
|
|
99
|
+
scene_package_batch_passed: typeof sceneBatchPassed === 'boolean' ? sceneBatchPassed : null,
|
|
100
|
+
scene_package_batch_failure_count: Number.isFinite(sceneBatchFailureCount) ? sceneBatchFailureCount : null,
|
|
101
|
+
generated_at: payload && payload.generated_at ? payload.generated_at : null
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildAutoHandoffRegressionComparison(currentSnapshot, previousSnapshot) {
|
|
106
|
+
const deltaSuccess = (
|
|
107
|
+
Number.isFinite(currentSnapshot.spec_success_rate_percent) &&
|
|
108
|
+
Number.isFinite(previousSnapshot.spec_success_rate_percent)
|
|
109
|
+
)
|
|
110
|
+
? Number((currentSnapshot.spec_success_rate_percent - previousSnapshot.spec_success_rate_percent).toFixed(2))
|
|
111
|
+
: null;
|
|
112
|
+
const deltaRiskRank = (
|
|
113
|
+
Number.isFinite(currentSnapshot.risk_level_rank) &&
|
|
114
|
+
Number.isFinite(previousSnapshot.risk_level_rank)
|
|
115
|
+
)
|
|
116
|
+
? currentSnapshot.risk_level_rank - previousSnapshot.risk_level_rank
|
|
117
|
+
: null;
|
|
118
|
+
const deltaFailedGoals = (
|
|
119
|
+
Number.isFinite(currentSnapshot.failed_goals) &&
|
|
120
|
+
Number.isFinite(previousSnapshot.failed_goals)
|
|
121
|
+
)
|
|
122
|
+
? currentSnapshot.failed_goals - previousSnapshot.failed_goals
|
|
123
|
+
: null;
|
|
124
|
+
const deltaElapsedMs = (
|
|
125
|
+
Number.isFinite(currentSnapshot.elapsed_ms) &&
|
|
126
|
+
Number.isFinite(previousSnapshot.elapsed_ms)
|
|
127
|
+
)
|
|
128
|
+
? currentSnapshot.elapsed_ms - previousSnapshot.elapsed_ms
|
|
129
|
+
: null;
|
|
130
|
+
const deltaOntologyQualityScore = (
|
|
131
|
+
Number.isFinite(currentSnapshot.ontology_quality_score) &&
|
|
132
|
+
Number.isFinite(previousSnapshot.ontology_quality_score)
|
|
133
|
+
)
|
|
134
|
+
? Number((currentSnapshot.ontology_quality_score - previousSnapshot.ontology_quality_score).toFixed(2))
|
|
135
|
+
: null;
|
|
136
|
+
const deltaOntologyUnmappedRules = (
|
|
137
|
+
Number.isFinite(currentSnapshot.ontology_unmapped_rules) &&
|
|
138
|
+
Number.isFinite(previousSnapshot.ontology_unmapped_rules)
|
|
139
|
+
)
|
|
140
|
+
? currentSnapshot.ontology_unmapped_rules - previousSnapshot.ontology_unmapped_rules
|
|
141
|
+
: null;
|
|
142
|
+
const deltaOntologyUndecidedDecisions = (
|
|
143
|
+
Number.isFinite(currentSnapshot.ontology_undecided_decisions) &&
|
|
144
|
+
Number.isFinite(previousSnapshot.ontology_undecided_decisions)
|
|
145
|
+
)
|
|
146
|
+
? currentSnapshot.ontology_undecided_decisions - previousSnapshot.ontology_undecided_decisions
|
|
147
|
+
: null;
|
|
148
|
+
const deltaBusinessRulePassRate = (
|
|
149
|
+
Number.isFinite(currentSnapshot.ontology_business_rule_pass_rate_percent) &&
|
|
150
|
+
Number.isFinite(previousSnapshot.ontology_business_rule_pass_rate_percent)
|
|
151
|
+
)
|
|
152
|
+
? Number((
|
|
153
|
+
currentSnapshot.ontology_business_rule_pass_rate_percent -
|
|
154
|
+
previousSnapshot.ontology_business_rule_pass_rate_percent
|
|
155
|
+
).toFixed(2))
|
|
156
|
+
: null;
|
|
157
|
+
const deltaDecisionResolvedRate = (
|
|
158
|
+
Number.isFinite(currentSnapshot.ontology_decision_resolved_rate_percent) &&
|
|
159
|
+
Number.isFinite(previousSnapshot.ontology_decision_resolved_rate_percent)
|
|
160
|
+
)
|
|
161
|
+
? Number((
|
|
162
|
+
currentSnapshot.ontology_decision_resolved_rate_percent -
|
|
163
|
+
previousSnapshot.ontology_decision_resolved_rate_percent
|
|
164
|
+
).toFixed(2))
|
|
165
|
+
: null;
|
|
166
|
+
const deltaSceneBatchFailureCount = (
|
|
167
|
+
Number.isFinite(currentSnapshot.scene_package_batch_failure_count) &&
|
|
168
|
+
Number.isFinite(previousSnapshot.scene_package_batch_failure_count)
|
|
169
|
+
)
|
|
170
|
+
? currentSnapshot.scene_package_batch_failure_count - previousSnapshot.scene_package_batch_failure_count
|
|
171
|
+
: null;
|
|
172
|
+
const deltaMoquiMatrixRegressionCount = (
|
|
173
|
+
Number.isFinite(currentSnapshot.moqui_matrix_regression_count) &&
|
|
174
|
+
Number.isFinite(previousSnapshot.moqui_matrix_regression_count)
|
|
175
|
+
)
|
|
176
|
+
? currentSnapshot.moqui_matrix_regression_count - previousSnapshot.moqui_matrix_regression_count
|
|
177
|
+
: null;
|
|
178
|
+
|
|
179
|
+
let trend = 'stable';
|
|
180
|
+
if (
|
|
181
|
+
(Number.isFinite(deltaSuccess) && deltaSuccess > 0) &&
|
|
182
|
+
(deltaRiskRank === null || deltaRiskRank <= 0) &&
|
|
183
|
+
(deltaFailedGoals === null || deltaFailedGoals <= 0) &&
|
|
184
|
+
(deltaOntologyQualityScore === null || deltaOntologyQualityScore >= 0) &&
|
|
185
|
+
(deltaOntologyUnmappedRules === null || deltaOntologyUnmappedRules <= 0) &&
|
|
186
|
+
(deltaOntologyUndecidedDecisions === null || deltaOntologyUndecidedDecisions <= 0) &&
|
|
187
|
+
(deltaSceneBatchFailureCount === null || deltaSceneBatchFailureCount <= 0)
|
|
188
|
+
) {
|
|
189
|
+
trend = 'improved';
|
|
190
|
+
} else if (
|
|
191
|
+
(Number.isFinite(deltaSuccess) && deltaSuccess < 0) ||
|
|
192
|
+
(deltaRiskRank !== null && deltaRiskRank > 0) ||
|
|
193
|
+
(deltaFailedGoals !== null && deltaFailedGoals > 0) ||
|
|
194
|
+
(deltaOntologyQualityScore !== null && deltaOntologyQualityScore < 0) ||
|
|
195
|
+
(deltaOntologyUnmappedRules !== null && deltaOntologyUnmappedRules > 0) ||
|
|
196
|
+
(deltaOntologyUndecidedDecisions !== null && deltaOntologyUndecidedDecisions > 0) ||
|
|
197
|
+
(deltaSceneBatchFailureCount !== null && deltaSceneBatchFailureCount > 0) ||
|
|
198
|
+
(deltaMoquiMatrixRegressionCount !== null && deltaMoquiMatrixRegressionCount > 0)
|
|
199
|
+
) {
|
|
200
|
+
trend = 'degraded';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
trend,
|
|
205
|
+
delta: {
|
|
206
|
+
spec_success_rate_percent: deltaSuccess,
|
|
207
|
+
risk_level_rank: deltaRiskRank,
|
|
208
|
+
failed_goals: deltaFailedGoals,
|
|
209
|
+
elapsed_ms: deltaElapsedMs,
|
|
210
|
+
ontology_quality_score: deltaOntologyQualityScore,
|
|
211
|
+
ontology_unmapped_rules: deltaOntologyUnmappedRules,
|
|
212
|
+
ontology_undecided_decisions: deltaOntologyUndecidedDecisions,
|
|
213
|
+
ontology_business_rule_pass_rate_percent: deltaBusinessRulePassRate,
|
|
214
|
+
ontology_decision_resolved_rate_percent: deltaDecisionResolvedRate,
|
|
215
|
+
moqui_matrix_regression_count: deltaMoquiMatrixRegressionCount,
|
|
216
|
+
scene_package_batch_failure_count: deltaSceneBatchFailureCount
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function buildAutoHandoffRegressionWindowTrend(series = []) {
|
|
222
|
+
const normalized = Array.isArray(series) ? series.filter(Boolean) : [];
|
|
223
|
+
if (normalized.length < 2) {
|
|
224
|
+
return {
|
|
225
|
+
trend: 'baseline',
|
|
226
|
+
delta: {
|
|
227
|
+
spec_success_rate_percent: null,
|
|
228
|
+
risk_level_rank: null,
|
|
229
|
+
failed_goals: null,
|
|
230
|
+
elapsed_ms: null,
|
|
231
|
+
ontology_quality_score: null,
|
|
232
|
+
ontology_unmapped_rules: null,
|
|
233
|
+
ontology_undecided_decisions: null,
|
|
234
|
+
ontology_business_rule_pass_rate_percent: null,
|
|
235
|
+
ontology_decision_resolved_rate_percent: null,
|
|
236
|
+
moqui_matrix_regression_count: null,
|
|
237
|
+
scene_package_batch_failure_count: null
|
|
238
|
+
},
|
|
239
|
+
has_baseline: false
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const latest = normalized[0];
|
|
243
|
+
const oldest = normalized[normalized.length - 1];
|
|
244
|
+
const comparison = buildAutoHandoffRegressionComparison(latest, oldest);
|
|
245
|
+
return {
|
|
246
|
+
trend: comparison.trend,
|
|
247
|
+
delta: comparison.delta,
|
|
248
|
+
has_baseline: true
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function buildAutoHandoffRegressionAggregates(series = []) {
|
|
253
|
+
const snapshots = Array.isArray(series) ? series.filter(Boolean) : [];
|
|
254
|
+
const successRates = snapshots
|
|
255
|
+
.map(item => Number(item.spec_success_rate_percent))
|
|
256
|
+
.filter(value => Number.isFinite(value));
|
|
257
|
+
const failedGoals = snapshots
|
|
258
|
+
.map(item => Number(item.failed_goals))
|
|
259
|
+
.filter(value => Number.isFinite(value));
|
|
260
|
+
const ontologyScores = snapshots
|
|
261
|
+
.map(item => Number(item.ontology_quality_score))
|
|
262
|
+
.filter(value => Number.isFinite(value));
|
|
263
|
+
const ontologyUnmappedRules = snapshots
|
|
264
|
+
.map(item => Number(item.ontology_unmapped_rules))
|
|
265
|
+
.filter(value => Number.isFinite(value));
|
|
266
|
+
const ontologyUndecidedDecisions = snapshots
|
|
267
|
+
.map(item => Number(item.ontology_undecided_decisions))
|
|
268
|
+
.filter(value => Number.isFinite(value));
|
|
269
|
+
const rulePassRates = snapshots
|
|
270
|
+
.map(item => Number(item.ontology_business_rule_pass_rate_percent))
|
|
271
|
+
.filter(value => Number.isFinite(value));
|
|
272
|
+
const decisionResolvedRates = snapshots
|
|
273
|
+
.map(item => Number(item.ontology_decision_resolved_rate_percent))
|
|
274
|
+
.filter(value => Number.isFinite(value));
|
|
275
|
+
const sceneBatchFailures = snapshots
|
|
276
|
+
.map(item => Number(item.scene_package_batch_failure_count))
|
|
277
|
+
.filter(value => Number.isFinite(value));
|
|
278
|
+
const moquiMatrixRegressions = snapshots
|
|
279
|
+
.map(item => Number(item.moqui_matrix_regression_count))
|
|
280
|
+
.filter(value => Number.isFinite(value));
|
|
281
|
+
const sceneBatchApplicables = snapshots.filter(item => typeof item.scene_package_batch_passed === 'boolean');
|
|
282
|
+
const sceneBatchPassedCount = sceneBatchApplicables.filter(item => item.scene_package_batch_passed === true).length;
|
|
283
|
+
const sceneBatchFailedCount = sceneBatchApplicables.filter(item => item.scene_package_batch_passed === false).length;
|
|
284
|
+
const riskLevels = {
|
|
285
|
+
low: 0,
|
|
286
|
+
medium: 0,
|
|
287
|
+
high: 0,
|
|
288
|
+
unknown: 0
|
|
289
|
+
};
|
|
290
|
+
snapshots.forEach(item => {
|
|
291
|
+
const risk = `${item && item.risk_level ? item.risk_level : 'unknown'}`.trim().toLowerCase();
|
|
292
|
+
if (Object.prototype.hasOwnProperty.call(riskLevels, risk)) {
|
|
293
|
+
riskLevels[risk] += 1;
|
|
294
|
+
} else {
|
|
295
|
+
riskLevels.unknown += 1;
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const averageSuccessRate = successRates.length > 0
|
|
300
|
+
? Number((successRates.reduce((sum, value) => sum + value, 0) / successRates.length).toFixed(2))
|
|
301
|
+
: null;
|
|
302
|
+
const averageFailedGoals = failedGoals.length > 0
|
|
303
|
+
? Number((failedGoals.reduce((sum, value) => sum + value, 0) / failedGoals.length).toFixed(2))
|
|
304
|
+
: null;
|
|
305
|
+
const averageOntologyScore = ontologyScores.length > 0
|
|
306
|
+
? Number((ontologyScores.reduce((sum, value) => sum + value, 0) / ontologyScores.length).toFixed(2))
|
|
307
|
+
: null;
|
|
308
|
+
const averageOntologyUnmappedRules = ontologyUnmappedRules.length > 0
|
|
309
|
+
? Number((ontologyUnmappedRules.reduce((sum, value) => sum + value, 0) / ontologyUnmappedRules.length).toFixed(2))
|
|
310
|
+
: null;
|
|
311
|
+
const averageOntologyUndecidedDecisions = ontologyUndecidedDecisions.length > 0
|
|
312
|
+
? Number((ontologyUndecidedDecisions.reduce((sum, value) => sum + value, 0) / ontologyUndecidedDecisions.length).toFixed(2))
|
|
313
|
+
: null;
|
|
314
|
+
const averageRulePassRate = rulePassRates.length > 0
|
|
315
|
+
? Number((rulePassRates.reduce((sum, value) => sum + value, 0) / rulePassRates.length).toFixed(2))
|
|
316
|
+
: null;
|
|
317
|
+
const averageDecisionResolvedRate = decisionResolvedRates.length > 0
|
|
318
|
+
? Number((decisionResolvedRates.reduce((sum, value) => sum + value, 0) / decisionResolvedRates.length).toFixed(2))
|
|
319
|
+
: null;
|
|
320
|
+
const averageSceneBatchFailures = sceneBatchFailures.length > 0
|
|
321
|
+
? Number((sceneBatchFailures.reduce((sum, value) => sum + value, 0) / sceneBatchFailures.length).toFixed(2))
|
|
322
|
+
: null;
|
|
323
|
+
const averageMoquiMatrixRegressions = moquiMatrixRegressions.length > 0
|
|
324
|
+
? Number((moquiMatrixRegressions.reduce((sum, value) => sum + value, 0) / moquiMatrixRegressions.length).toFixed(2))
|
|
325
|
+
: null;
|
|
326
|
+
const sceneBatchPassRate = sceneBatchApplicables.length > 0
|
|
327
|
+
? Number(((sceneBatchPassedCount / sceneBatchApplicables.length) * 100).toFixed(2))
|
|
328
|
+
: null;
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
avg_spec_success_rate_percent: averageSuccessRate,
|
|
332
|
+
min_spec_success_rate_percent: successRates.length > 0 ? Math.min(...successRates) : null,
|
|
333
|
+
max_spec_success_rate_percent: successRates.length > 0 ? Math.max(...successRates) : null,
|
|
334
|
+
avg_failed_goals: averageFailedGoals,
|
|
335
|
+
avg_ontology_quality_score: averageOntologyScore,
|
|
336
|
+
min_ontology_quality_score: ontologyScores.length > 0 ? Math.min(...ontologyScores) : null,
|
|
337
|
+
max_ontology_quality_score: ontologyScores.length > 0 ? Math.max(...ontologyScores) : null,
|
|
338
|
+
avg_ontology_unmapped_rules: averageOntologyUnmappedRules,
|
|
339
|
+
max_ontology_unmapped_rules: ontologyUnmappedRules.length > 0 ? Math.max(...ontologyUnmappedRules) : null,
|
|
340
|
+
avg_ontology_undecided_decisions: averageOntologyUndecidedDecisions,
|
|
341
|
+
max_ontology_undecided_decisions: ontologyUndecidedDecisions.length > 0 ? Math.max(...ontologyUndecidedDecisions) : null,
|
|
342
|
+
avg_ontology_business_rule_pass_rate_percent: averageRulePassRate,
|
|
343
|
+
avg_ontology_decision_resolved_rate_percent: averageDecisionResolvedRate,
|
|
344
|
+
scene_package_batch_applicable_count: sceneBatchApplicables.length,
|
|
345
|
+
scene_package_batch_passed_count: sceneBatchPassedCount,
|
|
346
|
+
scene_package_batch_failed_count: sceneBatchFailedCount,
|
|
347
|
+
scene_package_batch_pass_rate_percent: sceneBatchPassRate,
|
|
348
|
+
avg_scene_package_batch_failure_count: averageSceneBatchFailures,
|
|
349
|
+
max_scene_package_batch_failure_count: sceneBatchFailures.length > 0 ? Math.max(...sceneBatchFailures) : null,
|
|
350
|
+
avg_moqui_matrix_regression_count: averageMoquiMatrixRegressions,
|
|
351
|
+
max_moqui_matrix_regression_count: moquiMatrixRegressions.length > 0 ? Math.max(...moquiMatrixRegressions) : null,
|
|
352
|
+
risk_levels: riskLevels
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function buildAutoHandoffRegressionRiskLayers(series = []) {
|
|
357
|
+
const snapshots = Array.isArray(series) ? series.filter(Boolean) : [];
|
|
358
|
+
const levels = ['low', 'medium', 'high', 'unknown'];
|
|
359
|
+
const result = {};
|
|
360
|
+
|
|
361
|
+
levels.forEach(level => {
|
|
362
|
+
const scoped = snapshots.filter(item => {
|
|
363
|
+
const risk = `${item && item.risk_level ? item.risk_level : 'unknown'}`.trim().toLowerCase();
|
|
364
|
+
return risk === level;
|
|
365
|
+
});
|
|
366
|
+
const successRates = scoped
|
|
367
|
+
.map(item => Number(item.spec_success_rate_percent))
|
|
368
|
+
.filter(value => Number.isFinite(value));
|
|
369
|
+
const failedGoals = scoped
|
|
370
|
+
.map(item => Number(item.failed_goals))
|
|
371
|
+
.filter(value => Number.isFinite(value));
|
|
372
|
+
const ontologyScores = scoped
|
|
373
|
+
.map(item => Number(item.ontology_quality_score))
|
|
374
|
+
.filter(value => Number.isFinite(value));
|
|
375
|
+
const sceneBatchFailures = scoped
|
|
376
|
+
.map(item => Number(item.scene_package_batch_failure_count))
|
|
377
|
+
.filter(value => Number.isFinite(value));
|
|
378
|
+
const moquiMatrixRegressions = scoped
|
|
379
|
+
.map(item => Number(item.moqui_matrix_regression_count))
|
|
380
|
+
.filter(value => Number.isFinite(value));
|
|
381
|
+
const sceneBatchApplicable = scoped.filter(item => typeof item.scene_package_batch_passed === 'boolean');
|
|
382
|
+
const sceneBatchPassed = sceneBatchApplicable.filter(item => item.scene_package_batch_passed === true).length;
|
|
383
|
+
|
|
384
|
+
const avg = values => (
|
|
385
|
+
values.length > 0
|
|
386
|
+
? Number((values.reduce((sum, value) => sum + value, 0) / values.length).toFixed(2))
|
|
387
|
+
: null
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
result[level] = {
|
|
391
|
+
count: scoped.length,
|
|
392
|
+
sessions: scoped.map(item => item.session_id).filter(Boolean),
|
|
393
|
+
avg_spec_success_rate_percent: avg(successRates),
|
|
394
|
+
max_spec_success_rate_percent: successRates.length > 0 ? Math.max(...successRates) : null,
|
|
395
|
+
min_spec_success_rate_percent: successRates.length > 0 ? Math.min(...successRates) : null,
|
|
396
|
+
avg_failed_goals: avg(failedGoals),
|
|
397
|
+
avg_ontology_quality_score: avg(ontologyScores),
|
|
398
|
+
avg_scene_package_batch_failure_count: avg(sceneBatchFailures),
|
|
399
|
+
avg_moqui_matrix_regression_count: avg(moquiMatrixRegressions),
|
|
400
|
+
max_moqui_matrix_regression_count: moquiMatrixRegressions.length > 0 ? Math.max(...moquiMatrixRegressions) : null,
|
|
401
|
+
scene_package_batch_pass_rate_percent: sceneBatchApplicable.length > 0
|
|
402
|
+
? Number(((sceneBatchPassed / sceneBatchApplicable.length) * 100).toFixed(2))
|
|
403
|
+
: null
|
|
404
|
+
};
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function buildAutoHandoffRegressionRecommendations(payload = {}) {
|
|
411
|
+
const recommendations = [];
|
|
412
|
+
const seen = new Set();
|
|
413
|
+
const push = value => {
|
|
414
|
+
const text = `${value || ''}`.trim();
|
|
415
|
+
if (!text || seen.has(text)) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
seen.add(text);
|
|
419
|
+
recommendations.push(text);
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const current = payload.current || {};
|
|
423
|
+
const trend = `${payload.trend || 'stable'}`.trim().toLowerCase();
|
|
424
|
+
const windowTrend = payload.window_trend && payload.window_trend.trend
|
|
425
|
+
? `${payload.window_trend.trend}`.trim().toLowerCase()
|
|
426
|
+
: trend;
|
|
427
|
+
const currentFailed = Number(current.failed_goals);
|
|
428
|
+
const currentRisk = `${current.risk_level || 'unknown'}`.trim().toLowerCase();
|
|
429
|
+
const ontologyQuality = Number(current.ontology_quality_score);
|
|
430
|
+
const ontologyUnmappedRules = Number(current.ontology_unmapped_rules);
|
|
431
|
+
const ontologyUndecidedDecisions = Number(current.ontology_undecided_decisions);
|
|
432
|
+
const sceneBatchFailureCount = Number(current.scene_package_batch_failure_count);
|
|
433
|
+
const moquiMatrixRegressionCount = Number(current.moqui_matrix_regression_count);
|
|
434
|
+
const sceneBatchPassed = current.scene_package_batch_passed;
|
|
435
|
+
|
|
436
|
+
if (trend === 'degraded' || windowTrend === 'degraded') {
|
|
437
|
+
push(
|
|
438
|
+
`sce auto handoff run --manifest <path> --continue-from ${quoteCliArg(current.session_id || 'latest')} ` +
|
|
439
|
+
'--continue-strategy pending --json'
|
|
440
|
+
);
|
|
441
|
+
} else if (Number.isFinite(currentFailed) && currentFailed > 0) {
|
|
442
|
+
push(
|
|
443
|
+
`sce auto handoff run --manifest <path> --continue-from ${quoteCliArg(current.session_id || 'latest')} ` +
|
|
444
|
+
'--continue-strategy failed-only --json'
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (currentRisk === 'high') {
|
|
449
|
+
push('sce auto governance stats --days 14 --json');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (Number.isFinite(ontologyQuality) && ontologyQuality < 80) {
|
|
453
|
+
push('Strengthen ontology quality gate before next run: `--min-ontology-score 80`.');
|
|
454
|
+
}
|
|
455
|
+
if (Number.isFinite(ontologyUnmappedRules) && ontologyUnmappedRules > 0) {
|
|
456
|
+
push('Drive business-rule closure to zero unmapped rules (`--max-unmapped-rules 0`).');
|
|
457
|
+
}
|
|
458
|
+
if (Number.isFinite(ontologyUndecidedDecisions) && ontologyUndecidedDecisions > 0) {
|
|
459
|
+
push('Resolve pending decision logic entries (`--max-undecided-decisions 0`).');
|
|
460
|
+
}
|
|
461
|
+
if (sceneBatchPassed === false || (Number.isFinite(sceneBatchFailureCount) && sceneBatchFailureCount > 0)) {
|
|
462
|
+
push(
|
|
463
|
+
'Resolve scene package publish-batch gate failures and rerun: ' +
|
|
464
|
+
'`sce scene package-publish-batch --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
if (Number.isFinite(moquiMatrixRegressionCount) && moquiMatrixRegressionCount > 0) {
|
|
468
|
+
push(
|
|
469
|
+
'Recover Moqui matrix regressions and rerun baseline gate: ' +
|
|
470
|
+
'`sce scene moqui-baseline --include-all --compare-with .sce/reports/release-evidence/moqui-template-baseline.json --json`.'
|
|
471
|
+
);
|
|
472
|
+
for (const line of buildMoquiRegressionRecoverySequenceLines({
|
|
473
|
+
wrapCommands: true,
|
|
474
|
+
withPeriod: true
|
|
475
|
+
})) {
|
|
476
|
+
push(line);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if ((payload.window && Number(payload.window.actual) > 0) && (payload.window.requested !== payload.window.actual)) {
|
|
481
|
+
push('Increase regression coverage with `sce auto handoff regression --window 10 --json`.');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return recommendations;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function formatAutoHandoffRegressionValue(value, fallback = 'n/a') {
|
|
488
|
+
if (value === null || value === undefined) {
|
|
489
|
+
return fallback;
|
|
490
|
+
}
|
|
491
|
+
if (typeof value === 'number' && !Number.isFinite(value)) {
|
|
492
|
+
return fallback;
|
|
493
|
+
}
|
|
494
|
+
return `${value}`;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function getAutoHandoffMoquiCoverageMatrix(summary = {}) {
|
|
498
|
+
if (!summary || typeof summary !== 'object') {
|
|
499
|
+
return {};
|
|
500
|
+
}
|
|
501
|
+
return summary.coverage_matrix && typeof summary.coverage_matrix === 'object'
|
|
502
|
+
? summary.coverage_matrix
|
|
503
|
+
: {};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function getAutoHandoffMoquiCoverageMetric(summary = {}, metricName = '', field = 'rate_percent') {
|
|
507
|
+
const matrix = getAutoHandoffMoquiCoverageMatrix(summary);
|
|
508
|
+
const metric = matrix && matrix[metricName] && typeof matrix[metricName] === 'object'
|
|
509
|
+
? matrix[metricName]
|
|
510
|
+
: {};
|
|
511
|
+
const value = Number(metric[field]);
|
|
512
|
+
return Number.isFinite(value) ? value : null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function formatAutoHandoffMoquiCoverageMetric(summary = {}, metricName = '', field = 'rate_percent', suffix = '') {
|
|
516
|
+
const value = getAutoHandoffMoquiCoverageMetric(summary, metricName, field);
|
|
517
|
+
if (!Number.isFinite(value)) {
|
|
518
|
+
return 'n/a';
|
|
519
|
+
}
|
|
520
|
+
return `${value}${suffix}`;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function getAutoHandoffMoquiCoverageDeltaMatrix(compare = {}) {
|
|
524
|
+
if (!compare || typeof compare !== 'object') {
|
|
525
|
+
return {};
|
|
526
|
+
}
|
|
527
|
+
return compare.coverage_matrix_deltas && typeof compare.coverage_matrix_deltas === 'object'
|
|
528
|
+
? compare.coverage_matrix_deltas
|
|
529
|
+
: {};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function getAutoHandoffMoquiCoverageDeltaMetric(compare = {}, metricName = '', field = 'rate_percent') {
|
|
533
|
+
const matrix = getAutoHandoffMoquiCoverageDeltaMatrix(compare);
|
|
534
|
+
const metric = matrix && matrix[metricName] && typeof matrix[metricName] === 'object'
|
|
535
|
+
? matrix[metricName]
|
|
536
|
+
: {};
|
|
537
|
+
const value = Number(metric[field]);
|
|
538
|
+
return Number.isFinite(value) ? value : null;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function formatAutoHandoffMoquiCoverageDeltaMetric(compare = {}, metricName = '', field = 'rate_percent', suffix = '') {
|
|
542
|
+
const value = getAutoHandoffMoquiCoverageDeltaMetric(compare, metricName, field);
|
|
543
|
+
if (!Number.isFinite(value)) {
|
|
544
|
+
return 'n/a';
|
|
545
|
+
}
|
|
546
|
+
return `${value}${suffix}`;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function getAutoHandoffMoquiCoverageMetricLabel(metricName = '') {
|
|
550
|
+
const labels = {
|
|
551
|
+
graph_valid: 'graph-valid',
|
|
552
|
+
score_passed: 'score-passed',
|
|
553
|
+
entity_coverage: 'entity-coverage',
|
|
554
|
+
relation_coverage: 'relation-coverage',
|
|
555
|
+
business_rule_coverage: 'business-rule-coverage',
|
|
556
|
+
business_rule_closed: 'business-rule-closed',
|
|
557
|
+
decision_coverage: 'decision-coverage',
|
|
558
|
+
decision_closed: 'decision-closed',
|
|
559
|
+
baseline_passed: 'baseline-passed'
|
|
560
|
+
};
|
|
561
|
+
return labels[metricName] || metricName;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function buildAutoHandoffMoquiCoverageRegressions(compare = {}, dependencies = {}) {
|
|
565
|
+
const { normalizeHandoffText } = dependencies;
|
|
566
|
+
const source = compare && typeof compare === 'object' ? compare : {};
|
|
567
|
+
const predefined = Array.isArray(source.coverage_matrix_regressions)
|
|
568
|
+
? source.coverage_matrix_regressions
|
|
569
|
+
: null;
|
|
570
|
+
if (predefined) {
|
|
571
|
+
const normalized = predefined
|
|
572
|
+
.map(item => {
|
|
573
|
+
const metric = normalizeHandoffText(item && item.metric);
|
|
574
|
+
const deltaRate = Number(item && item.delta_rate_percent);
|
|
575
|
+
if (!metric || !Number.isFinite(deltaRate) || deltaRate >= 0) {
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
return {
|
|
579
|
+
metric,
|
|
580
|
+
label: normalizeHandoffText(item && item.label) || getAutoHandoffMoquiCoverageMetricLabel(metric),
|
|
581
|
+
delta_rate_percent: Number(deltaRate.toFixed(2))
|
|
582
|
+
};
|
|
583
|
+
})
|
|
584
|
+
.filter(Boolean);
|
|
585
|
+
if (normalized.length > 0) {
|
|
586
|
+
return normalized.sort((a, b) => {
|
|
587
|
+
if (a.delta_rate_percent !== b.delta_rate_percent) {
|
|
588
|
+
return a.delta_rate_percent - b.delta_rate_percent;
|
|
589
|
+
}
|
|
590
|
+
return `${a.metric}`.localeCompare(`${b.metric}`);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const deltaMatrix = getAutoHandoffMoquiCoverageDeltaMatrix(source);
|
|
596
|
+
return Object.entries(deltaMatrix)
|
|
597
|
+
.map(([metric, value]) => {
|
|
598
|
+
const deltaRate = Number(value && value.rate_percent);
|
|
599
|
+
if (!Number.isFinite(deltaRate) || deltaRate >= 0) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
return {
|
|
603
|
+
metric,
|
|
604
|
+
label: getAutoHandoffMoquiCoverageMetricLabel(metric),
|
|
605
|
+
delta_rate_percent: Number(deltaRate.toFixed(2))
|
|
606
|
+
};
|
|
607
|
+
})
|
|
608
|
+
.filter(Boolean)
|
|
609
|
+
.sort((a, b) => {
|
|
610
|
+
if (a.delta_rate_percent !== b.delta_rate_percent) {
|
|
611
|
+
return a.delta_rate_percent - b.delta_rate_percent;
|
|
612
|
+
}
|
|
613
|
+
return `${a.metric}`.localeCompare(`${b.metric}`);
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function formatAutoHandoffMoquiCoverageRegressions(compare = {}, limit = 3) {
|
|
618
|
+
const regressions = buildAutoHandoffMoquiCoverageRegressions(compare);
|
|
619
|
+
if (regressions.length === 0) {
|
|
620
|
+
return 'none';
|
|
621
|
+
}
|
|
622
|
+
const maxItems = Number.isFinite(Number(limit)) && Number(limit) > 0 ? Number(limit) : regressions.length;
|
|
623
|
+
return regressions
|
|
624
|
+
.slice(0, maxItems)
|
|
625
|
+
.map(item => `${item.label}:${item.delta_rate_percent}%`)
|
|
626
|
+
.join(' | ');
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function renderAutoHandoffRegressionAsciiBar(value, max = 100, width = 20) {
|
|
630
|
+
const parsed = Number(value);
|
|
631
|
+
if (!Number.isFinite(parsed)) {
|
|
632
|
+
return `${'.'.repeat(width)} n/a`;
|
|
633
|
+
}
|
|
634
|
+
const bounded = Math.max(0, Math.min(max, parsed));
|
|
635
|
+
const ratio = max > 0 ? bounded / max : 0;
|
|
636
|
+
const filled = Math.max(0, Math.min(width, Math.round(ratio * width)));
|
|
637
|
+
return `${'#'.repeat(filled)}${'.'.repeat(Math.max(0, width - filled))} ${Number(bounded.toFixed(2))}`;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function renderAutoHandoffRegressionMarkdown(payload = {}) {
|
|
641
|
+
const current = payload.current || {};
|
|
642
|
+
const previous = payload.previous || null;
|
|
643
|
+
const window = payload.window || { requested: 2, actual: 0 };
|
|
644
|
+
const delta = payload.delta || {};
|
|
645
|
+
const windowTrend = payload.window_trend || { trend: 'baseline', delta: {} };
|
|
646
|
+
const aggregates = payload.aggregates || {};
|
|
647
|
+
const riskLevels = aggregates.risk_levels || {};
|
|
648
|
+
const recommendations = Array.isArray(payload.recommendations) ? payload.recommendations : [];
|
|
649
|
+
const series = Array.isArray(payload.series) ? payload.series : [];
|
|
650
|
+
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
651
|
+
? payload.risk_layers
|
|
652
|
+
: {};
|
|
653
|
+
const trendSeriesLines = series.length > 0
|
|
654
|
+
? series.map(item => {
|
|
655
|
+
const sessionId = formatAutoHandoffRegressionValue(item.session_id);
|
|
656
|
+
const generatedAt = formatAutoHandoffRegressionValue(item.generated_at);
|
|
657
|
+
const riskLevel = formatAutoHandoffRegressionValue(item.risk_level);
|
|
658
|
+
const failedGoals = formatAutoHandoffRegressionValue(item.failed_goals);
|
|
659
|
+
const sceneBatch = item.scene_package_batch_passed === null || item.scene_package_batch_passed === undefined
|
|
660
|
+
? 'n/a'
|
|
661
|
+
: (item.scene_package_batch_passed ? 'pass' : 'fail');
|
|
662
|
+
const successBar = renderAutoHandoffRegressionAsciiBar(item.spec_success_rate_percent, 100, 20);
|
|
663
|
+
const ontologyBar = renderAutoHandoffRegressionAsciiBar(item.ontology_quality_score, 100, 20);
|
|
664
|
+
return `- ${sessionId} | ${generatedAt} | risk=${riskLevel} | failed=${failedGoals} | scene-batch=${sceneBatch} | success=${successBar} | ontology=${ontologyBar}`;
|
|
665
|
+
})
|
|
666
|
+
: ['- None'];
|
|
667
|
+
const riskLayerLines = ['low', 'medium', 'high', 'unknown'].map(level => {
|
|
668
|
+
const scoped = riskLayers[level] && typeof riskLayers[level] === 'object'
|
|
669
|
+
? riskLayers[level]
|
|
670
|
+
: {};
|
|
671
|
+
return (
|
|
672
|
+
`- ${level}: count=${formatAutoHandoffRegressionValue(scoped.count, '0')}, ` +
|
|
673
|
+
`avg_success=${formatAutoHandoffRegressionValue(scoped.avg_spec_success_rate_percent)}, ` +
|
|
674
|
+
`avg_failed_goals=${formatAutoHandoffRegressionValue(scoped.avg_failed_goals)}, ` +
|
|
675
|
+
`avg_ontology_quality=${formatAutoHandoffRegressionValue(scoped.avg_ontology_quality_score)}, ` +
|
|
676
|
+
`scene_batch_pass_rate=${formatAutoHandoffRegressionValue(scoped.scene_package_batch_pass_rate_percent)}%, ` +
|
|
677
|
+
`avg_moqui_matrix_regressions=${formatAutoHandoffRegressionValue(scoped.avg_moqui_matrix_regression_count, '0')}`
|
|
678
|
+
);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
const lines = [
|
|
682
|
+
'# Auto Handoff Regression Report',
|
|
683
|
+
'',
|
|
684
|
+
`- Session: ${formatAutoHandoffRegressionValue(current.session_id)}`,
|
|
685
|
+
`- Compared to: ${previous ? formatAutoHandoffRegressionValue(previous.session_id) : 'none'}`,
|
|
686
|
+
`- Trend: ${formatAutoHandoffRegressionValue(payload.trend)}`,
|
|
687
|
+
`- Window: ${formatAutoHandoffRegressionValue(window.actual)}/${formatAutoHandoffRegressionValue(window.requested)}`,
|
|
688
|
+
'',
|
|
689
|
+
'## Point Delta',
|
|
690
|
+
'',
|
|
691
|
+
`- Spec success rate delta: ${formatAutoHandoffRegressionValue(delta.spec_success_rate_percent)}`,
|
|
692
|
+
`- Risk level rank delta: ${formatAutoHandoffRegressionValue(delta.risk_level_rank)}`,
|
|
693
|
+
`- Failed goals delta: ${formatAutoHandoffRegressionValue(delta.failed_goals)}`,
|
|
694
|
+
`- Elapsed ms delta: ${formatAutoHandoffRegressionValue(delta.elapsed_ms)}`,
|
|
695
|
+
`- Ontology quality delta: ${formatAutoHandoffRegressionValue(delta.ontology_quality_score)}`,
|
|
696
|
+
`- Ontology unmapped rules delta: ${formatAutoHandoffRegressionValue(delta.ontology_unmapped_rules)}`,
|
|
697
|
+
`- Ontology undecided decisions delta: ${formatAutoHandoffRegressionValue(delta.ontology_undecided_decisions)}`,
|
|
698
|
+
`- Moqui matrix regression count delta: ${formatAutoHandoffRegressionValue(delta.moqui_matrix_regression_count)}`,
|
|
699
|
+
`- Scene package batch failure count delta: ${formatAutoHandoffRegressionValue(delta.scene_package_batch_failure_count)}`,
|
|
700
|
+
'',
|
|
701
|
+
'## Window Trend',
|
|
702
|
+
'',
|
|
703
|
+
`- Trend: ${formatAutoHandoffRegressionValue(windowTrend.trend)}`,
|
|
704
|
+
`- Success rate delta: ${formatAutoHandoffRegressionValue(windowTrend.delta && windowTrend.delta.spec_success_rate_percent)}`,
|
|
705
|
+
`- Risk level rank delta: ${formatAutoHandoffRegressionValue(windowTrend.delta && windowTrend.delta.risk_level_rank)}`,
|
|
706
|
+
`- Failed goals delta: ${formatAutoHandoffRegressionValue(windowTrend.delta && windowTrend.delta.failed_goals)}`,
|
|
707
|
+
`- Moqui matrix regression count delta: ${formatAutoHandoffRegressionValue(windowTrend.delta && windowTrend.delta.moqui_matrix_regression_count)}`,
|
|
708
|
+
'',
|
|
709
|
+
'## Aggregates',
|
|
710
|
+
'',
|
|
711
|
+
`- Avg spec success rate: ${formatAutoHandoffRegressionValue(aggregates.avg_spec_success_rate_percent)}`,
|
|
712
|
+
`- Min spec success rate: ${formatAutoHandoffRegressionValue(aggregates.min_spec_success_rate_percent)}`,
|
|
713
|
+
`- Max spec success rate: ${formatAutoHandoffRegressionValue(aggregates.max_spec_success_rate_percent)}`,
|
|
714
|
+
`- Avg failed goals: ${formatAutoHandoffRegressionValue(aggregates.avg_failed_goals)}`,
|
|
715
|
+
`- Avg ontology quality score: ${formatAutoHandoffRegressionValue(aggregates.avg_ontology_quality_score)}`,
|
|
716
|
+
`- Min ontology quality score: ${formatAutoHandoffRegressionValue(aggregates.min_ontology_quality_score)}`,
|
|
717
|
+
`- Max ontology quality score: ${formatAutoHandoffRegressionValue(aggregates.max_ontology_quality_score)}`,
|
|
718
|
+
`- Avg ontology unmapped rules: ${formatAutoHandoffRegressionValue(aggregates.avg_ontology_unmapped_rules)}`,
|
|
719
|
+
`- Max ontology unmapped rules: ${formatAutoHandoffRegressionValue(aggregates.max_ontology_unmapped_rules)}`,
|
|
720
|
+
`- Avg ontology undecided decisions: ${formatAutoHandoffRegressionValue(aggregates.avg_ontology_undecided_decisions)}`,
|
|
721
|
+
`- Max ontology undecided decisions: ${formatAutoHandoffRegressionValue(aggregates.max_ontology_undecided_decisions)}`,
|
|
722
|
+
`- Avg business rule pass rate: ${formatAutoHandoffRegressionValue(aggregates.avg_ontology_business_rule_pass_rate_percent)}`,
|
|
723
|
+
`- Avg decision resolved rate: ${formatAutoHandoffRegressionValue(aggregates.avg_ontology_decision_resolved_rate_percent)}`,
|
|
724
|
+
`- Scene package batch pass rate: ${formatAutoHandoffRegressionValue(aggregates.scene_package_batch_pass_rate_percent)}%`,
|
|
725
|
+
`- Scene package batch failed sessions: ${formatAutoHandoffRegressionValue(aggregates.scene_package_batch_failed_count, '0')}`,
|
|
726
|
+
`- Avg scene package batch failure count: ${formatAutoHandoffRegressionValue(aggregates.avg_scene_package_batch_failure_count)}`,
|
|
727
|
+
`- Avg Moqui matrix regression count: ${formatAutoHandoffRegressionValue(aggregates.avg_moqui_matrix_regression_count)}`,
|
|
728
|
+
`- Max Moqui matrix regression count: ${formatAutoHandoffRegressionValue(aggregates.max_moqui_matrix_regression_count)}`,
|
|
729
|
+
`- Risk levels: low=${formatAutoHandoffRegressionValue(riskLevels.low, '0')}, medium=${formatAutoHandoffRegressionValue(riskLevels.medium, '0')}, high=${formatAutoHandoffRegressionValue(riskLevels.high, '0')}, unknown=${formatAutoHandoffRegressionValue(riskLevels.unknown, '0')}`,
|
|
730
|
+
'',
|
|
731
|
+
'## Trend Series',
|
|
732
|
+
'',
|
|
733
|
+
...trendSeriesLines,
|
|
734
|
+
'',
|
|
735
|
+
'## Risk Layer View',
|
|
736
|
+
'',
|
|
737
|
+
...riskLayerLines,
|
|
738
|
+
'',
|
|
739
|
+
'## Recommendations'
|
|
740
|
+
];
|
|
741
|
+
|
|
742
|
+
if (recommendations.length === 0) {
|
|
743
|
+
lines.push('', '- None');
|
|
744
|
+
} else {
|
|
745
|
+
recommendations.forEach(item => {
|
|
746
|
+
lines.push('', `- ${item}`);
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return `${lines.join('\n')}\n`;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
function renderAutoHandoffEvidenceReviewMarkdown(payload = {}) {
|
|
755
|
+
const current = payload.current || {};
|
|
756
|
+
const currentOverview = payload.current_overview || {};
|
|
757
|
+
const gate = currentOverview.gate && typeof currentOverview.gate === 'object'
|
|
758
|
+
? currentOverview.gate
|
|
759
|
+
: {};
|
|
760
|
+
const gateActual = gate && gate.actual && typeof gate.actual === 'object'
|
|
761
|
+
? gate.actual
|
|
762
|
+
: {};
|
|
763
|
+
const releaseGatePreflight = currentOverview.release_gate_preflight && typeof currentOverview.release_gate_preflight === 'object'
|
|
764
|
+
? currentOverview.release_gate_preflight
|
|
765
|
+
: {};
|
|
766
|
+
const failureSummary = currentOverview.failure_summary && typeof currentOverview.failure_summary === 'object'
|
|
767
|
+
? currentOverview.failure_summary
|
|
768
|
+
: {};
|
|
769
|
+
const currentPolicy = currentOverview.policy && typeof currentOverview.policy === 'object'
|
|
770
|
+
? currentOverview.policy
|
|
771
|
+
: {};
|
|
772
|
+
const ontology = currentOverview.ontology_validation && typeof currentOverview.ontology_validation === 'object'
|
|
773
|
+
? currentOverview.ontology_validation
|
|
774
|
+
: {};
|
|
775
|
+
const ontologyMetrics = ontology && ontology.metrics && typeof ontology.metrics === 'object'
|
|
776
|
+
? ontology.metrics
|
|
777
|
+
: {};
|
|
778
|
+
const regression = currentOverview.regression && typeof currentOverview.regression === 'object'
|
|
779
|
+
? currentOverview.regression
|
|
780
|
+
: {};
|
|
781
|
+
const moquiBaseline = currentOverview.moqui_baseline && typeof currentOverview.moqui_baseline === 'object'
|
|
782
|
+
? currentOverview.moqui_baseline
|
|
783
|
+
: {};
|
|
784
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
785
|
+
? moquiBaseline.summary
|
|
786
|
+
: {};
|
|
787
|
+
const moquiScopeBreakdown = moquiSummary && moquiSummary.scope_breakdown && typeof moquiSummary.scope_breakdown === 'object'
|
|
788
|
+
? moquiSummary.scope_breakdown
|
|
789
|
+
: {};
|
|
790
|
+
const moquiGapFrequency = Array.isArray(moquiSummary && moquiSummary.gap_frequency)
|
|
791
|
+
? moquiSummary.gap_frequency
|
|
792
|
+
: [];
|
|
793
|
+
const moquiCompare = moquiBaseline && moquiBaseline.compare && typeof moquiBaseline.compare === 'object'
|
|
794
|
+
? moquiBaseline.compare
|
|
795
|
+
: {};
|
|
796
|
+
const moquiMatrixRegressions = buildAutoHandoffMoquiCoverageRegressions(moquiCompare);
|
|
797
|
+
const moquiDeltas = moquiCompare && moquiCompare.deltas && typeof moquiCompare.deltas === 'object'
|
|
798
|
+
? moquiCompare.deltas
|
|
799
|
+
: {};
|
|
800
|
+
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
801
|
+
? moquiCompare.failed_templates
|
|
802
|
+
: {};
|
|
803
|
+
const scenePackageBatch = currentOverview.scene_package_batch && typeof currentOverview.scene_package_batch === 'object'
|
|
804
|
+
? currentOverview.scene_package_batch
|
|
805
|
+
: {};
|
|
806
|
+
const scenePackageBatchSummary = scenePackageBatch && scenePackageBatch.summary && typeof scenePackageBatch.summary === 'object'
|
|
807
|
+
? scenePackageBatch.summary
|
|
808
|
+
: {};
|
|
809
|
+
const scenePackageBatchGate = scenePackageBatch && scenePackageBatch.batch_ontology_gate && typeof scenePackageBatch.batch_ontology_gate === 'object'
|
|
810
|
+
? scenePackageBatch.batch_ontology_gate
|
|
811
|
+
: {};
|
|
812
|
+
const scenePackageBatchFailures = Array.isArray(scenePackageBatchGate.failures)
|
|
813
|
+
? scenePackageBatchGate.failures
|
|
814
|
+
: [];
|
|
815
|
+
const capabilityCoverage = currentOverview.capability_coverage && typeof currentOverview.capability_coverage === 'object'
|
|
816
|
+
? currentOverview.capability_coverage
|
|
817
|
+
: {};
|
|
818
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
819
|
+
? capabilityCoverage.summary
|
|
820
|
+
: {};
|
|
821
|
+
const capabilityCompare = capabilityCoverage && capabilityCoverage.compare && typeof capabilityCoverage.compare === 'object'
|
|
822
|
+
? capabilityCoverage.compare
|
|
823
|
+
: {};
|
|
824
|
+
const capabilityGaps = Array.isArray(capabilityCoverage && capabilityCoverage.gaps)
|
|
825
|
+
? capabilityCoverage.gaps
|
|
826
|
+
: [];
|
|
827
|
+
const capabilityNormalization = capabilityCoverage && capabilityCoverage.normalization && typeof capabilityCoverage.normalization === 'object'
|
|
828
|
+
? capabilityCoverage.normalization
|
|
829
|
+
: {};
|
|
830
|
+
const capabilityWarnings = Array.isArray(capabilityCoverage && capabilityCoverage.warnings)
|
|
831
|
+
? capabilityCoverage.warnings
|
|
832
|
+
: [];
|
|
833
|
+
const window = payload.window || { requested: 5, actual: 0 };
|
|
834
|
+
const series = Array.isArray(payload.series) ? payload.series : [];
|
|
835
|
+
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
836
|
+
? payload.risk_layers
|
|
837
|
+
: {};
|
|
838
|
+
const recommendations = Array.isArray(payload.recommendations) ? payload.recommendations : [];
|
|
839
|
+
const governanceSnapshot = payload.governance_snapshot && typeof payload.governance_snapshot === 'object'
|
|
840
|
+
? payload.governance_snapshot
|
|
841
|
+
: null;
|
|
842
|
+
const governanceHealth = governanceSnapshot && governanceSnapshot.health &&
|
|
843
|
+
typeof governanceSnapshot.health === 'object'
|
|
844
|
+
? governanceSnapshot.health
|
|
845
|
+
: {};
|
|
846
|
+
const governanceReleaseGate = governanceHealth.release_gate && typeof governanceHealth.release_gate === 'object'
|
|
847
|
+
? governanceHealth.release_gate
|
|
848
|
+
: {};
|
|
849
|
+
const governanceHandoffQuality = governanceHealth.handoff_quality && typeof governanceHealth.handoff_quality === 'object'
|
|
850
|
+
? governanceHealth.handoff_quality
|
|
851
|
+
: {};
|
|
852
|
+
const trendSeriesLines = series.length > 0
|
|
853
|
+
? series.map(item => {
|
|
854
|
+
const sessionId = formatAutoHandoffRegressionValue(item.session_id);
|
|
855
|
+
const mergedAt = formatAutoHandoffRegressionValue(item.merged_at || item.generated_at);
|
|
856
|
+
const riskLevel = formatAutoHandoffRegressionValue(item.risk_level);
|
|
857
|
+
const failedGoals = formatAutoHandoffRegressionValue(item.failed_goals);
|
|
858
|
+
const sceneBatch = item.scene_package_batch_passed === null || item.scene_package_batch_passed === undefined
|
|
859
|
+
? 'n/a'
|
|
860
|
+
: (item.scene_package_batch_passed ? 'pass' : 'fail');
|
|
861
|
+
const successBar = renderAutoHandoffRegressionAsciiBar(item.spec_success_rate_percent, 100, 20);
|
|
862
|
+
const ontologyBar = renderAutoHandoffRegressionAsciiBar(item.ontology_quality_score, 100, 20);
|
|
863
|
+
const capabilityBar = renderAutoHandoffRegressionAsciiBar(item.capability_coverage_percent, 100, 20);
|
|
864
|
+
return (
|
|
865
|
+
`- ${sessionId} | ${mergedAt} | risk=${riskLevel} | failed=${failedGoals} | scene-batch=${sceneBatch} | ` +
|
|
866
|
+
`success=${successBar} | ontology=${ontologyBar} | capability=${capabilityBar}`
|
|
867
|
+
);
|
|
868
|
+
})
|
|
869
|
+
: ['- None'];
|
|
870
|
+
const riskLayerLines = ['low', 'medium', 'high', 'unknown'].map(level => {
|
|
871
|
+
const scoped = riskLayers[level] && typeof riskLayers[level] === 'object'
|
|
872
|
+
? riskLayers[level]
|
|
873
|
+
: {};
|
|
874
|
+
return (
|
|
875
|
+
`- ${level}: count=${formatAutoHandoffRegressionValue(scoped.count, '0')}, ` +
|
|
876
|
+
`avg_success=${formatAutoHandoffRegressionValue(scoped.avg_spec_success_rate_percent)}, ` +
|
|
877
|
+
`avg_failed_goals=${formatAutoHandoffRegressionValue(scoped.avg_failed_goals)}, ` +
|
|
878
|
+
`avg_ontology_quality=${formatAutoHandoffRegressionValue(scoped.avg_ontology_quality_score)}, ` +
|
|
879
|
+
`scene_batch_pass_rate=${formatAutoHandoffRegressionValue(scoped.scene_package_batch_pass_rate_percent)}%, ` +
|
|
880
|
+
`avg_moqui_matrix_regressions=${formatAutoHandoffRegressionValue(scoped.avg_moqui_matrix_regression_count, '0')}`
|
|
881
|
+
);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
const lines = [
|
|
885
|
+
'# Auto Handoff Release Evidence Review',
|
|
886
|
+
'',
|
|
887
|
+
`- Evidence file: ${formatAutoHandoffRegressionValue(payload.evidence_file)}`,
|
|
888
|
+
`- Session: ${formatAutoHandoffRegressionValue(current.session_id)}`,
|
|
889
|
+
`- Status: ${formatAutoHandoffRegressionValue(current.status)}`,
|
|
890
|
+
`- Trend: ${formatAutoHandoffRegressionValue(payload.trend)}`,
|
|
891
|
+
`- Window: ${formatAutoHandoffRegressionValue(window.actual)}/${formatAutoHandoffRegressionValue(window.requested)}`,
|
|
892
|
+
'',
|
|
893
|
+
'## Current Gate',
|
|
894
|
+
'',
|
|
895
|
+
`- Passed: ${gate.passed === true ? 'yes' : 'no'}`,
|
|
896
|
+
`- Spec success rate: ${formatAutoHandoffRegressionValue(gateActual.spec_success_rate_percent)}`,
|
|
897
|
+
`- Risk level: ${formatAutoHandoffRegressionValue(gateActual.risk_level)}`,
|
|
898
|
+
`- Ontology quality score: ${formatAutoHandoffRegressionValue(gateActual.ontology_quality_score)}`,
|
|
899
|
+
`- Unmapped business rules: ${formatAutoHandoffRegressionValue(gateActual.ontology_business_rule_unmapped)}`,
|
|
900
|
+
`- Undecided decisions: ${formatAutoHandoffRegressionValue(gateActual.ontology_decision_undecided)}`,
|
|
901
|
+
'',
|
|
902
|
+
'## Current Release Gate Preflight',
|
|
903
|
+
'',
|
|
904
|
+
`- Available: ${releaseGatePreflight.available === true ? 'yes' : 'no'}`,
|
|
905
|
+
`- Blocked: ${releaseGatePreflight.blocked === true ? 'yes' : 'no'}`,
|
|
906
|
+
`- Latest tag: ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_tag)}`,
|
|
907
|
+
`- Latest gate passed: ${releaseGatePreflight.latest_gate_passed === true ? 'yes' : (releaseGatePreflight.latest_gate_passed === false ? 'no' : 'n/a')}`,
|
|
908
|
+
`- Pass rate: ${formatAutoHandoffRegressionValue(releaseGatePreflight.pass_rate_percent)}%`,
|
|
909
|
+
`- Scene batch pass rate: ${formatAutoHandoffRegressionValue(releaseGatePreflight.scene_package_batch_pass_rate_percent)}%`,
|
|
910
|
+
`- Drift alert rate: ${formatAutoHandoffRegressionValue(releaseGatePreflight.drift_alert_rate_percent)}%`,
|
|
911
|
+
`- Drift blocked runs: ${formatAutoHandoffRegressionValue(releaseGatePreflight.drift_blocked_runs)}`,
|
|
912
|
+
`- Runtime block rate (latest/max): ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_weekly_ops_runtime_block_rate_percent)}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_block_rate_max_percent)}%`,
|
|
913
|
+
`- Runtime ui-mode violations (latest/total): ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_weekly_ops_runtime_ui_mode_violation_total, '0')}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_ui_mode_violation_total, '0')}`,
|
|
914
|
+
`- Runtime ui-mode violation rate (latest/run-rate/max): ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_weekly_ops_runtime_ui_mode_violation_rate_percent)}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_ui_mode_violation_run_rate_percent)}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_ui_mode_violation_rate_max_percent)}%`,
|
|
915
|
+
`- Reasons: ${Array.isArray(releaseGatePreflight.reasons) && releaseGatePreflight.reasons.length > 0 ? releaseGatePreflight.reasons.join(' | ') : 'none'}`,
|
|
916
|
+
`- Parse error: ${formatAutoHandoffRegressionValue(releaseGatePreflight.parse_error)}`,
|
|
917
|
+
'',
|
|
918
|
+
'## Current Failure Summary',
|
|
919
|
+
'',
|
|
920
|
+
`- Failed phase: ${formatAutoHandoffRegressionValue(failureSummary.failed_phase && failureSummary.failed_phase.id)}`,
|
|
921
|
+
`- Gate failed: ${failureSummary.gate_failed === true ? 'yes' : 'no'}`,
|
|
922
|
+
`- Release gate preflight blocked: ${failureSummary.release_gate_preflight_blocked === true ? 'yes' : 'no'}`,
|
|
923
|
+
`- Highlights: ${Array.isArray(failureSummary.highlights) && failureSummary.highlights.length > 0 ? failureSummary.highlights.join(' | ') : 'none'}`,
|
|
924
|
+
'',
|
|
925
|
+
'## Current Ontology',
|
|
926
|
+
'',
|
|
927
|
+
`- Status: ${formatAutoHandoffRegressionValue(ontology.status)}`,
|
|
928
|
+
`- Passed: ${ontology.passed === true ? 'yes' : 'no'}`,
|
|
929
|
+
`- Quality score: ${formatAutoHandoffRegressionValue(ontology.quality_score)}`,
|
|
930
|
+
`- Entity total: ${formatAutoHandoffRegressionValue(ontologyMetrics.entity_total)}`,
|
|
931
|
+
`- Relation total: ${formatAutoHandoffRegressionValue(ontologyMetrics.relation_total)}`,
|
|
932
|
+
`- Business rule unmapped: ${formatAutoHandoffRegressionValue(ontologyMetrics.business_rule_unmapped)}`,
|
|
933
|
+
`- Decision undecided: ${formatAutoHandoffRegressionValue(ontologyMetrics.decision_undecided)}`,
|
|
934
|
+
'',
|
|
935
|
+
'## Current Regression',
|
|
936
|
+
'',
|
|
937
|
+
`- Trend: ${formatAutoHandoffRegressionValue(regression.trend)}`,
|
|
938
|
+
`- Delta success rate: ${formatAutoHandoffRegressionValue(regression.delta && regression.delta.spec_success_rate_percent)}`,
|
|
939
|
+
`- Delta risk rank: ${formatAutoHandoffRegressionValue(regression.delta && regression.delta.risk_level_rank)}`,
|
|
940
|
+
`- Delta failed goals: ${formatAutoHandoffRegressionValue(regression.delta && regression.delta.failed_goals)}`,
|
|
941
|
+
'',
|
|
942
|
+
'## Current Moqui Baseline',
|
|
943
|
+
'',
|
|
944
|
+
`- Status: ${formatAutoHandoffRegressionValue(moquiBaseline.status)}`,
|
|
945
|
+
`- Portfolio passed: ${moquiSummary.portfolio_passed === true ? 'yes' : (moquiSummary.portfolio_passed === false ? 'no' : 'n/a')}`,
|
|
946
|
+
`- Avg score: ${formatAutoHandoffRegressionValue(moquiSummary.avg_score)}`,
|
|
947
|
+
`- Valid-rate: ${formatAutoHandoffRegressionValue(moquiSummary.valid_rate_percent)}%`,
|
|
948
|
+
`- Baseline failed templates: ${formatAutoHandoffRegressionValue(moquiSummary.baseline_failed)}`,
|
|
949
|
+
`- Matrix regression count: ${formatAutoHandoffRegressionValue(moquiMatrixRegressions.length, '0')}`,
|
|
950
|
+
`- Matrix regression gate (max): ${formatAutoHandoffRegressionValue(currentPolicy.max_moqui_matrix_regressions)}`,
|
|
951
|
+
`- Scope mix (moqui/suite/other): ${formatAutoHandoffRegressionValue(moquiScopeBreakdown.moqui_erp, '0')}/${formatAutoHandoffRegressionValue(moquiScopeBreakdown.scene_orchestration, '0')}/${formatAutoHandoffRegressionValue(moquiScopeBreakdown.other, '0')}`,
|
|
952
|
+
`- Entity coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'entity_coverage', 'rate_percent', '%')}`,
|
|
953
|
+
`- Relation coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'relation_coverage', 'rate_percent', '%')}`,
|
|
954
|
+
`- Business-rule coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'business_rule_coverage', 'rate_percent', '%')}`,
|
|
955
|
+
`- Business-rule closed: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'business_rule_closed', 'rate_percent', '%')}`,
|
|
956
|
+
`- Decision coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'decision_coverage', 'rate_percent', '%')}`,
|
|
957
|
+
`- Decision closed: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'decision_closed', 'rate_percent', '%')}`,
|
|
958
|
+
`- Delta avg score: ${formatAutoHandoffRegressionValue(moquiDeltas.avg_score)}`,
|
|
959
|
+
`- Delta valid-rate: ${formatAutoHandoffRegressionValue(moquiDeltas.valid_rate_percent)}%`,
|
|
960
|
+
`- Delta entity coverage: ${formatAutoHandoffMoquiCoverageDeltaMetric(moquiCompare, 'entity_coverage', 'rate_percent', '%')}`,
|
|
961
|
+
`- Delta business-rule closed: ${formatAutoHandoffMoquiCoverageDeltaMetric(moquiCompare, 'business_rule_closed', 'rate_percent', '%')}`,
|
|
962
|
+
`- Delta decision closed: ${formatAutoHandoffMoquiCoverageDeltaMetric(moquiCompare, 'decision_closed', 'rate_percent', '%')}`,
|
|
963
|
+
`- Matrix regressions: ${formatAutoHandoffMoquiCoverageRegressions(moquiCompare, 5)}`,
|
|
964
|
+
`- Newly failed templates: ${Array.isArray(moquiFailedTemplates.newly_failed) && moquiFailedTemplates.newly_failed.length > 0 ? moquiFailedTemplates.newly_failed.join(', ') : 'none'}`,
|
|
965
|
+
`- Recovered templates: ${Array.isArray(moquiFailedTemplates.recovered) && moquiFailedTemplates.recovered.length > 0 ? moquiFailedTemplates.recovered.join(', ') : 'none'}`,
|
|
966
|
+
`- Top baseline gaps: ${moquiGapFrequency.length > 0 ? moquiGapFrequency.slice(0, 3).map(item => `${item.gap}:${item.count}`).join(' | ') : 'none'}`,
|
|
967
|
+
`- Baseline JSON: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.json)}`,
|
|
968
|
+
'',
|
|
969
|
+
'## Current Scene Package Batch',
|
|
970
|
+
'',
|
|
971
|
+
`- Status: ${formatAutoHandoffRegressionValue(scenePackageBatch.status)}`,
|
|
972
|
+
`- Generated: ${scenePackageBatch.generated === true ? 'yes' : 'no'}`,
|
|
973
|
+
`- Selected specs: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.selected)}`,
|
|
974
|
+
`- Failed specs: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.failed)}`,
|
|
975
|
+
`- Batch gate passed: ${scenePackageBatchSummary.batch_gate_passed === true ? 'yes' : (scenePackageBatchSummary.batch_gate_passed === false ? 'no' : 'n/a')}`,
|
|
976
|
+
`- Batch gate failure count: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.batch_gate_failure_count)}`,
|
|
977
|
+
`- Ontology average score: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.ontology_average_score)}`,
|
|
978
|
+
`- Ontology valid-rate: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.ontology_valid_rate_percent)}%`,
|
|
979
|
+
`- Batch gate failures: ${scenePackageBatchFailures.length > 0 ? scenePackageBatchFailures.map(item => item && item.message ? item.message : '').filter(Boolean).join(' | ') : 'none'}`,
|
|
980
|
+
`- Scene batch JSON: ${formatAutoHandoffRegressionValue(scenePackageBatch.output && scenePackageBatch.output.json)}`,
|
|
981
|
+
'',
|
|
982
|
+
'## Current Capability Coverage',
|
|
983
|
+
'',
|
|
984
|
+
`- Status: ${formatAutoHandoffRegressionValue(capabilityCoverage.status)}`,
|
|
985
|
+
`- Passed: ${capabilitySummary.passed === true ? 'yes' : (capabilitySummary.passed === false ? 'no' : 'n/a')}`,
|
|
986
|
+
`- Coverage: ${formatAutoHandoffRegressionValue(capabilitySummary.coverage_percent)}%`,
|
|
987
|
+
`- Min required: ${formatAutoHandoffRegressionValue(capabilitySummary.min_required_percent)}%`,
|
|
988
|
+
`- Covered capabilities: ${formatAutoHandoffRegressionValue(capabilitySummary.covered_capabilities)}`,
|
|
989
|
+
`- Uncovered capabilities: ${formatAutoHandoffRegressionValue(capabilitySummary.uncovered_capabilities)}`,
|
|
990
|
+
`- Delta coverage: ${formatAutoHandoffRegressionValue(capabilityCompare.delta_coverage_percent)}%`,
|
|
991
|
+
`- Delta covered capabilities: ${formatAutoHandoffRegressionValue(capabilityCompare.delta_covered_capabilities)}`,
|
|
992
|
+
`- Newly covered: ${Array.isArray(capabilityCompare.newly_covered) && capabilityCompare.newly_covered.length > 0 ? capabilityCompare.newly_covered.join(', ') : 'none'}`,
|
|
993
|
+
`- Newly uncovered: ${Array.isArray(capabilityCompare.newly_uncovered) && capabilityCompare.newly_uncovered.length > 0 ? capabilityCompare.newly_uncovered.join(', ') : 'none'}`,
|
|
994
|
+
`- Lexicon version: ${formatAutoHandoffRegressionValue(capabilityNormalization.lexicon_version)}`,
|
|
995
|
+
`- Expected alias mapped: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.expected_alias_mapped) ? capabilityNormalization.expected_alias_mapped.length : 0)}`,
|
|
996
|
+
`- Expected deprecated alias: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.expected_deprecated_aliases) ? capabilityNormalization.expected_deprecated_aliases.length : 0)}`,
|
|
997
|
+
`- Expected unknown: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.expected_unknown) ? capabilityNormalization.expected_unknown.length : 0)}`,
|
|
998
|
+
`- Provided alias mapped: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.provided_alias_mapped) ? capabilityNormalization.provided_alias_mapped.length : 0)}`,
|
|
999
|
+
`- Provided deprecated alias: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.provided_deprecated_aliases) ? capabilityNormalization.provided_deprecated_aliases.length : 0)}`,
|
|
1000
|
+
`- Provided unknown: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.provided_unknown) ? capabilityNormalization.provided_unknown.length : 0)}`,
|
|
1001
|
+
`- Capability gaps: ${capabilityGaps.length > 0 ? capabilityGaps.join(', ') : 'none'}`,
|
|
1002
|
+
`- Coverage warnings: ${capabilityWarnings.length > 0 ? capabilityWarnings.join(' | ') : 'none'}`,
|
|
1003
|
+
`- Coverage JSON: ${formatAutoHandoffRegressionValue(capabilityCoverage.output && capabilityCoverage.output.json)}`,
|
|
1004
|
+
'',
|
|
1005
|
+
'## Trend Series',
|
|
1006
|
+
'',
|
|
1007
|
+
...trendSeriesLines,
|
|
1008
|
+
'',
|
|
1009
|
+
'## Risk Layer View',
|
|
1010
|
+
'',
|
|
1011
|
+
...riskLayerLines,
|
|
1012
|
+
'',
|
|
1013
|
+
'## Governance Snapshot',
|
|
1014
|
+
'',
|
|
1015
|
+
`- Risk level: ${formatAutoHandoffRegressionValue(governanceHealth.risk_level)}`,
|
|
1016
|
+
`- Concern count: ${formatAutoHandoffRegressionValue(Array.isArray(governanceHealth.concerns) ? governanceHealth.concerns.length : 0, '0')}`,
|
|
1017
|
+
`- Recommendation count: ${formatAutoHandoffRegressionValue(Array.isArray(governanceHealth.recommendations) ? governanceHealth.recommendations.length : 0, '0')}`,
|
|
1018
|
+
`- Release gate available: ${governanceReleaseGate.available === true ? 'yes' : 'no'}`,
|
|
1019
|
+
`- Release gate latest passed: ${governanceReleaseGate.latest_gate_passed === true ? 'yes' : (governanceReleaseGate.latest_gate_passed === false ? 'no' : 'n/a')}`,
|
|
1020
|
+
`- Handoff quality available: ${governanceHandoffQuality.available === true ? 'yes' : 'no'}`,
|
|
1021
|
+
`- Handoff latest status: ${formatAutoHandoffRegressionValue(governanceHandoffQuality.latest_status)}`,
|
|
1022
|
+
`- Handoff latest gate passed: ${governanceHandoffQuality.latest_gate_passed === true ? 'yes' : (governanceHandoffQuality.latest_gate_passed === false ? 'no' : 'n/a')}`,
|
|
1023
|
+
`- Handoff latest ontology score: ${formatAutoHandoffRegressionValue(governanceHandoffQuality.latest_ontology_quality_score)}`,
|
|
1024
|
+
'',
|
|
1025
|
+
'## Recommendations'
|
|
1026
|
+
];
|
|
1027
|
+
|
|
1028
|
+
if (recommendations.length === 0) {
|
|
1029
|
+
lines.push('', '- None');
|
|
1030
|
+
} else {
|
|
1031
|
+
recommendations.forEach(item => {
|
|
1032
|
+
lines.push('', `- ${item}`);
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
return `${lines.join('\n')}\n`;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
function renderAutoHandoffReleaseNotesDraft(payload = {}, context = {}, dependencies = {}) {
|
|
1041
|
+
const { normalizeHandoffReleaseVersion, normalizeHandoffReleaseDate } = dependencies;
|
|
1042
|
+
const current = payload.current || {};
|
|
1043
|
+
const currentOverview = payload.current_overview || {};
|
|
1044
|
+
const gate = currentOverview.gate && typeof currentOverview.gate === 'object'
|
|
1045
|
+
? currentOverview.gate
|
|
1046
|
+
: {};
|
|
1047
|
+
const gateActual = gate && gate.actual && typeof gate.actual === 'object'
|
|
1048
|
+
? gate.actual
|
|
1049
|
+
: {};
|
|
1050
|
+
const releaseGatePreflight = currentOverview.release_gate_preflight && typeof currentOverview.release_gate_preflight === 'object'
|
|
1051
|
+
? currentOverview.release_gate_preflight
|
|
1052
|
+
: {};
|
|
1053
|
+
const failureSummary = currentOverview.failure_summary && typeof currentOverview.failure_summary === 'object'
|
|
1054
|
+
? currentOverview.failure_summary
|
|
1055
|
+
: {};
|
|
1056
|
+
const currentPolicy = currentOverview.policy && typeof currentOverview.policy === 'object'
|
|
1057
|
+
? currentOverview.policy
|
|
1058
|
+
: {};
|
|
1059
|
+
const ontology = currentOverview.ontology_validation && typeof currentOverview.ontology_validation === 'object'
|
|
1060
|
+
? currentOverview.ontology_validation
|
|
1061
|
+
: {};
|
|
1062
|
+
const ontologyMetrics = ontology && ontology.metrics && typeof ontology.metrics === 'object'
|
|
1063
|
+
? ontology.metrics
|
|
1064
|
+
: {};
|
|
1065
|
+
const regression = currentOverview.regression && typeof currentOverview.regression === 'object'
|
|
1066
|
+
? currentOverview.regression
|
|
1067
|
+
: {};
|
|
1068
|
+
const moquiBaseline = currentOverview.moqui_baseline && typeof currentOverview.moqui_baseline === 'object'
|
|
1069
|
+
? currentOverview.moqui_baseline
|
|
1070
|
+
: {};
|
|
1071
|
+
const moquiSummary = moquiBaseline && moquiBaseline.summary && typeof moquiBaseline.summary === 'object'
|
|
1072
|
+
? moquiBaseline.summary
|
|
1073
|
+
: {};
|
|
1074
|
+
const moquiScopeBreakdown = moquiSummary && moquiSummary.scope_breakdown && typeof moquiSummary.scope_breakdown === 'object'
|
|
1075
|
+
? moquiSummary.scope_breakdown
|
|
1076
|
+
: {};
|
|
1077
|
+
const moquiGapFrequency = Array.isArray(moquiSummary && moquiSummary.gap_frequency)
|
|
1078
|
+
? moquiSummary.gap_frequency
|
|
1079
|
+
: [];
|
|
1080
|
+
const moquiCompare = moquiBaseline && moquiBaseline.compare && typeof moquiBaseline.compare === 'object'
|
|
1081
|
+
? moquiBaseline.compare
|
|
1082
|
+
: {};
|
|
1083
|
+
const moquiMatrixRegressions = buildAutoHandoffMoquiCoverageRegressions(moquiCompare);
|
|
1084
|
+
const moquiDeltas = moquiCompare && moquiCompare.deltas && typeof moquiCompare.deltas === 'object'
|
|
1085
|
+
? moquiCompare.deltas
|
|
1086
|
+
: {};
|
|
1087
|
+
const moquiFailedTemplates = moquiCompare && moquiCompare.failed_templates && typeof moquiCompare.failed_templates === 'object'
|
|
1088
|
+
? moquiCompare.failed_templates
|
|
1089
|
+
: {};
|
|
1090
|
+
const scenePackageBatch = currentOverview.scene_package_batch && typeof currentOverview.scene_package_batch === 'object'
|
|
1091
|
+
? currentOverview.scene_package_batch
|
|
1092
|
+
: {};
|
|
1093
|
+
const scenePackageBatchSummary = scenePackageBatch && scenePackageBatch.summary && typeof scenePackageBatch.summary === 'object'
|
|
1094
|
+
? scenePackageBatch.summary
|
|
1095
|
+
: {};
|
|
1096
|
+
const scenePackageBatchGate = scenePackageBatch && scenePackageBatch.batch_ontology_gate && typeof scenePackageBatch.batch_ontology_gate === 'object'
|
|
1097
|
+
? scenePackageBatch.batch_ontology_gate
|
|
1098
|
+
: {};
|
|
1099
|
+
const scenePackageBatchFailures = Array.isArray(scenePackageBatchGate.failures)
|
|
1100
|
+
? scenePackageBatchGate.failures
|
|
1101
|
+
: [];
|
|
1102
|
+
const capabilityCoverage = currentOverview.capability_coverage && typeof currentOverview.capability_coverage === 'object'
|
|
1103
|
+
? currentOverview.capability_coverage
|
|
1104
|
+
: {};
|
|
1105
|
+
const capabilitySummary = capabilityCoverage && capabilityCoverage.summary && typeof capabilityCoverage.summary === 'object'
|
|
1106
|
+
? capabilityCoverage.summary
|
|
1107
|
+
: {};
|
|
1108
|
+
const capabilityCompare = capabilityCoverage && capabilityCoverage.compare && typeof capabilityCoverage.compare === 'object'
|
|
1109
|
+
? capabilityCoverage.compare
|
|
1110
|
+
: {};
|
|
1111
|
+
const capabilityGaps = Array.isArray(capabilityCoverage && capabilityCoverage.gaps)
|
|
1112
|
+
? capabilityCoverage.gaps
|
|
1113
|
+
: [];
|
|
1114
|
+
const capabilityNormalization = capabilityCoverage && capabilityCoverage.normalization && typeof capabilityCoverage.normalization === 'object'
|
|
1115
|
+
? capabilityCoverage.normalization
|
|
1116
|
+
: {};
|
|
1117
|
+
const capabilityWarnings = Array.isArray(capabilityCoverage && capabilityCoverage.warnings)
|
|
1118
|
+
? capabilityCoverage.warnings
|
|
1119
|
+
: [];
|
|
1120
|
+
const riskLayers = payload.risk_layers && typeof payload.risk_layers === 'object'
|
|
1121
|
+
? payload.risk_layers
|
|
1122
|
+
: {};
|
|
1123
|
+
const statusCounts = payload.aggregates && payload.aggregates.status_counts
|
|
1124
|
+
? payload.aggregates.status_counts
|
|
1125
|
+
: {};
|
|
1126
|
+
const recommendations = Array.isArray(payload.recommendations) ? payload.recommendations : [];
|
|
1127
|
+
const governanceSnapshot = payload.governance_snapshot && typeof payload.governance_snapshot === 'object'
|
|
1128
|
+
? payload.governance_snapshot
|
|
1129
|
+
: null;
|
|
1130
|
+
const governanceHealth = governanceSnapshot && governanceSnapshot.health &&
|
|
1131
|
+
typeof governanceSnapshot.health === 'object'
|
|
1132
|
+
? governanceSnapshot.health
|
|
1133
|
+
: {};
|
|
1134
|
+
const governanceReleaseGate = governanceHealth.release_gate && typeof governanceHealth.release_gate === 'object'
|
|
1135
|
+
? governanceHealth.release_gate
|
|
1136
|
+
: {};
|
|
1137
|
+
const governanceHandoffQuality = governanceHealth.handoff_quality && typeof governanceHealth.handoff_quality === 'object'
|
|
1138
|
+
? governanceHealth.handoff_quality
|
|
1139
|
+
: {};
|
|
1140
|
+
const reviewFile = typeof context.reviewFile === 'string' && context.reviewFile.trim()
|
|
1141
|
+
? context.reviewFile.trim()
|
|
1142
|
+
: null;
|
|
1143
|
+
const version = normalizeHandoffReleaseVersion(context.version, '0.0.0');
|
|
1144
|
+
const releaseDate = normalizeHandoffReleaseDate(context.releaseDate);
|
|
1145
|
+
|
|
1146
|
+
const riskLines = ['low', 'medium', 'high', 'unknown'].map(level => {
|
|
1147
|
+
const scoped = riskLayers[level] && typeof riskLayers[level] === 'object'
|
|
1148
|
+
? riskLayers[level]
|
|
1149
|
+
: {};
|
|
1150
|
+
return (
|
|
1151
|
+
`- ${level}: count=${formatAutoHandoffRegressionValue(scoped.count, '0')}, ` +
|
|
1152
|
+
`avg_success=${formatAutoHandoffRegressionValue(scoped.avg_spec_success_rate_percent)}, ` +
|
|
1153
|
+
`avg_failed_goals=${formatAutoHandoffRegressionValue(scoped.avg_failed_goals)}, ` +
|
|
1154
|
+
`avg_ontology_quality=${formatAutoHandoffRegressionValue(scoped.avg_ontology_quality_score)}, ` +
|
|
1155
|
+
`avg_moqui_matrix_regressions=${formatAutoHandoffRegressionValue(scoped.avg_moqui_matrix_regression_count, '0')}`
|
|
1156
|
+
);
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
const lines = [
|
|
1160
|
+
`# Release Notes Draft: ${version}`,
|
|
1161
|
+
'',
|
|
1162
|
+
`Release date: ${releaseDate}`,
|
|
1163
|
+
'',
|
|
1164
|
+
'## Handoff Evidence Summary',
|
|
1165
|
+
'',
|
|
1166
|
+
`- Evidence file: ${formatAutoHandoffRegressionValue(payload.evidence_file)}`,
|
|
1167
|
+
`- Current session: ${formatAutoHandoffRegressionValue(current.session_id)}`,
|
|
1168
|
+
`- Current status: ${formatAutoHandoffRegressionValue(current.status)}`,
|
|
1169
|
+
`- Gate passed: ${gate.passed === true ? 'yes' : 'no'}`,
|
|
1170
|
+
`- Release gate preflight available: ${releaseGatePreflight.available === true ? 'yes' : 'no'}`,
|
|
1171
|
+
`- Release gate preflight blocked: ${releaseGatePreflight.blocked === true ? 'yes' : 'no'}`,
|
|
1172
|
+
`- Release gate preflight hard-gate: ${currentPolicy.require_release_gate_preflight === true ? 'enabled' : 'advisory'}`,
|
|
1173
|
+
`- Release gate preflight reasons: ${Array.isArray(releaseGatePreflight.reasons) && releaseGatePreflight.reasons.length > 0 ? releaseGatePreflight.reasons.join(' | ') : 'none'}`,
|
|
1174
|
+
`- Release gate runtime block rate (latest/max): ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_weekly_ops_runtime_block_rate_percent)}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_block_rate_max_percent)}%`,
|
|
1175
|
+
`- Release gate runtime ui-mode violations (latest/total): ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_weekly_ops_runtime_ui_mode_violation_total, '0')}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_ui_mode_violation_total, '0')}`,
|
|
1176
|
+
`- Release gate runtime ui-mode violation rate (latest/run-rate/max): ${formatAutoHandoffRegressionValue(releaseGatePreflight.latest_weekly_ops_runtime_ui_mode_violation_rate_percent)}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_ui_mode_violation_run_rate_percent)}/${formatAutoHandoffRegressionValue(releaseGatePreflight.weekly_ops_runtime_ui_mode_violation_rate_max_percent)}%`,
|
|
1177
|
+
`- Failure summary highlights: ${Array.isArray(failureSummary.highlights) && failureSummary.highlights.length > 0 ? failureSummary.highlights.join(' | ') : 'none'}`,
|
|
1178
|
+
`- Spec success rate: ${formatAutoHandoffRegressionValue(gateActual.spec_success_rate_percent)}`,
|
|
1179
|
+
`- Risk level: ${formatAutoHandoffRegressionValue(gateActual.risk_level)}`,
|
|
1180
|
+
`- Ontology quality score: ${formatAutoHandoffRegressionValue(gateActual.ontology_quality_score)}`,
|
|
1181
|
+
`- Ontology unmapped rules: ${formatAutoHandoffRegressionValue(gateActual.ontology_business_rule_unmapped, formatAutoHandoffRegressionValue(ontologyMetrics.business_rule_unmapped))}`,
|
|
1182
|
+
`- Ontology undecided decisions: ${formatAutoHandoffRegressionValue(gateActual.ontology_decision_undecided, formatAutoHandoffRegressionValue(ontologyMetrics.decision_undecided))}`,
|
|
1183
|
+
`- Regression trend: ${formatAutoHandoffRegressionValue(regression.trend, formatAutoHandoffRegressionValue(payload.trend))}`,
|
|
1184
|
+
`- Window trend: ${formatAutoHandoffRegressionValue(payload.window_trend && payload.window_trend.trend)}`,
|
|
1185
|
+
`- Gate pass rate (window): ${formatAutoHandoffRegressionValue(payload.aggregates && payload.aggregates.gate_pass_rate_percent)}%`,
|
|
1186
|
+
`- Moqui baseline portfolio passed: ${moquiSummary.portfolio_passed === true ? 'yes' : (moquiSummary.portfolio_passed === false ? 'no' : 'n/a')}`,
|
|
1187
|
+
`- Moqui baseline avg score: ${formatAutoHandoffRegressionValue(moquiSummary.avg_score)}`,
|
|
1188
|
+
`- Moqui baseline valid-rate: ${formatAutoHandoffRegressionValue(moquiSummary.valid_rate_percent)}%`,
|
|
1189
|
+
`- Moqui baseline failed templates: ${formatAutoHandoffRegressionValue(moquiSummary.baseline_failed)}`,
|
|
1190
|
+
`- Moqui matrix regression count: ${formatAutoHandoffRegressionValue(moquiMatrixRegressions.length, '0')}`,
|
|
1191
|
+
`- Moqui matrix regression gate (max): ${formatAutoHandoffRegressionValue(currentPolicy.max_moqui_matrix_regressions)}`,
|
|
1192
|
+
`- Moqui scope mix (moqui/suite/other): ${formatAutoHandoffRegressionValue(moquiScopeBreakdown.moqui_erp, '0')}/${formatAutoHandoffRegressionValue(moquiScopeBreakdown.scene_orchestration, '0')}/${formatAutoHandoffRegressionValue(moquiScopeBreakdown.other, '0')}`,
|
|
1193
|
+
`- Moqui entity coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'entity_coverage', 'rate_percent', '%')}`,
|
|
1194
|
+
`- Moqui relation coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'relation_coverage', 'rate_percent', '%')}`,
|
|
1195
|
+
`- Moqui business-rule coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'business_rule_coverage', 'rate_percent', '%')}`,
|
|
1196
|
+
`- Moqui business-rule closed: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'business_rule_closed', 'rate_percent', '%')}`,
|
|
1197
|
+
`- Moqui decision coverage: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'decision_coverage', 'rate_percent', '%')}`,
|
|
1198
|
+
`- Moqui decision closed: ${formatAutoHandoffMoquiCoverageMetric(moquiSummary, 'decision_closed', 'rate_percent', '%')}`,
|
|
1199
|
+
`- Moqui baseline avg score delta: ${formatAutoHandoffRegressionValue(moquiDeltas.avg_score)}`,
|
|
1200
|
+
`- Moqui baseline valid-rate delta: ${formatAutoHandoffRegressionValue(moquiDeltas.valid_rate_percent)}%`,
|
|
1201
|
+
`- Moqui entity coverage delta: ${formatAutoHandoffMoquiCoverageDeltaMetric(moquiCompare, 'entity_coverage', 'rate_percent', '%')}`,
|
|
1202
|
+
`- Moqui business-rule closed delta: ${formatAutoHandoffMoquiCoverageDeltaMetric(moquiCompare, 'business_rule_closed', 'rate_percent', '%')}`,
|
|
1203
|
+
`- Moqui decision closed delta: ${formatAutoHandoffMoquiCoverageDeltaMetric(moquiCompare, 'decision_closed', 'rate_percent', '%')}`,
|
|
1204
|
+
`- Moqui matrix regressions: ${formatAutoHandoffMoquiCoverageRegressions(moquiCompare, 5)}`,
|
|
1205
|
+
`- Moqui newly failed templates: ${Array.isArray(moquiFailedTemplates.newly_failed) && moquiFailedTemplates.newly_failed.length > 0 ? moquiFailedTemplates.newly_failed.join(', ') : 'none'}`,
|
|
1206
|
+
`- Moqui top baseline gaps: ${moquiGapFrequency.length > 0 ? moquiGapFrequency.slice(0, 3).map(item => `${item.gap}:${item.count}`).join(' | ') : 'none'}`,
|
|
1207
|
+
`- Scene package batch status: ${formatAutoHandoffRegressionValue(scenePackageBatch.status)}`,
|
|
1208
|
+
`- Scene package batch selected: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.selected)}`,
|
|
1209
|
+
`- Scene package batch failed: ${formatAutoHandoffRegressionValue(scenePackageBatchSummary.failed)}`,
|
|
1210
|
+
`- Scene package batch gate passed: ${scenePackageBatchSummary.batch_gate_passed === true ? 'yes' : (scenePackageBatchSummary.batch_gate_passed === false ? 'no' : 'n/a')}`,
|
|
1211
|
+
`- Scene package batch gate failures: ${scenePackageBatchFailures.length > 0 ? scenePackageBatchFailures.map(item => item && item.message ? item.message : '').filter(Boolean).join(' | ') : 'none'}`,
|
|
1212
|
+
`- Capability coverage status: ${formatAutoHandoffRegressionValue(capabilityCoverage.status)}`,
|
|
1213
|
+
`- Capability coverage passed: ${capabilitySummary.passed === true ? 'yes' : (capabilitySummary.passed === false ? 'no' : 'n/a')}`,
|
|
1214
|
+
`- Capability coverage: ${formatAutoHandoffRegressionValue(capabilitySummary.coverage_percent)}%`,
|
|
1215
|
+
`- Capability min required: ${formatAutoHandoffRegressionValue(capabilitySummary.min_required_percent)}%`,
|
|
1216
|
+
`- Capability coverage delta: ${formatAutoHandoffRegressionValue(capabilityCompare.delta_coverage_percent)}%`,
|
|
1217
|
+
`- Capability newly uncovered: ${Array.isArray(capabilityCompare.newly_uncovered) && capabilityCompare.newly_uncovered.length > 0 ? capabilityCompare.newly_uncovered.join(', ') : 'none'}`,
|
|
1218
|
+
`- Capability lexicon version: ${formatAutoHandoffRegressionValue(capabilityNormalization.lexicon_version)}`,
|
|
1219
|
+
`- Capability expected alias mapped: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.expected_alias_mapped) ? capabilityNormalization.expected_alias_mapped.length : 0)}`,
|
|
1220
|
+
`- Capability expected deprecated alias: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.expected_deprecated_aliases) ? capabilityNormalization.expected_deprecated_aliases.length : 0)}`,
|
|
1221
|
+
`- Capability provided deprecated alias: ${formatAutoHandoffRegressionValue(Array.isArray(capabilityNormalization.provided_deprecated_aliases) ? capabilityNormalization.provided_deprecated_aliases.length : 0)}`,
|
|
1222
|
+
`- Capability gaps: ${capabilityGaps.length > 0 ? capabilityGaps.join(', ') : 'none'}`,
|
|
1223
|
+
`- Capability warnings: ${capabilityWarnings.length > 0 ? capabilityWarnings.join(' | ') : 'none'}`,
|
|
1224
|
+
'',
|
|
1225
|
+
'## Status Breakdown',
|
|
1226
|
+
'',
|
|
1227
|
+
`- completed: ${formatAutoHandoffRegressionValue(statusCounts.completed, '0')}`,
|
|
1228
|
+
`- failed: ${formatAutoHandoffRegressionValue(statusCounts.failed, '0')}`,
|
|
1229
|
+
`- dry_run: ${formatAutoHandoffRegressionValue(statusCounts.dry_run, '0')}`,
|
|
1230
|
+
`- running: ${formatAutoHandoffRegressionValue(statusCounts.running, '0')}`,
|
|
1231
|
+
`- other: ${formatAutoHandoffRegressionValue(statusCounts.other, '0')}`,
|
|
1232
|
+
'',
|
|
1233
|
+
'## Risk Layer Snapshot',
|
|
1234
|
+
'',
|
|
1235
|
+
...riskLines,
|
|
1236
|
+
'',
|
|
1237
|
+
'## Governance Snapshot',
|
|
1238
|
+
'',
|
|
1239
|
+
`- Risk level: ${formatAutoHandoffRegressionValue(governanceHealth.risk_level)}`,
|
|
1240
|
+
`- Concern count: ${formatAutoHandoffRegressionValue(Array.isArray(governanceHealth.concerns) ? governanceHealth.concerns.length : 0, '0')}`,
|
|
1241
|
+
`- Recommendation count: ${formatAutoHandoffRegressionValue(Array.isArray(governanceHealth.recommendations) ? governanceHealth.recommendations.length : 0, '0')}`,
|
|
1242
|
+
`- Release gate available: ${governanceReleaseGate.available === true ? 'yes' : 'no'}`,
|
|
1243
|
+
`- Release gate latest passed: ${governanceReleaseGate.latest_gate_passed === true ? 'yes' : (governanceReleaseGate.latest_gate_passed === false ? 'no' : 'n/a')}`,
|
|
1244
|
+
`- Handoff quality available: ${governanceHandoffQuality.available === true ? 'yes' : 'no'}`,
|
|
1245
|
+
`- Handoff latest status: ${formatAutoHandoffRegressionValue(governanceHandoffQuality.latest_status)}`,
|
|
1246
|
+
`- Handoff latest gate passed: ${governanceHandoffQuality.latest_gate_passed === true ? 'yes' : (governanceHandoffQuality.latest_gate_passed === false ? 'no' : 'n/a')}`,
|
|
1247
|
+
`- Handoff latest ontology score: ${formatAutoHandoffRegressionValue(governanceHandoffQuality.latest_ontology_quality_score)}`,
|
|
1248
|
+
'',
|
|
1249
|
+
'## Release Evidence Artifacts',
|
|
1250
|
+
'',
|
|
1251
|
+
`- Evidence review report: ${reviewFile || 'n/a'}`,
|
|
1252
|
+
`- Handoff report: ${formatAutoHandoffRegressionValue(currentOverview.handoff_report_file)}`,
|
|
1253
|
+
`- Release evidence JSON: ${formatAutoHandoffRegressionValue(payload.evidence_file)}`,
|
|
1254
|
+
`- Moqui baseline JSON: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.json)}`,
|
|
1255
|
+
`- Moqui baseline markdown: ${formatAutoHandoffRegressionValue(moquiBaseline.output && moquiBaseline.output.markdown)}`,
|
|
1256
|
+
`- Scene package batch JSON: ${formatAutoHandoffRegressionValue(scenePackageBatch.output && scenePackageBatch.output.json)}`,
|
|
1257
|
+
`- Capability coverage JSON: ${formatAutoHandoffRegressionValue(capabilityCoverage.output && capabilityCoverage.output.json)}`,
|
|
1258
|
+
`- Capability coverage markdown: ${formatAutoHandoffRegressionValue(capabilityCoverage.output && capabilityCoverage.output.markdown)}`,
|
|
1259
|
+
`- Governance snapshot generated at: ${formatAutoHandoffRegressionValue(governanceSnapshot && governanceSnapshot.generated_at)}`,
|
|
1260
|
+
'',
|
|
1261
|
+
'## Recommendations'
|
|
1262
|
+
];
|
|
1263
|
+
|
|
1264
|
+
if (recommendations.length === 0) {
|
|
1265
|
+
lines.push('', '- None');
|
|
1266
|
+
} else {
|
|
1267
|
+
recommendations.forEach(item => {
|
|
1268
|
+
lines.push('', `- ${item}`);
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return `${lines.join('\n')}\n`;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
async function buildAutoHandoffRegression(projectPath, currentResult, dependencies = {}) {
|
|
1277
|
+
const { listAutoHandoffRunReports, buildAutoHandoffRegressionSnapshot, buildAutoHandoffRegressionComparison } = dependencies;
|
|
1278
|
+
const reports = await listAutoHandoffRunReports(projectPath);
|
|
1279
|
+
const previous = reports.find(item => item.session_id !== currentResult.session_id) || null;
|
|
1280
|
+
const currentSnapshot = buildAutoHandoffRegressionSnapshot(currentResult, dependencies);
|
|
1281
|
+
if (!previous) {
|
|
1282
|
+
return {
|
|
1283
|
+
mode: 'auto-handoff-regression',
|
|
1284
|
+
current: currentSnapshot,
|
|
1285
|
+
previous: null,
|
|
1286
|
+
trend: 'baseline',
|
|
1287
|
+
delta: {
|
|
1288
|
+
spec_success_rate_percent: null,
|
|
1289
|
+
risk_level_rank: null,
|
|
1290
|
+
failed_goals: null,
|
|
1291
|
+
elapsed_ms: null,
|
|
1292
|
+
ontology_quality_score: null,
|
|
1293
|
+
ontology_unmapped_rules: null,
|
|
1294
|
+
ontology_undecided_decisions: null,
|
|
1295
|
+
ontology_business_rule_pass_rate_percent: null,
|
|
1296
|
+
ontology_decision_resolved_rate_percent: null,
|
|
1297
|
+
scene_package_batch_failure_count: null
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
const previousSnapshot = buildAutoHandoffRegressionSnapshot(previous, dependencies);
|
|
1303
|
+
const comparison = buildAutoHandoffRegressionComparison(currentSnapshot, previousSnapshot);
|
|
1304
|
+
return {
|
|
1305
|
+
mode: 'auto-handoff-regression',
|
|
1306
|
+
current: currentSnapshot,
|
|
1307
|
+
previous: previousSnapshot,
|
|
1308
|
+
trend: comparison.trend,
|
|
1309
|
+
delta: comparison.delta
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
async function buildAutoHandoffRegressionReport(projectPath, options = {}, dependencies = {}) {
|
|
1314
|
+
const {
|
|
1315
|
+
listAutoHandoffRunReports,
|
|
1316
|
+
normalizeHandoffSessionQuery,
|
|
1317
|
+
normalizeHandoffRegressionWindow,
|
|
1318
|
+
buildAutoHandoffRegressionSnapshot,
|
|
1319
|
+
buildAutoHandoffRegressionComparison,
|
|
1320
|
+
buildAutoHandoffRegressionWindowTrend,
|
|
1321
|
+
buildAutoHandoffRegressionAggregates,
|
|
1322
|
+
buildAutoHandoffRegressionRiskLayers,
|
|
1323
|
+
buildAutoHandoffRegressionRecommendations
|
|
1324
|
+
} = dependencies;
|
|
1325
|
+
const reports = await listAutoHandoffRunReports(projectPath);
|
|
1326
|
+
if (reports.length === 0) {
|
|
1327
|
+
throw new Error('no handoff run reports found');
|
|
1328
|
+
}
|
|
1329
|
+
const query = normalizeHandoffSessionQuery(options.sessionId);
|
|
1330
|
+
const windowSize = normalizeHandoffRegressionWindow(options.window);
|
|
1331
|
+
let currentIndex = 0;
|
|
1332
|
+
if (query !== 'latest') {
|
|
1333
|
+
currentIndex = reports.findIndex(item => item.session_id === query);
|
|
1334
|
+
if (currentIndex < 0) {
|
|
1335
|
+
throw new Error(`handoff run session not found: ${query}`);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
const chainReports = reports.slice(currentIndex, currentIndex + windowSize);
|
|
1340
|
+
const series = chainReports.map(item => buildAutoHandoffRegressionSnapshot(item, dependencies));
|
|
1341
|
+
const currentSnapshot = series[0];
|
|
1342
|
+
const previousSnapshot = series[1] || null;
|
|
1343
|
+
const comparison = previousSnapshot
|
|
1344
|
+
? buildAutoHandoffRegressionComparison(currentSnapshot, previousSnapshot)
|
|
1345
|
+
: {
|
|
1346
|
+
trend: 'baseline',
|
|
1347
|
+
delta: {
|
|
1348
|
+
spec_success_rate_percent: null,
|
|
1349
|
+
risk_level_rank: null,
|
|
1350
|
+
failed_goals: null,
|
|
1351
|
+
elapsed_ms: null,
|
|
1352
|
+
ontology_quality_score: null,
|
|
1353
|
+
ontology_unmapped_rules: null,
|
|
1354
|
+
ontology_undecided_decisions: null,
|
|
1355
|
+
ontology_business_rule_pass_rate_percent: null,
|
|
1356
|
+
ontology_decision_resolved_rate_percent: null,
|
|
1357
|
+
scene_package_batch_failure_count: null
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
const windowTrend = buildAutoHandoffRegressionWindowTrend(series);
|
|
1361
|
+
const aggregates = buildAutoHandoffRegressionAggregates(series);
|
|
1362
|
+
const riskLayers = buildAutoHandoffRegressionRiskLayers(series);
|
|
1363
|
+
|
|
1364
|
+
const payload = {
|
|
1365
|
+
mode: 'auto-handoff-regression',
|
|
1366
|
+
current: currentSnapshot,
|
|
1367
|
+
previous: previousSnapshot,
|
|
1368
|
+
trend: comparison.trend,
|
|
1369
|
+
delta: comparison.delta,
|
|
1370
|
+
window: {
|
|
1371
|
+
requested: windowSize,
|
|
1372
|
+
actual: series.length
|
|
1373
|
+
},
|
|
1374
|
+
series,
|
|
1375
|
+
window_trend: windowTrend,
|
|
1376
|
+
aggregates,
|
|
1377
|
+
risk_layers: riskLayers,
|
|
1378
|
+
recommendations: []
|
|
1379
|
+
};
|
|
1380
|
+
payload.recommendations = buildAutoHandoffRegressionRecommendations(payload);
|
|
1381
|
+
return payload;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
module.exports = {
|
|
1386
|
+
buildAutoHandoffRegressionSnapshot,
|
|
1387
|
+
buildAutoHandoffRegressionComparison,
|
|
1388
|
+
buildAutoHandoffRegressionWindowTrend,
|
|
1389
|
+
buildAutoHandoffRegressionAggregates,
|
|
1390
|
+
buildAutoHandoffRegressionRiskLayers,
|
|
1391
|
+
buildAutoHandoffRegressionRecommendations,
|
|
1392
|
+
formatAutoHandoffRegressionValue,
|
|
1393
|
+
getAutoHandoffMoquiCoverageMatrix,
|
|
1394
|
+
getAutoHandoffMoquiCoverageMetric,
|
|
1395
|
+
formatAutoHandoffMoquiCoverageMetric,
|
|
1396
|
+
getAutoHandoffMoquiCoverageDeltaMatrix,
|
|
1397
|
+
getAutoHandoffMoquiCoverageDeltaMetric,
|
|
1398
|
+
formatAutoHandoffMoquiCoverageDeltaMetric,
|
|
1399
|
+
getAutoHandoffMoquiCoverageMetricLabel,
|
|
1400
|
+
buildAutoHandoffMoquiCoverageRegressions,
|
|
1401
|
+
formatAutoHandoffMoquiCoverageRegressions,
|
|
1402
|
+
renderAutoHandoffRegressionMarkdown,
|
|
1403
|
+
renderAutoHandoffEvidenceReviewMarkdown,
|
|
1404
|
+
renderAutoHandoffReleaseNotesDraft,
|
|
1405
|
+
buildAutoHandoffRegression,
|
|
1406
|
+
buildAutoHandoffRegressionReport
|
|
1407
|
+
};
|