scene-capability-engine 3.6.38 → 3.6.44
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 +63 -0
- package/bin/scene-capability-engine.js +42 -2
- package/docs/command-reference.md +27 -0
- package/docs/developer-guide.md +1 -1
- package/docs/document-governance.md +22 -2
- package/docs/releases/README.md +6 -0
- package/docs/releases/v3.6.39.md +24 -0
- package/docs/releases/v3.6.40.md +19 -0
- package/docs/releases/v3.6.41.md +20 -0
- package/docs/releases/v3.6.42.md +19 -0
- package/docs/releases/v3.6.43.md +17 -0
- package/docs/releases/v3.6.44.md +17 -0
- package/docs/spec-collaboration-guide.md +1 -1
- package/docs/state-migration-reconciliation-runbook.md +76 -0
- package/docs/state-storage-tiering.md +104 -0
- package/docs/zh/releases/README.md +6 -0
- package/docs/zh/releases/v3.6.39.md +24 -0
- package/docs/zh/releases/v3.6.40.md +19 -0
- package/docs/zh/releases/v3.6.41.md +20 -0
- package/docs/zh/releases/v3.6.42.md +19 -0
- package/docs/zh/releases/v3.6.43.md +17 -0
- package/docs/zh/releases/v3.6.44.md +17 -0
- package/lib/adoption/adoption-logger.js +1 -1
- package/lib/adoption/adoption-strategy.js +29 -29
- package/lib/adoption/detection-engine.js +16 -13
- package/lib/adoption/smart-orchestrator.js +3 -3
- package/lib/adoption/strategy-selector.js +19 -15
- package/lib/adoption/template-sync.js +3 -3
- package/lib/auto/autonomous-engine.js +5 -5
- package/lib/auto/handoff-release-gate-history-loaders-service.js +24 -4
- package/lib/auto/handoff-run-service.js +37 -0
- package/lib/backup/backup-system.js +10 -10
- package/lib/collab/collab-manager.js +8 -5
- package/lib/collab/dependency-manager.js +1 -1
- package/lib/commands/adopt.js +2 -2
- package/lib/commands/auto.js +239 -97
- package/lib/commands/collab.js +10 -4
- package/lib/commands/docs.js +8 -2
- package/lib/commands/scene.js +78 -18
- package/lib/commands/status.js +3 -3
- package/lib/commands/studio.js +8 -0
- package/lib/commands/watch.js +10 -1
- package/lib/governance/config-manager.js +16 -0
- package/lib/governance/diagnostic-engine.js +2 -1
- package/lib/governance/validation-engine.js +3 -2
- package/lib/repo/config-manager.js +2 -2
- package/lib/runtime/session-store.js +8 -0
- package/lib/spec/bootstrap/context-collector.js +5 -4
- package/lib/spec-gate/rules/default-rules.js +8 -8
- package/lib/state/sce-state-store.js +265 -0
- package/lib/state/state-migration-manager.js +27 -2
- package/lib/state/state-storage-policy.js +179 -0
- package/lib/upgrade/migration-engine.js +5 -5
- package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +3 -3
- package/lib/utils/tool-detector.js +4 -4
- package/lib/utils/validation.js +6 -6
- package/lib/watch/action-executor.js +10 -1
- package/lib/watch/event-debouncer.js +3 -0
- package/lib/watch/file-watcher.js +51 -10
- package/lib/watch/watch-manager.js +10 -1
- package/lib/workspace/multi/workspace-context-resolver.js +3 -3
- package/lib/workspace/multi/workspace-registry.js +3 -3
- package/lib/workspace/multi/workspace-state-manager.js +3 -3
- package/lib/workspace/spec-delivery-audit.js +553 -0
- package/lib/workspace/takeover-baseline.js +11 -0
- package/package.json +5 -1
- package/template/.sce/config/state-storage-policy.json +165 -0
|
@@ -40,7 +40,7 @@ class BackupSystem {
|
|
|
40
40
|
* @param {string} projectPath - Absolute path to project root
|
|
41
41
|
* @returns {string} - Absolute path to .sce directory
|
|
42
42
|
*/
|
|
43
|
-
|
|
43
|
+
getSceDir(projectPath) {
|
|
44
44
|
return path.join(projectPath, '.sce');
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -74,11 +74,11 @@ class BackupSystem {
|
|
|
74
74
|
const { type = 'manual' } = options;
|
|
75
75
|
|
|
76
76
|
try {
|
|
77
|
-
const
|
|
77
|
+
const sceDir = this.getSceDir(projectPath);
|
|
78
78
|
|
|
79
79
|
// Check if .sce/ exists
|
|
80
|
-
const
|
|
81
|
-
if (!
|
|
80
|
+
const sceExists = await pathExists(sceDir);
|
|
81
|
+
if (!sceExists) {
|
|
82
82
|
throw new Error('.sce/ directory does not exist');
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -100,7 +100,7 @@ class BackupSystem {
|
|
|
100
100
|
await ensureDirectory(backupPath);
|
|
101
101
|
|
|
102
102
|
// Copy .sce/ contents to backup (excluding backups/ itself)
|
|
103
|
-
const items = await listFiles(
|
|
103
|
+
const items = await listFiles(sceDir);
|
|
104
104
|
|
|
105
105
|
for (const item of items) {
|
|
106
106
|
// Skip the backups directory itself
|
|
@@ -108,7 +108,7 @@ class BackupSystem {
|
|
|
108
108
|
continue;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const sourcePath = path.join(
|
|
111
|
+
const sourcePath = path.join(sceDir, item);
|
|
112
112
|
const destPath = path.join(backupPath, item);
|
|
113
113
|
|
|
114
114
|
await copyDirectory(sourcePath, destPath, { overwrite: false });
|
|
@@ -243,20 +243,20 @@ class BackupSystem {
|
|
|
243
243
|
throw new Error(`Backup validation failed: ${backupId}`);
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
const
|
|
246
|
+
const sceDir = this.getSceDir(projectPath);
|
|
247
247
|
|
|
248
248
|
// Get list of items to restore (excluding metadata.json)
|
|
249
249
|
const items = await listFiles(backupPath);
|
|
250
250
|
const itemsToRestore = items.filter(item => item !== 'metadata.json');
|
|
251
251
|
|
|
252
252
|
// Remove existing .sce/ contents (except backups/)
|
|
253
|
-
const existingItems = await listFiles(
|
|
253
|
+
const existingItems = await listFiles(sceDir);
|
|
254
254
|
for (const item of existingItems) {
|
|
255
255
|
if (item === this.backupDirName) {
|
|
256
256
|
continue;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
const itemPath = path.join(
|
|
259
|
+
const itemPath = path.join(sceDir, item);
|
|
260
260
|
await remove(itemPath);
|
|
261
261
|
}
|
|
262
262
|
|
|
@@ -264,7 +264,7 @@ class BackupSystem {
|
|
|
264
264
|
const restoredFiles = [];
|
|
265
265
|
for (const item of itemsToRestore) {
|
|
266
266
|
const sourcePath = path.join(backupPath, item);
|
|
267
|
-
const destPath = path.join(
|
|
267
|
+
const destPath = path.join(sceDir, item);
|
|
268
268
|
|
|
269
269
|
await copyDirectory(sourcePath, destPath, { overwrite: true });
|
|
270
270
|
restoredFiles.push(item);
|
|
@@ -125,10 +125,10 @@ class CollaborationManager {
|
|
|
125
125
|
/**
|
|
126
126
|
* Assign a spec to a SCE instance
|
|
127
127
|
* @param {string} specName - Name of the spec
|
|
128
|
-
* @param {string}
|
|
128
|
+
* @param {string} sceInstance - SCE instance identifier
|
|
129
129
|
* @returns {Promise<Object>} Assignment result
|
|
130
130
|
*/
|
|
131
|
-
async assignSpec(specName,
|
|
131
|
+
async assignSpec(specName, sceInstance) {
|
|
132
132
|
const metadata = await this.metadataManager.readMetadata(specName);
|
|
133
133
|
|
|
134
134
|
if (!metadata) {
|
|
@@ -149,17 +149,20 @@ class CollaborationManager {
|
|
|
149
149
|
// Update assignment
|
|
150
150
|
const updated = await this.metadataManager.atomicUpdate(specName, (meta) => {
|
|
151
151
|
meta.assignment = {
|
|
152
|
-
|
|
152
|
+
sceInstance,
|
|
153
153
|
assignedAt: new Date().toISOString()
|
|
154
154
|
};
|
|
155
|
+
if (meta.assignment && Object.prototype.hasOwnProperty.call(meta.assignment, 'kiroInstance')) {
|
|
156
|
+
delete meta.assignment.kiroInstance;
|
|
157
|
+
}
|
|
155
158
|
return meta;
|
|
156
159
|
});
|
|
157
160
|
|
|
158
161
|
return {
|
|
159
162
|
success: true,
|
|
160
163
|
spec: specName,
|
|
161
|
-
|
|
162
|
-
message: `Assigned '${specName}' to '${
|
|
164
|
+
sceInstance,
|
|
165
|
+
message: `Assigned '${specName}' to '${sceInstance}'`
|
|
163
166
|
};
|
|
164
167
|
}
|
|
165
168
|
|
|
@@ -25,7 +25,7 @@ class DependencyManager {
|
|
|
25
25
|
nodes.push({
|
|
26
26
|
id: name,
|
|
27
27
|
status: metadata.status?.current || 'not-started',
|
|
28
|
-
|
|
28
|
+
sceInstance: metadata.assignment?.sceInstance || metadata.assignment?.kiroInstance || null,
|
|
29
29
|
type: metadata.type
|
|
30
30
|
});
|
|
31
31
|
|
package/lib/commands/adopt.js
CHANGED
|
@@ -220,7 +220,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
220
220
|
console.log(' - Preserve existing specs/ and steering/');
|
|
221
221
|
console.log(' - Add missing components');
|
|
222
222
|
console.log(' - Create/update version.json');
|
|
223
|
-
if (detection.
|
|
223
|
+
if (detection.hasSceDir) {
|
|
224
224
|
console.log(' - Create backup before changes');
|
|
225
225
|
}
|
|
226
226
|
} else if (strategy === 'full') {
|
|
@@ -487,7 +487,7 @@ async function adoptInteractive(projectPath, options) {
|
|
|
487
487
|
|
|
488
488
|
// 9. Create backup if needed (for non-conflict scenarios)
|
|
489
489
|
let backupId = null;
|
|
490
|
-
if (detection.
|
|
490
|
+
if (detection.hasSceDir && (strategy === 'partial' || strategy === 'full')) {
|
|
491
491
|
console.log(chalk.blue('📦 Creating backup...'));
|
|
492
492
|
const backupSystem = new BackupSystem();
|
|
493
493
|
|
package/lib/commands/auto.js
CHANGED
|
@@ -60,6 +60,7 @@ const fs = require('fs-extra');
|
|
|
60
60
|
const path = require('path');
|
|
61
61
|
const chalk = require('chalk');
|
|
62
62
|
const { spawnSync } = require('child_process');
|
|
63
|
+
const { auditSpecDeliverySync } = require('../workspace/spec-delivery-audit');
|
|
63
64
|
|
|
64
65
|
const AUTO_ARCHIVE_SCHEMA_VERSION = '1.0';
|
|
65
66
|
const AUTO_ARCHIVE_SCHEMA_SUPPORTED_VERSIONS = new Set([AUTO_ARCHIVE_SCHEMA_VERSION]);
|
|
@@ -95,6 +96,7 @@ const AUTO_HANDOFF_POLICY_PROFILE_PRESETS = {
|
|
|
95
96
|
require_capability_coverage: true,
|
|
96
97
|
require_capability_semantic: true,
|
|
97
98
|
require_capability_lexicon: true,
|
|
99
|
+
require_spec_delivery_sync: true,
|
|
98
100
|
require_release_gate_preflight: true,
|
|
99
101
|
dependency_batching: true,
|
|
100
102
|
release_evidence_window: 5
|
|
@@ -114,6 +116,7 @@ const AUTO_HANDOFF_POLICY_PROFILE_PRESETS = {
|
|
|
114
116
|
require_capability_coverage: true,
|
|
115
117
|
require_capability_semantic: true,
|
|
116
118
|
require_capability_lexicon: true,
|
|
119
|
+
require_spec_delivery_sync: true,
|
|
117
120
|
require_release_gate_preflight: true,
|
|
118
121
|
dependency_batching: true,
|
|
119
122
|
release_evidence_window: 5
|
|
@@ -133,6 +136,7 @@ const AUTO_HANDOFF_POLICY_PROFILE_PRESETS = {
|
|
|
133
136
|
require_capability_coverage: true,
|
|
134
137
|
require_capability_semantic: true,
|
|
135
138
|
require_capability_lexicon: true,
|
|
139
|
+
require_spec_delivery_sync: true,
|
|
136
140
|
require_release_gate_preflight: true,
|
|
137
141
|
dependency_batching: true,
|
|
138
142
|
release_evidence_window: 10
|
|
@@ -1983,6 +1987,8 @@ function registerAutoCommands(program) {
|
|
|
1983
1987
|
.description('Evaluate release-gate preflight readiness from gate-history signals')
|
|
1984
1988
|
.option('--profile <profile>', 'Handoff policy profile: default|moqui|enterprise (default: default)', 'default')
|
|
1985
1989
|
.option('--history-file <path>', `Release gate history file (default: ${AUTO_HANDOFF_RELEASE_GATE_HISTORY_FILE})`)
|
|
1990
|
+
.option('--require-spec-delivery-sync', 'Gate: require declared spec deliverables to be tracked, committed, and upstream-synced when manifests exist (default: enabled)')
|
|
1991
|
+
.option('--no-require-spec-delivery-sync', 'Gate: disable spec delivery sync hard requirement (not recommended)')
|
|
1986
1992
|
.option('--require-release-gate-preflight', 'Gate: require release-gate preflight signal to be available and unblocked (default: enabled)')
|
|
1987
1993
|
.option('--no-require-release-gate-preflight', 'Gate: disable release-gate preflight hard requirement (not recommended)')
|
|
1988
1994
|
.option('--release-evidence-window <n>', 'Release evidence trend window size (2-50, default from profile)', parseInt)
|
|
@@ -1997,10 +2003,15 @@ function registerAutoCommands(program) {
|
|
|
1997
2003
|
console.log(chalk.blue('Auto handoff preflight check:'));
|
|
1998
2004
|
console.log(chalk.gray(` Status: ${result.status}`));
|
|
1999
2005
|
console.log(chalk.gray(` Profile: ${result.policy.profile}`));
|
|
2006
|
+
console.log(chalk.gray(` Spec delivery sync: ${result.policy.require_spec_delivery_sync ? 'enabled' : 'advisory'}`));
|
|
2000
2007
|
console.log(chalk.gray(` Hard-gate preflight: ${result.policy.require_release_gate_preflight ? 'enabled' : 'advisory'}`));
|
|
2001
2008
|
console.log(chalk.gray(` History file: ${result.release_gate_preflight.file || 'n/a'}`));
|
|
2002
2009
|
console.log(chalk.gray(` Preflight available: ${result.release_gate_preflight.available === true ? 'yes' : 'no'}`));
|
|
2003
2010
|
console.log(chalk.gray(` Preflight blocked: ${result.release_gate_preflight.blocked === true ? 'yes' : 'no'}`));
|
|
2011
|
+
if (result.spec_delivery_sync) {
|
|
2012
|
+
console.log(chalk.gray(` Delivery manifests: ${result.spec_delivery_sync.summary.manifest_count}`));
|
|
2013
|
+
console.log(chalk.gray(` Delivery sync passed: ${result.spec_delivery_sync.passed === true ? 'yes' : 'no'}`));
|
|
2014
|
+
}
|
|
2004
2015
|
if (result.release_gate_preflight.latest_tag) {
|
|
2005
2016
|
console.log(chalk.gray(` Latest tag: ${result.release_gate_preflight.latest_tag}`));
|
|
2006
2017
|
}
|
|
@@ -2088,6 +2099,8 @@ function registerAutoCommands(program) {
|
|
|
2088
2099
|
.option('--no-require-capability-coverage', 'Gate: disable capability coverage requirement (not recommended)')
|
|
2089
2100
|
.option('--require-capability-lexicon', 'Gate: require capability lexicon normalization (unknown expected/provided aliases not allowed, default: enabled)')
|
|
2090
2101
|
.option('--no-require-capability-lexicon', 'Gate: disable capability lexicon normalization requirement (not recommended)')
|
|
2102
|
+
.option('--require-spec-delivery-sync', 'Gate: require declared spec deliverables to be tracked, committed, and upstream-synced when manifests exist (default: enabled)')
|
|
2103
|
+
.option('--no-require-spec-delivery-sync', 'Gate: disable spec delivery sync hard requirement (not recommended)')
|
|
2091
2104
|
.option('--require-release-gate-preflight', 'Gate: require release-gate preflight signal to be available and unblocked (default: enabled)')
|
|
2092
2105
|
.option('--no-require-release-gate-preflight', 'Gate: disable release-gate preflight hard requirement (not recommended)')
|
|
2093
2106
|
.option('--release-evidence-window <n>', 'Release evidence trend window size (2-50, default: 5)', parseInt)
|
|
@@ -2108,6 +2121,10 @@ function registerAutoCommands(program) {
|
|
|
2108
2121
|
if (result.template_diff) {
|
|
2109
2122
|
console.log(chalk.gray(` Template compatibility: ${result.template_diff.compatibility}`));
|
|
2110
2123
|
}
|
|
2124
|
+
if (result.spec_delivery_sync) {
|
|
2125
|
+
console.log(chalk.gray(` Delivery manifests: ${result.spec_delivery_sync.summary.manifest_count}`));
|
|
2126
|
+
console.log(chalk.gray(` Delivery sync passed: ${result.spec_delivery_sync.passed === true ? 'yes' : 'no'}`));
|
|
2127
|
+
}
|
|
2111
2128
|
if (result.dependency_execution && Array.isArray(result.dependency_execution.batches)) {
|
|
2112
2129
|
console.log(chalk.gray(` Execution batches: ${result.dependency_execution.batches.length}`));
|
|
2113
2130
|
}
|
|
@@ -7326,6 +7343,10 @@ function buildAutoHandoffRunPolicy(options = {}) {
|
|
|
7326
7343
|
options.requireCapabilityLexicon,
|
|
7327
7344
|
preset.require_capability_lexicon
|
|
7328
7345
|
),
|
|
7346
|
+
require_spec_delivery_sync: resolveAutoHandoffPolicyOptionBoolean(
|
|
7347
|
+
options.requireSpecDeliverySync,
|
|
7348
|
+
preset.require_spec_delivery_sync
|
|
7349
|
+
),
|
|
7329
7350
|
require_release_gate_preflight: resolveAutoHandoffPolicyOptionBoolean(
|
|
7330
7351
|
options.requireReleaseGatePreflight,
|
|
7331
7352
|
preset.require_release_gate_preflight
|
|
@@ -7899,6 +7920,34 @@ function evaluateAutoHandoffReleaseGatePreflightGateReasons(policy = {}, preflig
|
|
|
7899
7920
|
return reasons;
|
|
7900
7921
|
}
|
|
7901
7922
|
|
|
7923
|
+
function evaluateAutoHandoffSpecDeliveryGateReasons(policy = {}, deliveryAudit = null) {
|
|
7924
|
+
const reasons = [];
|
|
7925
|
+
if (policy.require_spec_delivery_sync !== true) {
|
|
7926
|
+
return reasons;
|
|
7927
|
+
}
|
|
7928
|
+
|
|
7929
|
+
const snapshot = deliveryAudit && typeof deliveryAudit === 'object' && !Array.isArray(deliveryAudit)
|
|
7930
|
+
? deliveryAudit
|
|
7931
|
+
: null;
|
|
7932
|
+
if (!snapshot) {
|
|
7933
|
+
reasons.push('spec delivery audit snapshot missing');
|
|
7934
|
+
return reasons;
|
|
7935
|
+
}
|
|
7936
|
+
if (snapshot.reason === 'no-manifests') {
|
|
7937
|
+
return reasons;
|
|
7938
|
+
}
|
|
7939
|
+
if (snapshot.passed !== true) {
|
|
7940
|
+
const violations = Array.isArray(snapshot.violations) ? snapshot.violations : [];
|
|
7941
|
+
if (violations.length > 0) {
|
|
7942
|
+
reasons.push(...violations);
|
|
7943
|
+
} else {
|
|
7944
|
+
reasons.push('spec delivery sync audit reported violations');
|
|
7945
|
+
}
|
|
7946
|
+
}
|
|
7947
|
+
|
|
7948
|
+
return reasons;
|
|
7949
|
+
}
|
|
7950
|
+
|
|
7902
7951
|
function buildAutoHandoffReleaseGatePreflight(signals = null) {
|
|
7903
7952
|
const source = signals && typeof signals === 'object' && !Array.isArray(signals)
|
|
7904
7953
|
? signals
|
|
@@ -7969,6 +8018,9 @@ function buildAutoHandoffPreflightCheckRecommendations(projectPath, result = {})
|
|
|
7969
8018
|
const preflight = result && result.release_gate_preflight && typeof result.release_gate_preflight === 'object'
|
|
7970
8019
|
? result.release_gate_preflight
|
|
7971
8020
|
: {};
|
|
8021
|
+
const deliveryAudit = result && result.spec_delivery_sync && typeof result.spec_delivery_sync === 'object'
|
|
8022
|
+
? result.spec_delivery_sync
|
|
8023
|
+
: {};
|
|
7972
8024
|
const reasons = Array.isArray(result.reasons) ? result.reasons : [];
|
|
7973
8025
|
const windowSize = Number.isInteger(policy.release_evidence_window)
|
|
7974
8026
|
? policy.release_evidence_window
|
|
@@ -7984,6 +8036,16 @@ function buildAutoHandoffPreflightCheckRecommendations(projectPath, result = {})
|
|
|
7984
8036
|
if (result.status !== 'pass' || preflight.blocked === true) {
|
|
7985
8037
|
push(`sce auto handoff evidence --window ${windowSize} --json`);
|
|
7986
8038
|
}
|
|
8039
|
+
if (
|
|
8040
|
+
deliveryAudit.reason === 'missing-manifest' ||
|
|
8041
|
+
deliveryAudit.reason === 'violations'
|
|
8042
|
+
) {
|
|
8043
|
+
push('sce workspace delivery-audit --json --strict');
|
|
8044
|
+
}
|
|
8045
|
+
if (Number.isFinite(Number(deliveryAudit.git && deliveryAudit.git.ahead)) && Number(deliveryAudit.git.ahead) > 0) {
|
|
8046
|
+
const branch = normalizeHandoffText(deliveryAudit.git && deliveryAudit.git.branch) || '<branch>';
|
|
8047
|
+
push(`git push origin ${branch}`);
|
|
8048
|
+
}
|
|
7987
8049
|
|
|
7988
8050
|
if (preflight.blocked === true) {
|
|
7989
8051
|
const governanceRecommendations = buildGovernanceCloseLoopRecommendations(
|
|
@@ -8014,23 +8076,41 @@ function buildAutoHandoffPreflightCheckRecommendations(projectPath, result = {})
|
|
|
8014
8076
|
'Ensure release workflow publishes `release-gate-history.json` and rerun preflight check.'
|
|
8015
8077
|
);
|
|
8016
8078
|
}
|
|
8079
|
+
if (reasons.some(item => `${item}`.includes('spec delivery'))) {
|
|
8080
|
+
push(
|
|
8081
|
+
'Declare feature deliverables in `.sce/specs/<spec>/deliverables.json`, commit tracked files, and push upstream before handoff.'
|
|
8082
|
+
);
|
|
8083
|
+
}
|
|
8017
8084
|
|
|
8018
8085
|
return recommendations;
|
|
8019
8086
|
}
|
|
8020
8087
|
|
|
8021
8088
|
async function buildAutoHandoffPreflightCheck(projectPath, options = {}) {
|
|
8022
8089
|
const policy = buildAutoHandoffRunPolicy(options);
|
|
8090
|
+
const specDeliverySync = await auditSpecDeliverySync(projectPath, {
|
|
8091
|
+
requireManifest: false
|
|
8092
|
+
});
|
|
8023
8093
|
const releaseGateSignals = await loadGovernanceReleaseGateSignals(projectPath, {
|
|
8024
8094
|
historyFile: options.historyFile
|
|
8025
8095
|
});
|
|
8026
8096
|
const releaseGatePreflight = buildAutoHandoffReleaseGatePreflight(releaseGateSignals);
|
|
8027
|
-
const hardGateReasons =
|
|
8028
|
-
policy,
|
|
8029
|
-
releaseGatePreflight
|
|
8030
|
-
|
|
8097
|
+
const hardGateReasons = [
|
|
8098
|
+
...evaluateAutoHandoffSpecDeliveryGateReasons(policy, specDeliverySync),
|
|
8099
|
+
...evaluateAutoHandoffReleaseGatePreflightGateReasons(policy, releaseGatePreflight)
|
|
8100
|
+
];
|
|
8031
8101
|
|
|
8032
8102
|
const advisoryReasons = [];
|
|
8033
8103
|
if (hardGateReasons.length === 0) {
|
|
8104
|
+
if (
|
|
8105
|
+
policy.require_spec_delivery_sync !== true &&
|
|
8106
|
+
specDeliverySync.reason !== 'no-manifests' &&
|
|
8107
|
+
specDeliverySync.passed !== true
|
|
8108
|
+
) {
|
|
8109
|
+
const deliveryReasons = Array.isArray(specDeliverySync.violations) && specDeliverySync.violations.length > 0
|
|
8110
|
+
? specDeliverySync.violations
|
|
8111
|
+
: ['spec delivery sync audit reported warnings'];
|
|
8112
|
+
advisoryReasons.push(...deliveryReasons.map((item) => `spec delivery sync advisory: ${item}`));
|
|
8113
|
+
}
|
|
8034
8114
|
if (releaseGatePreflight.parse_error) {
|
|
8035
8115
|
advisoryReasons.push(`release gate preflight parse error: ${releaseGatePreflight.parse_error}`);
|
|
8036
8116
|
} else if (releaseGatePreflight.available !== true) {
|
|
@@ -8055,9 +8135,11 @@ async function buildAutoHandoffPreflightCheck(projectPath, options = {}) {
|
|
|
8055
8135
|
hard_gate_reasons: hardGateReasons,
|
|
8056
8136
|
policy: {
|
|
8057
8137
|
profile: policy.profile,
|
|
8138
|
+
require_spec_delivery_sync: policy.require_spec_delivery_sync === true,
|
|
8058
8139
|
require_release_gate_preflight: policy.require_release_gate_preflight === true,
|
|
8059
8140
|
release_evidence_window: policy.release_evidence_window
|
|
8060
8141
|
},
|
|
8142
|
+
spec_delivery_sync: specDeliverySync,
|
|
8061
8143
|
release_gate_preflight: releaseGatePreflight,
|
|
8062
8144
|
signals: {
|
|
8063
8145
|
history_file: releaseGateSignals.file || releaseGatePreflight.file || null,
|
|
@@ -8571,6 +8653,9 @@ function buildAutoHandoffRunRecommendations(projectPath, result) {
|
|
|
8571
8653
|
const releaseGatePreflight = result && result.release_gate_preflight && typeof result.release_gate_preflight === 'object'
|
|
8572
8654
|
? result.release_gate_preflight
|
|
8573
8655
|
: null;
|
|
8656
|
+
const specDeliverySync = result && result.spec_delivery_sync && typeof result.spec_delivery_sync === 'object'
|
|
8657
|
+
? result.spec_delivery_sync
|
|
8658
|
+
: null;
|
|
8574
8659
|
if (releaseGatePreflight && releaseGatePreflight.blocked === true) {
|
|
8575
8660
|
push('sce auto handoff evidence --window 5 --json');
|
|
8576
8661
|
if (
|
|
@@ -8596,6 +8681,17 @@ function buildAutoHandoffRunRecommendations(projectPath, result) {
|
|
|
8596
8681
|
'--out .sce/reports/release-evidence/release-gate-history.json --json'
|
|
8597
8682
|
);
|
|
8598
8683
|
}
|
|
8684
|
+
if (
|
|
8685
|
+
specDeliverySync &&
|
|
8686
|
+
specDeliverySync.reason !== 'no-manifests' &&
|
|
8687
|
+
specDeliverySync.passed !== true
|
|
8688
|
+
) {
|
|
8689
|
+
push('sce workspace delivery-audit --json --strict');
|
|
8690
|
+
if (Number.isFinite(Number(specDeliverySync.git && specDeliverySync.git.ahead)) && Number(specDeliverySync.git.ahead) > 0) {
|
|
8691
|
+
const branch = normalizeHandoffText(specDeliverySync.git && specDeliverySync.git.branch) || '<branch>';
|
|
8692
|
+
push(`git push origin ${branch}`);
|
|
8693
|
+
}
|
|
8694
|
+
}
|
|
8599
8695
|
|
|
8600
8696
|
const riskLevel = result && result.gates && result.gates.actual && typeof result.gates.actual.risk_level === 'string'
|
|
8601
8697
|
? result.gates.actual.risk_level.trim().toLowerCase()
|
|
@@ -9888,6 +9984,8 @@ async function runAutoHandoff(projectPath, options = {}) {
|
|
|
9888
9984
|
loadGovernanceReleaseGateSignals,
|
|
9889
9985
|
completeAutoHandoffRunPhase,
|
|
9890
9986
|
evaluateAutoHandoffOntologyGateReasons,
|
|
9987
|
+
auditSpecDeliverySync,
|
|
9988
|
+
evaluateAutoHandoffSpecDeliveryGateReasons,
|
|
9891
9989
|
evaluateAutoHandoffReleaseGatePreflightGateReasons,
|
|
9892
9990
|
failAutoHandoffRunPhase,
|
|
9893
9991
|
buildAutoHandoffMoquiBaselineSnapshot,
|
|
@@ -11717,6 +11815,130 @@ async function loadGovernanceReleaseGateSignals(projectPath, options = {}) {
|
|
|
11717
11815
|
const parsed = Number(value);
|
|
11718
11816
|
return Number.isFinite(parsed) ? parsed : null;
|
|
11719
11817
|
};
|
|
11818
|
+
const buildSignalsSnapshot = ({ file, totalEntries, latest, aggregates, parseError = null }) => {
|
|
11819
|
+
const latestRiskLevel = normalizeHandoffText(latest && latest.risk_level);
|
|
11820
|
+
const latestWeeklyOpsRiskLevel = normalizeHandoffText(latest && latest.weekly_ops_risk_level);
|
|
11821
|
+
const normalizedTotalEntries = Number.isFinite(Number(totalEntries))
|
|
11822
|
+
? Number(totalEntries)
|
|
11823
|
+
: 0;
|
|
11824
|
+
const hasEntries = normalizedTotalEntries > 0 || Boolean(latest);
|
|
11825
|
+
return {
|
|
11826
|
+
...base,
|
|
11827
|
+
available: hasEntries,
|
|
11828
|
+
file: normalizeHandoffText(file) || base.file,
|
|
11829
|
+
total_entries: normalizedTotalEntries,
|
|
11830
|
+
latest_tag: normalizeHandoffText(latest && latest.tag) || null,
|
|
11831
|
+
latest_gate_passed: parseAutoHandoffGateBoolean(latest && latest.gate_passed, null),
|
|
11832
|
+
latest_risk_level: latestRiskLevel
|
|
11833
|
+
? normalizeAutoHandoffGateRiskLevel(latestRiskLevel)
|
|
11834
|
+
: null,
|
|
11835
|
+
pass_rate_percent: toNumber(aggregates && aggregates.pass_rate_percent),
|
|
11836
|
+
scene_package_batch_pass_rate_percent: toNumber(
|
|
11837
|
+
aggregates && aggregates.scene_package_batch_pass_rate_percent
|
|
11838
|
+
),
|
|
11839
|
+
scene_package_batch_failed_count: toNumber(
|
|
11840
|
+
aggregates && aggregates.scene_package_batch_failed_count
|
|
11841
|
+
),
|
|
11842
|
+
drift_alert_rate_percent: toNumber(aggregates && aggregates.drift_alert_rate_percent),
|
|
11843
|
+
drift_alert_runs: toNumber(aggregates && aggregates.drift_alert_runs),
|
|
11844
|
+
drift_blocked_runs: toNumber(aggregates && aggregates.drift_blocked_runs),
|
|
11845
|
+
latest_weekly_ops_blocked: parseAutoHandoffGateBoolean(latest && latest.weekly_ops_blocked, null),
|
|
11846
|
+
latest_weekly_ops_risk_level: latestWeeklyOpsRiskLevel
|
|
11847
|
+
? normalizeAutoHandoffGateRiskLevel(latestWeeklyOpsRiskLevel)
|
|
11848
|
+
: null,
|
|
11849
|
+
latest_weekly_ops_governance_status: normalizeHandoffText(
|
|
11850
|
+
latest && latest.weekly_ops_governance_status
|
|
11851
|
+
) || null,
|
|
11852
|
+
latest_weekly_ops_authorization_tier_block_rate_percent: toNumber(
|
|
11853
|
+
latest && latest.weekly_ops_authorization_tier_block_rate_percent
|
|
11854
|
+
),
|
|
11855
|
+
latest_weekly_ops_dialogue_authorization_block_rate_percent: toNumber(
|
|
11856
|
+
latest && latest.weekly_ops_dialogue_authorization_block_rate_percent
|
|
11857
|
+
),
|
|
11858
|
+
latest_weekly_ops_config_warning_count: toNumber(
|
|
11859
|
+
latest && latest.weekly_ops_config_warning_count
|
|
11860
|
+
),
|
|
11861
|
+
latest_weekly_ops_runtime_block_rate_percent: toNumber(
|
|
11862
|
+
latest && latest.weekly_ops_runtime_block_rate_percent
|
|
11863
|
+
),
|
|
11864
|
+
latest_weekly_ops_runtime_ui_mode_violation_total: toNumber(
|
|
11865
|
+
latest && latest.weekly_ops_runtime_ui_mode_violation_total
|
|
11866
|
+
),
|
|
11867
|
+
latest_weekly_ops_runtime_ui_mode_violation_rate_percent: toNumber(
|
|
11868
|
+
latest && latest.weekly_ops_runtime_ui_mode_violation_rate_percent
|
|
11869
|
+
),
|
|
11870
|
+
weekly_ops_known_runs: toNumber(aggregates && aggregates.weekly_ops_known_runs),
|
|
11871
|
+
weekly_ops_blocked_runs: toNumber(aggregates && aggregates.weekly_ops_blocked_runs),
|
|
11872
|
+
weekly_ops_block_rate_percent: toNumber(aggregates && aggregates.weekly_ops_block_rate_percent),
|
|
11873
|
+
weekly_ops_violations_total: toNumber(aggregates && aggregates.weekly_ops_violations_total),
|
|
11874
|
+
weekly_ops_warnings_total: toNumber(aggregates && aggregates.weekly_ops_warnings_total),
|
|
11875
|
+
weekly_ops_config_warnings_total: toNumber(
|
|
11876
|
+
aggregates && aggregates.weekly_ops_config_warnings_total
|
|
11877
|
+
),
|
|
11878
|
+
weekly_ops_authorization_tier_block_rate_max_percent: toNumber(
|
|
11879
|
+
aggregates && aggregates.weekly_ops_authorization_tier_block_rate_max_percent
|
|
11880
|
+
),
|
|
11881
|
+
weekly_ops_dialogue_authorization_block_rate_max_percent: toNumber(
|
|
11882
|
+
aggregates && aggregates.weekly_ops_dialogue_authorization_block_rate_max_percent
|
|
11883
|
+
),
|
|
11884
|
+
weekly_ops_runtime_block_rate_avg_percent: toNumber(
|
|
11885
|
+
aggregates && aggregates.weekly_ops_runtime_block_rate_avg_percent
|
|
11886
|
+
),
|
|
11887
|
+
weekly_ops_runtime_block_rate_max_percent: toNumber(
|
|
11888
|
+
aggregates && aggregates.weekly_ops_runtime_block_rate_max_percent
|
|
11889
|
+
),
|
|
11890
|
+
weekly_ops_runtime_ui_mode_violation_known_runs: toNumber(
|
|
11891
|
+
aggregates && aggregates.weekly_ops_runtime_ui_mode_violation_known_runs
|
|
11892
|
+
),
|
|
11893
|
+
weekly_ops_runtime_ui_mode_violation_runs: toNumber(
|
|
11894
|
+
aggregates && aggregates.weekly_ops_runtime_ui_mode_violation_runs
|
|
11895
|
+
),
|
|
11896
|
+
weekly_ops_runtime_ui_mode_violation_run_rate_percent: toNumber(
|
|
11897
|
+
aggregates && aggregates.weekly_ops_runtime_ui_mode_violation_run_rate_percent
|
|
11898
|
+
),
|
|
11899
|
+
weekly_ops_runtime_ui_mode_violation_total: toNumber(
|
|
11900
|
+
aggregates && aggregates.weekly_ops_runtime_ui_mode_violation_total
|
|
11901
|
+
),
|
|
11902
|
+
weekly_ops_runtime_ui_mode_violation_rate_avg_percent: toNumber(
|
|
11903
|
+
aggregates && aggregates.weekly_ops_runtime_ui_mode_violation_rate_avg_percent
|
|
11904
|
+
),
|
|
11905
|
+
weekly_ops_runtime_ui_mode_violation_rate_max_percent: toNumber(
|
|
11906
|
+
aggregates && aggregates.weekly_ops_runtime_ui_mode_violation_rate_max_percent
|
|
11907
|
+
),
|
|
11908
|
+
parse_error: parseError
|
|
11909
|
+
};
|
|
11910
|
+
};
|
|
11911
|
+
const loadFallbackSnapshot = async (parseError = null) => {
|
|
11912
|
+
const reportDir = path.dirname(historyFile);
|
|
11913
|
+
const reportResult = await loadAutoHandoffReleaseGateReports(projectPath, reportDir);
|
|
11914
|
+
const mergedEntries = mergeAutoHandoffReleaseGateHistoryEntries(reportResult.entries);
|
|
11915
|
+
if (mergedEntries.length === 0) {
|
|
11916
|
+
return parseError
|
|
11917
|
+
? {
|
|
11918
|
+
...base,
|
|
11919
|
+
parse_error: parseError
|
|
11920
|
+
}
|
|
11921
|
+
: base;
|
|
11922
|
+
}
|
|
11923
|
+
mergedEntries.sort((left, right) => {
|
|
11924
|
+
const leftTs = toAutoHandoffTimestamp(left && left.evaluated_at);
|
|
11925
|
+
const rightTs = toAutoHandoffTimestamp(right && right.evaluated_at);
|
|
11926
|
+
if (rightTs !== leftTs) {
|
|
11927
|
+
return rightTs - leftTs;
|
|
11928
|
+
}
|
|
11929
|
+
const leftTag = normalizeHandoffText(left && left.tag) || '';
|
|
11930
|
+
const rightTag = normalizeHandoffText(right && right.tag) || '';
|
|
11931
|
+
return rightTag.localeCompare(leftTag);
|
|
11932
|
+
});
|
|
11933
|
+
const latest = mergedEntries[0] || null;
|
|
11934
|
+
return buildSignalsSnapshot({
|
|
11935
|
+
file: normalizeHandoffText(latest && latest.file) || reportDir,
|
|
11936
|
+
totalEntries: mergedEntries.length,
|
|
11937
|
+
latest,
|
|
11938
|
+
aggregates: buildAutoHandoffReleaseGateHistoryAggregates(mergedEntries),
|
|
11939
|
+
parseError: null
|
|
11940
|
+
});
|
|
11941
|
+
};
|
|
11720
11942
|
const base = {
|
|
11721
11943
|
available: false,
|
|
11722
11944
|
file: historyFile,
|
|
@@ -11758,22 +11980,16 @@ async function loadGovernanceReleaseGateSignals(projectPath, options = {}) {
|
|
|
11758
11980
|
parse_error: null
|
|
11759
11981
|
};
|
|
11760
11982
|
if (!(await fs.pathExists(historyFile))) {
|
|
11761
|
-
return
|
|
11983
|
+
return loadFallbackSnapshot();
|
|
11762
11984
|
}
|
|
11763
11985
|
let payload = null;
|
|
11764
11986
|
try {
|
|
11765
11987
|
payload = await fs.readJson(historyFile);
|
|
11766
11988
|
} catch (error) {
|
|
11767
|
-
return {
|
|
11768
|
-
...base,
|
|
11769
|
-
parse_error: `${error.message}`
|
|
11770
|
-
};
|
|
11989
|
+
return loadFallbackSnapshot(`${error.message}`);
|
|
11771
11990
|
}
|
|
11772
11991
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
11773
|
-
return
|
|
11774
|
-
...base,
|
|
11775
|
-
parse_error: 'invalid release gate history payload'
|
|
11776
|
-
};
|
|
11992
|
+
return loadFallbackSnapshot('invalid release gate history payload');
|
|
11777
11993
|
}
|
|
11778
11994
|
const entries = Array.isArray(payload.entries) ? payload.entries : [];
|
|
11779
11995
|
const latest = payload.latest && typeof payload.latest === 'object'
|
|
@@ -11782,86 +11998,16 @@ async function loadGovernanceReleaseGateSignals(projectPath, options = {}) {
|
|
|
11782
11998
|
const aggregates = payload.aggregates && typeof payload.aggregates === 'object'
|
|
11783
11999
|
? payload.aggregates
|
|
11784
12000
|
: {};
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11790
|
-
|
|
11791
|
-
|
|
11792
|
-
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
: null,
|
|
11796
|
-
pass_rate_percent: toNumber(aggregates.pass_rate_percent),
|
|
11797
|
-
scene_package_batch_pass_rate_percent: toNumber(aggregates.scene_package_batch_pass_rate_percent),
|
|
11798
|
-
scene_package_batch_failed_count: toNumber(aggregates.scene_package_batch_failed_count),
|
|
11799
|
-
drift_alert_rate_percent: toNumber(aggregates.drift_alert_rate_percent),
|
|
11800
|
-
drift_alert_runs: toNumber(aggregates.drift_alert_runs),
|
|
11801
|
-
drift_blocked_runs: toNumber(aggregates.drift_blocked_runs),
|
|
11802
|
-
latest_weekly_ops_blocked: parseAutoHandoffGateBoolean(latest && latest.weekly_ops_blocked, null),
|
|
11803
|
-
latest_weekly_ops_risk_level: latestWeeklyOpsRiskLevel
|
|
11804
|
-
? normalizeAutoHandoffGateRiskLevel(latestWeeklyOpsRiskLevel)
|
|
11805
|
-
: null,
|
|
11806
|
-
latest_weekly_ops_governance_status: normalizeHandoffText(
|
|
11807
|
-
latest && latest.weekly_ops_governance_status
|
|
11808
|
-
) || null,
|
|
11809
|
-
latest_weekly_ops_authorization_tier_block_rate_percent: toNumber(
|
|
11810
|
-
latest && latest.weekly_ops_authorization_tier_block_rate_percent
|
|
11811
|
-
),
|
|
11812
|
-
latest_weekly_ops_dialogue_authorization_block_rate_percent: toNumber(
|
|
11813
|
-
latest && latest.weekly_ops_dialogue_authorization_block_rate_percent
|
|
11814
|
-
),
|
|
11815
|
-
latest_weekly_ops_config_warning_count: toNumber(
|
|
11816
|
-
latest && latest.weekly_ops_config_warning_count
|
|
11817
|
-
),
|
|
11818
|
-
latest_weekly_ops_runtime_block_rate_percent: toNumber(
|
|
11819
|
-
latest && latest.weekly_ops_runtime_block_rate_percent
|
|
11820
|
-
),
|
|
11821
|
-
latest_weekly_ops_runtime_ui_mode_violation_total: toNumber(
|
|
11822
|
-
latest && latest.weekly_ops_runtime_ui_mode_violation_total
|
|
11823
|
-
),
|
|
11824
|
-
latest_weekly_ops_runtime_ui_mode_violation_rate_percent: toNumber(
|
|
11825
|
-
latest && latest.weekly_ops_runtime_ui_mode_violation_rate_percent
|
|
11826
|
-
),
|
|
11827
|
-
weekly_ops_known_runs: toNumber(aggregates.weekly_ops_known_runs),
|
|
11828
|
-
weekly_ops_blocked_runs: toNumber(aggregates.weekly_ops_blocked_runs),
|
|
11829
|
-
weekly_ops_block_rate_percent: toNumber(aggregates.weekly_ops_block_rate_percent),
|
|
11830
|
-
weekly_ops_violations_total: toNumber(aggregates.weekly_ops_violations_total),
|
|
11831
|
-
weekly_ops_warnings_total: toNumber(aggregates.weekly_ops_warnings_total),
|
|
11832
|
-
weekly_ops_config_warnings_total: toNumber(aggregates.weekly_ops_config_warnings_total),
|
|
11833
|
-
weekly_ops_authorization_tier_block_rate_max_percent: toNumber(
|
|
11834
|
-
aggregates.weekly_ops_authorization_tier_block_rate_max_percent
|
|
11835
|
-
),
|
|
11836
|
-
weekly_ops_dialogue_authorization_block_rate_max_percent: toNumber(
|
|
11837
|
-
aggregates.weekly_ops_dialogue_authorization_block_rate_max_percent
|
|
11838
|
-
),
|
|
11839
|
-
weekly_ops_runtime_block_rate_avg_percent: toNumber(
|
|
11840
|
-
aggregates.weekly_ops_runtime_block_rate_avg_percent
|
|
11841
|
-
),
|
|
11842
|
-
weekly_ops_runtime_block_rate_max_percent: toNumber(
|
|
11843
|
-
aggregates.weekly_ops_runtime_block_rate_max_percent
|
|
11844
|
-
),
|
|
11845
|
-
weekly_ops_runtime_ui_mode_violation_known_runs: toNumber(
|
|
11846
|
-
aggregates.weekly_ops_runtime_ui_mode_violation_known_runs
|
|
11847
|
-
),
|
|
11848
|
-
weekly_ops_runtime_ui_mode_violation_runs: toNumber(
|
|
11849
|
-
aggregates.weekly_ops_runtime_ui_mode_violation_runs
|
|
11850
|
-
),
|
|
11851
|
-
weekly_ops_runtime_ui_mode_violation_run_rate_percent: toNumber(
|
|
11852
|
-
aggregates.weekly_ops_runtime_ui_mode_violation_run_rate_percent
|
|
11853
|
-
),
|
|
11854
|
-
weekly_ops_runtime_ui_mode_violation_total: toNumber(
|
|
11855
|
-
aggregates.weekly_ops_runtime_ui_mode_violation_total
|
|
11856
|
-
),
|
|
11857
|
-
weekly_ops_runtime_ui_mode_violation_rate_avg_percent: toNumber(
|
|
11858
|
-
aggregates.weekly_ops_runtime_ui_mode_violation_rate_avg_percent
|
|
11859
|
-
),
|
|
11860
|
-
weekly_ops_runtime_ui_mode_violation_rate_max_percent: toNumber(
|
|
11861
|
-
aggregates.weekly_ops_runtime_ui_mode_violation_rate_max_percent
|
|
11862
|
-
),
|
|
11863
|
-
parse_error: null
|
|
11864
|
-
};
|
|
12001
|
+
if (entries.length === 0 && !latest) {
|
|
12002
|
+
return loadFallbackSnapshot();
|
|
12003
|
+
}
|
|
12004
|
+
return buildSignalsSnapshot({
|
|
12005
|
+
file: historyFile,
|
|
12006
|
+
totalEntries: toNumber(payload.total_entries) || entries.length,
|
|
12007
|
+
latest,
|
|
12008
|
+
aggregates,
|
|
12009
|
+
parseError: null
|
|
12010
|
+
});
|
|
11865
12011
|
}
|
|
11866
12012
|
|
|
11867
12013
|
async function loadGovernanceHandoffQualitySignals(projectPath) {
|
|
@@ -12799,9 +12945,6 @@ function evaluateGovernanceReleaseGateBlockState(assessment) {
|
|
|
12799
12945
|
) {
|
|
12800
12946
|
reasons.push(`scene-batch-pass-rate-low:${snapshot.scene_package_batch_pass_rate_percent}`);
|
|
12801
12947
|
}
|
|
12802
|
-
if (Number.isFinite(snapshot.drift_alert_rate_percent) && snapshot.drift_alert_rate_percent > 0) {
|
|
12803
|
-
reasons.push(`drift-alert-rate-positive:${snapshot.drift_alert_rate_percent}`);
|
|
12804
|
-
}
|
|
12805
12948
|
if (Number.isFinite(snapshot.drift_blocked_runs) && snapshot.drift_blocked_runs > 0) {
|
|
12806
12949
|
reasons.push(`drift-blocked-runs-positive:${snapshot.drift_blocked_runs}`);
|
|
12807
12950
|
}
|
|
@@ -12995,7 +13138,6 @@ function evaluateGovernanceReleaseGateBlockState(assessment) {
|
|
|
12995
13138
|
snapshot.available === true &&
|
|
12996
13139
|
(
|
|
12997
13140
|
snapshot.latest_gate_passed === false ||
|
|
12998
|
-
(Number.isFinite(snapshot.drift_alert_rate_percent) && snapshot.drift_alert_rate_percent > 0) ||
|
|
12999
13141
|
(Number.isFinite(snapshot.drift_blocked_runs) && snapshot.drift_blocked_runs > 0)
|
|
13000
13142
|
)
|
|
13001
13143
|
);
|