scene-capability-engine 3.6.45 → 3.6.46

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 (56) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/docs/releases/README.md +1 -0
  3. package/docs/releases/v3.6.46.md +23 -0
  4. package/docs/zh/releases/README.md +1 -0
  5. package/docs/zh/releases/v3.6.46.md +23 -0
  6. package/package.json +4 -2
  7. package/scripts/auto-strategy-router.js +231 -0
  8. package/scripts/capability-mapping-report.js +339 -0
  9. package/scripts/check-branding-consistency.js +140 -0
  10. package/scripts/check-sce-tracking.js +54 -0
  11. package/scripts/check-skip-allowlist.js +94 -0
  12. package/scripts/errorbook-registry-health-gate.js +172 -0
  13. package/scripts/errorbook-release-gate.js +132 -0
  14. package/scripts/failure-attribution-repair.js +317 -0
  15. package/scripts/git-managed-gate.js +464 -0
  16. package/scripts/interactive-approval-event-projection.js +400 -0
  17. package/scripts/interactive-approval-workflow.js +829 -0
  18. package/scripts/interactive-authorization-tier-evaluate.js +413 -0
  19. package/scripts/interactive-change-plan-gate.js +225 -0
  20. package/scripts/interactive-context-bridge.js +617 -0
  21. package/scripts/interactive-customization-loop.js +1690 -0
  22. package/scripts/interactive-dialogue-governance.js +842 -0
  23. package/scripts/interactive-feedback-log.js +253 -0
  24. package/scripts/interactive-flow-smoke.js +238 -0
  25. package/scripts/interactive-flow.js +1059 -0
  26. package/scripts/interactive-governance-report.js +1112 -0
  27. package/scripts/interactive-intent-build.js +707 -0
  28. package/scripts/interactive-loop-smoke.js +215 -0
  29. package/scripts/interactive-moqui-adapter.js +304 -0
  30. package/scripts/interactive-plan-build.js +426 -0
  31. package/scripts/interactive-runtime-policy-evaluate.js +495 -0
  32. package/scripts/interactive-work-order-build.js +552 -0
  33. package/scripts/matrix-regression-gate.js +167 -0
  34. package/scripts/moqui-core-regression-suite.js +397 -0
  35. package/scripts/moqui-lexicon-audit.js +651 -0
  36. package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
  37. package/scripts/moqui-matrix-remediation-queue.js +852 -0
  38. package/scripts/moqui-metadata-extract.js +1340 -0
  39. package/scripts/moqui-rebuild-gate.js +167 -0
  40. package/scripts/moqui-release-summary.js +729 -0
  41. package/scripts/moqui-standard-rebuild.js +1370 -0
  42. package/scripts/moqui-template-baseline-report.js +682 -0
  43. package/scripts/npm-package-runtime-asset-check.js +221 -0
  44. package/scripts/problem-closure-gate.js +441 -0
  45. package/scripts/release-asset-integrity-check.js +216 -0
  46. package/scripts/release-asset-nonempty-normalize.js +166 -0
  47. package/scripts/release-drift-evaluate.js +223 -0
  48. package/scripts/release-drift-signals.js +255 -0
  49. package/scripts/release-governance-snapshot-export.js +132 -0
  50. package/scripts/release-ops-weekly-summary.js +934 -0
  51. package/scripts/release-risk-remediation-bundle.js +315 -0
  52. package/scripts/release-weekly-ops-gate.js +423 -0
  53. package/scripts/state-migration-reconciliation-gate.js +110 -0
  54. package/scripts/state-storage-tiering-audit.js +337 -0
  55. package/scripts/steering-content-audit.js +393 -0
  56. package/scripts/symbol-evidence-locate.js +366 -0
@@ -0,0 +1,729 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('path');
5
+ const fs = require('fs-extra');
6
+ const { buildMoquiRegressionRecoverySequenceLines } = require('../lib/auto/moqui-recovery-sequence');
7
+
8
+ const DEFAULT_EVIDENCE = '.sce/reports/release-evidence/handoff-runs.json';
9
+ const DEFAULT_BASELINE = '.sce/reports/release-evidence/moqui-template-baseline.json';
10
+ const DEFAULT_LEXICON = '.sce/reports/release-evidence/moqui-lexicon-audit.json';
11
+ const DEFAULT_CAPABILITY_MATRIX = '.sce/reports/handoff-capability-matrix.json';
12
+ const DEFAULT_INTERACTIVE_GOVERNANCE = '.sce/reports/interactive-governance-report.json';
13
+ const DEFAULT_MATRIX_REMEDIATION_PLAN = '.sce/reports/release-evidence/matrix-remediation-plan.json';
14
+ const DEFAULT_OUT = '.sce/reports/release-evidence/moqui-release-summary.json';
15
+ const DEFAULT_MARKDOWN_OUT = '.sce/reports/release-evidence/moqui-release-summary.md';
16
+
17
+ function parseArgs(argv) {
18
+ const options = {
19
+ evidence: DEFAULT_EVIDENCE,
20
+ baseline: DEFAULT_BASELINE,
21
+ lexicon: DEFAULT_LEXICON,
22
+ capabilityMatrix: DEFAULT_CAPABILITY_MATRIX,
23
+ interactiveGovernance: DEFAULT_INTERACTIVE_GOVERNANCE,
24
+ matrixRemediationPlan: DEFAULT_MATRIX_REMEDIATION_PLAN,
25
+ out: DEFAULT_OUT,
26
+ markdownOut: DEFAULT_MARKDOWN_OUT,
27
+ failOnGateFail: false,
28
+ json: false
29
+ };
30
+
31
+ for (let i = 0; i < argv.length; i += 1) {
32
+ const token = argv[i];
33
+ const next = argv[i + 1];
34
+ if (token === '--evidence' && next) {
35
+ options.evidence = next;
36
+ i += 1;
37
+ } else if (token === '--baseline' && next) {
38
+ options.baseline = next;
39
+ i += 1;
40
+ } else if (token === '--lexicon' && next) {
41
+ options.lexicon = next;
42
+ i += 1;
43
+ } else if (token === '--capability-matrix' && next) {
44
+ options.capabilityMatrix = next;
45
+ i += 1;
46
+ } else if (token === '--interactive-governance' && next) {
47
+ options.interactiveGovernance = next;
48
+ i += 1;
49
+ } else if (token === '--matrix-remediation-plan' && next) {
50
+ options.matrixRemediationPlan = next;
51
+ i += 1;
52
+ } else if (token === '--out' && next) {
53
+ options.out = next;
54
+ i += 1;
55
+ } else if (token === '--markdown-out' && next) {
56
+ options.markdownOut = next;
57
+ i += 1;
58
+ } else if (token === '--fail-on-gate-fail') {
59
+ options.failOnGateFail = true;
60
+ } else if (token === '--json') {
61
+ options.json = true;
62
+ } else if (token === '--help' || token === '-h') {
63
+ printHelpAndExit(0);
64
+ }
65
+ }
66
+
67
+ return options;
68
+ }
69
+
70
+ function printHelpAndExit(code) {
71
+ const lines = [
72
+ 'Usage: node scripts/moqui-release-summary.js [options]',
73
+ '',
74
+ 'Options:',
75
+ ` --evidence <path> Handoff release evidence JSON (default: ${DEFAULT_EVIDENCE})`,
76
+ ` --baseline <path> Moqui baseline JSON (default: ${DEFAULT_BASELINE})`,
77
+ ` --lexicon <path> Moqui lexicon audit JSON (default: ${DEFAULT_LEXICON})`,
78
+ ` --capability-matrix <path> Capability matrix JSON (default: ${DEFAULT_CAPABILITY_MATRIX})`,
79
+ ` --interactive-governance <path> Interactive governance report JSON (default: ${DEFAULT_INTERACTIVE_GOVERNANCE})`,
80
+ ` --matrix-remediation-plan <path> Matrix remediation plan JSON (default: ${DEFAULT_MATRIX_REMEDIATION_PLAN})`,
81
+ ` --out <path> Summary JSON output path (default: ${DEFAULT_OUT})`,
82
+ ` --markdown-out <path> Summary markdown output path (default: ${DEFAULT_MARKDOWN_OUT})`,
83
+ ' --fail-on-gate-fail Exit non-zero when summary gate status is failed',
84
+ ' --json Print summary JSON to stdout',
85
+ ' -h, --help Show this help'
86
+ ];
87
+ console.log(lines.join('\n'));
88
+ process.exit(code);
89
+ }
90
+
91
+ function normalizeBoolean(value) {
92
+ if (value === true) {
93
+ return true;
94
+ }
95
+ if (value === false) {
96
+ return false;
97
+ }
98
+ return null;
99
+ }
100
+
101
+ function normalizeNumber(value) {
102
+ const parsed = Number(value);
103
+ return Number.isFinite(parsed) ? parsed : null;
104
+ }
105
+
106
+ async function safeReadJson(cwd, candidatePath) {
107
+ const absolutePath = path.isAbsolute(candidatePath)
108
+ ? candidatePath
109
+ : path.resolve(cwd, candidatePath);
110
+ const relativePath = path.relative(cwd, absolutePath) || '.';
111
+ const exists = await fs.pathExists(absolutePath);
112
+ if (!exists) {
113
+ return {
114
+ path: relativePath,
115
+ exists: false,
116
+ parse_error: null,
117
+ payload: null
118
+ };
119
+ }
120
+
121
+ try {
122
+ const payload = await fs.readJson(absolutePath);
123
+ return {
124
+ path: relativePath,
125
+ exists: true,
126
+ parse_error: null,
127
+ payload
128
+ };
129
+ } catch (error) {
130
+ return {
131
+ path: relativePath,
132
+ exists: true,
133
+ parse_error: error.message,
134
+ payload: null
135
+ };
136
+ }
137
+ }
138
+
139
+ function pickLatestSession(evidencePayload) {
140
+ const sessions = Array.isArray(evidencePayload && evidencePayload.sessions)
141
+ ? evidencePayload.sessions
142
+ : [];
143
+ if (sessions.length === 0) {
144
+ return null;
145
+ }
146
+
147
+ const latestSessionId = typeof evidencePayload.latest_session_id === 'string'
148
+ ? evidencePayload.latest_session_id.trim()
149
+ : '';
150
+ if (latestSessionId) {
151
+ const matched = sessions.find(item => item && item.session_id === latestSessionId);
152
+ if (matched) {
153
+ return matched;
154
+ }
155
+ }
156
+
157
+ return sessions[0];
158
+ }
159
+
160
+ function extractBaseline(payload) {
161
+ const summary = payload && payload.summary && typeof payload.summary === 'object'
162
+ ? payload.summary
163
+ : {};
164
+ const compare = payload && payload.compare && typeof payload.compare === 'object'
165
+ ? payload.compare
166
+ : {};
167
+ const regressions = Array.isArray(compare.regressions)
168
+ ? compare.regressions
169
+ : [];
170
+ return {
171
+ status: payload && typeof payload.status === 'string' ? payload.status : null,
172
+ portfolio_passed: normalizeBoolean(summary.portfolio_passed),
173
+ avg_score: normalizeNumber(summary.avg_score),
174
+ valid_rate_percent: normalizeNumber(summary.valid_rate_percent),
175
+ baseline_failed: normalizeNumber(summary.baseline_failed),
176
+ regressions_count: regressions.length
177
+ };
178
+ }
179
+
180
+ function extractLexicon(payload) {
181
+ const summary = payload && payload.summary && typeof payload.summary === 'object'
182
+ ? payload.summary
183
+ : {};
184
+ return {
185
+ passed: normalizeBoolean(summary.passed),
186
+ expected_unknown_count: normalizeNumber(summary.expected_unknown_count),
187
+ provided_unknown_count: normalizeNumber(summary.provided_unknown_count),
188
+ uncovered_expected_count: normalizeNumber(summary.uncovered_expected_count),
189
+ coverage_percent: normalizeNumber(summary.coverage_percent)
190
+ };
191
+ }
192
+
193
+ function extractCapabilityCoverage(payload) {
194
+ const summary = payload && payload.summary && typeof payload.summary === 'object'
195
+ ? payload.summary
196
+ : {};
197
+ return {
198
+ passed: normalizeBoolean(summary.passed),
199
+ semantic_passed: normalizeBoolean(summary.semantic_passed),
200
+ coverage_percent: normalizeNumber(summary.coverage_percent),
201
+ semantic_complete_percent: normalizeNumber(summary.semantic_complete_percent),
202
+ covered_capabilities: normalizeNumber(summary.covered_capabilities),
203
+ uncovered_capabilities: normalizeNumber(summary.uncovered_capabilities)
204
+ };
205
+ }
206
+
207
+ function extractScenePackageBatch(payload) {
208
+ const summary = payload && payload.summary && typeof payload.summary === 'object'
209
+ ? payload.summary
210
+ : {};
211
+ const batchGate = payload && payload.batch_ontology_gate && typeof payload.batch_ontology_gate === 'object'
212
+ ? payload.batch_ontology_gate
213
+ : {};
214
+ return {
215
+ status: payload && typeof payload.status === 'string' ? payload.status : null,
216
+ batch_gate_passed: normalizeBoolean(
217
+ summary.batch_gate_passed !== undefined
218
+ ? summary.batch_gate_passed
219
+ : batchGate.passed
220
+ ),
221
+ failed: normalizeNumber(summary.failed),
222
+ selected: normalizeNumber(summary.selected)
223
+ };
224
+ }
225
+
226
+ function extractHandoffGate(sessionPayload) {
227
+ const gate = sessionPayload && sessionPayload.gate && typeof sessionPayload.gate === 'object'
228
+ ? sessionPayload.gate
229
+ : {};
230
+ const releasePreflight = sessionPayload && sessionPayload.release_gate_preflight
231
+ && typeof sessionPayload.release_gate_preflight === 'object'
232
+ ? sessionPayload.release_gate_preflight
233
+ : {};
234
+ const policy = sessionPayload && sessionPayload.policy && typeof sessionPayload.policy === 'object'
235
+ ? sessionPayload.policy
236
+ : {};
237
+ return {
238
+ session_id: sessionPayload && sessionPayload.session_id ? sessionPayload.session_id : null,
239
+ status: sessionPayload && sessionPayload.status ? sessionPayload.status : null,
240
+ merged_at: sessionPayload && sessionPayload.merged_at ? sessionPayload.merged_at : null,
241
+ gate_passed: normalizeBoolean(gate.passed),
242
+ spec_success_rate_percent: normalizeNumber(gate && gate.actual && gate.actual.spec_success_rate_percent),
243
+ risk_level: gate && gate.actual && typeof gate.actual.risk_level === 'string'
244
+ ? gate.actual.risk_level
245
+ : null,
246
+ release_preflight_unblocked: releasePreflight.blocked === true
247
+ ? false
248
+ : (releasePreflight.blocked === false ? true : null),
249
+ max_moqui_matrix_regressions: normalizeNumber(policy.max_moqui_matrix_regressions)
250
+ };
251
+ }
252
+
253
+ function extractCapabilityMatrix(payload) {
254
+ const gates = payload && payload.gates && typeof payload.gates === 'object'
255
+ ? payload.gates
256
+ : {};
257
+ const coverage = payload && payload.capability_coverage && typeof payload.capability_coverage === 'object'
258
+ ? payload.capability_coverage
259
+ : {};
260
+ const summary = coverage && coverage.summary && typeof coverage.summary === 'object'
261
+ ? coverage.summary
262
+ : {};
263
+ return {
264
+ status: payload && typeof payload.status === 'string' ? payload.status : null,
265
+ gate_passed: normalizeBoolean(gates.passed),
266
+ coverage_passed: normalizeBoolean(
267
+ gates.capability_coverage && gates.capability_coverage.passed
268
+ ),
269
+ semantic_passed: normalizeBoolean(
270
+ gates.capability_semantic && gates.capability_semantic.passed
271
+ ),
272
+ lexicon_passed: normalizeBoolean(
273
+ gates.capability_lexicon && gates.capability_lexicon.passed
274
+ ),
275
+ coverage_percent: normalizeNumber(summary.coverage_percent),
276
+ semantic_complete_percent: normalizeNumber(summary.semantic_complete_percent)
277
+ };
278
+ }
279
+
280
+ function extractInteractiveGovernance(payload) {
281
+ const summary = payload && payload.summary && typeof payload.summary === 'object'
282
+ ? payload.summary
283
+ : {};
284
+ const metrics = payload && payload.metrics && typeof payload.metrics === 'object'
285
+ ? payload.metrics
286
+ : {};
287
+ return {
288
+ status: typeof summary.status === 'string' ? summary.status : null,
289
+ breaches: normalizeNumber(summary.breaches),
290
+ warnings: normalizeNumber(summary.warnings),
291
+ matrix_signal_total: normalizeNumber(metrics.matrix_signal_total),
292
+ matrix_portfolio_pass_rate_percent: normalizeNumber(metrics.matrix_portfolio_pass_rate_percent),
293
+ matrix_regression_positive_rate_percent: normalizeNumber(metrics.matrix_regression_positive_rate_percent),
294
+ matrix_stage_error_rate_percent: normalizeNumber(metrics.matrix_stage_error_rate_percent)
295
+ };
296
+ }
297
+
298
+ function extractMatrixRemediation(payload) {
299
+ const summary = payload && payload.summary && typeof payload.summary === 'object'
300
+ ? payload.summary
301
+ : {};
302
+ const templatePriority = Array.isArray(payload && payload.template_priority_matrix)
303
+ ? payload.template_priority_matrix
304
+ : [];
305
+ const capabilityClusters = Array.isArray(payload && payload.capability_clusters)
306
+ ? payload.capability_clusters
307
+ : [];
308
+ const templatePriorityTop = templatePriority
309
+ .slice(0, 5)
310
+ .map(item => ({
311
+ template_id: item && item.template_id ? item.template_id : null,
312
+ recommended_phase: item && item.recommended_phase ? item.recommended_phase : null,
313
+ priority_score: normalizeNumber(item && item.priority_score)
314
+ }))
315
+ .filter(item => item.template_id);
316
+ const capabilityClustersTop = capabilityClusters
317
+ .slice(0, 5)
318
+ .map(item => ({
319
+ capability: item && item.capability ? item.capability : null,
320
+ priority_score: normalizeNumber(item && item.priority_score),
321
+ template_count: normalizeNumber(item && item.template_count)
322
+ }))
323
+ .filter(item => item.capability);
324
+ return {
325
+ template_priority_count: normalizeNumber(summary.template_priority_count),
326
+ capability_cluster_count: normalizeNumber(summary.capability_cluster_count),
327
+ capability_cluster_goal_count: normalizeNumber(summary.capability_cluster_goal_count),
328
+ template_priority_top: templatePriorityTop,
329
+ capability_clusters_top: capabilityClustersTop
330
+ };
331
+ }
332
+
333
+ function normalizeGateStatus(checks, matrixRegressionCheck) {
334
+ const requiredChecks = checks.filter(item => item.required);
335
+ const hasFailed = requiredChecks.some(item => item.value === false) || matrixRegressionCheck === false;
336
+ if (hasFailed) {
337
+ return 'failed';
338
+ }
339
+ const hasUnknown = requiredChecks.some(item => item.value === null) || matrixRegressionCheck === null;
340
+ if (hasUnknown) {
341
+ return 'incomplete';
342
+ }
343
+ return 'passed';
344
+ }
345
+
346
+ function buildRecommendations(summary, matrixRemediation = {}) {
347
+ const recommendations = [];
348
+ const push = (value) => {
349
+ const text = `${value || ''}`.trim();
350
+ if (!text || recommendations.includes(text)) {
351
+ return;
352
+ }
353
+ recommendations.push(text);
354
+ };
355
+
356
+ if (summary.gate_status === 'incomplete') {
357
+ push(
358
+ 'Generate baseline release evidence first: `npx sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
359
+ );
360
+ push(
361
+ 'Generate capability matrix evidence: `npx sce auto handoff capability-matrix --manifest docs/handoffs/handoff-manifest.json --fail-on-gap --json`.'
362
+ );
363
+ }
364
+
365
+ const map = new Map(summary.checks.map(item => [item.key, item.value]));
366
+ if (map.get('handoff_gate') === false) {
367
+ push(
368
+ 'Fix handoff gate failures and rerun: `npx sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
369
+ );
370
+ }
371
+ if (map.get('baseline_portfolio') === false) {
372
+ push(
373
+ 'Remediate baseline portfolio score/gaps: `npx sce scene moqui-baseline --include-all --fail-on-portfolio-fail --json`.'
374
+ );
375
+ }
376
+ if (map.get('scene_package_batch') === false) {
377
+ push(
378
+ 'Repair scene package batch ontology gate: `npx sce scene package-publish-batch --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
379
+ );
380
+ }
381
+ if (map.get('capability_coverage') === false || map.get('capability_semantic') === false) {
382
+ push(
383
+ 'Close capability and semantic gaps: `npx sce auto handoff capability-matrix --manifest docs/handoffs/handoff-manifest.json --fail-on-gap --json`.'
384
+ );
385
+ }
386
+ if (map.get('lexicon_gate') === false) {
387
+ push(
388
+ 'Align manifest/template aliases with canonical lexicon: `node scripts/moqui-lexicon-audit.js --manifest docs/handoffs/handoff-manifest.json --fail-on-gap --json`.'
389
+ );
390
+ }
391
+ if (map.get('release_preflight') === false) {
392
+ push(
393
+ 'Release gate preflight is blocked; resolve governance release-gate blockers and rerun handoff evidence.'
394
+ );
395
+ }
396
+ if (summary.matrix_regression_check === false) {
397
+ push(
398
+ 'Recover matrix regressions to policy limit before release: `npx sce auto handoff run --manifest docs/handoffs/handoff-manifest.json --dry-run --json`.'
399
+ );
400
+ push(
401
+ 'Generate phased matrix remediation package: `node scripts/moqui-matrix-remediation-queue.js --baseline .sce/reports/release-evidence/moqui-template-baseline.json --json`.'
402
+ );
403
+ for (const line of buildMoquiRegressionRecoverySequenceLines({
404
+ wrapCommands: true,
405
+ withPeriod: true,
406
+ clusterPhasedCommand: 'npm run run:matrix-remediation-clusters-phased -- --json',
407
+ includeStep1Alias: false,
408
+ baselinePhasedAlias: 'npm run run:matrix-remediation-phased -- --json'
409
+ })) {
410
+ push(line);
411
+ }
412
+ if (Array.isArray(matrixRemediation.template_priority_top) && matrixRemediation.template_priority_top.length > 0) {
413
+ push(
414
+ `Prioritize template recovery order: ${matrixRemediation.template_priority_top
415
+ .slice(0, 3)
416
+ .map(item => `${item.template_id}(${item.recommended_phase || 'n/a'})`)
417
+ .join(' -> ')}.`
418
+ );
419
+ }
420
+ if (Array.isArray(matrixRemediation.capability_clusters_top) && matrixRemediation.capability_clusters_top.length > 0) {
421
+ push(
422
+ `Prioritize capability closure clusters: ${matrixRemediation.capability_clusters_top
423
+ .slice(0, 3)
424
+ .map(item => `${item.capability}${Number.isFinite(item.priority_score) ? `(${item.priority_score})` : ''}`)
425
+ .join(' -> ')}.`
426
+ );
427
+ }
428
+ }
429
+ if (map.get('interactive_governance') === false) {
430
+ push(
431
+ 'Resolve interactive governance alerts and rerun: `npm run report:interactive-governance -- --period weekly --fail-on-alert --json`.'
432
+ );
433
+ }
434
+
435
+ if (recommendations.length === 0) {
436
+ push('No blocking issue detected in the available evidence.');
437
+ }
438
+
439
+ return recommendations;
440
+ }
441
+
442
+ function buildMarkdownReport(report) {
443
+ const lines = [];
444
+ lines.push('# Moqui Release Summary');
445
+ lines.push('');
446
+ lines.push(`- Generated at: ${report.generated_at}`);
447
+ lines.push(`- Gate status: ${report.summary.gate_status}`);
448
+ lines.push(
449
+ `- Gate passed: ${report.summary.gate_passed === null ? 'n/a' : (report.summary.gate_passed ? 'yes' : 'no')}`
450
+ );
451
+ lines.push('');
452
+ lines.push('## Current Session');
453
+ lines.push('');
454
+ lines.push(`- Session ID: ${report.handoff.session_id || 'n/a'}`);
455
+ lines.push(`- Status: ${report.handoff.status || 'n/a'}`);
456
+ lines.push(`- Merged at: ${report.handoff.merged_at || 'n/a'}`);
457
+ lines.push('');
458
+ lines.push('## Gate Checks');
459
+ lines.push('');
460
+ lines.push('| Check | Value | Required |');
461
+ lines.push('| --- | --- | --- |');
462
+ for (const check of report.summary.checks) {
463
+ const valueText = check.value === null ? 'n/a' : (check.value ? 'pass' : 'fail');
464
+ lines.push(`| ${check.key} | ${valueText} | ${check.required ? 'yes' : 'no'} |`);
465
+ }
466
+ lines.push('');
467
+ lines.push('## Signals');
468
+ lines.push('');
469
+ lines.push(`- Baseline portfolio passed: ${report.baseline.portfolio_passed === null ? 'n/a' : (report.baseline.portfolio_passed ? 'yes' : 'no')}`);
470
+ lines.push(`- Baseline avg score: ${report.baseline.avg_score === null ? 'n/a' : report.baseline.avg_score}`);
471
+ lines.push(`- Baseline valid-rate: ${report.baseline.valid_rate_percent === null ? 'n/a' : `${report.baseline.valid_rate_percent}%`}`);
472
+ lines.push(`- Lexicon passed: ${report.lexicon.passed === null ? 'n/a' : (report.lexicon.passed ? 'yes' : 'no')}`);
473
+ lines.push(`- Lexicon coverage: ${report.lexicon.coverage_percent === null ? 'n/a' : `${report.lexicon.coverage_percent}%`}`);
474
+ lines.push(`- Capability coverage passed: ${report.capability_coverage.passed === null ? 'n/a' : (report.capability_coverage.passed ? 'yes' : 'no')}`);
475
+ lines.push(`- Capability semantic passed: ${report.capability_coverage.semantic_passed === null ? 'n/a' : (report.capability_coverage.semantic_passed ? 'yes' : 'no')}`);
476
+ lines.push(`- Capability coverage: ${report.capability_coverage.coverage_percent === null ? 'n/a' : `${report.capability_coverage.coverage_percent}%`}`);
477
+ lines.push(`- Capability semantic completeness: ${report.capability_coverage.semantic_complete_percent === null ? 'n/a' : `${report.capability_coverage.semantic_complete_percent}%`}`);
478
+ lines.push(`- Scene package batch gate passed: ${report.scene_package_batch.batch_gate_passed === null ? 'n/a' : (report.scene_package_batch.batch_gate_passed ? 'yes' : 'no')}`);
479
+ lines.push(`- Interactive governance status: ${report.interactive_governance.status || 'n/a'}`);
480
+ lines.push(`- Interactive governance breaches: ${report.interactive_governance.breaches === null ? 'n/a' : report.interactive_governance.breaches}`);
481
+ lines.push(`- Interactive governance warnings: ${report.interactive_governance.warnings === null ? 'n/a' : report.interactive_governance.warnings}`);
482
+ lines.push(`- Interactive matrix pass-rate: ${report.interactive_governance.matrix_portfolio_pass_rate_percent === null ? 'n/a' : `${report.interactive_governance.matrix_portfolio_pass_rate_percent}%`}`);
483
+ lines.push(`- Interactive matrix regression-positive rate: ${report.interactive_governance.matrix_regression_positive_rate_percent === null ? 'n/a' : `${report.interactive_governance.matrix_regression_positive_rate_percent}%`}`);
484
+ lines.push(
485
+ `- Matrix regressions: ${report.summary.matrix_regressions === null ? 'n/a' : report.summary.matrix_regressions}` +
486
+ ` (max=${report.summary.max_matrix_regressions === null ? 'n/a' : report.summary.max_matrix_regressions})`
487
+ );
488
+ lines.push(
489
+ `- Matrix template priority count: ${report.matrix_remediation.template_priority_count === null ? 'n/a' : report.matrix_remediation.template_priority_count}`
490
+ );
491
+ lines.push(
492
+ `- Matrix capability cluster count: ${report.matrix_remediation.capability_cluster_count === null ? 'n/a' : report.matrix_remediation.capability_cluster_count}`
493
+ );
494
+ lines.push(
495
+ `- Matrix capability-cluster goals: ${report.matrix_remediation.capability_cluster_goal_count === null ? 'n/a' : report.matrix_remediation.capability_cluster_goal_count}`
496
+ );
497
+ lines.push('');
498
+ lines.push('## Inputs');
499
+ lines.push('');
500
+ lines.push('| Input | Path | Exists | Parse Error |');
501
+ lines.push('| --- | --- | --- | --- |');
502
+ for (const input of Object.values(report.inputs)) {
503
+ lines.push(
504
+ `| ${input.key} | ${input.path} | ${input.exists ? 'yes' : 'no'} | ${input.parse_error || 'none'} |`
505
+ );
506
+ }
507
+ if (
508
+ Array.isArray(report.matrix_remediation.template_priority_top) &&
509
+ report.matrix_remediation.template_priority_top.length > 0
510
+ ) {
511
+ lines.push('');
512
+ lines.push('## Matrix Template Priorities');
513
+ lines.push('');
514
+ for (const item of report.matrix_remediation.template_priority_top.slice(0, 5)) {
515
+ lines.push(
516
+ `- ${item.template_id} (${item.recommended_phase || 'n/a'}, ` +
517
+ `score=${item.priority_score === null ? 'n/a' : item.priority_score})`
518
+ );
519
+ }
520
+ }
521
+ if (
522
+ Array.isArray(report.matrix_remediation.capability_clusters_top) &&
523
+ report.matrix_remediation.capability_clusters_top.length > 0
524
+ ) {
525
+ lines.push('');
526
+ lines.push('## Matrix Capability Clusters');
527
+ lines.push('');
528
+ for (const item of report.matrix_remediation.capability_clusters_top.slice(0, 5)) {
529
+ lines.push(
530
+ `- ${item.capability} (score=${item.priority_score === null ? 'n/a' : item.priority_score}, ` +
531
+ `templates=${item.template_count === null ? 'n/a' : item.template_count})`
532
+ );
533
+ }
534
+ }
535
+ lines.push('');
536
+ lines.push('## Recommendations');
537
+ lines.push('');
538
+ for (const item of report.recommendations) {
539
+ lines.push(`- ${item}`);
540
+ }
541
+ return `${lines.join('\n')}\n`;
542
+ }
543
+
544
+ async function main() {
545
+ const options = parseArgs(process.argv.slice(2));
546
+ const cwd = process.cwd();
547
+
548
+ const [evidenceInput, baselineInput, lexiconInput, capabilityMatrixInput, interactiveGovernanceInput, matrixRemediationPlanInput] = await Promise.all([
549
+ safeReadJson(cwd, options.evidence),
550
+ safeReadJson(cwd, options.baseline),
551
+ safeReadJson(cwd, options.lexicon),
552
+ safeReadJson(cwd, options.capabilityMatrix),
553
+ safeReadJson(cwd, options.interactiveGovernance),
554
+ safeReadJson(cwd, options.matrixRemediationPlan)
555
+ ]);
556
+
557
+ const latestSession = pickLatestSession(evidenceInput.payload);
558
+ const handoff = extractHandoffGate(latestSession || {});
559
+ const baselineFromEvidence = extractBaseline(
560
+ latestSession && latestSession.moqui_baseline && typeof latestSession.moqui_baseline === 'object'
561
+ ? latestSession.moqui_baseline
562
+ : {}
563
+ );
564
+ const capabilityFromEvidence = extractCapabilityCoverage(
565
+ latestSession && latestSession.moqui_capability_coverage && typeof latestSession.moqui_capability_coverage === 'object'
566
+ ? latestSession.moqui_capability_coverage
567
+ : {}
568
+ );
569
+ const scenePackageBatch = extractScenePackageBatch(
570
+ latestSession && latestSession.scene_package_batch && typeof latestSession.scene_package_batch === 'object'
571
+ ? latestSession.scene_package_batch
572
+ : {}
573
+ );
574
+
575
+ const baselineFromFile = extractBaseline(
576
+ baselineInput.payload && typeof baselineInput.payload === 'object'
577
+ ? baselineInput.payload
578
+ : {}
579
+ );
580
+ const lexicon = extractLexicon(
581
+ lexiconInput.payload && typeof lexiconInput.payload === 'object'
582
+ ? lexiconInput.payload
583
+ : {}
584
+ );
585
+ const capabilityMatrix = extractCapabilityMatrix(
586
+ capabilityMatrixInput.payload && typeof capabilityMatrixInput.payload === 'object'
587
+ ? capabilityMatrixInput.payload
588
+ : {}
589
+ );
590
+ const interactiveGovernance = extractInteractiveGovernance(
591
+ interactiveGovernanceInput.payload && typeof interactiveGovernanceInput.payload === 'object'
592
+ ? interactiveGovernanceInput.payload
593
+ : {}
594
+ );
595
+ const matrixRemediation = extractMatrixRemediation(
596
+ matrixRemediationPlanInput.payload && typeof matrixRemediationPlanInput.payload === 'object'
597
+ ? matrixRemediationPlanInput.payload
598
+ : {}
599
+ );
600
+
601
+ const baseline = {
602
+ status: baselineFromFile.status || baselineFromEvidence.status || null,
603
+ portfolio_passed: baselineFromFile.portfolio_passed !== null
604
+ ? baselineFromFile.portfolio_passed
605
+ : baselineFromEvidence.portfolio_passed,
606
+ avg_score: baselineFromFile.avg_score !== null ? baselineFromFile.avg_score : baselineFromEvidence.avg_score,
607
+ valid_rate_percent: baselineFromFile.valid_rate_percent !== null
608
+ ? baselineFromFile.valid_rate_percent
609
+ : baselineFromEvidence.valid_rate_percent,
610
+ baseline_failed: baselineFromFile.baseline_failed !== null
611
+ ? baselineFromFile.baseline_failed
612
+ : baselineFromEvidence.baseline_failed,
613
+ regressions_count: baselineFromFile.regressions_count > 0
614
+ ? baselineFromFile.regressions_count
615
+ : baselineFromEvidence.regressions_count
616
+ };
617
+
618
+ const capabilityCoverage = {
619
+ passed: capabilityMatrix.coverage_passed !== null
620
+ ? capabilityMatrix.coverage_passed
621
+ : capabilityFromEvidence.passed,
622
+ semantic_passed: capabilityMatrix.semantic_passed !== null
623
+ ? capabilityMatrix.semantic_passed
624
+ : capabilityFromEvidence.semantic_passed,
625
+ coverage_percent: capabilityMatrix.coverage_percent !== null
626
+ ? capabilityMatrix.coverage_percent
627
+ : capabilityFromEvidence.coverage_percent,
628
+ semantic_complete_percent: capabilityMatrix.semantic_complete_percent !== null
629
+ ? capabilityMatrix.semantic_complete_percent
630
+ : capabilityFromEvidence.semantic_complete_percent,
631
+ covered_capabilities: capabilityFromEvidence.covered_capabilities,
632
+ uncovered_capabilities: capabilityFromEvidence.uncovered_capabilities
633
+ };
634
+
635
+ const matrixRegressions = baseline.regressions_count;
636
+ const maxMatrixRegressions = handoff.max_moqui_matrix_regressions;
637
+ const matrixRegressionCheck = (
638
+ matrixRegressions === null || maxMatrixRegressions === null
639
+ ? null
640
+ : matrixRegressions <= maxMatrixRegressions
641
+ );
642
+
643
+ const checks = [
644
+ { key: 'handoff_gate', value: handoff.gate_passed, required: true },
645
+ { key: 'baseline_portfolio', value: baseline.portfolio_passed, required: true },
646
+ { key: 'scene_package_batch', value: scenePackageBatch.batch_gate_passed, required: true },
647
+ { key: 'capability_coverage', value: capabilityCoverage.passed, required: true },
648
+ { key: 'capability_semantic', value: capabilityCoverage.semantic_passed, required: true },
649
+ {
650
+ key: 'lexicon_gate',
651
+ value: lexicon.passed !== null ? lexicon.passed : capabilityMatrix.lexicon_passed,
652
+ required: true
653
+ },
654
+ {
655
+ key: 'interactive_governance',
656
+ value: interactiveGovernance.status === 'ok'
657
+ ? true
658
+ : (interactiveGovernance.status === 'alert' ? false : null),
659
+ required: false
660
+ },
661
+ { key: 'release_preflight', value: handoff.release_preflight_unblocked, required: false }
662
+ ];
663
+
664
+ const gateStatus = normalizeGateStatus(checks, matrixRegressionCheck);
665
+ const gatePassed = gateStatus === 'passed'
666
+ ? true
667
+ : (gateStatus === 'failed' ? false : null);
668
+ const summary = {
669
+ gate_status: gateStatus,
670
+ gate_passed: gatePassed,
671
+ checks,
672
+ matrix_regressions: matrixRegressions,
673
+ max_matrix_regressions: maxMatrixRegressions,
674
+ matrix_regression_check: matrixRegressionCheck
675
+ };
676
+
677
+ const report = {
678
+ mode: 'moqui-release-summary',
679
+ generated_at: new Date().toISOString(),
680
+ inputs: {
681
+ evidence: { key: 'evidence', ...evidenceInput },
682
+ baseline: { key: 'baseline', ...baselineInput },
683
+ lexicon: { key: 'lexicon', ...lexiconInput },
684
+ capability_matrix: { key: 'capability_matrix', ...capabilityMatrixInput },
685
+ interactive_governance: { key: 'interactive_governance', ...interactiveGovernanceInput },
686
+ matrix_remediation_plan: { key: 'matrix_remediation_plan', ...matrixRemediationPlanInput }
687
+ },
688
+ handoff,
689
+ baseline,
690
+ lexicon,
691
+ capability_coverage: capabilityCoverage,
692
+ capability_matrix: capabilityMatrix,
693
+ interactive_governance: interactiveGovernance,
694
+ matrix_remediation: matrixRemediation,
695
+ scene_package_batch: scenePackageBatch,
696
+ summary
697
+ };
698
+ report.recommendations = buildRecommendations(report.summary, report.matrix_remediation);
699
+
700
+ const outPath = path.resolve(cwd, options.out);
701
+ const markdownOutPath = path.resolve(cwd, options.markdownOut);
702
+ await fs.ensureDir(path.dirname(outPath));
703
+ await fs.writeJson(outPath, report, { spaces: 2 });
704
+ await fs.ensureDir(path.dirname(markdownOutPath));
705
+ await fs.writeFile(markdownOutPath, buildMarkdownReport(report), 'utf8');
706
+
707
+ if (options.json) {
708
+ process.stdout.write(`${JSON.stringify({
709
+ ...report,
710
+ output: {
711
+ json: path.relative(cwd, outPath) || '.',
712
+ markdown: path.relative(cwd, markdownOutPath) || '.'
713
+ }
714
+ }, null, 2)}\n`);
715
+ } else {
716
+ process.stdout.write(`Moqui release summary generated (${summary.gate_status}).\n`);
717
+ process.stdout.write(`- JSON: ${path.relative(cwd, outPath) || '.'}\n`);
718
+ process.stdout.write(`- Markdown: ${path.relative(cwd, markdownOutPath) || '.'}\n`);
719
+ }
720
+
721
+ if (options.failOnGateFail && summary.gate_status === 'failed') {
722
+ process.exitCode = 2;
723
+ }
724
+ }
725
+
726
+ main().catch((error) => {
727
+ console.error(`Moqui release summary failed: ${error.message}`);
728
+ process.exit(1);
729
+ });