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.
Files changed (83) hide show
  1. package/CHANGELOG.md +86 -1
  2. package/README.md +119 -122
  3. package/README.zh.md +123 -121
  4. package/bin/scene-capability-engine.js +11 -0
  5. package/docs/README.md +21 -32
  6. package/docs/auto-refactor-index.md +384 -0
  7. package/docs/command-reference.md +94 -2
  8. package/docs/magicball-adaptation-task-checklist-v1.md +385 -0
  9. package/docs/magicball-app-bundle-sqlite-and-command-draft.md +539 -0
  10. package/docs/magicball-capability-iteration-api.md +2 -0
  11. package/docs/magicball-capability-iteration-ui.md +2 -0
  12. package/docs/magicball-capability-library.md +2 -0
  13. package/docs/magicball-cli-invocation-examples.md +336 -0
  14. package/docs/magicball-frontend-state-and-command-mapping.md +244 -0
  15. package/docs/magicball-integration-doc-index.md +137 -0
  16. package/docs/magicball-integration-issue-tracker.md +218 -0
  17. package/docs/magicball-mode-home-and-ontology-empty-state-playbook.md +249 -0
  18. package/docs/magicball-sce-adaptation-guide.md +203 -0
  19. package/docs/magicball-three-mode-alignment-plan.md +551 -0
  20. package/docs/magicball-ui-surface-checklist.md +126 -0
  21. package/docs/magicball-write-auth-adaptation-guide.md +328 -0
  22. package/docs/refactor-completion-roadmap.md +116 -0
  23. package/docs/zh/README.md +27 -30
  24. package/docs/zh/refactor-completion-roadmap.md +116 -0
  25. package/lib/app/registry-config.js +73 -0
  26. package/lib/app/registry-sync-service.js +228 -0
  27. package/lib/auto/archive-schema-service.js +276 -0
  28. package/lib/auto/archive-summary.js +60 -0
  29. package/lib/auto/batch-goal-input-service.js +543 -0
  30. package/lib/auto/batch-output.js +201 -0
  31. package/lib/auto/batch-summary-storage-service.js +110 -0
  32. package/lib/auto/close-loop-batch-service.js +116 -0
  33. package/lib/auto/close-loop-controller-service.js +287 -0
  34. package/lib/auto/close-loop-program-service.js +283 -0
  35. package/lib/auto/close-loop-recovery-service.js +191 -0
  36. package/lib/auto/close-loop-session-storage-service.js +50 -0
  37. package/lib/auto/controller-lock-service.js +55 -0
  38. package/lib/auto/controller-output.js +32 -0
  39. package/lib/auto/controller-queue-service.js +127 -0
  40. package/lib/auto/controller-session-storage-service.js +105 -0
  41. package/lib/auto/governance-advisory-service.js +208 -0
  42. package/lib/auto/governance-close-loop-service.js +411 -0
  43. package/lib/auto/governance-maintenance-presenter.js +162 -0
  44. package/lib/auto/governance-maintenance-service.js +112 -0
  45. package/lib/auto/governance-session-presenter.js +70 -0
  46. package/lib/auto/governance-session-storage-service.js +198 -0
  47. package/lib/auto/governance-signals.js +139 -0
  48. package/lib/auto/governance-stats-presenter.js +337 -0
  49. package/lib/auto/governance-stats-service.js +115 -0
  50. package/lib/auto/governance-summary.js +703 -0
  51. package/lib/auto/handoff-capability-matrix-service.js +281 -0
  52. package/lib/auto/handoff-evidence-review-service.js +251 -0
  53. package/lib/auto/handoff-release-evidence-service.js +190 -0
  54. package/lib/auto/handoff-release-gate-history-loaders-service.js +502 -0
  55. package/lib/auto/handoff-release-gate-history-service.js +257 -0
  56. package/lib/auto/handoff-reporting-service.js +1407 -0
  57. package/lib/auto/handoff-run-service.js +486 -0
  58. package/lib/auto/handoff-snapshots-service.js +645 -0
  59. package/lib/auto/observability-service.js +132 -0
  60. package/lib/auto/output-writer.js +34 -0
  61. package/lib/auto/program-auto-remediation-service.js +130 -0
  62. package/lib/auto/program-diagnostics.js +138 -0
  63. package/lib/auto/program-governance-helpers.js +306 -0
  64. package/lib/auto/program-governance-loop-service.js +413 -0
  65. package/lib/auto/program-output.js +106 -0
  66. package/lib/auto/program-summary.js +183 -0
  67. package/lib/auto/recovery-memory-service.js +684 -0
  68. package/lib/auto/recovery-selection-service.js +52 -0
  69. package/lib/auto/retention-policy.js +98 -0
  70. package/lib/auto/session-persistence-service.js +106 -0
  71. package/lib/auto/session-presenter.js +105 -0
  72. package/lib/auto/session-prune-service.js +190 -0
  73. package/lib/auto/session-query-service.js +249 -0
  74. package/lib/auto/spec-protection.js +141 -0
  75. package/lib/commands/app.js +911 -0
  76. package/lib/commands/assurance.js +212 -0
  77. package/lib/commands/auto.js +1091 -11063
  78. package/lib/commands/mode.js +321 -0
  79. package/lib/commands/ontology.js +415 -0
  80. package/lib/commands/pm.js +422 -0
  81. package/lib/ontology/seed-profiles.js +160 -0
  82. package/lib/state/sce-state-store.js +3369 -1200
  83. package/package.json +1 -1
@@ -0,0 +1,703 @@
1
+ const { parseAutoHandoffGateBoolean, normalizeHandoffText } = require('./governance-signals');
2
+ const { buildMoquiRegressionRecoverySequenceLines } = require('./moqui-recovery-sequence');
3
+
4
+ function deriveGovernanceRiskLevel(summary) {
5
+ const failureRate = Number(summary && summary.failure_rate_percent) || 0;
6
+ const pendingGoals = Number(summary && summary.pending_goals_sum) || 0;
7
+ const failedSessions = Number(summary && summary.failed_sessions) || 0;
8
+ const releaseGate = summary && summary.release_gate && typeof summary.release_gate === 'object'
9
+ ? summary.release_gate
10
+ : {};
11
+ const releaseGateAvailable = releaseGate.available === true;
12
+ const releaseGatePassed = parseAutoHandoffGateBoolean(releaseGate.latest_gate_passed, null);
13
+ const releaseGatePassRate = Number(releaseGate.pass_rate_percent);
14
+ const sceneBatchPassRate = Number(releaseGate.scene_package_batch_pass_rate_percent);
15
+ const driftAlertRate = Number(releaseGate.drift_alert_rate_percent);
16
+ const driftBlockedRuns = Number(releaseGate.drift_blocked_runs);
17
+ const weeklyOpsKnownRuns = Number(releaseGate.weekly_ops_known_runs);
18
+ const weeklyOpsBlockedRuns = Number(releaseGate.weekly_ops_blocked_runs);
19
+ const weeklyOpsBlockRate = Number(releaseGate.weekly_ops_block_rate_percent);
20
+ const weeklyOpsViolationsTotal = Number(releaseGate.weekly_ops_violations_total);
21
+ const weeklyOpsWarningsTotal = Number(releaseGate.weekly_ops_warnings_total);
22
+ const weeklyOpsConfigWarningsTotal = Number(releaseGate.weekly_ops_config_warnings_total);
23
+ const weeklyOpsAuthTierBlockRateMax = Number(
24
+ releaseGate.weekly_ops_authorization_tier_block_rate_max_percent
25
+ );
26
+ const weeklyOpsDialogueBlockRateMax = Number(
27
+ releaseGate.weekly_ops_dialogue_authorization_block_rate_max_percent
28
+ );
29
+ const weeklyOpsLatestRuntimeBlockRate = Number(
30
+ releaseGate.latest_weekly_ops_runtime_block_rate_percent
31
+ );
32
+ const weeklyOpsLatestRuntimeUiModeViolationTotal = Number(
33
+ releaseGate.latest_weekly_ops_runtime_ui_mode_violation_total
34
+ );
35
+ const weeklyOpsLatestRuntimeUiModeViolationRate = Number(
36
+ releaseGate.latest_weekly_ops_runtime_ui_mode_violation_rate_percent
37
+ );
38
+ const weeklyOpsRuntimeBlockRateMax = Number(
39
+ releaseGate.weekly_ops_runtime_block_rate_max_percent
40
+ );
41
+ const weeklyOpsRuntimeUiModeViolationTotal = Number(
42
+ releaseGate.weekly_ops_runtime_ui_mode_violation_total
43
+ );
44
+ const weeklyOpsRuntimeUiModeViolationRunRate = Number(
45
+ releaseGate.weekly_ops_runtime_ui_mode_violation_run_rate_percent
46
+ );
47
+ const weeklyOpsRuntimeUiModeViolationRateMax = Number(
48
+ releaseGate.weekly_ops_runtime_ui_mode_violation_rate_max_percent
49
+ );
50
+ const handoffQuality = summary && summary.handoff_quality && typeof summary.handoff_quality === 'object'
51
+ ? summary.handoff_quality
52
+ : {};
53
+ const handoffAvailable = handoffQuality.available === true && (Number(handoffQuality.total_runs) || 0) > 0;
54
+ const handoffLatestStatus = normalizeHandoffText(handoffQuality.latest_status);
55
+ const handoffLatestGatePassed = parseAutoHandoffGateBoolean(handoffQuality.latest_gate_passed, null);
56
+ const handoffLatestOntologyScore = Number(handoffQuality.latest_ontology_quality_score);
57
+ const handoffCapabilityPassed = parseAutoHandoffGateBoolean(handoffQuality.latest_capability_coverage_passed, null);
58
+ const handoffFailureRate = Number(handoffQuality.failure_rate_percent);
59
+ const handoffGatePassRate = Number(handoffQuality.gate_pass_rate_percent);
60
+ const handoffCapabilityPassRate = Number(handoffQuality.capability_coverage_pass_rate_percent);
61
+ const handoffLatestCapabilityExpectedUnknownCount = Number(
62
+ handoffQuality.latest_capability_expected_unknown_count
63
+ );
64
+ const handoffLatestCapabilityProvidedUnknownCount = Number(
65
+ handoffQuality.latest_capability_provided_unknown_count
66
+ );
67
+ const handoffCapabilityExpectedUnknownPositiveRate = Number(
68
+ handoffQuality.capability_expected_unknown_positive_rate_percent
69
+ );
70
+ const handoffCapabilityProvidedUnknownPositiveRate = Number(
71
+ handoffQuality.capability_provided_unknown_positive_rate_percent
72
+ );
73
+ const handoffLatestMoquiMatrixRegressionCount = Number(handoffQuality.latest_moqui_matrix_regression_count);
74
+ const handoffLatestMoquiMatrixRegressionGateMax = Number(handoffQuality.latest_moqui_matrix_regression_gate_max);
75
+ const handoffMoquiMatrixRegressionPositiveRate = Number(handoffQuality.moqui_matrix_regression_positive_rate_percent);
76
+ const handoffPreflightBlocked = parseAutoHandoffGateBoolean(
77
+ handoffQuality.latest_release_gate_preflight_blocked,
78
+ null
79
+ );
80
+ const handoffMatrixRegressionPositive = (
81
+ Number.isFinite(handoffLatestMoquiMatrixRegressionCount) &&
82
+ handoffLatestMoquiMatrixRegressionCount > 0
83
+ );
84
+ const handoffMatrixRegressionOverGate = (
85
+ handoffMatrixRegressionPositive &&
86
+ Number.isFinite(handoffLatestMoquiMatrixRegressionGateMax) &&
87
+ handoffLatestMoquiMatrixRegressionCount > handoffLatestMoquiMatrixRegressionGateMax
88
+ );
89
+ const handoffMatrixRegressionPressureHigh = (
90
+ Number.isFinite(handoffMoquiMatrixRegressionPositiveRate) &&
91
+ handoffMoquiMatrixRegressionPositiveRate >= 50
92
+ );
93
+ const handoffCapabilityLexiconUnknownPositive = (
94
+ (Number.isFinite(handoffLatestCapabilityExpectedUnknownCount) && handoffLatestCapabilityExpectedUnknownCount > 0) ||
95
+ (Number.isFinite(handoffLatestCapabilityProvidedUnknownCount) && handoffLatestCapabilityProvidedUnknownCount > 0)
96
+ );
97
+ const handoffCapabilityLexiconUnknownPressureHigh = (
98
+ (Number.isFinite(handoffCapabilityExpectedUnknownPositiveRate) && handoffCapabilityExpectedUnknownPositiveRate >= 50) ||
99
+ (Number.isFinite(handoffCapabilityProvidedUnknownPositiveRate) && handoffCapabilityProvidedUnknownPositiveRate >= 50)
100
+ );
101
+
102
+ let riskLevel = 'low';
103
+ if (failureRate >= 40 || pendingGoals >= 5) {
104
+ riskLevel = 'high';
105
+ } else if (failureRate >= 20 || pendingGoals > 0 || failedSessions > 0) {
106
+ riskLevel = 'medium';
107
+ }
108
+ if (releaseGateAvailable) {
109
+ const hasHighDriftPressure = (
110
+ (Number.isFinite(driftAlertRate) && driftAlertRate >= 50) ||
111
+ (Number.isFinite(driftBlockedRuns) && driftBlockedRuns > 0)
112
+ );
113
+ const hasLowPassRate = (
114
+ (Number.isFinite(releaseGatePassRate) && releaseGatePassRate < 60) ||
115
+ (Number.isFinite(sceneBatchPassRate) && sceneBatchPassRate < 60)
116
+ );
117
+ const hasHighWeeklyOpsPressure = (
118
+ (Number.isFinite(weeklyOpsBlockedRuns) && weeklyOpsBlockedRuns > 0) ||
119
+ (Number.isFinite(weeklyOpsBlockRate) && weeklyOpsBlockRate >= 40) ||
120
+ (Number.isFinite(weeklyOpsAuthTierBlockRateMax) && weeklyOpsAuthTierBlockRateMax >= 60) ||
121
+ (Number.isFinite(weeklyOpsDialogueBlockRateMax) && weeklyOpsDialogueBlockRateMax >= 60) ||
122
+ (Number.isFinite(weeklyOpsLatestRuntimeUiModeViolationTotal) && weeklyOpsLatestRuntimeUiModeViolationTotal > 0) ||
123
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationTotal) && weeklyOpsRuntimeUiModeViolationTotal > 0) ||
124
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationRunRate) && weeklyOpsRuntimeUiModeViolationRunRate > 0) ||
125
+ (Number.isFinite(weeklyOpsLatestRuntimeUiModeViolationRate) && weeklyOpsLatestRuntimeUiModeViolationRate > 0) ||
126
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationRateMax) && weeklyOpsRuntimeUiModeViolationRateMax > 0) ||
127
+ (Number.isFinite(weeklyOpsLatestRuntimeBlockRate) && weeklyOpsLatestRuntimeBlockRate >= 40) ||
128
+ (Number.isFinite(weeklyOpsRuntimeBlockRateMax) && weeklyOpsRuntimeBlockRateMax >= 40)
129
+ );
130
+ const hasMediumWeeklyOpsPressure = (
131
+ (Number.isFinite(weeklyOpsKnownRuns) && weeklyOpsKnownRuns > 0) && (
132
+ (Number.isFinite(weeklyOpsViolationsTotal) && weeklyOpsViolationsTotal > 0) ||
133
+ (Number.isFinite(weeklyOpsWarningsTotal) && weeklyOpsWarningsTotal > 0) ||
134
+ (Number.isFinite(weeklyOpsConfigWarningsTotal) && weeklyOpsConfigWarningsTotal > 0) ||
135
+ (Number.isFinite(weeklyOpsAuthTierBlockRateMax) && weeklyOpsAuthTierBlockRateMax > 40) ||
136
+ (Number.isFinite(weeklyOpsDialogueBlockRateMax) && weeklyOpsDialogueBlockRateMax > 40) ||
137
+ (Number.isFinite(weeklyOpsBlockRate) && weeklyOpsBlockRate > 0) ||
138
+ (Number.isFinite(weeklyOpsLatestRuntimeBlockRate) && weeklyOpsLatestRuntimeBlockRate > 0) ||
139
+ (Number.isFinite(weeklyOpsRuntimeBlockRateMax) && weeklyOpsRuntimeBlockRateMax > 0)
140
+ )
141
+ );
142
+ if (releaseGatePassed === false && (hasHighDriftPressure || hasLowPassRate)) {
143
+ riskLevel = 'high';
144
+ } else if (hasHighWeeklyOpsPressure) {
145
+ riskLevel = 'high';
146
+ } else if (
147
+ riskLevel !== 'high' && (
148
+ releaseGatePassed === false ||
149
+ (Number.isFinite(releaseGatePassRate) && releaseGatePassRate < 85) ||
150
+ (Number.isFinite(sceneBatchPassRate) && sceneBatchPassRate < 85) ||
151
+ (Number.isFinite(driftAlertRate) && driftAlertRate > 0) ||
152
+ hasMediumWeeklyOpsPressure
153
+ )
154
+ ) {
155
+ riskLevel = 'medium';
156
+ }
157
+ }
158
+ if (handoffAvailable) {
159
+ const handoffFailed = handoffLatestStatus && !['completed', 'dry-run', 'dry_run'].includes(handoffLatestStatus);
160
+ const handoffSevereQualityDrop = (
161
+ (Number.isFinite(handoffLatestOntologyScore) && handoffLatestOntologyScore < 70) ||
162
+ handoffCapabilityPassed === false
163
+ );
164
+ const handoffHighFailureRate = Number.isFinite(handoffFailureRate) && handoffFailureRate >= 40;
165
+ if (
166
+ handoffFailed ||
167
+ handoffHighFailureRate ||
168
+ handoffPreflightBlocked === true ||
169
+ handoffMatrixRegressionOverGate ||
170
+ handoffCapabilityLexiconUnknownPositive ||
171
+ (handoffLatestGatePassed === false && handoffSevereQualityDrop) ||
172
+ (handoffMatrixRegressionPositive && handoffMatrixRegressionPressureHigh) ||
173
+ handoffCapabilityLexiconUnknownPressureHigh
174
+ ) {
175
+ riskLevel = 'high';
176
+ } else if (
177
+ riskLevel !== 'high' && (
178
+ handoffLatestGatePassed === false ||
179
+ (Number.isFinite(handoffGatePassRate) && handoffGatePassRate < 85) ||
180
+ (Number.isFinite(handoffCapabilityPassRate) && handoffCapabilityPassRate < 85) ||
181
+ (Number.isFinite(handoffLatestOntologyScore) && handoffLatestOntologyScore < 85) ||
182
+ (Number.isFinite(handoffFailureRate) && handoffFailureRate > 0) ||
183
+ handoffMatrixRegressionPositive ||
184
+ (Number.isFinite(handoffMoquiMatrixRegressionPositiveRate) && handoffMoquiMatrixRegressionPositiveRate > 0) ||
185
+ (Number.isFinite(handoffCapabilityExpectedUnknownPositiveRate) && handoffCapabilityExpectedUnknownPositiveRate > 0) ||
186
+ (Number.isFinite(handoffCapabilityProvidedUnknownPositiveRate) && handoffCapabilityProvidedUnknownPositiveRate > 0)
187
+ )
188
+ ) {
189
+ riskLevel = 'medium';
190
+ }
191
+ }
192
+ return riskLevel;
193
+ }
194
+
195
+ function buildGovernanceConcerns(summary) {
196
+ const concerns = [];
197
+ const totalSessions = Number(summary && summary.total_sessions) || 0;
198
+ const failedSessions = Number(summary && summary.failed_sessions) || 0;
199
+ const pendingGoals = Number(summary && summary.pending_goals_sum) || 0;
200
+ const failureRate = Number(summary && summary.failure_rate_percent) || 0;
201
+ const recoverySignatures = Number(summary && summary.recovery_signature_count) || 0;
202
+ const releaseGate = summary && summary.release_gate && typeof summary.release_gate === 'object'
203
+ ? summary.release_gate
204
+ : {};
205
+ const releaseGateAvailable = releaseGate.available === true;
206
+ const releaseGatePassed = parseAutoHandoffGateBoolean(releaseGate.latest_gate_passed, null);
207
+ const releaseGatePassRate = Number(releaseGate.pass_rate_percent);
208
+ const sceneBatchPassRate = Number(releaseGate.scene_package_batch_pass_rate_percent);
209
+ const driftAlertRate = Number(releaseGate.drift_alert_rate_percent);
210
+ const driftBlockedRuns = Number(releaseGate.drift_blocked_runs);
211
+ const weeklyOpsKnownRuns = Number(releaseGate.weekly_ops_known_runs);
212
+ const weeklyOpsBlockedRuns = Number(releaseGate.weekly_ops_blocked_runs);
213
+ const weeklyOpsBlockRate = Number(releaseGate.weekly_ops_block_rate_percent);
214
+ const weeklyOpsViolationsTotal = Number(releaseGate.weekly_ops_violations_total);
215
+ const weeklyOpsWarningsTotal = Number(releaseGate.weekly_ops_warnings_total);
216
+ const weeklyOpsConfigWarningsTotal = Number(releaseGate.weekly_ops_config_warnings_total);
217
+ const weeklyOpsAuthTierBlockRateMax = Number(
218
+ releaseGate.weekly_ops_authorization_tier_block_rate_max_percent
219
+ );
220
+ const weeklyOpsDialogueBlockRateMax = Number(
221
+ releaseGate.weekly_ops_dialogue_authorization_block_rate_max_percent
222
+ );
223
+ const weeklyOpsLatestRuntimeBlockRate = Number(
224
+ releaseGate.latest_weekly_ops_runtime_block_rate_percent
225
+ );
226
+ const weeklyOpsLatestRuntimeUiModeViolationTotal = Number(
227
+ releaseGate.latest_weekly_ops_runtime_ui_mode_violation_total
228
+ );
229
+ const weeklyOpsLatestRuntimeUiModeViolationRate = Number(
230
+ releaseGate.latest_weekly_ops_runtime_ui_mode_violation_rate_percent
231
+ );
232
+ const weeklyOpsRuntimeBlockRateMax = Number(
233
+ releaseGate.weekly_ops_runtime_block_rate_max_percent
234
+ );
235
+ const weeklyOpsRuntimeUiModeViolationTotal = Number(
236
+ releaseGate.weekly_ops_runtime_ui_mode_violation_total
237
+ );
238
+ const weeklyOpsRuntimeUiModeViolationRunRate = Number(
239
+ releaseGate.weekly_ops_runtime_ui_mode_violation_run_rate_percent
240
+ );
241
+ const weeklyOpsRuntimeUiModeViolationRateMax = Number(
242
+ releaseGate.weekly_ops_runtime_ui_mode_violation_rate_max_percent
243
+ );
244
+ const handoffQuality = summary && summary.handoff_quality && typeof summary.handoff_quality === 'object'
245
+ ? summary.handoff_quality
246
+ : {};
247
+ const handoffAvailable = handoffQuality.available === true;
248
+ const handoffTotalRuns = Number(handoffQuality.total_runs) || 0;
249
+ const handoffLatestStatus = normalizeHandoffText(handoffQuality.latest_status);
250
+ const handoffLatestGatePassed = parseAutoHandoffGateBoolean(handoffQuality.latest_gate_passed, null);
251
+ const handoffLatestOntologyScore = Number(handoffQuality.latest_ontology_quality_score);
252
+ const handoffFailureRate = Number(handoffQuality.failure_rate_percent);
253
+ const handoffCapabilityPassRate = Number(handoffQuality.capability_coverage_pass_rate_percent);
254
+ const handoffLatestCapabilityExpectedUnknownCount = Number(
255
+ handoffQuality.latest_capability_expected_unknown_count
256
+ );
257
+ const handoffLatestCapabilityProvidedUnknownCount = Number(
258
+ handoffQuality.latest_capability_provided_unknown_count
259
+ );
260
+ const handoffCapabilityExpectedUnknownPositiveRate = Number(
261
+ handoffQuality.capability_expected_unknown_positive_rate_percent
262
+ );
263
+ const handoffCapabilityProvidedUnknownPositiveRate = Number(
264
+ handoffQuality.capability_provided_unknown_positive_rate_percent
265
+ );
266
+ const handoffLatestMoquiMatrixRegressionCount = Number(handoffQuality.latest_moqui_matrix_regression_count);
267
+ const handoffLatestMoquiMatrixRegressionGateMax = Number(handoffQuality.latest_moqui_matrix_regression_gate_max);
268
+ const handoffMaxMoquiMatrixRegressionCount = Number(handoffQuality.max_moqui_matrix_regression_count);
269
+ const handoffMoquiMatrixRegressionPositiveRate = Number(handoffQuality.moqui_matrix_regression_positive_rate_percent);
270
+ const handoffPreflightBlocked = parseAutoHandoffGateBoolean(
271
+ handoffQuality.latest_release_gate_preflight_blocked,
272
+ null
273
+ );
274
+
275
+ if (totalSessions === 0) {
276
+ concerns.push('No archived sessions found for the selected filter window.');
277
+ }
278
+ if (failedSessions > 0) {
279
+ concerns.push(`${failedSessions} failed session(s) detected across governance archives.`);
280
+ }
281
+ if (pendingGoals > 0) {
282
+ concerns.push(`${pendingGoals} pending controller goal(s) remain unprocessed.`);
283
+ }
284
+ if (failureRate >= 20) {
285
+ concerns.push(`Overall session failure rate is elevated at ${failureRate}%.`);
286
+ }
287
+ if (failedSessions > 0 && recoverySignatures === 0) {
288
+ concerns.push('Recovery memory has no signatures despite failed sessions.');
289
+ }
290
+ if (!releaseGateAvailable) {
291
+ concerns.push('Release gate history is unavailable; governance lacks handoff release trend context.');
292
+ } else {
293
+ if (releaseGatePassed === false) {
294
+ concerns.push('Latest release gate evaluation is failed.');
295
+ }
296
+ if (Number.isFinite(releaseGatePassRate) && releaseGatePassRate < 85) {
297
+ concerns.push(`Release gate pass rate is low at ${releaseGatePassRate}%.`);
298
+ }
299
+ if (Number.isFinite(sceneBatchPassRate) && sceneBatchPassRate < 85) {
300
+ concerns.push(`Scene package batch pass rate is low at ${sceneBatchPassRate}%.`);
301
+ }
302
+ if (Number.isFinite(driftAlertRate) && driftAlertRate > 0) {
303
+ concerns.push(`Release drift alert rate is ${driftAlertRate}%.`);
304
+ }
305
+ if (Number.isFinite(driftBlockedRuns) && driftBlockedRuns > 0) {
306
+ concerns.push(`${driftBlockedRuns} release(s) were blocked by drift alerts.`);
307
+ }
308
+ if (Number.isFinite(weeklyOpsKnownRuns) && weeklyOpsKnownRuns > 0) {
309
+ concerns.push(`Weekly ops signals observed in ${weeklyOpsKnownRuns} release gate run(s).`);
310
+ }
311
+ if (Number.isFinite(weeklyOpsBlockedRuns) && weeklyOpsBlockedRuns > 0) {
312
+ concerns.push(`${weeklyOpsBlockedRuns} release run(s) were blocked by weekly ops gate.`);
313
+ }
314
+ if (Number.isFinite(weeklyOpsBlockRate) && weeklyOpsBlockRate > 0) {
315
+ concerns.push(`Weekly ops block rate is ${weeklyOpsBlockRate}%.`);
316
+ }
317
+ if (Number.isFinite(weeklyOpsViolationsTotal) && weeklyOpsViolationsTotal > 0) {
318
+ concerns.push(`Weekly ops violations total is ${weeklyOpsViolationsTotal}.`);
319
+ }
320
+ if (Number.isFinite(weeklyOpsWarningsTotal) && weeklyOpsWarningsTotal > 0) {
321
+ concerns.push(`Weekly ops warnings total is ${weeklyOpsWarningsTotal}.`);
322
+ }
323
+ if (Number.isFinite(weeklyOpsConfigWarningsTotal) && weeklyOpsConfigWarningsTotal > 0) {
324
+ concerns.push(`Weekly ops config warnings total is ${weeklyOpsConfigWarningsTotal}.`);
325
+ }
326
+ if (Number.isFinite(weeklyOpsAuthTierBlockRateMax) && weeklyOpsAuthTierBlockRateMax > 40) {
327
+ concerns.push(`Weekly ops authorization-tier block-rate max is ${weeklyOpsAuthTierBlockRateMax}%.`);
328
+ }
329
+ if (Number.isFinite(weeklyOpsDialogueBlockRateMax) && weeklyOpsDialogueBlockRateMax > 40) {
330
+ concerns.push(`Weekly ops dialogue-authorization block-rate max is ${weeklyOpsDialogueBlockRateMax}%.`);
331
+ }
332
+ if (Number.isFinite(weeklyOpsLatestRuntimeBlockRate) && weeklyOpsLatestRuntimeBlockRate > 0) {
333
+ concerns.push(`Weekly ops latest runtime block rate is ${weeklyOpsLatestRuntimeBlockRate}%.`);
334
+ }
335
+ if (Number.isFinite(weeklyOpsRuntimeBlockRateMax) && weeklyOpsRuntimeBlockRateMax > 0) {
336
+ concerns.push(`Weekly ops runtime block-rate max is ${weeklyOpsRuntimeBlockRateMax}%.`);
337
+ }
338
+ if (
339
+ Number.isFinite(weeklyOpsLatestRuntimeUiModeViolationTotal) &&
340
+ weeklyOpsLatestRuntimeUiModeViolationTotal > 0
341
+ ) {
342
+ concerns.push(
343
+ `Weekly ops latest runtime ui-mode violations total is ${weeklyOpsLatestRuntimeUiModeViolationTotal}.`
344
+ );
345
+ }
346
+ if (
347
+ Number.isFinite(weeklyOpsLatestRuntimeUiModeViolationRate) &&
348
+ weeklyOpsLatestRuntimeUiModeViolationRate > 0
349
+ ) {
350
+ concerns.push(
351
+ `Weekly ops latest runtime ui-mode violation rate is ${weeklyOpsLatestRuntimeUiModeViolationRate}%.`
352
+ );
353
+ }
354
+ if (Number.isFinite(weeklyOpsRuntimeUiModeViolationTotal) && weeklyOpsRuntimeUiModeViolationTotal > 0) {
355
+ concerns.push(`Weekly ops runtime ui-mode violations total is ${weeklyOpsRuntimeUiModeViolationTotal}.`);
356
+ }
357
+ if (Number.isFinite(weeklyOpsRuntimeUiModeViolationRunRate) && weeklyOpsRuntimeUiModeViolationRunRate > 0) {
358
+ concerns.push(
359
+ `Weekly ops runtime ui-mode violation run rate is ${weeklyOpsRuntimeUiModeViolationRunRate}%.`
360
+ );
361
+ }
362
+ if (Number.isFinite(weeklyOpsRuntimeUiModeViolationRateMax) && weeklyOpsRuntimeUiModeViolationRateMax > 0) {
363
+ concerns.push(
364
+ `Weekly ops runtime ui-mode violation rate max is ${weeklyOpsRuntimeUiModeViolationRateMax}%.`
365
+ );
366
+ }
367
+ }
368
+ if (!handoffAvailable) {
369
+ concerns.push('Handoff release evidence is unavailable; governance lacks handoff quality context.');
370
+ } else if (handoffTotalRuns <= 0) {
371
+ concerns.push('Handoff release evidence has no runs yet.');
372
+ } else {
373
+ if (handoffLatestStatus && !['completed', 'dry-run', 'dry_run'].includes(handoffLatestStatus)) {
374
+ concerns.push(`Latest handoff run status is ${handoffLatestStatus}.`);
375
+ }
376
+ if (handoffLatestGatePassed === false) {
377
+ concerns.push('Latest handoff gate evaluation is failed.');
378
+ }
379
+ if (handoffPreflightBlocked === true) {
380
+ concerns.push('Latest handoff release gate preflight is blocked.');
381
+ }
382
+ if (Number.isFinite(handoffLatestOntologyScore) && handoffLatestOntologyScore < 85) {
383
+ concerns.push(`Latest handoff ontology score is low at ${handoffLatestOntologyScore}.`);
384
+ }
385
+ if (Number.isFinite(handoffFailureRate) && handoffFailureRate > 0) {
386
+ concerns.push(`Handoff run failure rate is ${handoffFailureRate}%.`);
387
+ }
388
+ if (Number.isFinite(handoffCapabilityPassRate) && handoffCapabilityPassRate < 85) {
389
+ concerns.push(`Handoff capability coverage pass rate is low at ${handoffCapabilityPassRate}%.`);
390
+ }
391
+ if (
392
+ Number.isFinite(handoffLatestCapabilityExpectedUnknownCount) &&
393
+ handoffLatestCapabilityExpectedUnknownCount > 0
394
+ ) {
395
+ concerns.push(
396
+ `Latest handoff manifest capability unknown count is ${handoffLatestCapabilityExpectedUnknownCount}.`
397
+ );
398
+ }
399
+ if (
400
+ Number.isFinite(handoffLatestCapabilityProvidedUnknownCount) &&
401
+ handoffLatestCapabilityProvidedUnknownCount > 0
402
+ ) {
403
+ concerns.push(
404
+ `Latest handoff template capability unknown count is ${handoffLatestCapabilityProvidedUnknownCount}.`
405
+ );
406
+ }
407
+ if (
408
+ Number.isFinite(handoffCapabilityExpectedUnknownPositiveRate) &&
409
+ handoffCapabilityExpectedUnknownPositiveRate > 0
410
+ ) {
411
+ concerns.push(
412
+ `Handoff manifest capability unknown positive rate is ${handoffCapabilityExpectedUnknownPositiveRate}%.`
413
+ );
414
+ }
415
+ if (
416
+ Number.isFinite(handoffCapabilityProvidedUnknownPositiveRate) &&
417
+ handoffCapabilityProvidedUnknownPositiveRate > 0
418
+ ) {
419
+ concerns.push(
420
+ `Handoff template capability unknown positive rate is ${handoffCapabilityProvidedUnknownPositiveRate}%.`
421
+ );
422
+ }
423
+ if (Number.isFinite(handoffLatestMoquiMatrixRegressionCount) && handoffLatestMoquiMatrixRegressionCount > 0) {
424
+ concerns.push(
425
+ `Latest handoff Moqui matrix regression count is ${handoffLatestMoquiMatrixRegressionCount}.`
426
+ );
427
+ }
428
+ if (
429
+ Number.isFinite(handoffLatestMoquiMatrixRegressionCount) &&
430
+ Number.isFinite(handoffLatestMoquiMatrixRegressionGateMax) &&
431
+ handoffLatestMoquiMatrixRegressionCount > handoffLatestMoquiMatrixRegressionGateMax
432
+ ) {
433
+ concerns.push(
434
+ `Latest handoff Moqui matrix regressions exceed gate (${handoffLatestMoquiMatrixRegressionCount} > ` +
435
+ `${handoffLatestMoquiMatrixRegressionGateMax}).`
436
+ );
437
+ }
438
+ if (Number.isFinite(handoffMoquiMatrixRegressionPositiveRate) && handoffMoquiMatrixRegressionPositiveRate > 0) {
439
+ concerns.push(
440
+ `Handoff Moqui matrix regression positive rate is ${handoffMoquiMatrixRegressionPositiveRate}%.`
441
+ );
442
+ }
443
+ if (Number.isFinite(handoffMaxMoquiMatrixRegressionCount) && handoffMaxMoquiMatrixRegressionCount > 0) {
444
+ concerns.push(`Handoff Moqui matrix regression max is ${handoffMaxMoquiMatrixRegressionCount}.`);
445
+ }
446
+ }
447
+
448
+ return concerns;
449
+ }
450
+
451
+ function buildGovernanceRecommendations(summary) {
452
+ const recommendations = [];
453
+ const failedSessions = Number(summary && summary.failed_sessions) || 0;
454
+ const pendingGoals = Number(summary && summary.pending_goals_sum) || 0;
455
+ const riskLevel = `${summary && summary.risk_level ? summary.risk_level : 'low'}`.trim().toLowerCase();
456
+ const releaseGate = summary && summary.release_gate && typeof summary.release_gate === 'object'
457
+ ? summary.release_gate
458
+ : {};
459
+ const releaseGateAvailable = releaseGate.available === true;
460
+ const releaseGatePassed = parseAutoHandoffGateBoolean(releaseGate.latest_gate_passed, null);
461
+ const driftAlertRate = Number(releaseGate.drift_alert_rate_percent);
462
+ const releaseGatePassRate = Number(releaseGate.pass_rate_percent);
463
+ const sceneBatchPassRate = Number(releaseGate.scene_package_batch_pass_rate_percent);
464
+ const weeklyOpsKnownRuns = Number(releaseGate.weekly_ops_known_runs);
465
+ const weeklyOpsBlockedRuns = Number(releaseGate.weekly_ops_blocked_runs);
466
+ const weeklyOpsBlockRate = Number(releaseGate.weekly_ops_block_rate_percent);
467
+ const weeklyOpsViolationsTotal = Number(releaseGate.weekly_ops_violations_total);
468
+ const weeklyOpsWarningsTotal = Number(releaseGate.weekly_ops_warnings_total);
469
+ const weeklyOpsConfigWarningsTotal = Number(releaseGate.weekly_ops_config_warnings_total);
470
+ const weeklyOpsAuthTierBlockRateMax = Number(
471
+ releaseGate.weekly_ops_authorization_tier_block_rate_max_percent
472
+ );
473
+ const weeklyOpsDialogueBlockRateMax = Number(
474
+ releaseGate.weekly_ops_dialogue_authorization_block_rate_max_percent
475
+ );
476
+ const weeklyOpsLatestRuntimeBlockRate = Number(
477
+ releaseGate.latest_weekly_ops_runtime_block_rate_percent
478
+ );
479
+ const weeklyOpsLatestRuntimeUiModeViolationTotal = Number(
480
+ releaseGate.latest_weekly_ops_runtime_ui_mode_violation_total
481
+ );
482
+ const weeklyOpsLatestRuntimeUiModeViolationRate = Number(
483
+ releaseGate.latest_weekly_ops_runtime_ui_mode_violation_rate_percent
484
+ );
485
+ const weeklyOpsRuntimeBlockRateMax = Number(
486
+ releaseGate.weekly_ops_runtime_block_rate_max_percent
487
+ );
488
+ const weeklyOpsRuntimeUiModeViolationTotal = Number(
489
+ releaseGate.weekly_ops_runtime_ui_mode_violation_total
490
+ );
491
+ const weeklyOpsRuntimeUiModeViolationRunRate = Number(
492
+ releaseGate.weekly_ops_runtime_ui_mode_violation_run_rate_percent
493
+ );
494
+ const weeklyOpsRuntimeUiModeViolationRateMax = Number(
495
+ releaseGate.weekly_ops_runtime_ui_mode_violation_rate_max_percent
496
+ );
497
+ const handoffQuality = summary && summary.handoff_quality && typeof summary.handoff_quality === 'object'
498
+ ? summary.handoff_quality
499
+ : {};
500
+ const handoffAvailable = handoffQuality.available === true;
501
+ const handoffTotalRuns = Number(handoffQuality.total_runs) || 0;
502
+ const handoffLatestStatus = normalizeHandoffText(handoffQuality.latest_status);
503
+ const handoffLatestGatePassed = parseAutoHandoffGateBoolean(handoffQuality.latest_gate_passed, null);
504
+ const handoffFailureRate = Number(handoffQuality.failure_rate_percent);
505
+ const handoffCapabilityPassRate = Number(handoffQuality.capability_coverage_pass_rate_percent);
506
+ const handoffLatestCapabilityExpectedUnknownCount = Number(
507
+ handoffQuality.latest_capability_expected_unknown_count
508
+ );
509
+ const handoffLatestCapabilityProvidedUnknownCount = Number(
510
+ handoffQuality.latest_capability_provided_unknown_count
511
+ );
512
+ const handoffCapabilityExpectedUnknownPositiveRate = Number(
513
+ handoffQuality.capability_expected_unknown_positive_rate_percent
514
+ );
515
+ const handoffCapabilityProvidedUnknownPositiveRate = Number(
516
+ handoffQuality.capability_provided_unknown_positive_rate_percent
517
+ );
518
+ const handoffLatestMoquiMatrixRegressionCount = Number(handoffQuality.latest_moqui_matrix_regression_count);
519
+ const handoffLatestMoquiMatrixRegressionGateMax = Number(handoffQuality.latest_moqui_matrix_regression_gate_max);
520
+ const handoffMoquiMatrixRegressionPositiveRate = Number(handoffQuality.moqui_matrix_regression_positive_rate_percent);
521
+ const handoffPreflightBlocked = parseAutoHandoffGateBoolean(
522
+ handoffQuality.latest_release_gate_preflight_blocked,
523
+ null
524
+ );
525
+
526
+ if (failedSessions > 0) {
527
+ recommendations.push('Run `sce auto close-loop-recover latest --recover-until-complete --json` to drain failed goals.');
528
+ }
529
+ if (pendingGoals > 0) {
530
+ recommendations.push('Run `sce auto close-loop-controller --controller-resume latest --json` to continue pending queue work.');
531
+ }
532
+ if (riskLevel === 'low') {
533
+ recommendations.push('Keep daily governance checks with `sce auto governance stats --days 14 --json`.');
534
+ } else if (riskLevel === 'high') {
535
+ recommendations.push('Apply stricter gate policy (`--program-gate-profile staging|prod`) before next program-scale run.');
536
+ }
537
+ if (!releaseGateAvailable) {
538
+ recommendations.push(
539
+ 'Generate/attach release gate history asset: ' +
540
+ '`sce auto handoff gate-index --dir .sce/reports/release-evidence --out .sce/reports/release-evidence/release-gate-history.json --json`.'
541
+ );
542
+ } else {
543
+ if (releaseGatePassed === false || (Number.isFinite(releaseGatePassRate) && releaseGatePassRate < 85)) {
544
+ recommendations.push('Recheck latest release evidence with `sce auto handoff evidence --window 5 --json`.');
545
+ }
546
+ if (
547
+ (Number.isFinite(driftAlertRate) && driftAlertRate > 0) ||
548
+ (Number.isFinite(sceneBatchPassRate) && sceneBatchPassRate < 85)
549
+ ) {
550
+ recommendations.push(
551
+ 'Stabilize scene package publish-batch quality and rerun: ' +
552
+ '`sce scene package-publish-batch --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
553
+ );
554
+ }
555
+ if (
556
+ (Number.isFinite(weeklyOpsKnownRuns) && weeklyOpsKnownRuns > 0) &&
557
+ (
558
+ (Number.isFinite(weeklyOpsBlockedRuns) && weeklyOpsBlockedRuns > 0) ||
559
+ (Number.isFinite(weeklyOpsBlockRate) && weeklyOpsBlockRate > 0) ||
560
+ (Number.isFinite(weeklyOpsViolationsTotal) && weeklyOpsViolationsTotal > 0) ||
561
+ (Number.isFinite(weeklyOpsWarningsTotal) && weeklyOpsWarningsTotal > 0) ||
562
+ (Number.isFinite(weeklyOpsRuntimeBlockRateMax) && weeklyOpsRuntimeBlockRateMax > 0) ||
563
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationTotal) && weeklyOpsRuntimeUiModeViolationTotal > 0) ||
564
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationRunRate) && weeklyOpsRuntimeUiModeViolationRunRate > 0)
565
+ )
566
+ ) {
567
+ recommendations.push(
568
+ 'Rebuild weekly ops summary and gate evidence with ' +
569
+ '`node scripts/release-ops-weekly-summary.js --json` + `node scripts/release-weekly-ops-gate.js`.'
570
+ );
571
+ recommendations.push(
572
+ 'Export weekly/drift remediation pack with ' +
573
+ '`node scripts/release-risk-remediation-bundle.js --gate-report .sce/reports/release-evidence/release-gate.json --json`.'
574
+ );
575
+ }
576
+ if (Number.isFinite(weeklyOpsConfigWarningsTotal) && weeklyOpsConfigWarningsTotal > 0) {
577
+ recommendations.push(
578
+ 'Fix invalid weekly ops threshold variables (`KSE_RELEASE_WEEKLY_OPS_*`) and rerun release gates ' +
579
+ 'to clear config warnings.'
580
+ );
581
+ }
582
+ if (
583
+ (Number.isFinite(weeklyOpsLatestRuntimeUiModeViolationTotal) && weeklyOpsLatestRuntimeUiModeViolationTotal > 0) ||
584
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationTotal) && weeklyOpsRuntimeUiModeViolationTotal > 0) ||
585
+ (Number.isFinite(weeklyOpsLatestRuntimeUiModeViolationRate) && weeklyOpsLatestRuntimeUiModeViolationRate > 0) ||
586
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationRateMax) && weeklyOpsRuntimeUiModeViolationRateMax > 0) ||
587
+ (Number.isFinite(weeklyOpsRuntimeUiModeViolationRunRate) && weeklyOpsRuntimeUiModeViolationRunRate > 0)
588
+ ) {
589
+ recommendations.push(
590
+ 'Rebuild interactive runtime governance evidence with ' +
591
+ '`node scripts/interactive-governance-report.js --period weekly --fail-on-alert --json`.'
592
+ );
593
+ recommendations.push(
594
+ 'Review runtime ui-mode policy baseline (`docs/interactive-customization/runtime-mode-policy-baseline.json`) ' +
595
+ 'to keep `user-app` suggestion-only and route apply traffic to `ops-console`.'
596
+ );
597
+ }
598
+ if (
599
+ (Number.isFinite(weeklyOpsLatestRuntimeBlockRate) && weeklyOpsLatestRuntimeBlockRate > 40) ||
600
+ (Number.isFinite(weeklyOpsRuntimeBlockRateMax) && weeklyOpsRuntimeBlockRateMax > 40)
601
+ ) {
602
+ recommendations.push(
603
+ 'Reduce runtime deny/review pressure by tuning authorization and runtime mode policy, then rerun ' +
604
+ '`node scripts/interactive-governance-report.js --period weekly --json`.'
605
+ );
606
+ }
607
+ if (
608
+ (Number.isFinite(weeklyOpsAuthTierBlockRateMax) && weeklyOpsAuthTierBlockRateMax > 40) ||
609
+ (Number.isFinite(weeklyOpsDialogueBlockRateMax) && weeklyOpsDialogueBlockRateMax > 40)
610
+ ) {
611
+ recommendations.push(
612
+ 'Tune authorization-tier policy pressure with ' +
613
+ '`node scripts/interactive-authorization-tier-evaluate.js --policy docs/interactive-customization/authorization-tier-policy-baseline.json --json`.'
614
+ );
615
+ recommendations.push(
616
+ 'Tune dialogue authorization policy pressure with ' +
617
+ '`node scripts/interactive-dialogue-governance.js --policy docs/interactive-customization/dialogue-governance-policy-baseline.json --authorization-dialogue-policy docs/interactive-customization/authorization-dialogue-policy-baseline.json --json`.'
618
+ );
619
+ }
620
+ }
621
+ if (!handoffAvailable) {
622
+ recommendations.push(
623
+ 'Generate handoff release evidence with ' +
624
+ '`sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
625
+ );
626
+ } else if (handoffTotalRuns > 0) {
627
+ const handoffMoquiMatrixRegressionPositive = (
628
+ Number.isFinite(handoffLatestMoquiMatrixRegressionCount) &&
629
+ handoffLatestMoquiMatrixRegressionCount > 0
630
+ );
631
+ const handoffMoquiMatrixRegressionOverGate = (
632
+ handoffMoquiMatrixRegressionPositive &&
633
+ Number.isFinite(handoffLatestMoquiMatrixRegressionGateMax) &&
634
+ handoffLatestMoquiMatrixRegressionCount > handoffLatestMoquiMatrixRegressionGateMax
635
+ );
636
+ if (
637
+ (handoffLatestStatus && !['completed', 'dry-run', 'dry_run'].includes(handoffLatestStatus)) ||
638
+ handoffLatestGatePassed === false ||
639
+ handoffPreflightBlocked === true
640
+ ) {
641
+ recommendations.push('Recheck handoff quality with `sce auto handoff evidence --window 5 --json`.');
642
+ recommendations.push(
643
+ 'Resume failed handoff goals with ' +
644
+ '`sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --continue-from latest --continue-strategy failed-only --json`.'
645
+ );
646
+ }
647
+ if (
648
+ (Number.isFinite(handoffFailureRate) && handoffFailureRate > 0) ||
649
+ (Number.isFinite(handoffCapabilityPassRate) && handoffCapabilityPassRate < 85)
650
+ ) {
651
+ recommendations.push(
652
+ 'Re-run default Moqui quality gates via ' +
653
+ '`sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
654
+ );
655
+ }
656
+ if (
657
+ (Number.isFinite(handoffLatestCapabilityExpectedUnknownCount) && handoffLatestCapabilityExpectedUnknownCount > 0) ||
658
+ (Number.isFinite(handoffLatestCapabilityProvidedUnknownCount) && handoffLatestCapabilityProvidedUnknownCount > 0) ||
659
+ (Number.isFinite(handoffCapabilityExpectedUnknownPositiveRate) && handoffCapabilityExpectedUnknownPositiveRate > 0) ||
660
+ (Number.isFinite(handoffCapabilityProvidedUnknownPositiveRate) && handoffCapabilityProvidedUnknownPositiveRate > 0)
661
+ ) {
662
+ recommendations.push(
663
+ 'Normalize capability lexicon gaps with ' +
664
+ '`node scripts/moqui-lexicon-audit.js --manifest docs/handoffs/handoff-manifest.json ' +
665
+ '--template-dir .sce/templates/scene-packages --fail-on-gap --json`.'
666
+ );
667
+ recommendations.push(
668
+ 'Re-run strict handoff lexicon gates with ' +
669
+ '`sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
670
+ );
671
+ }
672
+ if (
673
+ handoffMoquiMatrixRegressionPositive ||
674
+ handoffMoquiMatrixRegressionOverGate ||
675
+ (Number.isFinite(handoffMoquiMatrixRegressionPositiveRate) && handoffMoquiMatrixRegressionPositiveRate > 0)
676
+ ) {
677
+ recommendations.push(
678
+ 'Recover Moqui matrix regressions via ' +
679
+ '`sce auto handoff run --manifest docs/handoffs/handoff-manifest.json ' +
680
+ '--dry-run --max-moqui-matrix-regressions 0 --json`.'
681
+ );
682
+ recommendations.push(
683
+ 'Inspect Moqui baseline matrix drift with ' +
684
+ '`sce scene moqui-baseline --include-all ' +
685
+ '--compare-with .sce/reports/release-evidence/moqui-template-baseline.json --json`.'
686
+ );
687
+ recommendations.push(...buildMoquiRegressionRecoverySequenceLines({
688
+ wrapCommands: true,
689
+ withPeriod: true
690
+ }));
691
+ }
692
+ }
693
+
694
+ return Array.from(new Set(recommendations));
695
+ }
696
+
697
+ module.exports = {
698
+ deriveGovernanceRiskLevel,
699
+ buildGovernanceConcerns,
700
+ buildGovernanceRecommendations
701
+ };
702
+
703
+