scene-capability-engine 3.6.45 → 3.6.47

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 (72) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -0
  3. package/README.zh.md +1 -0
  4. package/docs/agent-runtime/symbol-evidence.schema.json +1 -1
  5. package/docs/command-reference.md +8 -0
  6. package/docs/interactive-customization/dialogue-governance-policy-baseline.json +4 -1
  7. package/docs/interactive-customization/embedded-assistant-authorization-dialogue-rules.md +5 -0
  8. package/docs/releases/README.md +2 -0
  9. package/docs/releases/v3.6.46.md +23 -0
  10. package/docs/releases/v3.6.47.md +23 -0
  11. package/docs/sce-business-mode-map.md +2 -1
  12. package/docs/sce-capability-matrix-e2e-example.md +2 -1
  13. package/docs/security-governance-default-baseline.md +2 -0
  14. package/docs/starter-kit/README.md +3 -0
  15. package/docs/zh/releases/README.md +2 -0
  16. package/docs/zh/releases/v3.6.46.md +23 -0
  17. package/docs/zh/releases/v3.6.47.md +23 -0
  18. package/lib/workspace/takeover-baseline.js +293 -1
  19. package/package.json +6 -2
  20. package/scripts/auto-strategy-router.js +231 -0
  21. package/scripts/capability-mapping-report.js +339 -0
  22. package/scripts/check-branding-consistency.js +140 -0
  23. package/scripts/check-sce-tracking.js +54 -0
  24. package/scripts/check-skip-allowlist.js +94 -0
  25. package/scripts/clarification-first-audit.js +322 -0
  26. package/scripts/errorbook-registry-health-gate.js +172 -0
  27. package/scripts/errorbook-release-gate.js +132 -0
  28. package/scripts/failure-attribution-repair.js +317 -0
  29. package/scripts/git-managed-gate.js +464 -0
  30. package/scripts/interactive-approval-event-projection.js +400 -0
  31. package/scripts/interactive-approval-workflow.js +829 -0
  32. package/scripts/interactive-authorization-tier-evaluate.js +413 -0
  33. package/scripts/interactive-change-plan-gate.js +225 -0
  34. package/scripts/interactive-context-bridge.js +617 -0
  35. package/scripts/interactive-customization-loop.js +1690 -0
  36. package/scripts/interactive-dialogue-governance.js +873 -0
  37. package/scripts/interactive-feedback-log.js +253 -0
  38. package/scripts/interactive-flow-smoke.js +238 -0
  39. package/scripts/interactive-flow.js +1059 -0
  40. package/scripts/interactive-governance-report.js +1112 -0
  41. package/scripts/interactive-intent-build.js +707 -0
  42. package/scripts/interactive-loop-smoke.js +215 -0
  43. package/scripts/interactive-moqui-adapter.js +304 -0
  44. package/scripts/interactive-plan-build.js +426 -0
  45. package/scripts/interactive-runtime-policy-evaluate.js +495 -0
  46. package/scripts/interactive-work-order-build.js +552 -0
  47. package/scripts/matrix-regression-gate.js +167 -0
  48. package/scripts/moqui-core-regression-suite.js +397 -0
  49. package/scripts/moqui-lexicon-audit.js +651 -0
  50. package/scripts/moqui-matrix-remediation-phased-runner.js +865 -0
  51. package/scripts/moqui-matrix-remediation-queue.js +852 -0
  52. package/scripts/moqui-metadata-extract.js +1340 -0
  53. package/scripts/moqui-rebuild-gate.js +167 -0
  54. package/scripts/moqui-release-summary.js +729 -0
  55. package/scripts/moqui-standard-rebuild.js +1370 -0
  56. package/scripts/moqui-template-baseline-report.js +682 -0
  57. package/scripts/npm-package-runtime-asset-check.js +221 -0
  58. package/scripts/problem-closure-gate.js +441 -0
  59. package/scripts/release-asset-integrity-check.js +216 -0
  60. package/scripts/release-asset-nonempty-normalize.js +166 -0
  61. package/scripts/release-drift-evaluate.js +223 -0
  62. package/scripts/release-drift-signals.js +255 -0
  63. package/scripts/release-governance-snapshot-export.js +132 -0
  64. package/scripts/release-ops-weekly-summary.js +934 -0
  65. package/scripts/release-risk-remediation-bundle.js +315 -0
  66. package/scripts/release-weekly-ops-gate.js +423 -0
  67. package/scripts/state-migration-reconciliation-gate.js +110 -0
  68. package/scripts/state-storage-tiering-audit.js +337 -0
  69. package/scripts/steering-content-audit.js +393 -0
  70. package/scripts/symbol-evidence-locate.js +370 -0
  71. package/template/.sce/README.md +1 -0
  72. package/template/.sce/steering/CORE_PRINCIPLES.md +25 -0
@@ -12,6 +12,122 @@ const {
12
12
  } = require('../state/state-storage-policy');
13
13
 
14
14
  const TAKEOVER_BASELINE_SCHEMA_VERSION = '1.0';
15
+ const CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING = '## 11. 业务场景未知时必须先澄清,禁止直接彻底禁用';
16
+ const CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION = [
17
+ CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
18
+ '',
19
+ '- 不了解业务场景、模块、页面、实体或业务约束时,默认动作是先补上下文、缩小范围、生成澄清问题。',
20
+ '- 禁止把“未知业务场景”直接等同于 `deny`、`disable`、answer-only 或其他一刀切兜底禁用。',
21
+ '- 只有在明确命中安全/权限/合规/破坏性规则后,才允许进入阻断;否则必须先完成业务范围澄清。',
22
+ '- 这条规则适用于所有接入 SCE 的项目、模式和交互面,不允许按项目例外绕过。'
23
+ ].join('\n');
24
+ const NO_BLIND_FIX_CORE_PRINCIPLE_HEADING = '## 12. 禁止盲改问题,必须先建立问题契约和证据';
25
+ const NO_BLIND_FIX_CORE_PRINCIPLE_SECTION = [
26
+ NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
27
+ '',
28
+ '- 修改问题前,必须先明确现象、复现条件、影响范围、预期行为和验证方式。',
29
+ '- 缺少日志、数据、接口样本、最小复现或问题契约时,应先补证据,不得靠猜测连续改代码碰运气。',
30
+ '- 若两轮修改仍未收敛,必须回到调试、定位和根因分析,禁止在未理解问题前盲目扩大改动面。'
31
+ ].join('\n');
32
+ const STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING = '## 13. Steering 条目变更必须先评估,禁止随意增删';
33
+ const STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION = [
34
+ STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
35
+ '',
36
+ '- 新增、删除或重写 steering 条目前,必须先评估它是否真属于长期原则,是否与现有条目重复,是否应迁移到 `CURRENT_CONTEXT.md`、Spec 或项目文档。',
37
+ '- steering 变更必须说明触发原因、适用范围以及与现有规则的关系;未经评估,不得把临时偏好、短期任务或偶发结论直接固化进去。',
38
+ '- 接管、升级和治理脚本只能补齐基线、修复漂移,不能把未经评估的项目习惯直接塞进 steering。'
39
+ ].join('\n');
40
+ const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING = '## 14. 问题修复时前后端接口不一致默认以后端契约为准';
41
+ const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION = [
42
+ BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
43
+ '',
44
+ '- 在修改问题的场景下,若前端调用后端 API 出现路径、方法、字段、状态码或响应结构不匹配,默认以后端现有接口契约为准。',
45
+ '- 除非明确要求新建接口或修改后端接口,否则禁止为了迁就前端错误调用去随意改后端实现或契约。',
46
+ '- 默认优先修正前端请求、映射、类型和兼容处理,使其与后端接口保持一致;若怀疑后端契约错误,应先确认再改。'
47
+ ].join('\n');
48
+ const REQUIRED_CORE_PRINCIPLE_SECTIONS = Object.freeze([
49
+ {
50
+ heading: CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
51
+ section: CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION
52
+ },
53
+ {
54
+ heading: NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
55
+ section: NO_BLIND_FIX_CORE_PRINCIPLE_SECTION
56
+ },
57
+ {
58
+ heading: STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
59
+ section: STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION
60
+ },
61
+ {
62
+ heading: BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
63
+ section: BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION
64
+ }
65
+ ]);
66
+
67
+ const ERRORBOOK_REGISTRY_DEFAULTS = Object.freeze({
68
+ enabled: true,
69
+ search_mode: 'remote',
70
+ cache_file: '.sce/errorbook/registry-cache.json',
71
+ sources: [
72
+ {
73
+ name: 'central',
74
+ enabled: true,
75
+ url: 'https://raw.githubusercontent.com/heguangyong/sce-errorbook-registry/main/registry/errorbook-registry.json',
76
+ index_url: 'https://raw.githubusercontent.com/heguangyong/sce-errorbook-registry/main/registry/errorbook-registry.index.json'
77
+ }
78
+ ]
79
+ });
80
+
81
+ const ERRORBOOK_CONVERGENCE_DEFAULTS = Object.freeze({
82
+ enabled: true,
83
+ canonical_mechanism: 'errorbook',
84
+ absorb_project_defined_mechanisms: true,
85
+ disallow_parallel_mechanisms: true,
86
+ intake_inventory_path: '.sce/errorbook/project-intake/custom-mechanism-inventory.json',
87
+ strategy: 'absorb_into_sce_errorbook'
88
+ });
89
+
90
+ const ERRORBOOK_PARALLEL_MECHANISM_KEYWORDS = Object.freeze([
91
+ '错题本',
92
+ '错题',
93
+ '故障复盘',
94
+ '事故复盘',
95
+ '问题复盘',
96
+ '复盘册',
97
+ 'mistake-book',
98
+ 'mistake_book',
99
+ 'mistakebook',
100
+ 'fault-book',
101
+ 'fault_book',
102
+ 'postmortem',
103
+ 'post-mortem',
104
+ 'lessons-learned',
105
+ 'lessons_learned',
106
+ 'defect-ledger',
107
+ 'defect_ledger',
108
+ 'issue-ledger',
109
+ 'issue_ledger',
110
+ 'incident-review',
111
+ 'incident_review'
112
+ ]);
113
+
114
+ const ERRORBOOK_SCAN_IGNORED_DIRS = new Set([
115
+ '.git',
116
+ '.hg',
117
+ '.svn',
118
+ '.sce',
119
+ 'node_modules',
120
+ 'dist',
121
+ 'build',
122
+ 'coverage',
123
+ '.next',
124
+ '.turbo',
125
+ '.idea',
126
+ '.vscode',
127
+ 'tmp',
128
+ 'temp',
129
+ '.tmp'
130
+ ]);
15
131
 
16
132
  const SESSION_GOVERNANCE_DEFAULTS = Object.freeze({
17
133
  schema_version: '1.0',
@@ -217,6 +333,7 @@ const TAKEOVER_DEFAULTS = Object.freeze({
217
333
  max_direct_fix_rounds_before_debug: 2,
218
334
  forbid_bypass_workarounds: true
219
335
  },
336
+ errorbook_convergence: _clone(ERRORBOOK_CONVERGENCE_DEFAULTS),
220
337
  migration_policy: {
221
338
  legacy_kiro_supported: false,
222
339
  require_manual_legacy_migration_confirmation: true
@@ -335,6 +452,113 @@ function _buildTakeoverBaselineConfig(existing, sceVersion) {
335
452
  };
336
453
  }
337
454
 
455
+ function _buildErrorbookRegistryConfig(existing) {
456
+ const base = _isObject(existing) ? _clone(existing) : {};
457
+ return {
458
+ ..._clone(ERRORBOOK_REGISTRY_DEFAULTS),
459
+ ...base,
460
+ sources: Array.isArray(base.sources) && base.sources.length > 0
461
+ ? _clone(base.sources)
462
+ : _clone(ERRORBOOK_REGISTRY_DEFAULTS.sources)
463
+ };
464
+ }
465
+
466
+ function _normalizeRelativePath(value) {
467
+ return `${value || ''}`.replace(/\\/g, '/');
468
+ }
469
+
470
+ function _findParallelErrorbookKeyword(relativePath) {
471
+ const normalized = _normalizeRelativePath(relativePath).toLowerCase();
472
+ return ERRORBOOK_PARALLEL_MECHANISM_KEYWORDS.find((keyword) => normalized.includes(keyword.toLowerCase())) || null;
473
+ }
474
+
475
+ function _shouldSkipErrorbookScanDir(dirName) {
476
+ return ERRORBOOK_SCAN_IGNORED_DIRS.has(`${dirName || ''}`.trim());
477
+ }
478
+
479
+ async function _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem, currentDir = projectPath, depth = 0, findings = []) {
480
+ let entries = [];
481
+ try {
482
+ entries = await fileSystem.readdir(currentDir, { withFileTypes: true });
483
+ } catch (_error) {
484
+ return findings;
485
+ }
486
+
487
+ for (const entry of entries) {
488
+ const absolutePath = path.join(currentDir, entry.name);
489
+ const relativePath = _toRelativePosix(projectPath, absolutePath);
490
+
491
+ if (entry.isDirectory()) {
492
+ if (_shouldSkipErrorbookScanDir(entry.name)) {
493
+ continue;
494
+ }
495
+
496
+ const keyword = _findParallelErrorbookKeyword(relativePath);
497
+ if (keyword) {
498
+ findings.push({
499
+ path: relativePath,
500
+ kind: 'directory',
501
+ keyword,
502
+ action: 'absorb_into_sce_errorbook'
503
+ });
504
+ }
505
+
506
+ if (depth < 5) {
507
+ await _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem, absolutePath, depth + 1, findings);
508
+ }
509
+ continue;
510
+ }
511
+
512
+ if (!entry.isFile()) {
513
+ continue;
514
+ }
515
+
516
+ const keyword = _findParallelErrorbookKeyword(relativePath);
517
+ if (!keyword) {
518
+ continue;
519
+ }
520
+
521
+ findings.push({
522
+ path: relativePath,
523
+ kind: 'file',
524
+ keyword,
525
+ action: 'absorb_into_sce_errorbook'
526
+ });
527
+ }
528
+
529
+ return findings;
530
+ }
531
+
532
+ function _dedupeFindings(findings = []) {
533
+ const seen = new Set();
534
+ return findings.filter((item) => {
535
+ const key = `${item.kind}:${item.path}`;
536
+ if (seen.has(key)) {
537
+ return false;
538
+ }
539
+ seen.add(key);
540
+ return true;
541
+ }).sort((left, right) => `${left.path}`.localeCompare(`${right.path}`));
542
+ }
543
+
544
+ function _buildErrorbookConvergenceInventory(sceVersion, findings = []) {
545
+ const dedupedFindings = _dedupeFindings(findings);
546
+ return {
547
+ schema_version: TAKEOVER_BASELINE_SCHEMA_VERSION,
548
+ canonical_mechanism: 'errorbook',
549
+ strategy: 'absorb_into_sce_errorbook',
550
+ last_aligned_sce_version: sceVersion,
551
+ summary: {
552
+ detected_custom_mechanisms: dedupedFindings.length
553
+ },
554
+ guidance: [
555
+ 'Absorb reusable failure-remediation knowledge into .sce/errorbook instead of keeping project-defined parallel mistake-book flows.',
556
+ 'Use `sce errorbook record` for curated entries and `sce errorbook incident *` for short trial-and-error loops before curation.'
557
+ ],
558
+ findings: dedupedFindings
559
+ };
560
+ }
561
+
338
562
  async function _reconcileJsonFile(filePath, desired, options = {}) {
339
563
  const {
340
564
  projectPath,
@@ -403,6 +627,37 @@ async function _reconcileSteeringContract(projectPath, options = {}) {
403
627
  };
404
628
  }
405
629
 
630
+ async function _reconcileCorePrinciplesBaseline(projectPath, options = {}) {
631
+ const { apply, fileSystem } = options;
632
+ const corePrinciplesPath = path.join(projectPath, SCE_STEERING_DIR, DEFAULT_LAYER_FILES.core_principles);
633
+ const exists = await fileSystem.pathExists(corePrinciplesPath);
634
+ const existingContent = exists ? await fileSystem.readFile(corePrinciplesPath, 'utf8') : '';
635
+ const missingSections = REQUIRED_CORE_PRINCIPLE_SECTIONS.filter(({ heading }) => !existingContent.includes(heading));
636
+ const changed = missingSections.length > 0;
637
+
638
+ if (apply && changed) {
639
+ const normalized = `${existingContent || ''}`.trimEnd();
640
+ const appendedSections = missingSections.map((item) => item.section).join('\n\n');
641
+ const nextContent = normalized
642
+ ? `${normalized}\n\n${appendedSections}\n`
643
+ : `${appendedSections}\n`;
644
+ await fileSystem.ensureDir(path.dirname(corePrinciplesPath));
645
+ await fileSystem.writeFile(corePrinciplesPath, nextContent, 'utf8');
646
+ }
647
+
648
+ return {
649
+ path: _toRelativePosix(projectPath, corePrinciplesPath),
650
+ existed: exists,
651
+ changed,
652
+ status: !exists ? (changed ? 'created' : 'unchanged') : (changed ? 'updated' : 'unchanged'),
653
+ managed_by: 'takeover-baseline',
654
+ details: {
655
+ missing_required_headings_before: missingSections.map((item) => item.heading),
656
+ required_headings: REQUIRED_CORE_PRINCIPLE_SECTIONS.map((item) => item.heading)
657
+ }
658
+ };
659
+ }
660
+
406
661
  function _summarize(items) {
407
662
  const summary = {
408
663
  created: 0,
@@ -477,33 +732,38 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
477
732
  const adoptionPath = path.join(sceRoot, 'adoption-config.json');
478
733
  const autoConfigPath = path.join(sceRoot, 'auto', 'config.json');
479
734
  const takeoverConfigPath = path.join(sceRoot, 'config', 'takeover-baseline.json');
735
+ const errorbookRegistryPath = path.join(sceRoot, 'config', 'errorbook-registry.json');
480
736
  const sessionGovernancePath = path.join(sceRoot, 'config', 'session-governance.json');
481
737
  const specDomainPolicyPath = path.join(sceRoot, 'config', 'spec-domain-policy.json');
482
738
  const problemEvalPolicyPath = path.join(sceRoot, 'config', 'problem-eval-policy.json');
483
739
  const problemClosurePolicyPath = path.join(sceRoot, 'config', 'problem-closure-policy.json');
484
740
  const studioIntakePolicyPath = path.join(sceRoot, 'config', 'studio-intake-policy.json');
485
741
  const stateStoragePolicyPath = path.join(sceRoot, 'config', 'state-storage-policy.json');
742
+ const errorbookInventoryPath = path.join(sceRoot, 'errorbook', 'project-intake', 'custom-mechanism-inventory.json');
486
743
  const reportPath = path.join(sceRoot, 'reports', 'takeover-baseline-latest.json');
487
744
 
488
745
  const existingAdoption = await _readJsonSafe(adoptionPath, fileSystem);
489
746
  const existingAuto = await _readJsonSafe(autoConfigPath, fileSystem);
490
747
  const existingTakeover = await _readJsonSafe(takeoverConfigPath, fileSystem);
748
+ const existingErrorbookRegistry = await _readJsonSafe(errorbookRegistryPath, fileSystem);
491
749
  const existingSessionGovernance = await _readJsonSafe(sessionGovernancePath, fileSystem);
492
750
  const existingSpecDomainPolicy = await _readJsonSafe(specDomainPolicyPath, fileSystem);
493
751
  const existingProblemEvalPolicy = await _readJsonSafe(problemEvalPolicyPath, fileSystem);
494
752
  const existingProblemClosurePolicy = await _readJsonSafe(problemClosurePolicyPath, fileSystem);
495
753
  const existingStudioIntakePolicy = await _readJsonSafe(studioIntakePolicyPath, fileSystem);
496
754
  const existingStateStoragePolicy = await _readJsonSafe(stateStoragePolicyPath, fileSystem);
497
-
498
755
  const desiredAdoption = _buildAdoptionConfig(existingAdoption, nowIso, sceVersion);
499
756
  const desiredAutoConfig = _buildAutoConfig(existingAuto);
500
757
  const desiredTakeover = _buildTakeoverBaselineConfig(existingTakeover, sceVersion);
758
+ const desiredErrorbookRegistry = _buildErrorbookRegistryConfig(existingErrorbookRegistry);
501
759
  const desiredSessionGovernance = _deepMerge(existingSessionGovernance || {}, SESSION_GOVERNANCE_DEFAULTS);
502
760
  const desiredSpecDomainPolicy = _deepMerge(existingSpecDomainPolicy || {}, SPEC_DOMAIN_POLICY_DEFAULTS);
503
761
  const desiredProblemEvalPolicy = _deepMerge(existingProblemEvalPolicy || {}, PROBLEM_EVAL_POLICY_DEFAULTS);
504
762
  const desiredProblemClosurePolicy = _deepMerge(existingProblemClosurePolicy || {}, PROBLEM_CLOSURE_POLICY_DEFAULTS);
505
763
  const desiredStudioIntakePolicy = _deepMerge(existingStudioIntakePolicy || {}, STUDIO_INTAKE_POLICY_DEFAULTS);
506
764
  const desiredStateStoragePolicy = _deepMerge(existingStateStoragePolicy || {}, cloneStateStoragePolicyDefaults());
765
+ const customErrorbookFindings = await _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem);
766
+ const desiredErrorbookInventory = _buildErrorbookConvergenceInventory(sceVersion, customErrorbookFindings);
507
767
 
508
768
  const fileResults = [];
509
769
  fileResults.push(await _reconcileJsonFile(adoptionPath, desiredAdoption, {
@@ -521,6 +781,11 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
521
781
  apply,
522
782
  fileSystem
523
783
  }));
784
+ fileResults.push(await _reconcileJsonFile(errorbookRegistryPath, desiredErrorbookRegistry, {
785
+ projectPath,
786
+ apply,
787
+ fileSystem
788
+ }));
524
789
  fileResults.push(await _reconcileJsonFile(sessionGovernancePath, desiredSessionGovernance, {
525
790
  projectPath,
526
791
  apply,
@@ -551,10 +816,20 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
551
816
  apply,
552
817
  fileSystem
553
818
  }));
819
+ fileResults.push(await _reconcileJsonFile(errorbookInventoryPath, desiredErrorbookInventory, {
820
+ projectPath,
821
+ apply,
822
+ fileSystem,
823
+ managedBy: 'errorbook-convergence'
824
+ }));
554
825
  fileResults.push(await _reconcileSteeringContract(projectPath, {
555
826
  apply,
556
827
  fileSystem
557
828
  }));
829
+ fileResults.push(await _reconcileCorePrinciplesBaseline(projectPath, {
830
+ apply,
831
+ fileSystem
832
+ }));
558
833
 
559
834
  const auditFiles = _toAuditStatus(fileResults, apply);
560
835
  const summary = _summarize(auditFiles);
@@ -571,6 +846,12 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
571
846
  sce_version: sceVersion,
572
847
  drift_count: driftCount,
573
848
  enforced_defaults: _clone(TAKEOVER_DEFAULTS),
849
+ errorbook_convergence: {
850
+ canonical_mechanism: 'errorbook',
851
+ strategy: 'absorb_into_sce_errorbook',
852
+ detected_custom_mechanism_count: desiredErrorbookInventory.summary.detected_custom_mechanisms,
853
+ inventory_file: _toRelativePosix(projectPath, errorbookInventoryPath)
854
+ },
574
855
  files: auditFiles,
575
856
  summary
576
857
  };
@@ -595,6 +876,17 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
595
876
  }
596
877
 
597
878
  module.exports = {
879
+ CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
880
+ CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION,
881
+ NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
882
+ NO_BLIND_FIX_CORE_PRINCIPLE_SECTION,
883
+ STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
884
+ STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION,
885
+ BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
886
+ BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION,
887
+ REQUIRED_CORE_PRINCIPLE_SECTIONS,
888
+ ERRORBOOK_REGISTRY_DEFAULTS,
889
+ ERRORBOOK_CONVERGENCE_DEFAULTS,
598
890
  TAKEOVER_BASELINE_SCHEMA_VERSION,
599
891
  TAKEOVER_DEFAULTS,
600
892
  SESSION_GOVERNANCE_DEFAULTS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.6.45",
3
+ "version": "3.6.47",
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": {
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "bin/",
12
12
  "lib/",
13
+ "scripts/",
13
14
  "template/",
14
15
  "!template/.sce/tools/__pycache__/",
15
16
  "!template/.sce/tools/**/*.pyc",
@@ -37,10 +38,13 @@
37
38
  "test:interactive-flow-smoke": "node scripts/interactive-flow-smoke.js --json",
38
39
  "test:skip-audit": "node scripts/check-skip-allowlist.js",
39
40
  "test:sce-tracking": "node scripts/check-sce-tracking.js",
41
+ "gate:npm-runtime-assets": "node scripts/npm-package-runtime-asset-check.js --fail-on-violation",
40
42
  "test:brand-consistency": "node scripts/check-branding-consistency.js",
41
43
  "audit:steering": "node scripts/steering-content-audit.js --fail-on-error",
44
+ "audit:clarification-first": "node scripts/clarification-first-audit.js --fail-on-violation",
42
45
  "audit:state-storage": "node scripts/state-storage-tiering-audit.js",
43
46
  "report:steering-audit": "node scripts/steering-content-audit.js --json",
47
+ "report:clarification-first-audit": "node scripts/clarification-first-audit.js --json",
44
48
  "report:state-storage": "node scripts/state-storage-tiering-audit.js --json",
45
49
  "report:interactive-approval-projection": "node scripts/interactive-approval-event-projection.js --action doctor --json",
46
50
  "audit:interactive-approval-projection": "node scripts/interactive-approval-event-projection.js --action doctor --fail-on-drift --fail-on-parse-error",
@@ -82,7 +86,7 @@
82
86
  "gate:release-asset-integrity": "node scripts/release-asset-integrity-check.js",
83
87
  "report:release-risk-remediation": "node scripts/release-risk-remediation-bundle.js --json",
84
88
  "report:moqui-core-regression": "node scripts/moqui-core-regression-suite.js --json",
85
- "prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run test:brand-consistency && npm run audit:steering && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
89
+ "prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run gate:npm-runtime-assets && npm run test:brand-consistency && npm run audit:steering && npm run audit:clarification-first && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
86
90
  "publish:manual": "npm publish --access public",
87
91
  "install-global": "npm install -g .",
88
92
  "uninstall-global": "npm uninstall -g scene-capability-engine"
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ function readJsonFile(filePath) {
8
+ const resolved = path.resolve(filePath);
9
+ if (!fs.existsSync(resolved)) {
10
+ throw new Error(`file not found: ${filePath}`);
11
+ }
12
+ return JSON.parse(fs.readFileSync(resolved, 'utf8'));
13
+ }
14
+
15
+ function toBool(value, fallback = false) {
16
+ if (typeof value === 'boolean') {
17
+ return value;
18
+ }
19
+ if (typeof value === 'string') {
20
+ const lowered = value.trim().toLowerCase();
21
+ if (['1', 'true', 'yes', 'y', 'on'].includes(lowered)) {
22
+ return true;
23
+ }
24
+ if (['0', 'false', 'no', 'n', 'off'].includes(lowered)) {
25
+ return false;
26
+ }
27
+ }
28
+ return fallback;
29
+ }
30
+
31
+ function toFiniteNumber(value, fallback = 0) {
32
+ const num = Number(value);
33
+ return Number.isFinite(num) ? num : fallback;
34
+ }
35
+
36
+ function normalizeInput(input = {}) {
37
+ const goalTypeRaw = typeof input.goal_type === 'string' ? input.goal_type.trim().toLowerCase() : '';
38
+ return {
39
+ goal_type: goalTypeRaw || 'unknown',
40
+ requires_write: toBool(input.requires_write, false),
41
+ high_risk: toBool(input.high_risk, false),
42
+ last_run_failed: toBool(input.last_run_failed, false),
43
+ has_rollback_checkpoint: toBool(input.has_rollback_checkpoint, false),
44
+ test_failures: toFiniteNumber(input.test_failures, 0),
45
+ changed_files: toFiniteNumber(input.changed_files, 0),
46
+ user_explicit_answer_only: toBool(input.user_explicit_answer_only, false),
47
+ user_explicit_rollback: toBool(input.user_explicit_rollback, false)
48
+ };
49
+ }
50
+
51
+ function resolvePolicy(policy = {}) {
52
+ const fallback = {
53
+ answer_only_goal_types: ['question', 'analysis', 'explain', 'summarize'],
54
+ rollback_when: {
55
+ require_checkpoint: true,
56
+ require_high_risk_or_explicit: true
57
+ },
58
+ code_fix_when_tests_fail: true
59
+ };
60
+ const answerTypes = Array.isArray(policy.answer_only_goal_types)
61
+ ? policy.answer_only_goal_types
62
+ .map(item => `${item || ''}`.trim().toLowerCase())
63
+ .filter(Boolean)
64
+ : fallback.answer_only_goal_types;
65
+ return {
66
+ answer_only_goal_types: answerTypes.length > 0 ? answerTypes : fallback.answer_only_goal_types,
67
+ rollback_when: {
68
+ require_checkpoint: toBool(
69
+ policy.rollback_when && policy.rollback_when.require_checkpoint,
70
+ fallback.rollback_when.require_checkpoint
71
+ ),
72
+ require_high_risk_or_explicit: toBool(
73
+ policy.rollback_when && policy.rollback_when.require_high_risk_or_explicit,
74
+ fallback.rollback_when.require_high_risk_or_explicit
75
+ )
76
+ },
77
+ code_fix_when_tests_fail: toBool(policy.code_fix_when_tests_fail, fallback.code_fix_when_tests_fail)
78
+ };
79
+ }
80
+
81
+ function evaluateStrategy(input = {}, policyInput = {}) {
82
+ const payload = normalizeInput(input);
83
+ const policy = resolvePolicy(policyInput);
84
+ const reasons = [];
85
+ let decision = 'answer_only';
86
+ let confidence = 'low';
87
+
88
+ if (payload.user_explicit_answer_only) {
89
+ decision = 'answer_only';
90
+ confidence = 'high';
91
+ reasons.push('explicit user instruction: answer only');
92
+ } else if (payload.user_explicit_rollback) {
93
+ const checkpointOk = !policy.rollback_when.require_checkpoint || payload.has_rollback_checkpoint;
94
+ const riskGateOk = !policy.rollback_when.require_high_risk_or_explicit || payload.high_risk || payload.user_explicit_rollback;
95
+ if (checkpointOk && riskGateOk) {
96
+ decision = 'rollback';
97
+ confidence = 'high';
98
+ reasons.push('explicit user instruction: rollback');
99
+ } else {
100
+ decision = 'answer_only';
101
+ confidence = 'medium';
102
+ reasons.push('rollback requested but preconditions are not met');
103
+ }
104
+ } else if (
105
+ payload.last_run_failed
106
+ && payload.has_rollback_checkpoint
107
+ && payload.high_risk
108
+ && payload.changed_files > 0
109
+ ) {
110
+ decision = 'rollback';
111
+ confidence = 'high';
112
+ reasons.push('last run failed with high risk and rollback checkpoint available');
113
+ } else if (
114
+ policy.answer_only_goal_types.includes(payload.goal_type)
115
+ && !payload.requires_write
116
+ ) {
117
+ decision = 'answer_only';
118
+ confidence = 'high';
119
+ reasons.push(`goal_type=${payload.goal_type} with no write requirement`);
120
+ } else if (
121
+ policy.code_fix_when_tests_fail
122
+ && payload.test_failures > 0
123
+ && payload.changed_files > 0
124
+ ) {
125
+ decision = 'code_fix';
126
+ confidence = 'high';
127
+ reasons.push('tests failing after code changes, prioritize focused repair');
128
+ } else if (payload.requires_write || payload.goal_type === 'feature' || payload.goal_type === 'bugfix') {
129
+ decision = 'code_change';
130
+ confidence = 'medium';
131
+ reasons.push('write-required goal needs implementation changes');
132
+ } else {
133
+ decision = 'answer_only';
134
+ confidence = 'low';
135
+ reasons.push('insufficient signals for safe code changes');
136
+ }
137
+
138
+ const next_actions = [];
139
+ if (decision === 'rollback') {
140
+ next_actions.push('execute rollback to latest stable checkpoint');
141
+ next_actions.push('collect failure evidence before reattempt');
142
+ } else if (decision === 'code_fix') {
143
+ next_actions.push('locate failing symbols and failing tests first');
144
+ next_actions.push('apply minimal patch and re-run targeted tests');
145
+ } else if (decision === 'code_change') {
146
+ next_actions.push('confirm affected scope and symbol locations');
147
+ next_actions.push('implement change and run validation tests');
148
+ } else {
149
+ next_actions.push('answer request with evidence and constraints');
150
+ next_actions.push('avoid repository writes in current turn');
151
+ }
152
+
153
+ return {
154
+ mode: 'auto-strategy-router',
155
+ decision,
156
+ confidence,
157
+ reasons,
158
+ next_actions,
159
+ input: payload,
160
+ policy
161
+ };
162
+ }
163
+
164
+ function parseArgs(argv = []) {
165
+ const options = {
166
+ input: null,
167
+ inputFile: '',
168
+ policyFile: '',
169
+ json: false
170
+ };
171
+ for (let i = 0; i < argv.length; i += 1) {
172
+ const token = argv[i];
173
+ if (token === '--input') {
174
+ options.input = argv[i + 1] || '';
175
+ i += 1;
176
+ continue;
177
+ }
178
+ if (token === '--input-file') {
179
+ options.inputFile = argv[i + 1] || '';
180
+ i += 1;
181
+ continue;
182
+ }
183
+ if (token === '--policy-file') {
184
+ options.policyFile = argv[i + 1] || '';
185
+ i += 1;
186
+ continue;
187
+ }
188
+ if (token === '--json') {
189
+ options.json = true;
190
+ continue;
191
+ }
192
+ if (token === '-h' || token === '--help') {
193
+ console.log([
194
+ 'Usage:',
195
+ ' node scripts/auto-strategy-router.js --input-file <path> [--policy-file <path>] --json',
196
+ ' node scripts/auto-strategy-router.js --input \'{\"goal_type\":\"bugfix\",\"requires_write\":true}\' --json'
197
+ ].join('\n'));
198
+ process.exit(0);
199
+ }
200
+ }
201
+ return options;
202
+ }
203
+
204
+ if (require.main === module) {
205
+ const args = parseArgs(process.argv.slice(2));
206
+ let inputPayload = {};
207
+ let policyPayload = {};
208
+ if (args.inputFile) {
209
+ inputPayload = readJsonFile(args.inputFile);
210
+ } else if (args.input) {
211
+ inputPayload = JSON.parse(args.input);
212
+ }
213
+ if (args.policyFile) {
214
+ policyPayload = readJsonFile(args.policyFile);
215
+ }
216
+ const result = evaluateStrategy(inputPayload, policyPayload);
217
+ if (args.json) {
218
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
219
+ } else {
220
+ process.stdout.write(
221
+ `[auto-strategy-router] decision=${result.decision} confidence=${result.confidence} reasons=${result.reasons.join('; ')}\n`
222
+ );
223
+ }
224
+ }
225
+
226
+ module.exports = {
227
+ evaluateStrategy,
228
+ normalizeInput,
229
+ parseArgs,
230
+ resolvePolicy
231
+ };