scene-capability-engine 3.0.3 → 3.0.6

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/README.md CHANGED
@@ -411,12 +411,14 @@ Tip: `sce spec bootstrap|pipeline run|gate run --specs ...` now defaults to this
411
411
  "maxParallel": 3,
412
412
  "timeoutSeconds": 900,
413
413
  "maxRetries": 2,
414
- "rateLimitMaxRetries": 6,
415
- "rateLimitBackoffBaseMs": 1000,
416
- "rateLimitBackoffMaxMs": 30000,
414
+ "rateLimitMaxRetries": 8,
415
+ "rateLimitBackoffBaseMs": 1500,
416
+ "rateLimitBackoffMaxMs": 60000,
417
417
  "rateLimitAdaptiveParallel": true,
418
418
  "rateLimitParallelFloor": 1,
419
- "rateLimitCooldownMs": 30000,
419
+ "rateLimitCooldownMs": 45000,
420
+ "rateLimitLaunchBudgetPerMinute": 8,
421
+ "rateLimitLaunchBudgetWindowMs": 60000,
420
422
  "apiKeyEnvVar": "CODEX_API_KEY",
421
423
  "codexArgs": ["--skip-git-repo-check"],
422
424
  "codexCommand": "npx @openai/codex"
@@ -725,7 +725,11 @@ Close-loop controller session maintenance:
725
725
  Cross-archive autonomous governance maintenance:
726
726
  - `sce auto governance stats [--days <n>] [--status <csv>] [--json]`: aggregate a unified governance snapshot from session/batch-session/controller-session archives plus recovery memory state.
727
727
  - JSON output includes `totals`, `throughput`, `health` (`risk_level`, `concerns`, `recommendations`, `release_gate`, `handoff_quality`), `top_master_specs`, `recovery_memory`, and full per-archive stats under `archives`.
728
- - `health.handoff_quality` carries Moqui matrix regression governance signals:
728
+ - `health.handoff_quality` carries Moqui matrix + capability lexicon governance signals:
729
+ - `latest_capability_expected_unknown_count`
730
+ - `latest_capability_provided_unknown_count`
731
+ - `capability_expected_unknown_positive_rate_percent`
732
+ - `capability_provided_unknown_positive_rate_percent`
729
733
  - `latest_moqui_matrix_regression_count`
730
734
  - `latest_moqui_matrix_regression_gate_max`
731
735
  - `avg_moqui_matrix_regression_count`
@@ -743,6 +747,10 @@ Cross-archive autonomous governance maintenance:
743
747
  - `--execute-advisory` enables automatic advisory action execution (`recover-latest`, `controller-resume-latest`) when governance assessment detects failed sessions or controller pending goals; sce auto-selects the latest actionable advisory source and reports `skipped` (not `failed`) when no actionable source exists.
744
748
  - JSON output includes round-by-round risk/action telemetry (`rounds`, with `risk_before/risk_after` and `release_gate_before/release_gate_after`), advisory telemetry (`execute_advisory`, `advisory_policy`, `advisory_summary`, `rounds[*].advisory_actions`), `stop_detail` + `recommendations` for explicit blocking reasons, plus `initial_assessment`, `final_assessment`, and convergence metadata.
745
749
  - Release-gate block reasons now include handoff matrix regression reasons when present:
750
+ - `handoff-capability-expected-unknown-positive:<n>`
751
+ - `handoff-capability-provided-unknown-positive:<n>`
752
+ - `handoff-capability-expected-unknown-positive-rate:<percent>`
753
+ - `handoff-capability-provided-unknown-positive-rate:<percent>`
746
754
  - `handoff-moqui-matrix-regressions-positive:<n>`
747
755
  - `handoff-moqui-matrix-regressions-over-gate:<n>/<max>`
748
756
  - `sce auto governance session list [--limit <n>] [--status <csv>] [--resume-only] [--json]`: list persisted governance close-loop sessions (`--resume-only` filters to resumed-chain sessions only).
@@ -779,6 +787,7 @@ Dual-track handoff integration:
779
787
  - `sce auto handoff queue --manifest <path> [--out <path>] [--append] [--no-include-known-gaps] [--dry-run] [--json]`: generate close-loop batch goal queue from handoff manifest and optionally persist line-based queue file (default `.kiro/auto/handoff-goals.lines`).
780
788
  - `sce auto handoff template-diff --manifest <path> [--json]`: compare manifest templates against local template exports/registry and report `missing_in_local` and `extra_in_local`.
781
789
  - `sce auto handoff capability-matrix --manifest <path> [--strict] [--strict-warnings] [--min-capability-coverage <n>] [--min-capability-semantic <n>] [--no-require-capability-semantic] [--format <json|markdown>] [--out <path>] [--remediation-queue-out <path>] [--fail-on-gap] [--json]`: generate a fast Moqui capability matrix (`template-diff + baseline + capability coverage + semantic completeness`) and optionally fail fast on gaps.
790
+ - When `manifest.capabilities` is empty, sce auto-infers canonical expected capabilities from `manifest.templates` using the Moqui lexicon before deciding whether capability coverage should be skipped.
782
791
  - `sce auto handoff run --manifest <path> [--out <path>] [--queue-out <path>] [--append] [--no-include-known-gaps] [--continue-from <session|latest|file>] [--continue-strategy <auto|pending|failed-only>] [--dry-run] [--strict] [--strict-warnings] [--no-dependency-batching] [--min-spec-success-rate <n>] [--max-risk-level <level>] [--max-moqui-matrix-regressions <n>] [--no-require-ontology-validation] [--no-require-moqui-baseline] [--min-capability-coverage <n>] [--no-require-capability-coverage] [--require-release-gate-preflight] [--release-evidence-window <n>] [--json]`: execute handoff end-to-end (`plan -> queue -> close-loop-batch -> observability`) with automatic report archive to `.kiro/reports/handoff-runs/<session>.json`.
783
792
  - Default mode is dependency-aware: spec integration goals are grouped into dependency batches and executed in topological order.
784
793
  - `--continue-from` resumes pending goals from an existing handoff run report (`latest`, session id, or JSON file path). For safety, sce enforces manifest-path consistency between the previous report and current run.
@@ -789,6 +798,7 @@ Dual-track handoff integration:
789
798
  - `moqui_baseline.summary` now includes `scope_breakdown`, `coverage_matrix`, and `gap_frequency` for ER/BR/decision closure tracking.
790
799
  - `moqui_baseline.compare` now includes `coverage_matrix_deltas` and `coverage_matrix_regressions` for trend-level entity/relation/rule/decision closure movement and negative-delta alerts (used by matrix-regression hard gate).
791
800
  - Run output includes `moqui_capability_coverage` snapshot by default (when manifest `capabilities` is declared), with artifacts at `.kiro/reports/release-evidence/moqui-capability-coverage.json` and `.kiro/reports/release-evidence/moqui-capability-coverage.md`.
801
+ - When `manifest.capabilities` is not declared, sce attempts lexicon-based capability inference from `manifest.templates` first; only fully non-mappable manifests keep capability coverage in skipped mode.
792
802
  - Run output includes `release_gate_preflight` (latest release gate history signal snapshot + blocked reasons) and carries this context into `warnings`.
793
803
  - `release_gate_preflight` is advisory by default; use `--require-release-gate-preflight` to hard-fail when preflight is unavailable/blocked.
794
804
  - When Moqui baseline/capability gates fail, sce auto-generates remediation queue lines at `.kiro/auto/moqui-remediation.lines`.
@@ -814,11 +824,14 @@ Dual-track handoff integration:
814
824
  - Default scan dir is `.kiro/reports/release-evidence`, default output file is `.kiro/reports/release-evidence/release-gate-history.json`.
815
825
  - `--history-file` merges an existing index (for example, previous release asset) before dedup/refresh.
816
826
  - `--keep` retains latest N entries (`1-5000`, default `200`).
817
- - Aggregates include scene package batch, drift, and release-preflight/hard-gate signals (`scene_package_batch_*`, `drift_alert_*`, `drift_block_*`, `release_gate_preflight_*`) when present in gate reports.
827
+ - Aggregates include scene package batch, capability unknown trend, drift, and release-preflight/hard-gate signals (`scene_package_batch_*`, `capability_expected_unknown_*`, `capability_provided_unknown_*`, `drift_alert_*`, `drift_block_*`, `release_gate_preflight_*`) when present in gate reports.
818
828
  - `--markdown-out <path>` writes a human-readable trend card markdown for PR/Issue handoff.
819
829
 
820
830
  Moqui template library lexicon audit (script-level governance helper):
821
831
  - `node scripts/moqui-lexicon-audit.js [--manifest <path>] [--template-dir <path>] [--lexicon <path>] [--out <path>] [--markdown-out <path>] [--fail-on-gap] [--json]`: audit manifest/template capability names against canonical Moqui lexicon; reports unknown aliases and uncovered expected capabilities.
832
+ - Expected capability scope uses `manifest.capabilities` first; when empty, it infers canonical expected capabilities from `manifest.templates` and emits `expected_scope` metadata (`source`, `inferred_*`, `unresolved_templates`).
833
+ - By default, template capability auditing is scoped to `manifest.templates` (when matched), reducing noise from unrelated templates.
834
+ - Template scope matching normalizes `sce.scene--*` / `kse.scene--*` prefixes, so renamed template namespaces still map correctly.
822
835
 
823
836
  Recommended `.kiro/config/orchestrator.json`:
824
837
 
@@ -828,12 +841,14 @@ Recommended `.kiro/config/orchestrator.json`:
828
841
  "maxParallel": 3,
829
842
  "timeoutSeconds": 900,
830
843
  "maxRetries": 2,
831
- "rateLimitMaxRetries": 6,
832
- "rateLimitBackoffBaseMs": 1000,
833
- "rateLimitBackoffMaxMs": 30000,
844
+ "rateLimitMaxRetries": 8,
845
+ "rateLimitBackoffBaseMs": 1500,
846
+ "rateLimitBackoffMaxMs": 60000,
834
847
  "rateLimitAdaptiveParallel": true,
835
848
  "rateLimitParallelFloor": 1,
836
- "rateLimitCooldownMs": 30000,
849
+ "rateLimitCooldownMs": 45000,
850
+ "rateLimitLaunchBudgetPerMinute": 8,
851
+ "rateLimitLaunchBudgetWindowMs": 60000,
837
852
  "apiKeyEnvVar": "CODEX_API_KEY",
838
853
  "codexArgs": ["--skip-git-repo-check"],
839
854
  "codexCommand": "npx @openai/codex"
@@ -17,8 +17,10 @@ sce defaults already enforce the baseline below:
17
17
  - `sce auto handoff run`: requires Moqui baseline portfolio pass by default.
18
18
  - `sce auto handoff run`: enforces Moqui matrix regression hard-gate by default (`max_moqui_matrix_regressions=0`).
19
19
  - `sce auto handoff run`: evaluates capability coverage matrix by default when manifest `capabilities` is declared (default minimum `100%`).
20
+ - `sce auto handoff run` / `sce auto handoff capability-matrix`: enforces capability lexicon normalization by default (expected/provided unknown aliases are blocked unless explicitly bypassed).
20
21
  - `sce auto handoff capability-matrix`: enforces both capability coverage and capability semantic completeness (default minimum `100%` for each).
21
22
  - `sce auto governance stats` / `sce auto governance close-loop`: treats Moqui matrix regressions as first-class risk/block signals (including over-gate stop reasons).
23
+ - `sce auto governance stats` / `sce auto governance close-loop`: treats capability lexicon unknown-count signals as first-class risk/block signals.
22
24
  - `sce scene package-publish-batch`:
23
25
  - ontology validation required by default
24
26
  - batch ontology gate defaults:
@@ -6848,6 +6848,75 @@ function collectUniqueIdentifiers(rawEntries, fieldCandidates, label) {
6848
6848
  return { values, warnings };
6849
6849
  }
6850
6850
 
6851
+ function normalizeAutoHandoffTemplateCapabilityCandidate(value) {
6852
+ if (value === undefined || value === null) {
6853
+ return null;
6854
+ }
6855
+ const raw = `${value}`.trim();
6856
+ if (!raw) {
6857
+ return null;
6858
+ }
6859
+ const normalizedPath = raw.toLowerCase().replace(/\\/g, '/');
6860
+ const baseName = normalizedPath.split('/').pop() || normalizedPath;
6861
+ let candidate = baseName.replace(/^[a-z0-9-]+\.scene--/, 'scene--');
6862
+ candidate = candidate.replace(/^scene--/, '');
6863
+ candidate = candidate.replace(
6864
+ /--\d+\.\d+\.\d+(?:-[a-z0-9.-]+)?(?:\+[a-z0-9.-]+)?$/,
6865
+ ''
6866
+ );
6867
+ candidate = candidate.replace(/--\d{4}(?:-\d{2}){1,2}(?:-[a-z0-9-]+)?$/, '');
6868
+ return normalizeMoquiCapabilityToken(candidate);
6869
+ }
6870
+
6871
+ function inferManifestCapabilitiesFromTemplates(
6872
+ templateIdentifiers = [],
6873
+ lexiconIndex = MOQUI_CAPABILITY_LEXICON_INDEX
6874
+ ) {
6875
+ const inferred = [];
6876
+ const inferredSet = new Set();
6877
+ const inferredFrom = [];
6878
+ const unresolvedTemplates = [];
6879
+ const unresolvedSet = new Set();
6880
+
6881
+ if (!Array.isArray(templateIdentifiers) || templateIdentifiers.length === 0) {
6882
+ return {
6883
+ capabilities: inferred,
6884
+ inferred_from: inferredFrom,
6885
+ unresolved_templates: unresolvedTemplates
6886
+ };
6887
+ }
6888
+
6889
+ for (const templateIdentifier of templateIdentifiers) {
6890
+ const candidate = normalizeAutoHandoffTemplateCapabilityCandidate(templateIdentifier);
6891
+ if (!candidate) {
6892
+ continue;
6893
+ }
6894
+ const descriptor = resolveMoquiCapabilityDescriptor(candidate, lexiconIndex);
6895
+ if (descriptor && descriptor.is_known) {
6896
+ if (!inferredSet.has(descriptor.canonical)) {
6897
+ inferredSet.add(descriptor.canonical);
6898
+ inferred.push(descriptor.canonical);
6899
+ }
6900
+ inferredFrom.push({
6901
+ template: templateIdentifier,
6902
+ normalized_template: candidate,
6903
+ capability: descriptor.canonical
6904
+ });
6905
+ continue;
6906
+ }
6907
+ if (!unresolvedSet.has(templateIdentifier)) {
6908
+ unresolvedSet.add(templateIdentifier);
6909
+ unresolvedTemplates.push(templateIdentifier);
6910
+ }
6911
+ }
6912
+
6913
+ return {
6914
+ capabilities: inferred,
6915
+ inferred_from: inferredFrom,
6916
+ unresolved_templates: unresolvedTemplates
6917
+ };
6918
+ }
6919
+
6851
6920
  function normalizeHandoffDependencyEntry(entry) {
6852
6921
  return normalizeHandoffIdentifier(entry, [
6853
6922
  'name',
@@ -7128,8 +7197,32 @@ function normalizeAutoHandoffManifest(payload = {}) {
7128
7197
  'capabilities'
7129
7198
  );
7130
7199
  validationWarnings.push(...capabilitiesCollected.warnings);
7200
+ const capabilityInference = inferManifestCapabilitiesFromTemplates(
7201
+ templatesCollected.values,
7202
+ MOQUI_CAPABILITY_LEXICON_INDEX
7203
+ );
7204
+ let capabilityValues = capabilitiesCollected.values;
7205
+ let capabilitySource = 'manifest';
7131
7206
  if (capabilitiesCollected.values.length === 0) {
7132
- validationWarnings.push('capabilities is empty; capability coverage gate will be skipped unless capabilities are declared');
7207
+ if (capabilityInference.capabilities.length > 0) {
7208
+ capabilityValues = capabilityInference.capabilities;
7209
+ capabilitySource = 'inferred-from-templates';
7210
+ validationWarnings.push(
7211
+ `capabilities not declared; inferred ${capabilityValues.length} canonical capabilities from templates`
7212
+ );
7213
+ if (capabilityInference.unresolved_templates.length > 0) {
7214
+ const preview = capabilityInference.unresolved_templates.slice(0, 5).join(', ');
7215
+ const suffix = capabilityInference.unresolved_templates.length > 5
7216
+ ? ` (+${capabilityInference.unresolved_templates.length - 5} more)`
7217
+ : '';
7218
+ validationWarnings.push(
7219
+ `template capability inference skipped ${capabilityInference.unresolved_templates.length} templates not found in lexicon: ${preview}${suffix}`
7220
+ );
7221
+ }
7222
+ } else {
7223
+ capabilitySource = 'none';
7224
+ validationWarnings.push('capabilities is empty; capability coverage gate will be skipped unless capabilities are declared');
7225
+ }
7133
7226
  }
7134
7227
 
7135
7228
  const knownGapCollected = collectKnownGaps(payload.known_gaps);
@@ -7153,7 +7246,16 @@ function normalizeAutoHandoffManifest(payload = {}) {
7153
7246
  spec_descriptors: specsCollected.descriptors,
7154
7247
  dependency_batches: dependencyBatches,
7155
7248
  templates: templatesCollected.values,
7156
- capabilities: capabilitiesCollected.values,
7249
+ capabilities: capabilityValues,
7250
+ capability_source: capabilitySource,
7251
+ capability_inference: {
7252
+ applied: capabilitySource === 'inferred-from-templates',
7253
+ inferred_count: capabilityInference.capabilities.length,
7254
+ inferred_capabilities: capabilityInference.capabilities,
7255
+ inferred_from_templates: capabilityInference.inferred_from,
7256
+ unresolved_template_count: capabilityInference.unresolved_templates.length,
7257
+ unresolved_templates: capabilityInference.unresolved_templates
7258
+ },
7157
7259
  known_gaps: knownGapCollected.gaps,
7158
7260
  ontology_validation: ontologyValidation,
7159
7261
  next_batch: nextBatch,
@@ -7268,6 +7370,17 @@ async function buildAutoHandoffPlan(projectPath, options = {}) {
7268
7370
  dependency_batches: handoff.dependency_batches,
7269
7371
  templates: handoff.templates,
7270
7372
  capabilities: handoff.capabilities,
7373
+ capability_source: handoff.capability_source || 'manifest',
7374
+ capability_inference: handoff.capability_inference && typeof handoff.capability_inference === 'object'
7375
+ ? handoff.capability_inference
7376
+ : {
7377
+ applied: false,
7378
+ inferred_count: 0,
7379
+ inferred_capabilities: [],
7380
+ inferred_from_templates: [],
7381
+ unresolved_template_count: 0,
7382
+ unresolved_templates: []
7383
+ },
7271
7384
  known_gaps: handoff.known_gaps,
7272
7385
  ontology_validation: handoff.ontology_validation,
7273
7386
  next_batch: handoff.next_batch
@@ -8954,6 +9067,24 @@ function buildAutoHandoffReleaseGateHistoryEntry(entry = {}, options = {}) {
8954
9067
  ? entry.scene_package_batch_failure_count
8955
9068
  : signalMap.scene_package_batch_failure_count
8956
9069
  );
9070
+ const capabilityExpectedUnknownCount = parseAutoHandoffGateNumber(
9071
+ entry.capability_expected_unknown_count !== undefined
9072
+ ? entry.capability_expected_unknown_count
9073
+ : (
9074
+ signalMap.capability_expected_unknown_count !== undefined
9075
+ ? signalMap.capability_expected_unknown_count
9076
+ : signalMap.capability_lexicon_expected_unknown_count
9077
+ )
9078
+ );
9079
+ const capabilityProvidedUnknownCount = parseAutoHandoffGateNumber(
9080
+ entry.capability_provided_unknown_count !== undefined
9081
+ ? entry.capability_provided_unknown_count
9082
+ : (
9083
+ signalMap.capability_provided_unknown_count !== undefined
9084
+ ? signalMap.capability_provided_unknown_count
9085
+ : signalMap.capability_lexicon_provided_unknown_count
9086
+ )
9087
+ );
8957
9088
  const releaseGatePreflightAvailable = parseAutoHandoffGateBoolean(
8958
9089
  entry.release_gate_preflight_available !== undefined
8959
9090
  ? entry.release_gate_preflight_available
@@ -9058,6 +9189,12 @@ function buildAutoHandoffReleaseGateHistoryEntry(entry = {}, options = {}) {
9058
9189
  scene_package_batch_status: sceneBatchStatus || null,
9059
9190
  scene_package_batch_passed: typeof sceneBatchPassed === 'boolean' ? sceneBatchPassed : null,
9060
9191
  scene_package_batch_failure_count: Number.isFinite(sceneBatchFailureCount) ? sceneBatchFailureCount : null,
9192
+ capability_expected_unknown_count: Number.isFinite(capabilityExpectedUnknownCount)
9193
+ ? Math.max(0, Number(capabilityExpectedUnknownCount))
9194
+ : null,
9195
+ capability_provided_unknown_count: Number.isFinite(capabilityProvidedUnknownCount)
9196
+ ? Math.max(0, Number(capabilityProvidedUnknownCount))
9197
+ : null,
9061
9198
  release_gate_preflight_available: typeof releaseGatePreflightAvailable === 'boolean'
9062
9199
  ? releaseGatePreflightAvailable
9063
9200
  : null,
@@ -9220,6 +9357,12 @@ function buildAutoHandoffReleaseGateHistoryAggregates(entries = []) {
9220
9357
  let preflightAvailableRuns = 0;
9221
9358
  let preflightBlockedRuns = 0;
9222
9359
  let preflightHardGateRuns = 0;
9360
+ let capabilityExpectedUnknownKnownRuns = 0;
9361
+ let capabilityExpectedUnknownPositiveRuns = 0;
9362
+ let capabilityProvidedUnknownKnownRuns = 0;
9363
+ let capabilityProvidedUnknownPositiveRuns = 0;
9364
+ const capabilityExpectedUnknownCounts = [];
9365
+ const capabilityProvidedUnknownCounts = [];
9223
9366
  const sceneBatchFailureCounts = [];
9224
9367
  let sceneBatchApplicableCount = 0;
9225
9368
  let sceneBatchPassedCount = 0;
@@ -9268,6 +9411,28 @@ function buildAutoHandoffReleaseGateHistoryAggregates(entries = []) {
9268
9411
  if (Number.isFinite(sceneBatchFailureCount)) {
9269
9412
  sceneBatchFailureCounts.push(sceneBatchFailureCount);
9270
9413
  }
9414
+ const capabilityExpectedUnknownCount = parseAutoHandoffGateNumber(
9415
+ entry && entry.capability_expected_unknown_count
9416
+ );
9417
+ if (Number.isFinite(capabilityExpectedUnknownCount)) {
9418
+ const normalizedCount = Math.max(0, Number(capabilityExpectedUnknownCount));
9419
+ capabilityExpectedUnknownKnownRuns += 1;
9420
+ capabilityExpectedUnknownCounts.push(normalizedCount);
9421
+ if (normalizedCount > 0) {
9422
+ capabilityExpectedUnknownPositiveRuns += 1;
9423
+ }
9424
+ }
9425
+ const capabilityProvidedUnknownCount = parseAutoHandoffGateNumber(
9426
+ entry && entry.capability_provided_unknown_count
9427
+ );
9428
+ if (Number.isFinite(capabilityProvidedUnknownCount)) {
9429
+ const normalizedCount = Math.max(0, Number(capabilityProvidedUnknownCount));
9430
+ capabilityProvidedUnknownKnownRuns += 1;
9431
+ capabilityProvidedUnknownCounts.push(normalizedCount);
9432
+ if (normalizedCount > 0) {
9433
+ capabilityProvidedUnknownPositiveRuns += 1;
9434
+ }
9435
+ }
9271
9436
  const preflightAvailable = parseAutoHandoffGateBoolean(
9272
9437
  entry && entry.release_gate_preflight_available,
9273
9438
  null
@@ -9348,6 +9513,24 @@ function buildAutoHandoffReleaseGateHistoryAggregates(entries = []) {
9348
9513
  const maxSceneBatchFailureCount = sceneBatchFailureCounts.length > 0
9349
9514
  ? Number(Math.max(...sceneBatchFailureCounts).toFixed(2))
9350
9515
  : null;
9516
+ const avgCapabilityExpectedUnknownCount = capabilityExpectedUnknownCounts.length > 0
9517
+ ? Number((capabilityExpectedUnknownCounts.reduce((sum, value) => sum + value, 0) / capabilityExpectedUnknownCounts.length).toFixed(2))
9518
+ : null;
9519
+ const maxCapabilityExpectedUnknownCount = capabilityExpectedUnknownCounts.length > 0
9520
+ ? Number(Math.max(...capabilityExpectedUnknownCounts).toFixed(2))
9521
+ : null;
9522
+ const capabilityExpectedUnknownPositiveRate = capabilityExpectedUnknownKnownRuns > 0
9523
+ ? Number(((capabilityExpectedUnknownPositiveRuns / capabilityExpectedUnknownKnownRuns) * 100).toFixed(2))
9524
+ : null;
9525
+ const avgCapabilityProvidedUnknownCount = capabilityProvidedUnknownCounts.length > 0
9526
+ ? Number((capabilityProvidedUnknownCounts.reduce((sum, value) => sum + value, 0) / capabilityProvidedUnknownCounts.length).toFixed(2))
9527
+ : null;
9528
+ const maxCapabilityProvidedUnknownCount = capabilityProvidedUnknownCounts.length > 0
9529
+ ? Number(Math.max(...capabilityProvidedUnknownCounts).toFixed(2))
9530
+ : null;
9531
+ const capabilityProvidedUnknownPositiveRate = capabilityProvidedUnknownKnownRuns > 0
9532
+ ? Number(((capabilityProvidedUnknownPositiveRuns / capabilityProvidedUnknownKnownRuns) * 100).toFixed(2))
9533
+ : null;
9351
9534
  const driftAlertRate = driftKnownRuns > 0
9352
9535
  ? Number(((driftAlertRuns / driftKnownRuns) * 100).toFixed(2))
9353
9536
  : null;
@@ -9380,6 +9563,16 @@ function buildAutoHandoffReleaseGateHistoryAggregates(entries = []) {
9380
9563
  scene_package_batch_pass_rate_percent: sceneBatchPassRate,
9381
9564
  avg_scene_package_batch_failure_count: avgSceneBatchFailureCount,
9382
9565
  max_scene_package_batch_failure_count: maxSceneBatchFailureCount,
9566
+ capability_expected_unknown_known_runs: capabilityExpectedUnknownKnownRuns,
9567
+ capability_expected_unknown_positive_runs: capabilityExpectedUnknownPositiveRuns,
9568
+ capability_expected_unknown_positive_rate_percent: capabilityExpectedUnknownPositiveRate,
9569
+ avg_capability_expected_unknown_count: avgCapabilityExpectedUnknownCount,
9570
+ max_capability_expected_unknown_count: maxCapabilityExpectedUnknownCount,
9571
+ capability_provided_unknown_known_runs: capabilityProvidedUnknownKnownRuns,
9572
+ capability_provided_unknown_positive_runs: capabilityProvidedUnknownPositiveRuns,
9573
+ capability_provided_unknown_positive_rate_percent: capabilityProvidedUnknownPositiveRate,
9574
+ avg_capability_provided_unknown_count: avgCapabilityProvidedUnknownCount,
9575
+ max_capability_provided_unknown_count: maxCapabilityProvidedUnknownCount,
9383
9576
  drift_known_runs: driftKnownRuns,
9384
9577
  drift_alert_total: driftAlertTotal,
9385
9578
  drift_alert_runs: driftAlertRuns,
@@ -9445,6 +9638,8 @@ async function buildAutoHandoffReleaseGateHistoryIndex(projectPath, options = {}
9445
9638
  risk_level: latestEntry.risk_level,
9446
9639
  scene_package_batch_passed: latestEntry.scene_package_batch_passed,
9447
9640
  scene_package_batch_failure_count: latestEntry.scene_package_batch_failure_count,
9641
+ capability_expected_unknown_count: latestEntry.capability_expected_unknown_count,
9642
+ capability_provided_unknown_count: latestEntry.capability_provided_unknown_count,
9448
9643
  release_gate_preflight_available: latestEntry.release_gate_preflight_available,
9449
9644
  release_gate_preflight_blocked: latestEntry.release_gate_preflight_blocked,
9450
9645
  require_release_gate_preflight: latestEntry.require_release_gate_preflight,
@@ -9490,6 +9685,8 @@ function renderAutoHandoffReleaseGateHistoryMarkdown(payload = {}) {
9490
9685
  lines.push(`- Risk level: ${formatAutoHandoffRegressionValue(latest.risk_level)}`);
9491
9686
  lines.push(`- Scene package batch: ${latest.scene_package_batch_passed === true ? 'pass' : (latest.scene_package_batch_passed === false ? 'fail' : 'n/a')}`);
9492
9687
  lines.push(`- Scene package batch failures: ${formatAutoHandoffRegressionValue(latest.scene_package_batch_failure_count)}`);
9688
+ lines.push(`- Capability expected unknown count: ${formatAutoHandoffRegressionValue(latest.capability_expected_unknown_count, '0')}`);
9689
+ lines.push(`- Capability provided unknown count: ${formatAutoHandoffRegressionValue(latest.capability_provided_unknown_count, '0')}`);
9493
9690
  lines.push(`- Release preflight available: ${latest.release_gate_preflight_available === true ? 'yes' : (latest.release_gate_preflight_available === false ? 'no' : 'n/a')}`);
9494
9691
  lines.push(`- Release preflight blocked: ${latest.release_gate_preflight_blocked === true ? 'yes' : (latest.release_gate_preflight_blocked === false ? 'no' : 'n/a')}`);
9495
9692
  lines.push(`- Release preflight hard-gate: ${latest.require_release_gate_preflight === true ? 'enabled' : (latest.require_release_gate_preflight === false ? 'advisory' : 'n/a')}`);
@@ -9511,6 +9708,12 @@ function renderAutoHandoffReleaseGateHistoryMarkdown(payload = {}) {
9511
9708
  lines.push(`- Scene package batch pass rate: ${formatAutoHandoffRegressionValue(aggregates.scene_package_batch_pass_rate_percent)}%`);
9512
9709
  lines.push(`- Scene package batch failed: ${formatAutoHandoffRegressionValue(aggregates.scene_package_batch_failed_count, '0')}`);
9513
9710
  lines.push(`- Avg scene package batch failures: ${formatAutoHandoffRegressionValue(aggregates.avg_scene_package_batch_failure_count)}`);
9711
+ lines.push(`- Capability expected unknown positive rate: ${formatAutoHandoffRegressionValue(aggregates.capability_expected_unknown_positive_rate_percent)}%`);
9712
+ lines.push(`- Avg capability expected unknown count: ${formatAutoHandoffRegressionValue(aggregates.avg_capability_expected_unknown_count)}`);
9713
+ lines.push(`- Max capability expected unknown count: ${formatAutoHandoffRegressionValue(aggregates.max_capability_expected_unknown_count)}`);
9714
+ lines.push(`- Capability provided unknown positive rate: ${formatAutoHandoffRegressionValue(aggregates.capability_provided_unknown_positive_rate_percent)}%`);
9715
+ lines.push(`- Avg capability provided unknown count: ${formatAutoHandoffRegressionValue(aggregates.avg_capability_provided_unknown_count)}`);
9716
+ lines.push(`- Max capability provided unknown count: ${formatAutoHandoffRegressionValue(aggregates.max_capability_provided_unknown_count)}`);
9514
9717
  lines.push(`- Drift alert runs: ${formatAutoHandoffRegressionValue(aggregates.drift_alert_runs, '0')}`);
9515
9718
  lines.push(`- Drift blocked runs: ${formatAutoHandoffRegressionValue(aggregates.drift_blocked_runs, '0')}`);
9516
9719
  lines.push(`- Drift alert rate: ${formatAutoHandoffRegressionValue(aggregates.drift_alert_rate_percent)}%`);
@@ -9542,6 +9745,14 @@ function renderAutoHandoffReleaseGateHistoryMarkdown(payload = {}) {
9542
9745
  const sceneBatchFailures = formatAutoHandoffRegressionValue(
9543
9746
  entry && entry.scene_package_batch_failure_count
9544
9747
  );
9748
+ const capabilityExpectedUnknown = formatAutoHandoffRegressionValue(
9749
+ entry && entry.capability_expected_unknown_count,
9750
+ '0'
9751
+ );
9752
+ const capabilityProvidedUnknown = formatAutoHandoffRegressionValue(
9753
+ entry && entry.capability_provided_unknown_count,
9754
+ '0'
9755
+ );
9545
9756
  const preflightBlocked = entry && entry.release_gate_preflight_blocked === true
9546
9757
  ? 'yes'
9547
9758
  : (entry && entry.release_gate_preflight_blocked === false ? 'no' : 'n/a');
@@ -9554,7 +9765,8 @@ function renderAutoHandoffReleaseGateHistoryMarkdown(payload = {}) {
9554
9765
  : (entry && entry.drift_blocked === false ? 'no' : 'n/a');
9555
9766
  lines.push(
9556
9767
  `- ${tag} | passed=${passed} | risk=${risk} | scene-batch=${sceneBatch} | ` +
9557
- `scene-failures=${sceneBatchFailures} | preflight-blocked=${preflightBlocked} | hard-gate=${preflightHardGate} | ` +
9768
+ `scene-failures=${sceneBatchFailures} | capability-unknown=${capabilityExpectedUnknown}/${capabilityProvidedUnknown} | ` +
9769
+ `preflight-blocked=${preflightBlocked} | hard-gate=${preflightHardGate} | ` +
9558
9770
  `drift-alerts=${driftAlerts} | drift-blocked=${driftBlocked} | ` +
9559
9771
  `success=${successRate} | violations=${violations} | at=${evaluatedAt}`
9560
9772
  );
@@ -13373,6 +13585,18 @@ async function buildAutoHandoffCapabilityMatrix(projectPath, options = {}) {
13373
13585
  capability_count: Array.isArray(plan.handoff && plan.handoff.capabilities)
13374
13586
  ? plan.handoff.capabilities.length
13375
13587
  : 0,
13588
+ capability_source: normalizeHandoffText(plan.handoff && plan.handoff.capability_source) || 'manifest',
13589
+ capability_inference: plan.handoff && plan.handoff.capability_inference &&
13590
+ typeof plan.handoff.capability_inference === 'object'
13591
+ ? plan.handoff.capability_inference
13592
+ : {
13593
+ applied: false,
13594
+ inferred_count: 0,
13595
+ inferred_capabilities: [],
13596
+ inferred_from_templates: [],
13597
+ unresolved_template_count: 0,
13598
+ unresolved_templates: []
13599
+ },
13376
13600
  capabilities: Array.isArray(plan.handoff && plan.handoff.capabilities)
13377
13601
  ? plan.handoff.capabilities
13378
13602
  : []
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.02.18",
2
+ "version": "2026.02.18.1",
3
3
  "source": "sce-moqui-core",
4
4
  "capabilities": [
5
5
  {
@@ -8,7 +8,8 @@
8
8
  "order-query-read",
9
9
  "order-read",
10
10
  "moqui-order-query-read",
11
- "moqui-order-read"
11
+ "moqui-order-read",
12
+ "scene.erp.order.query.read"
12
13
  ],
13
14
  "deprecated_aliases": [
14
15
  "order-query",
@@ -21,7 +22,8 @@
21
22
  "order-fulfillment-workflow",
22
23
  "order-fulfillment",
23
24
  "fulfillment-workflow",
24
- "moqui-order-fulfillment"
25
+ "moqui-order-fulfillment",
26
+ "scene.erp.order.fulfillment.workflow"
25
27
  ],
26
28
  "deprecated_aliases": [
27
29
  "order-fulfilment-workflow",
@@ -34,7 +36,8 @@
34
36
  "inventory-reserve-adjust",
35
37
  "inventory-adjust",
36
38
  "inventory-reserve",
37
- "moqui-inventory-reserve-adjust"
39
+ "moqui-inventory-reserve-adjust",
40
+ "scene.erp.inventory.reserve.adjust"
38
41
  ],
39
42
  "deprecated_aliases": [
40
43
  "inventory-adjustment",
@@ -16,13 +16,13 @@ const path = require('path');
16
16
  const fsUtils = require('../utils/fs-utils');
17
17
 
18
18
  const SPECS_DIR = '.kiro/specs';
19
- const DEFAULT_RATE_LIMIT_MAX_RETRIES = 6;
20
- const DEFAULT_RATE_LIMIT_BACKOFF_BASE_MS = 1000;
21
- const DEFAULT_RATE_LIMIT_BACKOFF_MAX_MS = 30000;
19
+ const DEFAULT_RATE_LIMIT_MAX_RETRIES = 8;
20
+ const DEFAULT_RATE_LIMIT_BACKOFF_BASE_MS = 1500;
21
+ const DEFAULT_RATE_LIMIT_BACKOFF_MAX_MS = 60000;
22
22
  const DEFAULT_RATE_LIMIT_ADAPTIVE_PARALLEL = true;
23
23
  const DEFAULT_RATE_LIMIT_PARALLEL_FLOOR = 1;
24
- const DEFAULT_RATE_LIMIT_COOLDOWN_MS = 30000;
25
- const DEFAULT_RATE_LIMIT_LAUNCH_BUDGET_PER_MINUTE = 12;
24
+ const DEFAULT_RATE_LIMIT_COOLDOWN_MS = 45000;
25
+ const DEFAULT_RATE_LIMIT_LAUNCH_BUDGET_PER_MINUTE = 8;
26
26
  const DEFAULT_RATE_LIMIT_LAUNCH_BUDGET_WINDOW_MS = 60000;
27
27
  const DEFAULT_AGENT_WAIT_TIMEOUT_SECONDS = 600;
28
28
  const AGENT_WAIT_TIMEOUT_GRACE_MS = 30000;
@@ -35,6 +35,7 @@ const RATE_LIMIT_ERROR_PATTERNS = [
35
35
  /resource exhausted/i,
36
36
  /quota exceeded/i,
37
37
  /exceeded.*quota/i,
38
+ /exceeded retry limit/i,
38
39
  /requests per minute/i,
39
40
  /tokens per minute/i,
40
41
  ];
@@ -44,13 +44,13 @@ const DEFAULT_CONFIG = Object.freeze({
44
44
  maxParallel: 3,
45
45
  timeoutSeconds: 600,
46
46
  maxRetries: 2,
47
- rateLimitMaxRetries: 6,
48
- rateLimitBackoffBaseMs: 1000,
49
- rateLimitBackoffMaxMs: 30000,
47
+ rateLimitMaxRetries: 8,
48
+ rateLimitBackoffBaseMs: 1500,
49
+ rateLimitBackoffMaxMs: 60000,
50
50
  rateLimitAdaptiveParallel: true,
51
51
  rateLimitParallelFloor: 1,
52
- rateLimitCooldownMs: 30000,
53
- rateLimitLaunchBudgetPerMinute: 12,
52
+ rateLimitCooldownMs: 45000,
53
+ rateLimitLaunchBudgetPerMinute: 8,
54
54
  rateLimitLaunchBudgetWindowMs: 60000,
55
55
  apiKeyEnvVar: 'CODEX_API_KEY',
56
56
  bootstrapTemplate: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.0.3",
3
+ "version": "3.0.6",
4
4
  "description": "SCE (Scene Capability Engine) - A CLI tool and npm package for spec-driven development with AI coding assistants.",
5
5
  "main": "index.js",
6
6
  "bin": {