scene-capability-engine 3.6.39 → 3.6.45

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 (49) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/bin/scene-capability-engine.js +78 -4
  3. package/docs/command-reference.md +5 -0
  4. package/docs/developer-guide.md +1 -1
  5. package/docs/releases/README.md +6 -0
  6. package/docs/releases/v3.6.40.md +19 -0
  7. package/docs/releases/v3.6.41.md +20 -0
  8. package/docs/releases/v3.6.42.md +19 -0
  9. package/docs/releases/v3.6.43.md +17 -0
  10. package/docs/releases/v3.6.44.md +17 -0
  11. package/docs/releases/v3.6.45.md +18 -0
  12. package/docs/spec-collaboration-guide.md +1 -1
  13. package/docs/zh/releases/README.md +6 -0
  14. package/docs/zh/releases/v3.6.40.md +19 -0
  15. package/docs/zh/releases/v3.6.41.md +20 -0
  16. package/docs/zh/releases/v3.6.42.md +19 -0
  17. package/docs/zh/releases/v3.6.43.md +17 -0
  18. package/docs/zh/releases/v3.6.44.md +17 -0
  19. package/docs/zh/releases/v3.6.45.md +18 -0
  20. package/lib/adoption/adoption-logger.js +1 -1
  21. package/lib/adoption/adoption-strategy.js +29 -29
  22. package/lib/adoption/detection-engine.js +16 -13
  23. package/lib/adoption/smart-orchestrator.js +3 -3
  24. package/lib/adoption/strategy-selector.js +19 -15
  25. package/lib/adoption/template-sync.js +3 -3
  26. package/lib/auto/autonomous-engine.js +5 -5
  27. package/lib/auto/handoff-release-gate-history-loaders-service.js +24 -4
  28. package/lib/auto/handoff-run-service.js +37 -0
  29. package/lib/backup/backup-system.js +10 -10
  30. package/lib/collab/collab-manager.js +8 -5
  31. package/lib/collab/dependency-manager.js +1 -1
  32. package/lib/commands/adopt.js +2 -2
  33. package/lib/commands/auto.js +239 -97
  34. package/lib/commands/collab.js +10 -4
  35. package/lib/commands/status.js +3 -3
  36. package/lib/commands/studio.js +8 -0
  37. package/lib/repo/config-manager.js +2 -2
  38. package/lib/spec/bootstrap/context-collector.js +5 -4
  39. package/lib/spec-gate/rules/default-rules.js +8 -8
  40. package/lib/upgrade/migration-engine.js +5 -5
  41. package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +3 -3
  42. package/lib/utils/tool-detector.js +4 -4
  43. package/lib/utils/validation.js +6 -6
  44. package/lib/workspace/collab-governance-audit.js +575 -0
  45. package/lib/workspace/multi/workspace-context-resolver.js +3 -3
  46. package/lib/workspace/multi/workspace-registry.js +3 -3
  47. package/lib/workspace/multi/workspace-state-manager.js +3 -3
  48. package/lib/workspace/spec-delivery-audit.js +553 -0
  49. package/package.json +1 -1
@@ -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 = evaluateAutoHandoffReleaseGatePreflightGateReasons(
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 base;
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
- const latestRiskLevel = normalizeHandoffText(latest && latest.risk_level);
11786
- const latestWeeklyOpsRiskLevel = normalizeHandoffText(latest && latest.weekly_ops_risk_level);
11787
- return {
11788
- ...base,
11789
- available: true,
11790
- total_entries: toNumber(payload.total_entries) || entries.length,
11791
- latest_tag: normalizeHandoffText(latest && latest.tag) || null,
11792
- latest_gate_passed: parseAutoHandoffGateBoolean(latest && latest.gate_passed, null),
11793
- latest_risk_level: latestRiskLevel
11794
- ? normalizeAutoHandoffGateRiskLevel(latestRiskLevel)
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
  );
@@ -90,7 +90,10 @@ function registerCollabCommands(program) {
90
90
  console.log(chalk.gray('Type:'), status.metadata.type);
91
91
  console.log(chalk.gray('Status:'), status.metadata.status.current);
92
92
  if (status.metadata.assignment) {
93
- console.log(chalk.gray('Assigned to:'), status.metadata.assignment.sceInstance);
93
+ console.log(
94
+ chalk.gray('Assigned to:'),
95
+ status.metadata.assignment.sceInstance || status.metadata.assignment.kiroInstance
96
+ );
94
97
  }
95
98
  if (status.metadata.dependencies && status.metadata.dependencies.length > 0) {
96
99
  console.log(chalk.gray('Dependencies:'));
@@ -105,8 +108,11 @@ function registerCollabCommands(program) {
105
108
 
106
109
  for (const { name, metadata } of status.specs) {
107
110
  const symbol = getStatusSymbol(metadata.status.current);
111
+ const assignedInstance = metadata.assignment
112
+ ? (metadata.assignment.sceInstance || metadata.assignment.kiroInstance)
113
+ : null;
108
114
  const assignment = metadata.assignment
109
- ? chalk.gray(`(${metadata.assignment.sceInstance})`)
115
+ ? chalk.gray(`(${assignedInstance})`)
110
116
  : chalk.gray('(unassigned)');
111
117
  console.log(`${symbol} ${name} ${assignment}`);
112
118
  }
@@ -127,12 +133,12 @@ function registerCollabCommands(program) {
127
133
  collab
128
134
  .command('assign <spec-name> <SCE-instance>')
129
135
  .description('Assign a spec to a SCE instance')
130
- .action(async (specName, kiroInstance) => {
136
+ .action(async (specName, sceInstance) => {
131
137
  try {
132
138
  const workspaceRoot = process.cwd();
133
139
  const manager = new CollaborationManager(workspaceRoot);
134
140
 
135
- const result = await manager.assignSpec(specName, kiroInstance);
141
+ const result = await manager.assignSpec(specName, sceInstance);
136
142
 
137
143
  if (result.success) {
138
144
  console.log(chalk.green('✓'), result.message);
@@ -30,10 +30,10 @@ async function statusCommand(options = {}) {
30
30
 
31
31
  try {
32
32
  // 1. Check if .sce/ exists
33
- const kiroPath = path.join(projectPath, '.sce');
34
- const kiroExists = await fs.pathExists(kiroPath);
33
+ const scePath = path.join(projectPath, '.sce');
34
+ const sceExists = await fs.pathExists(scePath);
35
35
 
36
- if (!kiroExists) {
36
+ if (!sceExists) {
37
37
  console.log(chalk.yellow('⚠️ No .sce/ directory found'));
38
38
  console.log();
39
39
  console.log('This project has not been adopted yet.');
@@ -502,6 +502,14 @@ async function buildReleaseGateSteps(options = {}, dependencies = {}) {
502
502
  required: true
503
503
  });
504
504
 
505
+ steps.push({
506
+ id: 'spec-delivery-audit',
507
+ name: 'spec delivery sync audit',
508
+ command: 'node',
509
+ args: ['bin/sce.js', 'workspace', 'delivery-audit', '--json', '--strict'],
510
+ required: true
511
+ });
512
+
505
513
  const gitManagedGateScript = path.join(projectPath, 'scripts', 'git-managed-gate.js');
506
514
  const hasGitManagedGateScript = await fileSystem.pathExists(gitManagedGateScript);
507
515
  steps.push({
@@ -131,8 +131,8 @@ class ConfigManager {
131
131
 
132
132
  try {
133
133
  // Ensure .sce directory exists
134
- const kiroDir = path.dirname(configPath);
135
- await fs.mkdir(kiroDir, { recursive: true });
134
+ const sceDir = path.dirname(configPath);
135
+ await fs.mkdir(sceDir, { recursive: true });
136
136
 
137
137
  // Write configuration with pretty formatting
138
138
  const jsonContent = JSON.stringify(config, null, 2);
@@ -7,14 +7,15 @@ class ContextCollector {
7
7
  }
8
8
 
9
9
  async collect() {
10
- const kiroDir = path.join(this.projectPath, '.sce');
11
- const specsDir = path.join(kiroDir, 'specs');
12
- const hasKiro = await fs.pathExists(kiroDir);
10
+ const sceDir = path.join(this.projectPath, '.sce');
11
+ const specsDir = path.join(sceDir, 'specs');
12
+ const hasSceDir = await fs.pathExists(sceDir);
13
13
  const existingSpecs = await this._listSpecs(specsDir);
14
14
 
15
15
  return {
16
16
  projectPath: this.projectPath,
17
- hasKiro,
17
+ hasSceDir,
18
+ hasKiro: hasSceDir,
18
19
  specsDir,
19
20
  existingSpecs,
20
21
  totalSpecs: existingSpecs.length,
@@ -87,25 +87,25 @@ function createDefaultRules(projectPath = process.cwd()) {
87
87
  id: 'config_consistency',
88
88
  description: 'Verify project-level sce config baseline exists',
89
89
  async execute() {
90
- const kiroDir = path.join(projectPath, '.sce');
91
- const configDir = path.join(kiroDir, 'config');
92
- const hasKiro = await fs.pathExists(kiroDir);
90
+ const sceDir = path.join(projectPath, '.sce');
91
+ const configDir = path.join(sceDir, 'config');
92
+ const hasSceDir = await fs.pathExists(sceDir);
93
93
  const hasConfig = await fs.pathExists(configDir);
94
94
 
95
- const ratio = hasKiro && hasConfig ? 1 : hasKiro ? 0.5 : 0;
95
+ const ratio = hasSceDir && hasConfig ? 1 : hasSceDir ? 0.5 : 0;
96
96
  const warnings = [];
97
- if (!hasKiro) {
97
+ if (!hasSceDir) {
98
98
  warnings.push('.sce directory missing');
99
99
  }
100
- if (hasKiro && !hasConfig) {
100
+ if (hasSceDir && !hasConfig) {
101
101
  warnings.push('.sce/config directory missing');
102
102
  }
103
103
 
104
104
  return {
105
- passed: hasKiro,
105
+ passed: hasSceDir,
106
106
  ratio,
107
107
  details: {
108
- hasKiro,
108
+ hasSceDir,
109
109
  hasConfig
110
110
  },
111
111
  warnings