scene-capability-engine 3.6.51 → 3.6.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/docs/command-reference.md +7 -4
- package/docs/errorbook-registry.md +24 -5
- package/docs/magicball-adaptation-task-checklist-v1.md +18 -1
- package/docs/magicball-cli-invocation-examples.md +7 -0
- package/docs/magicball-integration-issue-tracker.md +2 -2
- package/docs/magicball-sce-adaptation-guide.md +2 -2
- package/docs/magicball-write-auth-adaptation-guide.md +7 -0
- package/docs/multi-agent-coordination-guide.md +2 -2
- package/docs/releases/v3.6.52.md +20 -0
- package/docs/releases/v3.6.53.md +19 -0
- package/docs/zh/releases/v3.6.52.md +20 -0
- package/docs/zh/releases/v3.6.53.md +19 -0
- package/lib/commands/app.js +144 -17
- package/lib/commands/errorbook.js +104 -7
- package/lib/commands/mode.js +40 -10
- package/lib/workspace/collab-governance-audit.js +261 -0
- package/lib/workspace/takeover-baseline.js +90 -3
- package/package.json +1 -1
- package/template/.sce/README.md +2 -2
- package/template/.sce/config/errorbook-registry.json +14 -0
- package/template/.sce/knowledge/errorbook/project-shared-registry.json +15 -0
|
@@ -18,6 +18,15 @@ const TEMPORARY_MITIGATION_TAG = 'temporary-mitigation';
|
|
|
18
18
|
const DEFAULT_ERRORBOOK_REGISTRY_CONFIG = '.sce/config/errorbook-registry.json';
|
|
19
19
|
const DEFAULT_ERRORBOOK_REGISTRY_CACHE = '.sce/errorbook/registry-cache.json';
|
|
20
20
|
const DEFAULT_ERRORBOOK_REGISTRY_EXPORT = '.sce/errorbook/exports/errorbook-registry-export.json';
|
|
21
|
+
const DEFAULT_PROJECT_SHARED_ERRORBOOK_REGISTRY = '.sce/knowledge/errorbook/project-shared-registry.json';
|
|
22
|
+
const DEFAULT_PROJECT_SHARED_ERRORBOOK_STATUSES = Object.freeze(['verified', 'promoted']);
|
|
23
|
+
const DEFAULT_PROJECT_SHARED_ERRORBOOK_MIN_QUALITY = 75;
|
|
24
|
+
const DEFAULT_PROJECT_SHARED_ERRORBOOK_PROJECTION = Object.freeze({
|
|
25
|
+
enabled: true,
|
|
26
|
+
file: DEFAULT_PROJECT_SHARED_ERRORBOOK_REGISTRY,
|
|
27
|
+
statuses: [...DEFAULT_PROJECT_SHARED_ERRORBOOK_STATUSES],
|
|
28
|
+
min_quality: DEFAULT_PROJECT_SHARED_ERRORBOOK_MIN_QUALITY
|
|
29
|
+
});
|
|
21
30
|
const STATUS_RANK = Object.freeze({
|
|
22
31
|
deprecated: 0,
|
|
23
32
|
candidate: 1,
|
|
@@ -107,6 +116,10 @@ function nowIso() {
|
|
|
107
116
|
return new Date().toISOString();
|
|
108
117
|
}
|
|
109
118
|
|
|
119
|
+
function cloneJson(value) {
|
|
120
|
+
return JSON.parse(JSON.stringify(value));
|
|
121
|
+
}
|
|
122
|
+
|
|
110
123
|
function normalizeText(value) {
|
|
111
124
|
if (typeof value !== 'string') {
|
|
112
125
|
return '';
|
|
@@ -1036,6 +1049,26 @@ function normalizeStatusList(values = [], fallback = ['promoted']) {
|
|
|
1036
1049
|
return unique;
|
|
1037
1050
|
}
|
|
1038
1051
|
|
|
1052
|
+
function normalizeProjectSharedProjection(input = {}) {
|
|
1053
|
+
const candidate = input && typeof input === 'object' && !Array.isArray(input)
|
|
1054
|
+
? input
|
|
1055
|
+
: {};
|
|
1056
|
+
const minQualityCandidate = candidate.min_quality ?? candidate.minQuality;
|
|
1057
|
+
const minQuality = Number.isFinite(Number(minQualityCandidate))
|
|
1058
|
+
? Math.max(0, Math.min(100, Number(minQualityCandidate)))
|
|
1059
|
+
: DEFAULT_PROJECT_SHARED_ERRORBOOK_MIN_QUALITY;
|
|
1060
|
+
|
|
1061
|
+
return {
|
|
1062
|
+
enabled: normalizeBoolean(candidate.enabled, true),
|
|
1063
|
+
file: normalizeText(candidate.file || candidate.out || candidate.path || DEFAULT_PROJECT_SHARED_ERRORBOOK_REGISTRY),
|
|
1064
|
+
statuses: normalizeStatusList(
|
|
1065
|
+
candidate.statuses || candidate.status || DEFAULT_PROJECT_SHARED_ERRORBOOK_STATUSES,
|
|
1066
|
+
DEFAULT_PROJECT_SHARED_ERRORBOOK_STATUSES
|
|
1067
|
+
),
|
|
1068
|
+
min_quality: minQuality
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1039
1072
|
function normalizeRegistrySource(input = {}) {
|
|
1040
1073
|
const candidate = input || {};
|
|
1041
1074
|
const name = normalizeText(candidate.name) || 'default';
|
|
@@ -1067,7 +1100,8 @@ async function readErrorbookRegistryConfig(paths, fileSystem = fs) {
|
|
|
1067
1100
|
enabled: false,
|
|
1068
1101
|
search_mode: 'cache',
|
|
1069
1102
|
cache_file: DEFAULT_ERRORBOOK_REGISTRY_CACHE,
|
|
1070
|
-
sources: []
|
|
1103
|
+
sources: [],
|
|
1104
|
+
project_shared_projection: cloneJson(DEFAULT_PROJECT_SHARED_ERRORBOOK_PROJECTION)
|
|
1071
1105
|
};
|
|
1072
1106
|
if (!await fileSystem.pathExists(paths.configFile)) {
|
|
1073
1107
|
return fallback;
|
|
@@ -1083,7 +1117,55 @@ async function readErrorbookRegistryConfig(paths, fileSystem = fs) {
|
|
|
1083
1117
|
enabled: normalizeBoolean(payload.enabled, true),
|
|
1084
1118
|
search_mode: normalizeRegistryMode(payload.search_mode || payload.searchMode, 'cache'),
|
|
1085
1119
|
cache_file: normalizeText(payload.cache_file || payload.cacheFile || DEFAULT_ERRORBOOK_REGISTRY_CACHE),
|
|
1086
|
-
sources
|
|
1120
|
+
sources,
|
|
1121
|
+
project_shared_projection: normalizeProjectSharedProjection(
|
|
1122
|
+
payload.project_shared_projection || payload.projectSharedProjection
|
|
1123
|
+
)
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
async function refreshProjectSharedErrorbookProjection(projectPath, fileSystem = fs, options = {}) {
|
|
1128
|
+
const registryPaths = resolveErrorbookRegistryPaths(projectPath, {
|
|
1129
|
+
configPath: options.config
|
|
1130
|
+
});
|
|
1131
|
+
const registryConfig = await readErrorbookRegistryConfig(registryPaths, fileSystem);
|
|
1132
|
+
const projection = normalizeProjectSharedProjection(
|
|
1133
|
+
options.projectSharedProjection || registryConfig.project_shared_projection
|
|
1134
|
+
);
|
|
1135
|
+
const projectionFile = resolveProjectPath(
|
|
1136
|
+
projectPath,
|
|
1137
|
+
projection.file,
|
|
1138
|
+
DEFAULT_PROJECT_SHARED_ERRORBOOK_REGISTRY
|
|
1139
|
+
);
|
|
1140
|
+
|
|
1141
|
+
if (projection.enabled !== true) {
|
|
1142
|
+
return {
|
|
1143
|
+
enabled: false,
|
|
1144
|
+
refreshed: false,
|
|
1145
|
+
file: projectionFile,
|
|
1146
|
+
statuses: projection.statuses,
|
|
1147
|
+
min_quality: projection.min_quality,
|
|
1148
|
+
total_entries: 0
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
const exportResult = await runErrorbookExportCommand({
|
|
1153
|
+
out: projection.file,
|
|
1154
|
+
status: projection.statuses.join(','),
|
|
1155
|
+
minQuality: projection.min_quality,
|
|
1156
|
+
silent: true
|
|
1157
|
+
}, {
|
|
1158
|
+
projectPath,
|
|
1159
|
+
fileSystem
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
return {
|
|
1163
|
+
enabled: true,
|
|
1164
|
+
refreshed: true,
|
|
1165
|
+
file: exportResult.out_file,
|
|
1166
|
+
statuses: exportResult.statuses,
|
|
1167
|
+
min_quality: exportResult.min_quality,
|
|
1168
|
+
total_entries: exportResult.total_entries
|
|
1087
1169
|
};
|
|
1088
1170
|
}
|
|
1089
1171
|
|
|
@@ -1322,6 +1404,7 @@ async function searchRegistryRemote(options = {}, dependencies = {}) {
|
|
|
1322
1404
|
|
|
1323
1405
|
const warnings = [];
|
|
1324
1406
|
let shardSources = [];
|
|
1407
|
+
const localFileSource = !isHttpSource(source.source);
|
|
1325
1408
|
if (source.index_url) {
|
|
1326
1409
|
try {
|
|
1327
1410
|
const indexPayload = await loadRegistryPayload(projectPath, source.index_url, fileSystem);
|
|
@@ -1332,7 +1415,10 @@ async function searchRegistryRemote(options = {}, dependencies = {}) {
|
|
|
1332
1415
|
}
|
|
1333
1416
|
|
|
1334
1417
|
if (shardSources.length === 0) {
|
|
1335
|
-
if (
|
|
1418
|
+
if (localFileSource) {
|
|
1419
|
+
shardSources = [source.source];
|
|
1420
|
+
warnings.push('local registry file source scanned directly without index');
|
|
1421
|
+
} else if (allowRemoteFullscan) {
|
|
1336
1422
|
shardSources = [source.source];
|
|
1337
1423
|
warnings.push('remote index unavailable; fallback to full-source scan');
|
|
1338
1424
|
} else {
|
|
@@ -1769,13 +1855,15 @@ async function runErrorbookRecordCommand(options = {}, dependencies = {}) {
|
|
|
1769
1855
|
const incidentLoop = await syncIncidentLoopForRecord(paths, normalized, entry, {
|
|
1770
1856
|
nowIso: entry.updated_at
|
|
1771
1857
|
}, fileSystem);
|
|
1858
|
+
const projectSharedProjection = await refreshProjectSharedErrorbookProjection(projectPath, fileSystem, options);
|
|
1772
1859
|
|
|
1773
1860
|
const result = {
|
|
1774
1861
|
mode: 'errorbook-record',
|
|
1775
1862
|
created,
|
|
1776
1863
|
deduplicated,
|
|
1777
1864
|
entry,
|
|
1778
|
-
incident_loop: incidentLoop
|
|
1865
|
+
incident_loop: incidentLoop,
|
|
1866
|
+
project_shared_projection: projectSharedProjection
|
|
1779
1867
|
};
|
|
1780
1868
|
|
|
1781
1869
|
if (options.json) {
|
|
@@ -2575,11 +2663,13 @@ async function runErrorbookPromoteCommand(options = {}, dependencies = {}) {
|
|
|
2575
2663
|
}
|
|
2576
2664
|
index.entries.sort((left, right) => `${right.updated_at}`.localeCompare(`${left.updated_at}`));
|
|
2577
2665
|
await writeErrorbookIndex(paths, index, fileSystem);
|
|
2666
|
+
const projectSharedProjection = await refreshProjectSharedErrorbookProjection(projectPath, fileSystem, options);
|
|
2578
2667
|
|
|
2579
2668
|
const result = {
|
|
2580
2669
|
mode: 'errorbook-promote',
|
|
2581
2670
|
promoted: true,
|
|
2582
|
-
entry
|
|
2671
|
+
entry,
|
|
2672
|
+
project_shared_projection: projectSharedProjection
|
|
2583
2673
|
};
|
|
2584
2674
|
|
|
2585
2675
|
if (options.json) {
|
|
@@ -2672,11 +2762,13 @@ async function runErrorbookDeprecateCommand(options = {}, dependencies = {}) {
|
|
|
2672
2762
|
}
|
|
2673
2763
|
index.entries.sort((left, right) => `${right.updated_at}`.localeCompare(`${left.updated_at}`));
|
|
2674
2764
|
await writeErrorbookIndex(paths, index, fileSystem);
|
|
2765
|
+
const projectSharedProjection = await refreshProjectSharedErrorbookProjection(projectPath, fileSystem, options);
|
|
2675
2766
|
|
|
2676
2767
|
const result = {
|
|
2677
2768
|
mode: 'errorbook-deprecate',
|
|
2678
2769
|
deprecated: true,
|
|
2679
|
-
entry
|
|
2770
|
+
entry,
|
|
2771
|
+
project_shared_projection: projectSharedProjection
|
|
2680
2772
|
};
|
|
2681
2773
|
|
|
2682
2774
|
if (options.json) {
|
|
@@ -2744,11 +2836,13 @@ async function runErrorbookRequalifyCommand(options = {}, dependencies = {}) {
|
|
|
2744
2836
|
}
|
|
2745
2837
|
index.entries.sort((left, right) => `${right.updated_at}`.localeCompare(`${left.updated_at}`));
|
|
2746
2838
|
await writeErrorbookIndex(paths, index, fileSystem);
|
|
2839
|
+
const projectSharedProjection = await refreshProjectSharedErrorbookProjection(projectPath, fileSystem, options);
|
|
2747
2840
|
|
|
2748
2841
|
const result = {
|
|
2749
2842
|
mode: 'errorbook-requalify',
|
|
2750
2843
|
requalified: true,
|
|
2751
|
-
entry
|
|
2844
|
+
entry,
|
|
2845
|
+
project_shared_projection: projectSharedProjection
|
|
2752
2846
|
};
|
|
2753
2847
|
|
|
2754
2848
|
if (options.json) {
|
|
@@ -3009,6 +3103,8 @@ module.exports = {
|
|
|
3009
3103
|
DEFAULT_ERRORBOOK_REGISTRY_CONFIG,
|
|
3010
3104
|
DEFAULT_ERRORBOOK_REGISTRY_CACHE,
|
|
3011
3105
|
DEFAULT_ERRORBOOK_REGISTRY_EXPORT,
|
|
3106
|
+
DEFAULT_PROJECT_SHARED_ERRORBOOK_REGISTRY,
|
|
3107
|
+
DEFAULT_PROJECT_SHARED_ERRORBOOK_PROJECTION,
|
|
3012
3108
|
HIGH_RISK_SIGNAL_TAGS,
|
|
3013
3109
|
DEBUG_EVIDENCE_TAGS,
|
|
3014
3110
|
DEFAULT_PROMOTE_MIN_QUALITY,
|
|
@@ -3035,5 +3131,6 @@ module.exports = {
|
|
|
3035
3131
|
runErrorbookReleaseGateCommand,
|
|
3036
3132
|
runErrorbookDeprecateCommand,
|
|
3037
3133
|
runErrorbookRequalifyCommand,
|
|
3134
|
+
refreshProjectSharedErrorbookProjection,
|
|
3038
3135
|
registerErrorbookCommands
|
|
3039
3136
|
};
|
package/lib/commands/mode.js
CHANGED
|
@@ -37,18 +37,44 @@ function isFreshProjectionCache(cacheRecord, ttlSeconds) {
|
|
|
37
37
|
return (Date.now() - generatedAt) <= maxAgeMs;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
function getRuntimeProjectionState(graph = {}) {
|
|
41
41
|
const bundle = graph.bundle || {};
|
|
42
42
|
const runtimeRelease = graph.runtime_release || {};
|
|
43
|
-
const sceneBindings = Array.isArray(graph.scene_bindings) ? graph.scene_bindings : [];
|
|
44
43
|
const metadata = bundle.metadata && typeof bundle.metadata === 'object' ? bundle.metadata : {};
|
|
45
44
|
const installation = metadata.runtime_installation && typeof metadata.runtime_installation === 'object'
|
|
46
45
|
? metadata.runtime_installation
|
|
47
46
|
: {};
|
|
47
|
+
const runtimeActivation = metadata.runtime_activation && typeof metadata.runtime_activation === 'object'
|
|
48
|
+
? metadata.runtime_activation
|
|
49
|
+
: {};
|
|
48
50
|
const serviceCatalog = metadata.service_catalog && typeof metadata.service_catalog === 'object'
|
|
49
51
|
? metadata.service_catalog
|
|
50
52
|
: {};
|
|
51
53
|
const releases = Array.isArray(serviceCatalog.releases) ? serviceCatalog.releases : [];
|
|
54
|
+
const installStatus = normalizeString(installation.status) || 'not-installed';
|
|
55
|
+
const installedReleaseId = installStatus === 'installed'
|
|
56
|
+
? (normalizeString(installation.release_id) || null)
|
|
57
|
+
: null;
|
|
58
|
+
const activeReleaseId = normalizeString(
|
|
59
|
+
bundle.runtime_release_id
|
|
60
|
+
|| runtimeRelease.release_id
|
|
61
|
+
|| runtimeActivation.active_release_id
|
|
62
|
+
) || null;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
installation,
|
|
66
|
+
releases,
|
|
67
|
+
installStatus,
|
|
68
|
+
installedReleaseId,
|
|
69
|
+
activeReleaseId
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function buildApplicationHome(graph = {}, dependencies = {}) {
|
|
74
|
+
const bundle = graph.bundle || {};
|
|
75
|
+
const runtimeRelease = graph.runtime_release || {};
|
|
76
|
+
const sceneBindings = Array.isArray(graph.scene_bindings) ? graph.scene_bindings : [];
|
|
77
|
+
const state = getRuntimeProjectionState(graph);
|
|
52
78
|
return {
|
|
53
79
|
mode: 'application-home',
|
|
54
80
|
query: {
|
|
@@ -60,8 +86,10 @@ async function buildApplicationHome(graph = {}, dependencies = {}) {
|
|
|
60
86
|
environment: bundle.environment || null,
|
|
61
87
|
release_status: runtimeRelease.release_status || null,
|
|
62
88
|
runtime_status: runtimeRelease.runtime_status || null,
|
|
63
|
-
install_status:
|
|
64
|
-
|
|
89
|
+
install_status: state.installStatus,
|
|
90
|
+
installed_release_id: state.installedReleaseId,
|
|
91
|
+
active_release_id: state.activeReleaseId,
|
|
92
|
+
release_count: state.releases.length
|
|
65
93
|
},
|
|
66
94
|
relations: {
|
|
67
95
|
runtime_release_id: bundle.runtime_release_id || null,
|
|
@@ -69,20 +97,22 @@ async function buildApplicationHome(graph = {}, dependencies = {}) {
|
|
|
69
97
|
engineering_project_id: bundle.engineering_project_id || null,
|
|
70
98
|
default_scene_id: bundle.default_scene_id || null
|
|
71
99
|
},
|
|
72
|
-
items: releases,
|
|
100
|
+
items: state.releases,
|
|
73
101
|
view_model: {
|
|
74
102
|
projection: 'application',
|
|
75
103
|
app_id: bundle.app_id || null,
|
|
76
104
|
app_key: bundle.app_key || null,
|
|
77
105
|
app_name: bundle.app_name || null,
|
|
78
106
|
entrypoint: runtimeRelease.entrypoint || null,
|
|
79
|
-
current_release:
|
|
80
|
-
|
|
81
|
-
|
|
107
|
+
current_release: state.activeReleaseId,
|
|
108
|
+
installed_release_id: state.installedReleaseId,
|
|
109
|
+
active_release_id: state.activeReleaseId,
|
|
110
|
+
current_environment: bundle.environment || state.installation.current_environment || null,
|
|
111
|
+
install_root: state.installation.install_root || null,
|
|
82
112
|
scene_binding_count: sceneBindings.length,
|
|
83
|
-
release_count: releases.length
|
|
113
|
+
release_count: state.releases.length
|
|
84
114
|
},
|
|
85
|
-
mb_status: runtimeRelease.runtime_status ||
|
|
115
|
+
mb_status: runtimeRelease.runtime_status || state.installStatus || bundle.status || 'unknown'
|
|
86
116
|
};
|
|
87
117
|
}
|
|
88
118
|
|
|
@@ -50,6 +50,10 @@ const ACTIVE_TEXT_SCAN_EXCLUDES = Object.freeze([
|
|
|
50
50
|
|
|
51
51
|
const LEGACY_REFERENCE_REGEX = /\.kiro(?:[\\/]|-workspaces\b)/;
|
|
52
52
|
const MULTI_AGENT_CONFIG_REFERENCE = '.sce/config/multi-agent.json';
|
|
53
|
+
const ERRORBOOK_REGISTRY_CONFIG_PATH = '.sce/config/errorbook-registry.json';
|
|
54
|
+
const PROJECT_SHARED_ERRORBOOK_REGISTRY_PATH = '.sce/knowledge/errorbook/project-shared-registry.json';
|
|
55
|
+
const PROJECT_SHARED_ERRORBOOK_SOURCE_NAME = 'project-shared';
|
|
56
|
+
const ADOPTION_CONFIG_PATH = '.sce/adoption-config.json';
|
|
53
57
|
|
|
54
58
|
const REQUIRED_GITIGNORE_RULES = Object.freeze([
|
|
55
59
|
{ rule: '.sce/steering/CURRENT_CONTEXT.md', sample: '.sce/steering/CURRENT_CONTEXT.md' },
|
|
@@ -377,6 +381,250 @@ function validateMultiAgentConfig(payload) {
|
|
|
377
381
|
return violations;
|
|
378
382
|
}
|
|
379
383
|
|
|
384
|
+
function validateErrorbookRegistryConfig(payload) {
|
|
385
|
+
const violations = [];
|
|
386
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
387
|
+
violations.push('errorbook registry config must be a JSON object');
|
|
388
|
+
return violations;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (typeof payload.enabled !== 'boolean') {
|
|
392
|
+
violations.push('errorbook registry config must declare boolean field "enabled"');
|
|
393
|
+
} else if (payload.enabled !== true) {
|
|
394
|
+
violations.push('errorbook registry config must keep "enabled" set to true under co-work baseline');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (typeof payload.cache_file !== 'string' || !payload.cache_file.trim()) {
|
|
398
|
+
violations.push('errorbook registry config must declare non-empty field "cache_file"');
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const projection = payload.project_shared_projection;
|
|
402
|
+
if (!projection || typeof projection !== 'object' || Array.isArray(projection)) {
|
|
403
|
+
violations.push('errorbook registry config must declare object field "project_shared_projection"');
|
|
404
|
+
} else {
|
|
405
|
+
if (projection.enabled !== true) {
|
|
406
|
+
violations.push('errorbook registry config must keep project_shared_projection.enabled=true under co-work baseline');
|
|
407
|
+
}
|
|
408
|
+
if (typeof projection.file !== 'string' || !projection.file.trim()) {
|
|
409
|
+
violations.push('errorbook registry config must declare non-empty project_shared_projection.file');
|
|
410
|
+
}
|
|
411
|
+
if (!Array.isArray(projection.statuses) || projection.statuses.length === 0) {
|
|
412
|
+
violations.push('errorbook registry config must declare non-empty project_shared_projection.statuses');
|
|
413
|
+
}
|
|
414
|
+
if (!Number.isFinite(Number(projection.min_quality))) {
|
|
415
|
+
violations.push('errorbook registry config must declare numeric project_shared_projection.min_quality');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const sources = Array.isArray(payload.sources) ? payload.sources : [];
|
|
420
|
+
if (sources.length === 0) {
|
|
421
|
+
violations.push('errorbook registry config must declare at least one registry source');
|
|
422
|
+
return violations;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const enabledSources = sources.filter((item) => {
|
|
426
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
const enabled = item.enabled !== false;
|
|
430
|
+
const source = typeof item.url === 'string' && item.url.trim()
|
|
431
|
+
? item.url.trim()
|
|
432
|
+
: typeof item.file === 'string' && item.file.trim()
|
|
433
|
+
? item.file.trim()
|
|
434
|
+
: typeof item.path === 'string' && item.path.trim()
|
|
435
|
+
? item.path.trim()
|
|
436
|
+
: '';
|
|
437
|
+
return enabled && Boolean(source);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
if (enabledSources.length === 0) {
|
|
441
|
+
violations.push('errorbook registry config must keep at least one enabled source with a non-empty url/file');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (projection && typeof projection === 'object' && !Array.isArray(projection)) {
|
|
445
|
+
const hasProjectSharedSource = enabledSources.some((item) => {
|
|
446
|
+
const name = typeof item.name === 'string' ? item.name.trim() : '';
|
|
447
|
+
const file = typeof item.file === 'string' ? item.file.trim() : '';
|
|
448
|
+
const sourcePath = typeof item.path === 'string' ? item.path.trim() : '';
|
|
449
|
+
return name === PROJECT_SHARED_ERRORBOOK_SOURCE_NAME
|
|
450
|
+
|| file === projection.file
|
|
451
|
+
|| sourcePath === projection.file;
|
|
452
|
+
});
|
|
453
|
+
if (!hasProjectSharedSource) {
|
|
454
|
+
violations.push('errorbook registry config must keep an enabled project-shared source aligned with project_shared_projection.file');
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return violations;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async function inspectErrorbookRegistry(projectRoot, gitSnapshot, options = {}, dependencies = {}) {
|
|
462
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
463
|
+
const configPath = path.join(projectRoot, '.sce', 'config', 'errorbook-registry.json');
|
|
464
|
+
const exists = await fileSystem.pathExists(configPath);
|
|
465
|
+
const report = {
|
|
466
|
+
file: ERRORBOOK_REGISTRY_CONFIG_PATH,
|
|
467
|
+
exists,
|
|
468
|
+
valid: false,
|
|
469
|
+
enabled: null,
|
|
470
|
+
enabled_source_count: 0,
|
|
471
|
+
project_shared_projection_file: PROJECT_SHARED_ERRORBOOK_REGISTRY_PATH,
|
|
472
|
+
project_shared_projection_exists: false,
|
|
473
|
+
project_shared_projection_tracked: null,
|
|
474
|
+
warnings: [],
|
|
475
|
+
violations: [],
|
|
476
|
+
passed: true,
|
|
477
|
+
reason: 'passed'
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
if (!exists) {
|
|
481
|
+
report.passed = false;
|
|
482
|
+
report.reason = 'missing-config';
|
|
483
|
+
report.violations.push('shared errorbook registry config is missing');
|
|
484
|
+
return report;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
let payload;
|
|
488
|
+
try {
|
|
489
|
+
payload = await fileSystem.readJson(configPath);
|
|
490
|
+
} catch (error) {
|
|
491
|
+
report.passed = false;
|
|
492
|
+
report.reason = 'invalid-json';
|
|
493
|
+
report.violations.push(`invalid errorbook registry config: ${error.message}`);
|
|
494
|
+
return report;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const validationErrors = validateErrorbookRegistryConfig(payload);
|
|
498
|
+
report.valid = validationErrors.length === 0;
|
|
499
|
+
report.enabled = typeof payload.enabled === 'boolean' ? payload.enabled : null;
|
|
500
|
+
report.project_shared_projection_file = payload
|
|
501
|
+
&& payload.project_shared_projection
|
|
502
|
+
&& typeof payload.project_shared_projection.file === 'string'
|
|
503
|
+
&& payload.project_shared_projection.file.trim()
|
|
504
|
+
? normalizeRelativePath(projectRoot, payload.project_shared_projection.file.trim()) || payload.project_shared_projection.file.trim()
|
|
505
|
+
: PROJECT_SHARED_ERRORBOOK_REGISTRY_PATH;
|
|
506
|
+
report.enabled_source_count = Array.isArray(payload.sources)
|
|
507
|
+
? payload.sources.filter((item) => {
|
|
508
|
+
if (!item || typeof item !== 'object' || Array.isArray(item) || item.enabled === false) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
return (
|
|
512
|
+
(typeof item.url === 'string' && item.url.trim())
|
|
513
|
+
|| (typeof item.file === 'string' && item.file.trim())
|
|
514
|
+
|| (typeof item.path === 'string' && item.path.trim())
|
|
515
|
+
);
|
|
516
|
+
}).length
|
|
517
|
+
: 0;
|
|
518
|
+
|
|
519
|
+
if (validationErrors.length > 0) {
|
|
520
|
+
report.passed = false;
|
|
521
|
+
report.reason = 'invalid-config';
|
|
522
|
+
report.violations.push(...validationErrors);
|
|
523
|
+
return report;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const projectionFile = report.project_shared_projection_file;
|
|
527
|
+
const projectionAbsolutePath = path.isAbsolute(projectionFile)
|
|
528
|
+
? projectionFile
|
|
529
|
+
: path.join(projectRoot, projectionFile);
|
|
530
|
+
report.project_shared_projection_exists = await fileSystem.pathExists(projectionAbsolutePath);
|
|
531
|
+
if (!report.project_shared_projection_exists) {
|
|
532
|
+
report.passed = false;
|
|
533
|
+
report.reason = 'missing-project-shared-projection';
|
|
534
|
+
report.violations.push(`shared project errorbook projection file is missing: ${projectionFile}`);
|
|
535
|
+
return report;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
try {
|
|
539
|
+
const projectionPayload = await fileSystem.readJson(projectionAbsolutePath);
|
|
540
|
+
if (!projectionPayload || typeof projectionPayload !== 'object' || Array.isArray(projectionPayload)) {
|
|
541
|
+
report.violations.push(`shared project errorbook projection must be a JSON object: ${projectionFile}`);
|
|
542
|
+
} else if (!Array.isArray(projectionPayload.entries)) {
|
|
543
|
+
report.violations.push(`shared project errorbook projection must declare entries[]: ${projectionFile}`);
|
|
544
|
+
}
|
|
545
|
+
} catch (error) {
|
|
546
|
+
report.violations.push(`invalid shared project errorbook projection: ${error.message}`);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (gitSnapshot && gitSnapshot.available === true) {
|
|
550
|
+
report.project_shared_projection_tracked = gitSnapshot.tracked_files.has(projectionFile);
|
|
551
|
+
if (report.project_shared_projection_tracked !== true) {
|
|
552
|
+
report.violations.push(`shared project errorbook projection must be tracked by git: ${projectionFile}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (report.violations.length > 0) {
|
|
557
|
+
report.passed = false;
|
|
558
|
+
report.reason = 'invalid-config';
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return report;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async function inspectErrorbookConvergence(projectRoot, options = {}, dependencies = {}) {
|
|
565
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
566
|
+
const configPath = path.join(projectRoot, '.sce', 'adoption-config.json');
|
|
567
|
+
const exists = await fileSystem.pathExists(configPath);
|
|
568
|
+
const report = {
|
|
569
|
+
file: ADOPTION_CONFIG_PATH,
|
|
570
|
+
exists,
|
|
571
|
+
managed_project: exists,
|
|
572
|
+
warnings: [],
|
|
573
|
+
violations: [],
|
|
574
|
+
passed: true,
|
|
575
|
+
reason: exists ? 'passed' : 'not-managed'
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
if (!exists) {
|
|
579
|
+
return report;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
let payload;
|
|
583
|
+
try {
|
|
584
|
+
payload = await fileSystem.readJson(configPath);
|
|
585
|
+
} catch (error) {
|
|
586
|
+
report.passed = false;
|
|
587
|
+
report.reason = 'invalid-json';
|
|
588
|
+
report.violations.push(`invalid adoption config: ${error.message}`);
|
|
589
|
+
return report;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const convergence = payload
|
|
593
|
+
&& payload.defaults
|
|
594
|
+
&& payload.defaults.errorbook_convergence
|
|
595
|
+
&& typeof payload.defaults.errorbook_convergence === 'object'
|
|
596
|
+
&& !Array.isArray(payload.defaults.errorbook_convergence)
|
|
597
|
+
? payload.defaults.errorbook_convergence
|
|
598
|
+
: null;
|
|
599
|
+
|
|
600
|
+
if (!convergence) {
|
|
601
|
+
report.passed = false;
|
|
602
|
+
report.reason = 'missing-convergence';
|
|
603
|
+
report.violations.push('managed adoption baseline is missing defaults.errorbook_convergence');
|
|
604
|
+
return report;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (convergence.enabled !== true) {
|
|
608
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.enabled=true');
|
|
609
|
+
}
|
|
610
|
+
if (convergence.canonical_mechanism !== 'errorbook') {
|
|
611
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.canonical_mechanism=errorbook');
|
|
612
|
+
}
|
|
613
|
+
if (convergence.disallow_parallel_mechanisms !== true) {
|
|
614
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.disallow_parallel_mechanisms=true');
|
|
615
|
+
}
|
|
616
|
+
if (convergence.strategy !== 'absorb_into_sce_errorbook') {
|
|
617
|
+
report.violations.push('managed adoption baseline must keep errorbook_convergence.strategy=absorb_into_sce_errorbook');
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (report.violations.length > 0) {
|
|
621
|
+
report.passed = false;
|
|
622
|
+
report.reason = 'convergence-drift';
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
return report;
|
|
626
|
+
}
|
|
627
|
+
|
|
380
628
|
async function inspectMultiAgentConfig(projectRoot, scanResult, options = {}, dependencies = {}) {
|
|
381
629
|
const fileSystem = dependencies.fileSystem || fs;
|
|
382
630
|
const configPath = path.join(projectRoot, '.sce', 'config', 'multi-agent.json');
|
|
@@ -497,6 +745,8 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
497
745
|
const runtimeTracking = inspectRuntimeTracking(gitSnapshot);
|
|
498
746
|
const scanResult = await scanActiveTextReferences(projectRoot, gitSnapshot.tracked_files, options, dependencies);
|
|
499
747
|
const multiAgent = await inspectMultiAgentConfig(projectRoot, scanResult, options, dependencies);
|
|
748
|
+
const errorbookRegistry = await inspectErrorbookRegistry(projectRoot, gitSnapshot, options, dependencies);
|
|
749
|
+
const errorbookConvergence = await inspectErrorbookConvergence(projectRoot, options, dependencies);
|
|
500
750
|
const steeringBoundary = inspectSteeringBoundary(projectRoot);
|
|
501
751
|
|
|
502
752
|
const legacyReferences = {
|
|
@@ -521,6 +771,8 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
521
771
|
gitignore,
|
|
522
772
|
runtime_tracking: runtimeTracking,
|
|
523
773
|
multi_agent: multiAgent,
|
|
774
|
+
errorbook_registry: errorbookRegistry,
|
|
775
|
+
errorbook_convergence: errorbookConvergence,
|
|
524
776
|
legacy_references: legacyReferences,
|
|
525
777
|
steering_boundary: steeringBoundary,
|
|
526
778
|
summary: {
|
|
@@ -528,6 +780,8 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
528
780
|
tracked_runtime_files: runtimeTracking.tracked_runtime_files.length,
|
|
529
781
|
multi_agent_warnings: multiAgent.warnings.length,
|
|
530
782
|
multi_agent_violations: multiAgent.violations.length,
|
|
783
|
+
errorbook_registry_violations: errorbookRegistry.violations.length,
|
|
784
|
+
errorbook_convergence_violations: errorbookConvergence.violations.length,
|
|
531
785
|
legacy_reference_count: legacyReferences.matches.length,
|
|
532
786
|
steering_boundary_violations: steeringBoundary.violations.length
|
|
533
787
|
},
|
|
@@ -541,12 +795,16 @@ async function auditCollabGovernance(projectRoot = process.cwd(), options = {},
|
|
|
541
795
|
report.warnings.push(...(gitSnapshot.available === true ? gitSnapshot.warnings : []));
|
|
542
796
|
report.warnings.push(...runtimeTracking.warnings);
|
|
543
797
|
report.warnings.push(...multiAgent.warnings);
|
|
798
|
+
report.warnings.push(...errorbookRegistry.warnings);
|
|
799
|
+
report.warnings.push(...errorbookConvergence.warnings);
|
|
544
800
|
report.warnings.push(...legacyReferences.warnings);
|
|
545
801
|
report.warnings.push(...steeringBoundary.warnings);
|
|
546
802
|
|
|
547
803
|
report.violations.push(...gitignore.violations);
|
|
548
804
|
report.violations.push(...runtimeTracking.violations);
|
|
549
805
|
report.violations.push(...multiAgent.violations);
|
|
806
|
+
report.violations.push(...errorbookRegistry.violations);
|
|
807
|
+
report.violations.push(...errorbookConvergence.violations);
|
|
550
808
|
report.violations.push(...legacyReferences.violations);
|
|
551
809
|
report.violations.push(
|
|
552
810
|
...steeringBoundary.violations.map((item) => `steering boundary violation: ${item.path || item.name}`)
|
|
@@ -568,8 +826,11 @@ module.exports = {
|
|
|
568
826
|
RUNTIME_TRACKED_PATTERNS,
|
|
569
827
|
auditCollabGovernance,
|
|
570
828
|
inspectGitignore,
|
|
829
|
+
inspectErrorbookConvergence,
|
|
830
|
+
inspectErrorbookRegistry,
|
|
571
831
|
inspectMultiAgentConfig,
|
|
572
832
|
inspectRuntimeTracking,
|
|
573
833
|
scanActiveTextReferences,
|
|
834
|
+
validateErrorbookRegistryConfig,
|
|
574
835
|
validateMultiAgentConfig
|
|
575
836
|
};
|