scene-capability-engine 3.6.44 → 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.
- package/CHANGELOG.md +25 -0
- package/bin/scene-capability-engine.js +36 -2
- package/docs/command-reference.md +5 -0
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.45.md +18 -0
- package/docs/releases/v3.6.46.md +23 -0
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.45.md +18 -0
- package/docs/zh/releases/v3.6.46.md +23 -0
- package/lib/workspace/collab-governance-audit.js +575 -0
- package/package.json +4 -2
- package/scripts/auto-strategy-router.js +231 -0
- package/scripts/capability-mapping-report.js +339 -0
- package/scripts/check-branding-consistency.js +140 -0
- package/scripts/check-sce-tracking.js +54 -0
- package/scripts/check-skip-allowlist.js +94 -0
- package/scripts/errorbook-registry-health-gate.js +172 -0
- package/scripts/errorbook-release-gate.js +132 -0
- package/scripts/failure-attribution-repair.js +317 -0
- package/scripts/git-managed-gate.js +464 -0
- package/scripts/interactive-approval-event-projection.js +400 -0
- package/scripts/interactive-approval-workflow.js +829 -0
- package/scripts/interactive-authorization-tier-evaluate.js +413 -0
- package/scripts/interactive-change-plan-gate.js +225 -0
- package/scripts/interactive-context-bridge.js +617 -0
- package/scripts/interactive-customization-loop.js +1690 -0
- package/scripts/interactive-dialogue-governance.js +842 -0
- package/scripts/interactive-feedback-log.js +253 -0
- package/scripts/interactive-flow-smoke.js +238 -0
- package/scripts/interactive-flow.js +1059 -0
- package/scripts/interactive-governance-report.js +1112 -0
- package/scripts/interactive-intent-build.js +707 -0
- package/scripts/interactive-loop-smoke.js +215 -0
- package/scripts/interactive-moqui-adapter.js +304 -0
- package/scripts/interactive-plan-build.js +426 -0
- package/scripts/interactive-runtime-policy-evaluate.js +495 -0
- package/scripts/interactive-work-order-build.js +552 -0
- package/scripts/matrix-regression-gate.js +167 -0
- package/scripts/moqui-core-regression-suite.js +397 -0
- package/scripts/moqui-lexicon-audit.js +651 -0
- package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
- package/scripts/moqui-matrix-remediation-queue.js +852 -0
- package/scripts/moqui-metadata-extract.js +1340 -0
- package/scripts/moqui-rebuild-gate.js +167 -0
- package/scripts/moqui-release-summary.js +729 -0
- package/scripts/moqui-standard-rebuild.js +1370 -0
- package/scripts/moqui-template-baseline-report.js +682 -0
- package/scripts/npm-package-runtime-asset-check.js +221 -0
- package/scripts/problem-closure-gate.js +441 -0
- package/scripts/release-asset-integrity-check.js +216 -0
- package/scripts/release-asset-nonempty-normalize.js +166 -0
- package/scripts/release-drift-evaluate.js +223 -0
- package/scripts/release-drift-signals.js +255 -0
- package/scripts/release-governance-snapshot-export.js +132 -0
- package/scripts/release-ops-weekly-summary.js +934 -0
- package/scripts/release-risk-remediation-bundle.js +315 -0
- package/scripts/release-weekly-ops-gate.js +423 -0
- package/scripts/state-migration-reconciliation-gate.js +110 -0
- package/scripts/state-storage-tiering-audit.js +337 -0
- package/scripts/steering-content-audit.js +393 -0
- package/scripts/symbol-evidence-locate.js +366 -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
|
+
});
|