scene-capability-engine 3.6.45 → 3.6.47

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 (72) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -0
  3. package/README.zh.md +1 -0
  4. package/docs/agent-runtime/symbol-evidence.schema.json +1 -1
  5. package/docs/command-reference.md +8 -0
  6. package/docs/interactive-customization/dialogue-governance-policy-baseline.json +4 -1
  7. package/docs/interactive-customization/embedded-assistant-authorization-dialogue-rules.md +5 -0
  8. package/docs/releases/README.md +2 -0
  9. package/docs/releases/v3.6.46.md +23 -0
  10. package/docs/releases/v3.6.47.md +23 -0
  11. package/docs/sce-business-mode-map.md +2 -1
  12. package/docs/sce-capability-matrix-e2e-example.md +2 -1
  13. package/docs/security-governance-default-baseline.md +2 -0
  14. package/docs/starter-kit/README.md +3 -0
  15. package/docs/zh/releases/README.md +2 -0
  16. package/docs/zh/releases/v3.6.46.md +23 -0
  17. package/docs/zh/releases/v3.6.47.md +23 -0
  18. package/lib/workspace/takeover-baseline.js +293 -1
  19. package/package.json +6 -2
  20. package/scripts/auto-strategy-router.js +231 -0
  21. package/scripts/capability-mapping-report.js +339 -0
  22. package/scripts/check-branding-consistency.js +140 -0
  23. package/scripts/check-sce-tracking.js +54 -0
  24. package/scripts/check-skip-allowlist.js +94 -0
  25. package/scripts/clarification-first-audit.js +322 -0
  26. package/scripts/errorbook-registry-health-gate.js +172 -0
  27. package/scripts/errorbook-release-gate.js +132 -0
  28. package/scripts/failure-attribution-repair.js +317 -0
  29. package/scripts/git-managed-gate.js +464 -0
  30. package/scripts/interactive-approval-event-projection.js +400 -0
  31. package/scripts/interactive-approval-workflow.js +829 -0
  32. package/scripts/interactive-authorization-tier-evaluate.js +413 -0
  33. package/scripts/interactive-change-plan-gate.js +225 -0
  34. package/scripts/interactive-context-bridge.js +617 -0
  35. package/scripts/interactive-customization-loop.js +1690 -0
  36. package/scripts/interactive-dialogue-governance.js +873 -0
  37. package/scripts/interactive-feedback-log.js +253 -0
  38. package/scripts/interactive-flow-smoke.js +238 -0
  39. package/scripts/interactive-flow.js +1059 -0
  40. package/scripts/interactive-governance-report.js +1112 -0
  41. package/scripts/interactive-intent-build.js +707 -0
  42. package/scripts/interactive-loop-smoke.js +215 -0
  43. package/scripts/interactive-moqui-adapter.js +304 -0
  44. package/scripts/interactive-plan-build.js +426 -0
  45. package/scripts/interactive-runtime-policy-evaluate.js +495 -0
  46. package/scripts/interactive-work-order-build.js +552 -0
  47. package/scripts/matrix-regression-gate.js +167 -0
  48. package/scripts/moqui-core-regression-suite.js +397 -0
  49. package/scripts/moqui-lexicon-audit.js +651 -0
  50. package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
  51. package/scripts/moqui-matrix-remediation-queue.js +852 -0
  52. package/scripts/moqui-metadata-extract.js +1340 -0
  53. package/scripts/moqui-rebuild-gate.js +167 -0
  54. package/scripts/moqui-release-summary.js +729 -0
  55. package/scripts/moqui-standard-rebuild.js +1370 -0
  56. package/scripts/moqui-template-baseline-report.js +682 -0
  57. package/scripts/npm-package-runtime-asset-check.js +221 -0
  58. package/scripts/problem-closure-gate.js +441 -0
  59. package/scripts/release-asset-integrity-check.js +216 -0
  60. package/scripts/release-asset-nonempty-normalize.js +166 -0
  61. package/scripts/release-drift-evaluate.js +223 -0
  62. package/scripts/release-drift-signals.js +255 -0
  63. package/scripts/release-governance-snapshot-export.js +132 -0
  64. package/scripts/release-ops-weekly-summary.js +934 -0
  65. package/scripts/release-risk-remediation-bundle.js +315 -0
  66. package/scripts/release-weekly-ops-gate.js +423 -0
  67. package/scripts/state-migration-reconciliation-gate.js +110 -0
  68. package/scripts/state-storage-tiering-audit.js +337 -0
  69. package/scripts/steering-content-audit.js +393 -0
  70. package/scripts/symbol-evidence-locate.js +370 -0
  71. package/template/.sce/README.md +1 -0
  72. package/template/.sce/steering/CORE_PRINCIPLES.md +25 -0
@@ -0,0 +1,423 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+
6
+ function appendSummary(summaryPath, lines = []) {
7
+ if (!summaryPath) {
8
+ return;
9
+ }
10
+ fs.appendFileSync(summaryPath, `${lines.join('\n')}\n\n`, 'utf8');
11
+ }
12
+
13
+ function readValue(env, name, fallback = '') {
14
+ const value = env[name];
15
+ return value === undefined || value === null ? fallback : `${value}`.trim();
16
+ }
17
+
18
+ function parseBoolean(raw, fallback) {
19
+ const value = `${raw || ''}`.trim().toLowerCase();
20
+ if (!value) {
21
+ return fallback;
22
+ }
23
+ if (['1', 'true', 'yes', 'y', 'on'].includes(value)) {
24
+ return true;
25
+ }
26
+ if (['0', 'false', 'no', 'n', 'off'].includes(value)) {
27
+ return false;
28
+ }
29
+ return fallback;
30
+ }
31
+
32
+ function normalizeRiskLevel(raw, fallback = 'medium') {
33
+ const value = `${raw || ''}`.trim().toLowerCase();
34
+ if (!value) {
35
+ return fallback;
36
+ }
37
+ if (['low', 'medium', 'high', 'unknown'].includes(value)) {
38
+ return value;
39
+ }
40
+ return fallback;
41
+ }
42
+
43
+ function riskRank(level) {
44
+ const normalized = normalizeRiskLevel(level, 'unknown');
45
+ if (normalized === 'low') {
46
+ return 1;
47
+ }
48
+ if (normalized === 'medium') {
49
+ return 2;
50
+ }
51
+ if (normalized === 'high') {
52
+ return 3;
53
+ }
54
+ return 4;
55
+ }
56
+
57
+ function parseOptionalNumberWithWarning(env, name, warnings) {
58
+ const raw = readValue(env, name, '');
59
+ if (!raw) {
60
+ return null;
61
+ }
62
+ const parsed = Number(raw);
63
+ if (Number.isFinite(parsed)) {
64
+ return parsed;
65
+ }
66
+ warnings.push(`invalid number ${name}=${raw}, fallback=default`);
67
+ return null;
68
+ }
69
+
70
+ function safeReadJson(file) {
71
+ if (!file || !fs.existsSync(file)) {
72
+ return {
73
+ ok: false,
74
+ error: `missing file: ${file || 'n/a'}`,
75
+ payload: null
76
+ };
77
+ }
78
+ try {
79
+ return {
80
+ ok: true,
81
+ error: null,
82
+ payload: JSON.parse(fs.readFileSync(file, 'utf8'))
83
+ };
84
+ } catch (error) {
85
+ return {
86
+ ok: false,
87
+ error: `parse error: ${error.message}`,
88
+ payload: null
89
+ };
90
+ }
91
+ }
92
+
93
+ function normalizeNumber(value) {
94
+ const parsed = Number(value);
95
+ return Number.isFinite(parsed) ? parsed : null;
96
+ }
97
+
98
+ function buildWeeklyOpsSignals(payload) {
99
+ const health = payload && payload.health && typeof payload.health === 'object'
100
+ ? payload.health
101
+ : {};
102
+ const snapshots = payload && payload.snapshots && typeof payload.snapshots === 'object'
103
+ ? payload.snapshots
104
+ : {};
105
+ const governance = snapshots.interactive_governance && typeof snapshots.interactive_governance === 'object'
106
+ ? snapshots.interactive_governance
107
+ : {};
108
+ const matrixSignals = snapshots.matrix_signals && typeof snapshots.matrix_signals === 'object'
109
+ ? snapshots.matrix_signals
110
+ : {};
111
+ const handoff = snapshots.handoff && typeof snapshots.handoff === 'object'
112
+ ? snapshots.handoff
113
+ : {};
114
+
115
+ return {
116
+ risk: normalizeRiskLevel(health.risk, 'unknown'),
117
+ concerns_count: Array.isArray(health.concerns) ? health.concerns.length : 0,
118
+ governance_status: typeof governance.status === 'string' ? governance.status : null,
119
+ governance_breaches: normalizeNumber(governance.breaches),
120
+ authorization_tier_block_rate_percent: normalizeNumber(governance.authorization_tier_block_rate_percent),
121
+ dialogue_authorization_block_rate_percent: normalizeNumber(governance.dialogue_authorization_block_rate_percent),
122
+ runtime_block_rate_percent: normalizeNumber(governance.runtime_block_rate_percent),
123
+ runtime_ui_mode_violation_total: normalizeNumber(governance.runtime_ui_mode_violation_total),
124
+ runtime_ui_mode_violation_rate_percent: normalizeNumber(governance.runtime_ui_mode_violation_rate_percent),
125
+ business_mode_unknown_signal_total: normalizeNumber(governance.business_mode_unknown_signal_total),
126
+ matrix_regression_positive_rate_percent: normalizeNumber(matrixSignals.regression_positive_rate_percent),
127
+ handoff_gate_pass_rate_percent: normalizeNumber(handoff.gate_pass_rate_percent)
128
+ };
129
+ }
130
+
131
+ function mergeGateReport(gateReportFile, payload) {
132
+ if (!gateReportFile) {
133
+ return;
134
+ }
135
+ let base = {};
136
+ try {
137
+ if (fs.existsSync(gateReportFile)) {
138
+ base = JSON.parse(fs.readFileSync(gateReportFile, 'utf8'));
139
+ }
140
+ } catch (_error) {
141
+ base = {};
142
+ }
143
+ base.weekly_ops = payload;
144
+ base.updated_at = payload.evaluated_at;
145
+ fs.writeFileSync(gateReportFile, `${JSON.stringify(base, null, 2)}\n`, 'utf8');
146
+ }
147
+
148
+ function evaluateReleaseWeeklyOpsGate(options = {}) {
149
+ const env = options.env && typeof options.env === 'object'
150
+ ? options.env
151
+ : process.env;
152
+ const now = typeof options.now === 'function'
153
+ ? options.now
154
+ : () => new Date().toISOString();
155
+
156
+ const summaryFile = readValue(env, 'RELEASE_WEEKLY_OPS_SUMMARY_FILE', '');
157
+ const enforce = parseBoolean(readValue(env, 'RELEASE_WEEKLY_OPS_ENFORCE', ''), true);
158
+ const requireSummary = parseBoolean(readValue(env, 'RELEASE_WEEKLY_OPS_REQUIRE_SUMMARY', ''), true);
159
+ const maxRiskLevel = normalizeRiskLevel(readValue(env, 'RELEASE_WEEKLY_OPS_MAX_RISK_LEVEL', ''), 'medium');
160
+ const configWarnings = [];
161
+ const maxGovernanceBreaches = parseOptionalNumberWithWarning(
162
+ env,
163
+ 'RELEASE_WEEKLY_OPS_MAX_GOVERNANCE_BREACHES',
164
+ configWarnings
165
+ );
166
+ const maxAuthorizationTierBlockRatePercentRaw = parseOptionalNumberWithWarning(
167
+ env,
168
+ 'RELEASE_WEEKLY_OPS_MAX_AUTHORIZATION_TIER_BLOCK_RATE_PERCENT',
169
+ configWarnings
170
+ );
171
+ const maxAuthorizationTierBlockRatePercent = Number.isFinite(maxAuthorizationTierBlockRatePercentRaw)
172
+ ? maxAuthorizationTierBlockRatePercentRaw
173
+ : 40;
174
+ const maxDialogueAuthorizationBlockRatePercentRaw = parseOptionalNumberWithWarning(
175
+ env,
176
+ 'RELEASE_WEEKLY_OPS_MAX_DIALOGUE_AUTHORIZATION_BLOCK_RATE_PERCENT',
177
+ configWarnings
178
+ );
179
+ const maxDialogueAuthorizationBlockRatePercent = Number.isFinite(maxDialogueAuthorizationBlockRatePercentRaw)
180
+ ? maxDialogueAuthorizationBlockRatePercentRaw
181
+ : 40;
182
+ const maxRuntimeUiModeViolationTotalRaw = parseOptionalNumberWithWarning(
183
+ env,
184
+ 'RELEASE_WEEKLY_OPS_MAX_RUNTIME_UI_MODE_VIOLATION_TOTAL',
185
+ configWarnings
186
+ );
187
+ const maxRuntimeUiModeViolationTotal = Number.isFinite(maxRuntimeUiModeViolationTotalRaw)
188
+ ? maxRuntimeUiModeViolationTotalRaw
189
+ : 0;
190
+ const maxRuntimeUiModeViolationRatePercent = parseOptionalNumberWithWarning(
191
+ env,
192
+ 'RELEASE_WEEKLY_OPS_MAX_RUNTIME_UI_MODE_VIOLATION_RATE_PERCENT',
193
+ configWarnings
194
+ );
195
+ const maxBusinessModeUnknownSignalTotalRaw = parseOptionalNumberWithWarning(
196
+ env,
197
+ 'RELEASE_WEEKLY_OPS_MAX_BUSINESS_MODE_UNKNOWN_SIGNAL_TOTAL',
198
+ configWarnings
199
+ );
200
+ const maxBusinessModeUnknownSignalTotal = Number.isFinite(maxBusinessModeUnknownSignalTotalRaw)
201
+ ? maxBusinessModeUnknownSignalTotalRaw
202
+ : 0;
203
+ const maxMatrixRegressionPositiveRatePercent = parseOptionalNumberWithWarning(
204
+ env,
205
+ 'RELEASE_WEEKLY_OPS_MAX_MATRIX_REGRESSION_RATE_PERCENT',
206
+ configWarnings
207
+ );
208
+ const gateReportFile = readValue(env, 'RELEASE_GATE_REPORT_FILE', '');
209
+ const summaryPath = readValue(env, 'GITHUB_STEP_SUMMARY', '');
210
+
211
+ const violations = [];
212
+ const warnings = configWarnings.slice();
213
+ const summaryResult = safeReadJson(summaryFile);
214
+ let signals = null;
215
+
216
+ if (!summaryResult.ok) {
217
+ if (requireSummary) {
218
+ violations.push(summaryResult.error);
219
+ } else {
220
+ warnings.push(summaryResult.error);
221
+ }
222
+ } else {
223
+ signals = buildWeeklyOpsSignals(summaryResult.payload);
224
+ if (riskRank(signals.risk) > riskRank(maxRiskLevel)) {
225
+ violations.push(`weekly ops risk ${signals.risk} exceeds max ${maxRiskLevel}`);
226
+ }
227
+ if (
228
+ Number.isFinite(maxGovernanceBreaches)
229
+ && Number.isFinite(signals.governance_breaches)
230
+ && signals.governance_breaches > maxGovernanceBreaches
231
+ ) {
232
+ violations.push(
233
+ `weekly ops governance breaches ${signals.governance_breaches} exceeds max ${maxGovernanceBreaches}`
234
+ );
235
+ }
236
+ if (
237
+ Number.isFinite(maxAuthorizationTierBlockRatePercent)
238
+ && Number.isFinite(signals.authorization_tier_block_rate_percent)
239
+ && signals.authorization_tier_block_rate_percent > maxAuthorizationTierBlockRatePercent
240
+ ) {
241
+ violations.push(
242
+ `weekly ops authorization-tier block rate ${signals.authorization_tier_block_rate_percent}% exceeds max ${maxAuthorizationTierBlockRatePercent}%`
243
+ );
244
+ }
245
+ if (
246
+ Number.isFinite(maxDialogueAuthorizationBlockRatePercent)
247
+ && Number.isFinite(signals.dialogue_authorization_block_rate_percent)
248
+ && signals.dialogue_authorization_block_rate_percent > maxDialogueAuthorizationBlockRatePercent
249
+ ) {
250
+ violations.push(
251
+ `weekly ops dialogue-authorization block rate ${signals.dialogue_authorization_block_rate_percent}% exceeds max ${maxDialogueAuthorizationBlockRatePercent}%`
252
+ );
253
+ }
254
+ if (
255
+ Number.isFinite(maxRuntimeUiModeViolationTotal)
256
+ && Number.isFinite(signals.runtime_ui_mode_violation_total)
257
+ && signals.runtime_ui_mode_violation_total > maxRuntimeUiModeViolationTotal
258
+ ) {
259
+ violations.push(
260
+ `weekly ops runtime ui-mode violation total ${signals.runtime_ui_mode_violation_total} exceeds max ${maxRuntimeUiModeViolationTotal}`
261
+ );
262
+ }
263
+ if (
264
+ Number.isFinite(maxRuntimeUiModeViolationRatePercent)
265
+ && Number.isFinite(signals.runtime_ui_mode_violation_rate_percent)
266
+ && signals.runtime_ui_mode_violation_rate_percent > maxRuntimeUiModeViolationRatePercent
267
+ ) {
268
+ violations.push(
269
+ `weekly ops runtime ui-mode violation rate ${signals.runtime_ui_mode_violation_rate_percent}% exceeds max ${maxRuntimeUiModeViolationRatePercent}%`
270
+ );
271
+ }
272
+ if (
273
+ Number.isFinite(maxBusinessModeUnknownSignalTotal)
274
+ && Number.isFinite(signals.business_mode_unknown_signal_total)
275
+ && signals.business_mode_unknown_signal_total > maxBusinessModeUnknownSignalTotal
276
+ ) {
277
+ violations.push(
278
+ `weekly ops business-mode unknown signal total ${signals.business_mode_unknown_signal_total} exceeds max ${maxBusinessModeUnknownSignalTotal}`
279
+ );
280
+ }
281
+ if (
282
+ Number.isFinite(maxMatrixRegressionPositiveRatePercent)
283
+ && Number.isFinite(signals.matrix_regression_positive_rate_percent)
284
+ && signals.matrix_regression_positive_rate_percent > maxMatrixRegressionPositiveRatePercent
285
+ ) {
286
+ violations.push(
287
+ `weekly ops matrix regression-positive rate ${signals.matrix_regression_positive_rate_percent}% exceeds max ${maxMatrixRegressionPositiveRatePercent}%`
288
+ );
289
+ }
290
+ }
291
+
292
+ const blocked = enforce && violations.length > 0;
293
+ const evaluatedAt = now();
294
+ const payload = {
295
+ mode: 'release-weekly-ops-gate',
296
+ evaluated_at: evaluatedAt,
297
+ summary_file: summaryFile || null,
298
+ available: summaryResult.ok,
299
+ enforce,
300
+ require_summary: requireSummary,
301
+ max_risk_level: maxRiskLevel,
302
+ max_governance_breaches: maxGovernanceBreaches,
303
+ max_authorization_tier_block_rate_percent: maxAuthorizationTierBlockRatePercent,
304
+ max_dialogue_authorization_block_rate_percent: maxDialogueAuthorizationBlockRatePercent,
305
+ max_runtime_ui_mode_violation_total: maxRuntimeUiModeViolationTotal,
306
+ max_runtime_ui_mode_violation_rate_percent: maxRuntimeUiModeViolationRatePercent,
307
+ max_business_mode_unknown_signal_total: maxBusinessModeUnknownSignalTotal,
308
+ max_matrix_regression_positive_rate_percent: maxMatrixRegressionPositiveRatePercent,
309
+ config_warnings: configWarnings,
310
+ signals,
311
+ warnings,
312
+ violations,
313
+ blocked
314
+ };
315
+
316
+ mergeGateReport(gateReportFile, payload);
317
+
318
+ const summaryLines = [
319
+ '## Release Weekly Ops Gate',
320
+ '',
321
+ `- enforce: ${enforce}`,
322
+ `- require summary: ${requireSummary}`,
323
+ `- max risk level: ${maxRiskLevel}`,
324
+ `- summary file: ${summaryFile || 'n/a'}`,
325
+ `- available: ${summaryResult.ok}`
326
+ ];
327
+ if (Number.isFinite(maxGovernanceBreaches)) {
328
+ summaryLines.push(`- max governance breaches: ${maxGovernanceBreaches}`);
329
+ }
330
+ if (Number.isFinite(maxAuthorizationTierBlockRatePercent)) {
331
+ summaryLines.push(`- max authorization-tier block rate: ${maxAuthorizationTierBlockRatePercent}%`);
332
+ }
333
+ if (Number.isFinite(maxDialogueAuthorizationBlockRatePercent)) {
334
+ summaryLines.push(`- max dialogue-authorization block rate: ${maxDialogueAuthorizationBlockRatePercent}%`);
335
+ }
336
+ if (Number.isFinite(maxRuntimeUiModeViolationTotal)) {
337
+ summaryLines.push(`- max runtime ui-mode violation total: ${maxRuntimeUiModeViolationTotal}`);
338
+ }
339
+ if (Number.isFinite(maxRuntimeUiModeViolationRatePercent)) {
340
+ summaryLines.push(`- max runtime ui-mode violation rate: ${maxRuntimeUiModeViolationRatePercent}%`);
341
+ }
342
+ if (Number.isFinite(maxBusinessModeUnknownSignalTotal)) {
343
+ summaryLines.push(`- max business-mode unknown signal total: ${maxBusinessModeUnknownSignalTotal}`);
344
+ }
345
+ if (Number.isFinite(maxMatrixRegressionPositiveRatePercent)) {
346
+ summaryLines.push(`- max matrix regression-positive rate: ${maxMatrixRegressionPositiveRatePercent}%`);
347
+ }
348
+ if (signals) {
349
+ summaryLines.push(`- risk: ${signals.risk}`);
350
+ summaryLines.push(`- governance breaches: ${signals.governance_breaches === null ? 'n/a' : signals.governance_breaches}`);
351
+ summaryLines.push(
352
+ `- authorization-tier block rate: ${signals.authorization_tier_block_rate_percent === null ? 'n/a' : `${signals.authorization_tier_block_rate_percent}%`}`
353
+ );
354
+ summaryLines.push(
355
+ `- dialogue-authorization block rate: ${signals.dialogue_authorization_block_rate_percent === null ? 'n/a' : `${signals.dialogue_authorization_block_rate_percent}%`}`
356
+ );
357
+ summaryLines.push(
358
+ `- runtime ui-mode violation total: ${signals.runtime_ui_mode_violation_total === null ? 'n/a' : signals.runtime_ui_mode_violation_total}`
359
+ );
360
+ summaryLines.push(
361
+ `- runtime ui-mode violation rate: ${signals.runtime_ui_mode_violation_rate_percent === null ? 'n/a' : `${signals.runtime_ui_mode_violation_rate_percent}%`}`
362
+ );
363
+ summaryLines.push(
364
+ `- business-mode unknown signal total: ${signals.business_mode_unknown_signal_total === null ? 'n/a' : signals.business_mode_unknown_signal_total}`
365
+ );
366
+ summaryLines.push(
367
+ `- matrix regression-positive rate: ${signals.matrix_regression_positive_rate_percent === null ? 'n/a' : `${signals.matrix_regression_positive_rate_percent}%`}`
368
+ );
369
+ summaryLines.push(
370
+ `- handoff gate pass rate: ${signals.handoff_gate_pass_rate_percent === null ? 'n/a' : `${signals.handoff_gate_pass_rate_percent}%`}`
371
+ );
372
+ }
373
+ if (warnings.length > 0) {
374
+ summaryLines.push('', '### Warnings');
375
+ warnings.forEach(item => summaryLines.push(`- ${item}`));
376
+ }
377
+ if (violations.length > 0) {
378
+ summaryLines.push('', '### Violations');
379
+ violations.forEach(item => summaryLines.push(`- ${item}`));
380
+ } else {
381
+ summaryLines.push('', '### Result', '- gate passed');
382
+ }
383
+ appendSummary(summaryPath, summaryLines);
384
+
385
+ console.log(
386
+ `[release-weekly-ops-gate] enforce=${enforce} require_summary=${requireSummary} `
387
+ + `max_risk_level=${maxRiskLevel} available=${summaryResult.ok}`
388
+ );
389
+ if (signals) {
390
+ console.log(
391
+ `[release-weekly-ops-gate] risk=${signals.risk} governance_breaches=${signals.governance_breaches === null ? 'n/a' : signals.governance_breaches} `
392
+ + `authorization_tier_block_rate=${signals.authorization_tier_block_rate_percent === null ? 'n/a' : `${signals.authorization_tier_block_rate_percent}%`} `
393
+ + `dialogue_authorization_block_rate=${signals.dialogue_authorization_block_rate_percent === null ? 'n/a' : `${signals.dialogue_authorization_block_rate_percent}%`} `
394
+ + `runtime_ui_mode_violation_total=${signals.runtime_ui_mode_violation_total === null ? 'n/a' : signals.runtime_ui_mode_violation_total} `
395
+ + `runtime_ui_mode_violation_rate=${signals.runtime_ui_mode_violation_rate_percent === null ? 'n/a' : `${signals.runtime_ui_mode_violation_rate_percent}%`} `
396
+ + `business_mode_unknown_signal_total=${signals.business_mode_unknown_signal_total === null ? 'n/a' : signals.business_mode_unknown_signal_total} `
397
+ + `matrix_regression_positive_rate=${signals.matrix_regression_positive_rate_percent === null ? 'n/a' : `${signals.matrix_regression_positive_rate_percent}%`}`
398
+ );
399
+ }
400
+ warnings.forEach(item => console.warn(`[release-weekly-ops-gate] warning=${item}`));
401
+ if (violations.length > 0) {
402
+ console.error(`[release-weekly-ops-gate] violations=${violations.join('; ')}`);
403
+ } else {
404
+ console.log('[release-weekly-ops-gate] passed');
405
+ }
406
+
407
+ return {
408
+ exit_code: blocked ? 1 : 0,
409
+ blocked,
410
+ warnings,
411
+ violations,
412
+ payload
413
+ };
414
+ }
415
+
416
+ if (require.main === module) {
417
+ const result = evaluateReleaseWeeklyOpsGate();
418
+ process.exit(result.exit_code);
419
+ }
420
+
421
+ module.exports = {
422
+ evaluateReleaseWeeklyOpsGate
423
+ };
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const fs = require('fs-extra');
5
+ const { runStateDoctor } = require('../lib/state/state-migration-manager');
6
+
7
+ function parseArgs(argv = []) {
8
+ const options = {
9
+ projectPath: process.cwd(),
10
+ json: false,
11
+ failOnBlocking: false,
12
+ failOnAlert: false,
13
+ failOnPending: false
14
+ };
15
+
16
+ for (let index = 0; index < argv.length; index += 1) {
17
+ const token = argv[index];
18
+ const next = argv[index + 1];
19
+ if (token === '--workspace' || token === '--project-path') {
20
+ if (next) {
21
+ options.projectPath = path.resolve(next);
22
+ index += 1;
23
+ }
24
+ continue;
25
+ }
26
+ if (token === '--json') {
27
+ options.json = true;
28
+ continue;
29
+ }
30
+ if (token === '--fail-on-blocking') {
31
+ options.failOnBlocking = true;
32
+ continue;
33
+ }
34
+ if (token === '--fail-on-alert') {
35
+ options.failOnAlert = true;
36
+ continue;
37
+ }
38
+ if (token === '--fail-on-pending') {
39
+ options.failOnPending = true;
40
+ continue;
41
+ }
42
+ }
43
+
44
+ return options;
45
+ }
46
+
47
+ function summarizePendingChecks(checks = []) {
48
+ return checks
49
+ .filter((item) => item.sync_status === 'pending-migration')
50
+ .map((item) => item.id);
51
+ }
52
+
53
+ async function main() {
54
+ const options = parseArgs(process.argv.slice(2));
55
+ const doctor = await runStateDoctor({}, {
56
+ projectPath: options.projectPath,
57
+ fileSystem: fs
58
+ });
59
+
60
+ const pending = summarizePendingChecks(doctor.checks);
61
+ const blocking = Array.isArray(doctor.blocking) ? doctor.blocking : [];
62
+ const alerts = Array.isArray(doctor.alerts) ? doctor.alerts : [];
63
+
64
+ const reasons = [];
65
+ if (options.failOnBlocking && blocking.length > 0) {
66
+ reasons.push(...blocking.map((item) => `blocking:${item}`));
67
+ }
68
+ if (options.failOnAlert && alerts.length > 0) {
69
+ reasons.push(...alerts.map((item) => `alert:${item}`));
70
+ }
71
+ if (options.failOnPending && pending.length > 0) {
72
+ reasons.push(...pending.map((item) => `pending:${item}`));
73
+ }
74
+
75
+ const passed = reasons.length === 0;
76
+ const payload = {
77
+ mode: 'state-migration-reconciliation-gate',
78
+ success: passed,
79
+ passed,
80
+ workspace: path.relative(process.cwd(), options.projectPath).replace(/\\/g, '/'),
81
+ fail_on_blocking: options.failOnBlocking,
82
+ fail_on_alert: options.failOnAlert,
83
+ fail_on_pending: options.failOnPending,
84
+ blocking,
85
+ alerts,
86
+ pending_components: pending,
87
+ reasons,
88
+ doctor
89
+ };
90
+
91
+ if (options.json) {
92
+ console.log(JSON.stringify(payload, null, 2));
93
+ } else if (!passed) {
94
+ console.error(`[state-migration-reconciliation-gate] blocked`);
95
+ for (const reason of reasons) {
96
+ console.error(`[state-migration-reconciliation-gate] reason=${reason}`);
97
+ }
98
+ } else {
99
+ console.log('[state-migration-reconciliation-gate] passed');
100
+ }
101
+
102
+ if (!passed) {
103
+ process.exitCode = 2;
104
+ }
105
+ }
106
+
107
+ main().catch((error) => {
108
+ console.error(error && error.message ? error.message : `${error}`);
109
+ process.exitCode = 1;
110
+ });