scene-capability-engine 3.0.4 → 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"
@@ -787,6 +787,7 @@ Dual-track handoff integration:
787
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`).
788
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`.
789
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.
790
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`.
791
792
  - Default mode is dependency-aware: spec integration goals are grouped into dependency batches and executed in topological order.
792
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.
@@ -797,6 +798,7 @@ Dual-track handoff integration:
797
798
  - `moqui_baseline.summary` now includes `scope_breakdown`, `coverage_matrix`, and `gap_frequency` for ER/BR/decision closure tracking.
798
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).
799
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.
800
802
  - Run output includes `release_gate_preflight` (latest release gate history signal snapshot + blocked reasons) and carries this context into `warnings`.
801
803
  - `release_gate_preflight` is advisory by default; use `--require-release-gate-preflight` to hard-fail when preflight is unavailable/blocked.
802
804
  - When Moqui baseline/capability gates fail, sce auto-generates remediation queue lines at `.kiro/auto/moqui-remediation.lines`.
@@ -827,6 +829,7 @@ Dual-track handoff integration:
827
829
 
828
830
  Moqui template library lexicon audit (script-level governance helper):
829
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`).
830
833
  - By default, template capability auditing is scoped to `manifest.templates` (when matched), reducing noise from unrelated templates.
831
834
  - Template scope matching normalizes `sce.scene--*` / `kse.scene--*` prefixes, so renamed template namespaces still map correctly.
832
835
 
@@ -838,12 +841,14 @@ Recommended `.kiro/config/orchestrator.json`:
838
841
  "maxParallel": 3,
839
842
  "timeoutSeconds": 900,
840
843
  "maxRetries": 2,
841
- "rateLimitMaxRetries": 6,
842
- "rateLimitBackoffBaseMs": 1000,
843
- "rateLimitBackoffMaxMs": 30000,
844
+ "rateLimitMaxRetries": 8,
845
+ "rateLimitBackoffBaseMs": 1500,
846
+ "rateLimitBackoffMaxMs": 60000,
844
847
  "rateLimitAdaptiveParallel": true,
845
848
  "rateLimitParallelFloor": 1,
846
- "rateLimitCooldownMs": 30000,
849
+ "rateLimitCooldownMs": 45000,
850
+ "rateLimitLaunchBudgetPerMinute": 8,
851
+ "rateLimitLaunchBudgetWindowMs": 60000,
847
852
  "apiKeyEnvVar": "CODEX_API_KEY",
848
853
  "codexArgs": ["--skip-git-repo-check"],
849
854
  "codexCommand": "npx @openai/codex"
@@ -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
@@ -13472,6 +13585,18 @@ async function buildAutoHandoffCapabilityMatrix(projectPath, options = {}) {
13472
13585
  capability_count: Array.isArray(plan.handoff && plan.handoff.capabilities)
13473
13586
  ? plan.handoff.capabilities.length
13474
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
+ },
13475
13600
  capabilities: Array.isArray(plan.handoff && plan.handoff.capabilities)
13476
13601
  ? plan.handoff.capabilities
13477
13602
  : []
@@ -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.4",
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": {