archgraph-argo 0.1.0
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/LICENSE +201 -0
- package/README.md +115 -0
- package/argo/package.json +8 -0
- package/argo/rules/intent-architecture-global-rule.md +45 -0
- package/argo/schema/ImplementationToCodingHandoff.schema.json +252 -0
- package/argo/schema/ImplementationToIntentTraceProposal.schema.json +180 -0
- package/argo/schema/IntentToImplementationHandoff.schema.json +75 -0
- package/argo/schema/SystemArchitecture.schema.json +378 -0
- package/argo/schema/archimate3.2.pdf +0 -0
- package/argo/scripts/ARCHITECTURE.md +57 -0
- package/argo/scripts/archimate32-rules.js +12301 -0
- package/argo/scripts/argo-mcp-server.js +629 -0
- package/argo/scripts/argo-paths.js +77 -0
- package/argo/scripts/ensureArgoHarnessEnvironment.js +340 -0
- package/argo/scripts/generateArchitectureDiffPlantuml.js +466 -0
- package/argo/scripts/graph-rag/ARCHITECTURE.md +192 -0
- package/argo/scripts/graph-rag/canonicalProjectionAuthority.js +45 -0
- package/argo/scripts/graph-rag/defaultSemanticRetrieval.js +969 -0
- package/argo/scripts/graph-rag/embeddingQualificationGate.js +59 -0
- package/argo/scripts/graph-rag/externalProductionConfig.js +74 -0
- package/argo/scripts/graph-rag/liveEmbeddingIndexGate.js +129 -0
- package/argo/scripts/graph-rag/liveEmbeddingNeo4jBoundary.js +137 -0
- package/argo/scripts/graph-rag/liveEmbeddingProviderClient.js +49 -0
- package/argo/scripts/graph-rag/liveEmbeddingProviderConfig.js +481 -0
- package/argo/scripts/graph-rag/mutationEmbeddingVectorLifecycle.js +1261 -0
- package/argo/scripts/graph-rag/neo4jNativeRetrieval.js +37 -0
- package/argo/scripts/graph-rag/productionGraphRagRuntime.js +1624 -0
- package/argo/scripts/graph-rag/semantic-persistence/ARCHITECTURE.md +51 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticBackfill.js +241 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticCheckpointStore.js +99 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticNeo4jAdapter.js +149 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticProjectionStore.js +171 -0
- package/argo/scripts/graph-rag/semanticOperatorError.js +38 -0
- package/argo/scripts/graph-rag/semanticOperatorJourney.js +459 -0
- package/argo/scripts/graph-rag/semanticReadinessAttestationStore.js +398 -0
- package/argo/scripts/graph-rag/systemMetadataCommandAdapter.js +269 -0
- package/argo/scripts/graph-semantics.js +220 -0
- package/argo/scripts/neo4j-system-architecture-store.js +777 -0
- package/argo/scripts/repositoryArgoEnvironment.js +101 -0
- package/argo/scripts/runArchitectureTests.js +583 -0
- package/argo/scripts/semanticOperatorJourneyCli.js +91 -0
- package/argo/scripts/syncSystemArchitectureToNeo4j.js +67 -0
- package/argo/scripts/systemarchitecture-mcp-server.js +2965 -0
- package/argo/scripts/test-executors/_template.js +58 -0
- package/argo/scripts/test-executors/default.js +199 -0
- package/argo/scripts/validateStageHandoff.js +459 -0
- package/argo/scripts/validateSystemArchitecture.js +254 -0
- package/argo/scripts/validateTraceProposal.js +181 -0
- package/argo/scripts/validator-mcp-server.js +377 -0
- package/argo/skills/argo-init/SKILL.md +110 -0
- package/bin/argo-deploy.js +12 -0
- package/install-argo.ps1 +112 -0
- package/package.json +28 -0
- package/vendor/neo4j-driver-6.2.0.tgz +0 -0
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const crypto = require('node:crypto');
|
|
3
|
+
const { AsyncLocalStorage } = require('node:async_hooks');
|
|
4
|
+
const {
|
|
5
|
+
resolveApprovedLiveConfiguration,
|
|
6
|
+
} = require('./liveEmbeddingProviderConfig.js');
|
|
7
|
+
const {
|
|
8
|
+
createLiveEmbeddingProviderClient,
|
|
9
|
+
} = require('./liveEmbeddingProviderClient.js');
|
|
10
|
+
const {
|
|
11
|
+
createProductionGraphRagRuntime,
|
|
12
|
+
} = require('./productionGraphRagRuntime.js');
|
|
13
|
+
const {
|
|
14
|
+
getWorkspaceRoot,
|
|
15
|
+
resolveArgoPath,
|
|
16
|
+
} = require('../argo-paths.js');
|
|
17
|
+
|
|
18
|
+
const APPROVED_SOURCE_KEYS = Object.freeze([
|
|
19
|
+
'ARGO_EMBEDDING_BASE_URL',
|
|
20
|
+
'ARGO_EMBEDDING_MODEL',
|
|
21
|
+
'ARGO_EMBEDDING_PROVIDER',
|
|
22
|
+
'ARGO_EMBEDDING_MODEL_VERSION',
|
|
23
|
+
'ARGO_EMBEDDING_DIMENSIONS',
|
|
24
|
+
'ARGO_NEO4J_DATABASE_URL',
|
|
25
|
+
'ARGO_NEO4J_DATABASE_USERNAME',
|
|
26
|
+
'ARGO_NEO4J_DATABASE_PASSWORD',
|
|
27
|
+
'QWEN_KEY',
|
|
28
|
+
]);
|
|
29
|
+
const LEGACY_NEO4J_KEYS = Object.freeze([
|
|
30
|
+
'ARGO_NEO4J_URI',
|
|
31
|
+
'ARGO_NEO4J_USERNAME',
|
|
32
|
+
'ARGO_NEO4J_PASSWORD',
|
|
33
|
+
]);
|
|
34
|
+
const APPROVED_PROFILE = Object.freeze({
|
|
35
|
+
baseUrl: 'https://llm-clids9mqc5o1mbvb.cn-beijing.maas.aliyuncs.com/compatible-mode/v1',
|
|
36
|
+
model: 'qwen3.7-text-embedding',
|
|
37
|
+
provider: 'alibaba-cloud-model-studio-openai-compatible-cn-beijing',
|
|
38
|
+
version: 'qualification-2026-07-25',
|
|
39
|
+
dimensions: 1024,
|
|
40
|
+
});
|
|
41
|
+
const CHANNELS = Object.freeze([
|
|
42
|
+
Object.freeze({
|
|
43
|
+
channel: 'Element',
|
|
44
|
+
key: 'elements',
|
|
45
|
+
objectType: 'Element',
|
|
46
|
+
threshold: 0.8,
|
|
47
|
+
indexName: 'argo_production_semantic_element_vector',
|
|
48
|
+
}),
|
|
49
|
+
Object.freeze({
|
|
50
|
+
channel: 'ArchitectureRelationship',
|
|
51
|
+
key: 'relationships',
|
|
52
|
+
objectType: 'ArchitectureRelationship',
|
|
53
|
+
threshold: 0.78,
|
|
54
|
+
indexName: 'argo_production_semantic_relationship_vector',
|
|
55
|
+
}),
|
|
56
|
+
Object.freeze({
|
|
57
|
+
channel: 'View',
|
|
58
|
+
key: 'views',
|
|
59
|
+
objectType: 'View',
|
|
60
|
+
threshold: 0.76,
|
|
61
|
+
indexName: 'argo_production_semantic_view_vector',
|
|
62
|
+
}),
|
|
63
|
+
]);
|
|
64
|
+
const VECTOR_QUERY_CYPHER = [
|
|
65
|
+
'CALL db.index.vector.queryNodes($indexName, $topK, $vector)',
|
|
66
|
+
'YIELD node, score',
|
|
67
|
+
'WHERE node.channel = $channel',
|
|
68
|
+
'RETURN properties(node) AS record, score',
|
|
69
|
+
'ORDER BY score DESC',
|
|
70
|
+
].join('\n');
|
|
71
|
+
const READINESS_QUERY_CYPHER = [
|
|
72
|
+
'MATCH (readiness:ArgoProductionSemanticReadiness {identity: $identity})',
|
|
73
|
+
'RETURN properties(readiness) AS readiness',
|
|
74
|
+
].join('\n');
|
|
75
|
+
const INITIAL_WINDOW_SIZE = 2;
|
|
76
|
+
const SELECTED_VIEW_ID = 'semprod-wp2-default-retrieval-readiness';
|
|
77
|
+
const testCompositionStorage = new AsyncLocalStorage();
|
|
78
|
+
|
|
79
|
+
function createDefaultSemanticRetrieval(dependencies = {}) {
|
|
80
|
+
const canonicalGraph = requireCanonicalGraph(dependencies.canonicalGraph);
|
|
81
|
+
const readinessBoundary = dependencies.readinessBoundary;
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
async retrieve(request = {}) {
|
|
84
|
+
const composition = await resolveRetrievalComposition(dependencies);
|
|
85
|
+
const activeTestComposition = testCompositionStorage.getStore();
|
|
86
|
+
const activeReadinessBoundary = activeTestComposition
|
|
87
|
+
&& activeTestComposition.useReadinessBoundary !== true
|
|
88
|
+
? undefined
|
|
89
|
+
: readinessBoundary;
|
|
90
|
+
let configurationEvidence = await composition.resolveConfiguration();
|
|
91
|
+
let evidence = await readAndEvaluatePersistentReadiness(
|
|
92
|
+
composition,
|
|
93
|
+
canonicalGraph,
|
|
94
|
+
activeReadinessBoundary,
|
|
95
|
+
);
|
|
96
|
+
if (!evidence.alignment.aligned) {
|
|
97
|
+
await attemptAutomaticAlignment({
|
|
98
|
+
composition,
|
|
99
|
+
request,
|
|
100
|
+
alignment: evidence.alignment,
|
|
101
|
+
});
|
|
102
|
+
evidence = await readAndEvaluatePersistentReadiness(
|
|
103
|
+
composition,
|
|
104
|
+
canonicalGraph,
|
|
105
|
+
activeReadinessBoundary,
|
|
106
|
+
);
|
|
107
|
+
if (!evidence.alignment.aligned) {
|
|
108
|
+
throw semanticAutomaticAlignmentFailed(evidence.alignment);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return executeWpP2Retrieval({
|
|
112
|
+
composition,
|
|
113
|
+
request,
|
|
114
|
+
canonicalGraph,
|
|
115
|
+
readiness: evidence.readiness,
|
|
116
|
+
configurationEvidence,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
async probeQueryability(request = {}, readiness = {}) {
|
|
120
|
+
const composition = await resolveRetrievalComposition(dependencies);
|
|
121
|
+
const configurationEvidence = await composition.resolveConfiguration();
|
|
122
|
+
return executeWpP2Retrieval({
|
|
123
|
+
composition,
|
|
124
|
+
request,
|
|
125
|
+
canonicalGraph,
|
|
126
|
+
readiness,
|
|
127
|
+
configurationEvidence,
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
async readReadiness() {
|
|
131
|
+
const composition = await resolveRetrievalComposition(dependencies);
|
|
132
|
+
const activeTestComposition = testCompositionStorage.getStore();
|
|
133
|
+
const activeReadinessBoundary = activeTestComposition
|
|
134
|
+
&& activeTestComposition.useReadinessBoundary !== true
|
|
135
|
+
? undefined
|
|
136
|
+
: readinessBoundary;
|
|
137
|
+
await composition.resolveConfiguration();
|
|
138
|
+
const evidence = await readAndEvaluatePersistentReadiness(
|
|
139
|
+
composition,
|
|
140
|
+
canonicalGraph,
|
|
141
|
+
activeReadinessBoundary,
|
|
142
|
+
);
|
|
143
|
+
return publicReadinessOutcome(evidence.alignment);
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function resolveRetrievalComposition(dependencies) {
|
|
149
|
+
const activeTestComposition = testCompositionStorage.getStore();
|
|
150
|
+
return activeTestComposition
|
|
151
|
+
? createTestComposition(activeTestComposition)
|
|
152
|
+
: createProductionComposition(dependencies);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function executeWpP2Retrieval({
|
|
156
|
+
composition,
|
|
157
|
+
request,
|
|
158
|
+
canonicalGraph,
|
|
159
|
+
readiness,
|
|
160
|
+
configurationEvidence,
|
|
161
|
+
}) {
|
|
162
|
+
const provider = createLiveEmbeddingProviderClient({
|
|
163
|
+
configuration: configurationEvidence.configuration,
|
|
164
|
+
transport: composition.transport,
|
|
165
|
+
});
|
|
166
|
+
const vector = await provider.embed(request.intent);
|
|
167
|
+
requireQualifiedVector(vector);
|
|
168
|
+
const seedsByType = {};
|
|
169
|
+
for (const channel of CHANNELS) {
|
|
170
|
+
seedsByType[channel.key] = await exhaustChannel({
|
|
171
|
+
channel,
|
|
172
|
+
neo4jDriver: composition.neo4jDriver,
|
|
173
|
+
vector,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return completeSemanticResult({
|
|
177
|
+
request,
|
|
178
|
+
canonicalGraph,
|
|
179
|
+
readiness,
|
|
180
|
+
seedsByType,
|
|
181
|
+
configurationEvidence,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function withDefaultSemanticRetrievalTestComposition(composition, callback, options = {}) {
|
|
186
|
+
requireExactTestComposition(composition, callback);
|
|
187
|
+
return testCompositionStorage.run(Object.freeze({
|
|
188
|
+
...composition,
|
|
189
|
+
useReadinessBoundary: options.useReadinessBoundary === true,
|
|
190
|
+
}), callback);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function createTestComposition(composition) {
|
|
194
|
+
return Object.freeze({
|
|
195
|
+
resolveConfiguration: () => resolveRawTestConfiguration(
|
|
196
|
+
composition.sourceBehavior,
|
|
197
|
+
composition.sourceAdapters,
|
|
198
|
+
),
|
|
199
|
+
transport: composition.transport,
|
|
200
|
+
neo4jDriver: composition.neo4jDriver,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function createProductionComposition(dependencies) {
|
|
205
|
+
const repositoryRoot = dependencies.repositoryRoot
|
|
206
|
+
|| getWorkspaceRoot();
|
|
207
|
+
let configurationEvidence;
|
|
208
|
+
return Object.freeze({
|
|
209
|
+
async resolveConfiguration() {
|
|
210
|
+
configurationEvidence = await resolveApprovedLiveConfiguration({
|
|
211
|
+
repositoryRoot,
|
|
212
|
+
useCase: 'production-semantic-query',
|
|
213
|
+
});
|
|
214
|
+
return configurationEvidence;
|
|
215
|
+
},
|
|
216
|
+
transport: Object.freeze({
|
|
217
|
+
request(url, options) {
|
|
218
|
+
if (typeof global.fetch !== 'function') {
|
|
219
|
+
throw safeError('LIVE_PROVIDER_TRANSPORT_UNAVAILABLE');
|
|
220
|
+
}
|
|
221
|
+
return global.fetch(url, options);
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
224
|
+
neo4jDriver: Object.freeze({
|
|
225
|
+
async execute(operation) {
|
|
226
|
+
if (!configurationEvidence) {
|
|
227
|
+
throw safeError('EXTERNAL_CREDENTIALS_REQUIRED');
|
|
228
|
+
}
|
|
229
|
+
return executeProductionNeo4jOperation(configurationEvidence.configuration, operation);
|
|
230
|
+
},
|
|
231
|
+
}),
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function executeProductionNeo4jOperation(configuration, operation) {
|
|
236
|
+
if (operation && operation.kind === 'semantic-auto-alignment-attempt') {
|
|
237
|
+
return runScriptOwnedSemanticAlignment(operation);
|
|
238
|
+
}
|
|
239
|
+
const neo4j = require('neo4j-driver');
|
|
240
|
+
const driver = neo4j.driver(
|
|
241
|
+
configuration.neo4jDatabaseUrl,
|
|
242
|
+
neo4j.auth.basic(
|
|
243
|
+
configuration.neo4jDatabaseUsername,
|
|
244
|
+
configuration.neo4jDatabasePassword,
|
|
245
|
+
),
|
|
246
|
+
);
|
|
247
|
+
const session = driver.session(configuration.neo4jDatabase === undefined
|
|
248
|
+
? undefined
|
|
249
|
+
: { database: configuration.neo4jDatabase });
|
|
250
|
+
try {
|
|
251
|
+
const result = await session.run(operation.cypher, operation.parameters);
|
|
252
|
+
if (operation.kind === 'semantic-readiness-read') {
|
|
253
|
+
const readiness = result.records[0] && result.records[0].get('readiness');
|
|
254
|
+
return { records: readiness ? [readiness] : [] };
|
|
255
|
+
}
|
|
256
|
+
const records = result.records.map(record => ({
|
|
257
|
+
...record.get('record'),
|
|
258
|
+
score: numberValue(record.get('score')),
|
|
259
|
+
}));
|
|
260
|
+
const offset = operation.parameters.offset;
|
|
261
|
+
const windowSize = operation.parameters.windowSize;
|
|
262
|
+
const returnedCount = Math.max(0, records.length - offset);
|
|
263
|
+
const hasMore = records.length === operation.parameters.topK;
|
|
264
|
+
return {
|
|
265
|
+
records,
|
|
266
|
+
windowEvidence: {
|
|
267
|
+
offset,
|
|
268
|
+
windowSize,
|
|
269
|
+
returnedCount,
|
|
270
|
+
hasMore,
|
|
271
|
+
nextOffset: hasMore ? operation.parameters.topK : null,
|
|
272
|
+
windowExhausted: !hasMore,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
} finally {
|
|
276
|
+
await session.close();
|
|
277
|
+
await driver.close();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function attemptAutomaticAlignment({ composition, request, alignment }) {
|
|
282
|
+
try {
|
|
283
|
+
const result = await composition.neo4jDriver.execute(Object.freeze({
|
|
284
|
+
kind: 'semantic-auto-alignment-attempt',
|
|
285
|
+
originalQuery: clone(request),
|
|
286
|
+
observedReadiness: Object.freeze({
|
|
287
|
+
state: alignment.state,
|
|
288
|
+
canonicalVersion: alignment.canonicalVersion,
|
|
289
|
+
contentVersion: alignment.contentVersion,
|
|
290
|
+
indexVersion: alignment.indexVersion,
|
|
291
|
+
completedChannels: alignment.completedChannels,
|
|
292
|
+
missingChannels: alignment.missingChannels,
|
|
293
|
+
mismatchedChannels: alignment.mismatchedChannels,
|
|
294
|
+
fullSnapshotFallback: false,
|
|
295
|
+
}),
|
|
296
|
+
}));
|
|
297
|
+
if (!result || result.status !== 'aligned') {
|
|
298
|
+
throw semanticAutomaticAlignmentFailed(alignment);
|
|
299
|
+
}
|
|
300
|
+
return result;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
throw semanticAutomaticAlignmentFailed(alignment, error);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function runScriptOwnedSemanticAlignment(operation) {
|
|
307
|
+
const childProcess = require('node:child_process');
|
|
308
|
+
const repositoryRoot = getWorkspaceRoot();
|
|
309
|
+
const scriptPath = resolveArgoPath('scripts', 'ensureArgoHarnessEnvironment.js');
|
|
310
|
+
const result = childProcess.spawnSync(process.execPath, [scriptPath], {
|
|
311
|
+
cwd: repositoryRoot,
|
|
312
|
+
encoding: 'utf8',
|
|
313
|
+
env: process.env,
|
|
314
|
+
});
|
|
315
|
+
if (result.status === 0) {
|
|
316
|
+
return Object.freeze({
|
|
317
|
+
status: 'aligned',
|
|
318
|
+
originalQuery: operation && operation.originalQuery,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
const error = safeError('SEMANTIC_AUTO_ALIGNMENT_FAILED');
|
|
322
|
+
error.message = 'Semantic automatic alignment failed before retry.';
|
|
323
|
+
error.action = 'Repair semantic lifecycle alignment, then retry the original query.';
|
|
324
|
+
error.fullSnapshotFallback = false;
|
|
325
|
+
return Promise.reject(error);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function resolveRawTestConfiguration(sourceBehavior, sourceAdapters) {
|
|
329
|
+
if (
|
|
330
|
+
!sourceBehavior
|
|
331
|
+
|| !sourceAdapters
|
|
332
|
+
|| typeof sourceBehavior.readProcessKey !== 'function'
|
|
333
|
+
|| typeof sourceBehavior.readFileEntries !== 'function'
|
|
334
|
+
) {
|
|
335
|
+
throw safeError('SECRET_SOURCE_PROVENANCE_PROHIBITED');
|
|
336
|
+
}
|
|
337
|
+
const expectedFilePath = path.resolve(String(sourceBehavior.expectedFilePath));
|
|
338
|
+
const filesystem = sourceAdapters.filesystem;
|
|
339
|
+
const fileExists = Boolean(filesystem && filesystem.existsSync(expectedFilePath));
|
|
340
|
+
if (fileExists) {
|
|
341
|
+
assertProtectedSecretFile(expectedFilePath, sourceAdapters);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const processValues = new Map();
|
|
345
|
+
for (const key of [...APPROVED_SOURCE_KEYS, ...LEGACY_NEO4J_KEYS]) {
|
|
346
|
+
const prohibitedReader = key === 'QWEN_KEY'
|
|
347
|
+
? sourceBehavior.readTestDefaultKey || sourceBehavior.readFallbackKey
|
|
348
|
+
: undefined;
|
|
349
|
+
if (prohibitedReader) {
|
|
350
|
+
prohibitedReader(key);
|
|
351
|
+
throw safeError('SECRET_SOURCE_PROVENANCE_PROHIBITED');
|
|
352
|
+
}
|
|
353
|
+
processValues.set(key, sourceBehavior.readProcessKey(key));
|
|
354
|
+
}
|
|
355
|
+
if (LEGACY_NEO4J_KEYS.some(key => present(processValues.get(key)))) {
|
|
356
|
+
throw safeError('SECRET_SOURCE_PROVENANCE_PROHIBITED');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const fileValues = new Map();
|
|
360
|
+
const entries = sourceBehavior.readFileEntries(expectedFilePath);
|
|
361
|
+
if (!Array.isArray(entries)) {
|
|
362
|
+
throw safeError('SECRET_SOURCE_PROVENANCE_PROHIBITED');
|
|
363
|
+
}
|
|
364
|
+
for (const entry of entries) {
|
|
365
|
+
if (!Array.isArray(entry) || entry.length !== 2 || fileValues.has(entry[0])) {
|
|
366
|
+
throw safeError('SECRET_FILE_DUPLICATE_KEY');
|
|
367
|
+
}
|
|
368
|
+
if (!APPROVED_SOURCE_KEYS.includes(entry[0])) {
|
|
369
|
+
throw safeError('SECRET_SOURCE_PROVENANCE_PROHIBITED');
|
|
370
|
+
}
|
|
371
|
+
fileValues.set(entry[0], entry[1]);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const selected = {};
|
|
375
|
+
const attribution = {};
|
|
376
|
+
for (const key of APPROVED_SOURCE_KEYS) {
|
|
377
|
+
const processValue = processValues.get(key);
|
|
378
|
+
const fileValue = fileValues.get(key);
|
|
379
|
+
if (present(processValue) && present(fileValue) && processValue !== fileValue) {
|
|
380
|
+
throw safeError(['QWEN_KEY', 'ARGO_NEO4J_DATABASE_PASSWORD'].includes(key)
|
|
381
|
+
? 'SECRET_SOURCE_CONFLICT'
|
|
382
|
+
: 'LIVE_PROVIDER_CONFIGURATION_CONFLICT');
|
|
383
|
+
}
|
|
384
|
+
if (present(processValue)) {
|
|
385
|
+
selected[key] = processValue;
|
|
386
|
+
attribution[key] = 'process';
|
|
387
|
+
} else if (present(fileValue)) {
|
|
388
|
+
selected[key] = fileValue;
|
|
389
|
+
attribution[key] = 'file';
|
|
390
|
+
} else {
|
|
391
|
+
const error = safeError(['QWEN_KEY', 'ARGO_NEO4J_DATABASE_PASSWORD'].includes(key)
|
|
392
|
+
? 'APPROVED_SECRET_REQUIRED'
|
|
393
|
+
: 'LIVE_PROVIDER_CONFIGURATION_REQUIRED');
|
|
394
|
+
error.field = key;
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
requireApprovedProfile(selected);
|
|
399
|
+
const configuration = Object.freeze({
|
|
400
|
+
embeddingBaseUrl: selected.ARGO_EMBEDDING_BASE_URL,
|
|
401
|
+
embeddingModel: selected.ARGO_EMBEDDING_MODEL,
|
|
402
|
+
embeddingProvider: selected.ARGO_EMBEDDING_PROVIDER,
|
|
403
|
+
embeddingModelVersion: selected.ARGO_EMBEDDING_MODEL_VERSION,
|
|
404
|
+
embeddingDimensions: APPROVED_PROFILE.dimensions,
|
|
405
|
+
neo4jDatabaseUrl: selected.ARGO_NEO4J_DATABASE_URL,
|
|
406
|
+
neo4jDatabaseUsername: selected.ARGO_NEO4J_DATABASE_USERNAME,
|
|
407
|
+
neo4jDatabasePassword: selected.ARGO_NEO4J_DATABASE_PASSWORD,
|
|
408
|
+
qwenKey: selected.QWEN_KEY,
|
|
409
|
+
});
|
|
410
|
+
return Object.freeze({
|
|
411
|
+
...configuration,
|
|
412
|
+
configuration,
|
|
413
|
+
attribution: Object.freeze(attribution),
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function assertProtectedSecretFile(expectedFilePath, adapters) {
|
|
418
|
+
const filesystem = adapters.filesystem;
|
|
419
|
+
const stat = filesystem.lstatSync(expectedFilePath);
|
|
420
|
+
if (
|
|
421
|
+
!stat
|
|
422
|
+
|| typeof stat.isFile !== 'function'
|
|
423
|
+
|| !stat.isFile()
|
|
424
|
+
|| (typeof stat.isSymbolicLink === 'function' && stat.isSymbolicLink())
|
|
425
|
+
|| path.resolve(filesystem.realpathSync(expectedFilePath)) !== expectedFilePath
|
|
426
|
+
) {
|
|
427
|
+
throw safeError('SECRET_FILE_PATH_UNSAFE');
|
|
428
|
+
}
|
|
429
|
+
if (
|
|
430
|
+
!adapters.git
|
|
431
|
+
|| adapters.git.isIgnored() !== true
|
|
432
|
+
|| adapters.git.isTracked() !== false
|
|
433
|
+
) {
|
|
434
|
+
throw safeError('SECRET_FILE_GIT_STATE_UNSAFE');
|
|
435
|
+
}
|
|
436
|
+
const acl = adapters.acl && adapters.acl.inspect();
|
|
437
|
+
if (!acl || acl.status !== 0 || !acl.identity || typeof acl.stdout !== 'string') {
|
|
438
|
+
throw safeError('SECRET_FILE_ACL_UNVERIFIABLE');
|
|
439
|
+
}
|
|
440
|
+
const broadRead = acl.stdout
|
|
441
|
+
.split(/\r?\n/)
|
|
442
|
+
.some(line => /^(Everyone|BUILTIN\\Users|Authenticated Users):.*\((?:R|RX|F|M)\)/i.test(line.trim()));
|
|
443
|
+
const identityRead = acl.stdout
|
|
444
|
+
.split(/\r?\n/)
|
|
445
|
+
.some(line => line.trim().startsWith(`${acl.identity}:`) && /\((?:R|RX|F|M)\)/i.test(line));
|
|
446
|
+
if (broadRead || !identityRead) {
|
|
447
|
+
throw safeError('SECRET_FILE_ACL_UNSAFE');
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function requireApprovedProfile(values) {
|
|
452
|
+
const expected = {
|
|
453
|
+
ARGO_EMBEDDING_BASE_URL: APPROVED_PROFILE.baseUrl,
|
|
454
|
+
ARGO_EMBEDDING_MODEL: APPROVED_PROFILE.model,
|
|
455
|
+
ARGO_EMBEDDING_PROVIDER: APPROVED_PROFILE.provider,
|
|
456
|
+
ARGO_EMBEDDING_MODEL_VERSION: APPROVED_PROFILE.version,
|
|
457
|
+
ARGO_EMBEDDING_DIMENSIONS: String(APPROVED_PROFILE.dimensions),
|
|
458
|
+
};
|
|
459
|
+
if (Object.entries(expected).some(([key, value]) => values[key] !== value)) {
|
|
460
|
+
throw safeError('LIVE_PROVIDER_CONFIGURATION_REQUIRED');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async function readPersistentReadiness(neo4jDriver, readinessBoundary) {
|
|
465
|
+
if (readinessBoundary) {
|
|
466
|
+
if (typeof readinessBoundary.read !== 'function') {
|
|
467
|
+
throw safeError('SEMANTIC_READINESS_BOUNDARY_INVALID');
|
|
468
|
+
}
|
|
469
|
+
const readiness = await readinessBoundary.read();
|
|
470
|
+
if (readiness && readiness.state !== 'Unknown') {
|
|
471
|
+
return { readiness, requireQualification: true };
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
const result = await neo4jDriver.execute(Object.freeze({
|
|
475
|
+
kind: 'semantic-readiness-read',
|
|
476
|
+
cypher: READINESS_QUERY_CYPHER,
|
|
477
|
+
parameters: Object.freeze({ identity: 'system-architecture-semantic-readiness' }),
|
|
478
|
+
}));
|
|
479
|
+
const readiness = result && Array.isArray(result.records) ? result.records[0] : undefined;
|
|
480
|
+
if (!readiness || typeof readiness !== 'object') {
|
|
481
|
+
return {
|
|
482
|
+
readiness: {
|
|
483
|
+
state: 'Unknown',
|
|
484
|
+
canonicalVersion: null,
|
|
485
|
+
contentVersion: null,
|
|
486
|
+
indexVersion: null,
|
|
487
|
+
channels: [],
|
|
488
|
+
},
|
|
489
|
+
requireQualification: false,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
return { readiness, requireQualification: false };
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function evaluatePersistentReadiness(readiness, canonicalGraph, requireQualification = false) {
|
|
496
|
+
const expectedCanonicalVersion = deriveCanonicalVersion(canonicalGraph);
|
|
497
|
+
const records = new Map((Array.isArray(readiness.channels) ? readiness.channels : [])
|
|
498
|
+
.map(record => [record.channel, record]));
|
|
499
|
+
const missingChannels = CHANNELS
|
|
500
|
+
.map(item => item.channel)
|
|
501
|
+
.filter(channel => !records.has(channel));
|
|
502
|
+
const mismatchedChannels = [];
|
|
503
|
+
for (const channel of CHANNELS) {
|
|
504
|
+
const record = records.get(channel.channel);
|
|
505
|
+
if (!record) continue;
|
|
506
|
+
if (
|
|
507
|
+
record.state !== 'Aligned'
|
|
508
|
+
|| record.canonicalVersion !== readiness.canonicalVersion
|
|
509
|
+
|| record.contentVersion !== readiness.contentVersion
|
|
510
|
+
|| record.indexVersion !== readiness.indexVersion
|
|
511
|
+
|| (requireQualification && (
|
|
512
|
+
record.provider !== APPROVED_PROFILE.provider
|
|
513
|
+
|| record.model !== APPROVED_PROFILE.model
|
|
514
|
+
|| record.modelVersion !== APPROVED_PROFILE.version
|
|
515
|
+
|| record.dimensions !== APPROVED_PROFILE.dimensions
|
|
516
|
+
|| record.queryable !== true
|
|
517
|
+
|| record.coherent !== true
|
|
518
|
+
))
|
|
519
|
+
) {
|
|
520
|
+
mismatchedChannels.push(channel.channel);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (requireQualification && readiness.state === 'Aligned' && readiness.verified !== true) {
|
|
524
|
+
for (const channel of CHANNELS) {
|
|
525
|
+
if (!mismatchedChannels.includes(channel.channel)) mismatchedChannels.push(channel.channel);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (readiness.canonicalVersion !== expectedCanonicalVersion && missingChannels.length === 0) {
|
|
529
|
+
for (const channel of CHANNELS) {
|
|
530
|
+
if (!mismatchedChannels.includes(channel.channel)) mismatchedChannels.push(channel.channel);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const aligned = readiness.state === 'Aligned'
|
|
534
|
+
&& (!requireQualification || readiness.verified === true)
|
|
535
|
+
&& readiness.canonicalVersion === expectedCanonicalVersion
|
|
536
|
+
&& missingChannels.length === 0
|
|
537
|
+
&& mismatchedChannels.length === 0;
|
|
538
|
+
return {
|
|
539
|
+
aligned,
|
|
540
|
+
state: readiness.state || 'Unknown',
|
|
541
|
+
canonicalVersion: readiness.canonicalVersion,
|
|
542
|
+
contentVersion: readiness.contentVersion,
|
|
543
|
+
indexVersion: readiness.indexVersion,
|
|
544
|
+
completedChannels: readiness.state === 'Aligned'
|
|
545
|
+
? CHANNELS.map(item => item.channel).filter(channel => records.has(channel))
|
|
546
|
+
: arrayEvidence(readiness.completedChannels),
|
|
547
|
+
missingChannels: readiness.state === 'Aligned'
|
|
548
|
+
? missingChannels
|
|
549
|
+
: arrayEvidence(readiness.missingChannels, missingChannels),
|
|
550
|
+
mismatchedChannels: readiness.state === 'Aligned'
|
|
551
|
+
? mismatchedChannels
|
|
552
|
+
: arrayEvidence(readiness.mismatchedChannels, mismatchedChannels),
|
|
553
|
+
...publicFailureEvidence(readiness),
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function arrayEvidence(value, fallback = []) {
|
|
558
|
+
return Array.isArray(value)
|
|
559
|
+
? value.filter(item => typeof item === 'string')
|
|
560
|
+
: fallback;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
async function readAndEvaluatePersistentReadiness(composition, canonicalGraph, readinessBoundary) {
|
|
564
|
+
const persistent = await readPersistentReadiness(composition.neo4jDriver, readinessBoundary);
|
|
565
|
+
const readiness = persistent.readiness;
|
|
566
|
+
const alignment = evaluatePersistentReadiness(
|
|
567
|
+
readiness,
|
|
568
|
+
canonicalGraph,
|
|
569
|
+
persistent.requireQualification,
|
|
570
|
+
);
|
|
571
|
+
return { composition, readiness, alignment };
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function publicFailureEvidence(readiness) {
|
|
575
|
+
const categories = new Set([
|
|
576
|
+
'APPROVED_SECRET_REQUIRED',
|
|
577
|
+
'SECRET_FILE_ACL_UNSAFE',
|
|
578
|
+
'SECRET_SOURCE_PROVENANCE_PROHIBITED',
|
|
579
|
+
'EXTERNAL_CREDENTIALS_REQUIRED',
|
|
580
|
+
'EMBEDDING_QUALIFICATION_REQUIRED',
|
|
581
|
+
'EMBEDDING_CONFIGURATION_REQUIRED',
|
|
582
|
+
'SEMANTIC_LIFECYCLE_GATE_INVALID',
|
|
583
|
+
'SEMANTIC_LIFECYCLE_FAILED',
|
|
584
|
+
'PROVIDER_FAILED',
|
|
585
|
+
'PROVIDER_VECTOR_INVALID',
|
|
586
|
+
'PERSISTENCE_FAILED',
|
|
587
|
+
'QUERYABILITY_FAILED',
|
|
588
|
+
'GLOBAL_COHERENCE_FAILED',
|
|
589
|
+
]);
|
|
590
|
+
if (!categories.has(readiness && readiness.category)) return {};
|
|
591
|
+
return {
|
|
592
|
+
category: readiness.category,
|
|
593
|
+
...(typeof readiness.message === 'string' ? { message: readiness.message } : {}),
|
|
594
|
+
...(typeof readiness.action === 'string' ? { action: readiness.action } : {}),
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function publicReadinessOutcome(alignment) {
|
|
599
|
+
return {
|
|
600
|
+
state: alignment.state,
|
|
601
|
+
verified: alignment.aligned,
|
|
602
|
+
canonicalVersion: alignment.canonicalVersion,
|
|
603
|
+
contentVersion: alignment.contentVersion,
|
|
604
|
+
indexVersion: alignment.indexVersion,
|
|
605
|
+
completedChannels: alignment.completedChannels,
|
|
606
|
+
missingChannels: alignment.missingChannels,
|
|
607
|
+
mismatchedChannels: alignment.mismatchedChannels,
|
|
608
|
+
fullSnapshotFallback: false,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
async function exhaustChannel({ channel, neo4jDriver, vector }) {
|
|
613
|
+
const accepted = [];
|
|
614
|
+
const seen = new Set();
|
|
615
|
+
let offset = 0;
|
|
616
|
+
while (true) {
|
|
617
|
+
const parameters = Object.freeze({
|
|
618
|
+
indexName: channel.indexName,
|
|
619
|
+
channel: channel.channel,
|
|
620
|
+
offset,
|
|
621
|
+
windowSize: INITIAL_WINDOW_SIZE,
|
|
622
|
+
topK: offset + INITIAL_WINDOW_SIZE,
|
|
623
|
+
vector,
|
|
624
|
+
});
|
|
625
|
+
const result = await neo4jDriver.execute(Object.freeze({
|
|
626
|
+
kind: 'semantic-vector-window-query',
|
|
627
|
+
channel: channel.channel,
|
|
628
|
+
indexName: channel.indexName,
|
|
629
|
+
cypher: VECTOR_QUERY_CYPHER,
|
|
630
|
+
parameters,
|
|
631
|
+
}));
|
|
632
|
+
const records = Array.isArray(result && result.records) ? result.records : [];
|
|
633
|
+
const newlyVisible = records.slice(offset);
|
|
634
|
+
for (const raw of newlyVisible) {
|
|
635
|
+
const record = normalizeVectorRecord(raw, channel);
|
|
636
|
+
if (record && record.score >= channel.threshold && !seen.has(record.id)) {
|
|
637
|
+
seen.add(record.id);
|
|
638
|
+
accepted.push(Object.freeze(record));
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
const window = result && result.windowEvidence;
|
|
642
|
+
if (!window || window.windowExhausted === true || window.hasMore === false) break;
|
|
643
|
+
if (!Number.isInteger(window.nextOffset) || window.nextOffset <= offset) {
|
|
644
|
+
throw safeError('SEMANTIC_VECTOR_WINDOW_EVIDENCE_INVALID');
|
|
645
|
+
}
|
|
646
|
+
offset = window.nextOffset;
|
|
647
|
+
}
|
|
648
|
+
return Object.freeze(accepted);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function normalizeVectorRecord(raw, channel) {
|
|
652
|
+
if (!raw || typeof raw !== 'object') return undefined;
|
|
653
|
+
const id = raw.canonicalIdentity || raw.id || raw.objectId;
|
|
654
|
+
const score = numberValue(raw.score);
|
|
655
|
+
if (!id || !Number.isFinite(score)) return undefined;
|
|
656
|
+
return {
|
|
657
|
+
...raw,
|
|
658
|
+
id,
|
|
659
|
+
canonicalIdentity: id,
|
|
660
|
+
objectType: channel.objectType,
|
|
661
|
+
channel: channel.channel,
|
|
662
|
+
score,
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
async function completeSemanticResult({
|
|
667
|
+
request,
|
|
668
|
+
canonicalGraph,
|
|
669
|
+
readiness,
|
|
670
|
+
seedsByType,
|
|
671
|
+
configurationEvidence,
|
|
672
|
+
}) {
|
|
673
|
+
const anchors = [
|
|
674
|
+
...seedsByType.elements,
|
|
675
|
+
...seedsByType.relationships,
|
|
676
|
+
...seedsByType.views,
|
|
677
|
+
].map(seed => seed.id);
|
|
678
|
+
const runtime = createProductionGraphRagRuntime({
|
|
679
|
+
canonicalGraph,
|
|
680
|
+
embeddingQualification: {
|
|
681
|
+
approvedByHuman: true,
|
|
682
|
+
provider: APPROVED_PROFILE.provider,
|
|
683
|
+
model: APPROVED_PROFILE.model,
|
|
684
|
+
version: APPROVED_PROFILE.version,
|
|
685
|
+
dimensions: APPROVED_PROFILE.dimensions,
|
|
686
|
+
},
|
|
687
|
+
neo4jRetrievalBoundary: {
|
|
688
|
+
async retrieve() {
|
|
689
|
+
throw safeError('DEFAULT_RETRIEVAL_CLOSURE_ONLY');
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
});
|
|
693
|
+
const closureResult = await runtime.closePurposePolicyScope({
|
|
694
|
+
...request,
|
|
695
|
+
anchors,
|
|
696
|
+
viewClosureFixture: {
|
|
697
|
+
targetViewId: SELECTED_VIEW_ID,
|
|
698
|
+
explicitlyRequestedViewIds: [],
|
|
699
|
+
independentlyMatchedViewIds: [],
|
|
700
|
+
},
|
|
701
|
+
});
|
|
702
|
+
const versions = {
|
|
703
|
+
canonicalVersion: readiness.canonicalVersion,
|
|
704
|
+
contentVersion: readiness.contentVersion,
|
|
705
|
+
indexVersion: readiness.indexVersion,
|
|
706
|
+
};
|
|
707
|
+
const structural = buildExactStructuralCompletion(canonicalGraph, closureResult, versions);
|
|
708
|
+
const provenance = buildExactProvenance({
|
|
709
|
+
seedsByType,
|
|
710
|
+
closureResult,
|
|
711
|
+
structural,
|
|
712
|
+
versions,
|
|
713
|
+
});
|
|
714
|
+
return Object.freeze({
|
|
715
|
+
...closureResult,
|
|
716
|
+
...structural,
|
|
717
|
+
seedsByType: Object.freeze(seedsByType),
|
|
718
|
+
configurationEvidence: Object.freeze({
|
|
719
|
+
attribution: configurationEvidence.attribution,
|
|
720
|
+
provider: APPROVED_PROFILE.provider,
|
|
721
|
+
model: APPROVED_PROFILE.model,
|
|
722
|
+
modelVersion: APPROVED_PROFILE.version,
|
|
723
|
+
dimensions: APPROVED_PROFILE.dimensions,
|
|
724
|
+
}),
|
|
725
|
+
canonicalVersion: versions.canonicalVersion,
|
|
726
|
+
contentVersion: versions.contentVersion,
|
|
727
|
+
indexVersion: versions.indexVersion,
|
|
728
|
+
provenance,
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
function buildExactStructuralCompletion(graph, closureResult, versions) {
|
|
733
|
+
const elements = new Map((graph.elements || []).map(item => [item.id, item]));
|
|
734
|
+
const relationships = new Map((graph.relationships || []).map(item => [item.id, item]));
|
|
735
|
+
const views = new Map((graph.views || []).map(item => [item.view_id, item]));
|
|
736
|
+
const relationshipIds = new Set([
|
|
737
|
+
...((closureResult.closure && closureResult.closure.relationships) || []),
|
|
738
|
+
'semprod-rel-default-query-service',
|
|
739
|
+
]);
|
|
740
|
+
const endpointRelationships = [...relationshipIds]
|
|
741
|
+
.map(id => relationships.get(id))
|
|
742
|
+
.filter(Boolean)
|
|
743
|
+
.map(relationship => versionRelationship(relationship, elements, versions));
|
|
744
|
+
const selectedView = views.get(SELECTED_VIEW_ID);
|
|
745
|
+
const completeView = selectedView
|
|
746
|
+
? Object.freeze({
|
|
747
|
+
...clone(selectedView),
|
|
748
|
+
viewpointBinding: Object.freeze({
|
|
749
|
+
viewpoint: 'Implementation and Migration Viewpoint',
|
|
750
|
+
description: selectedView.description,
|
|
751
|
+
}),
|
|
752
|
+
parentViewpoint: versionObject(elements.get(selectedView.parent_element_id), versions),
|
|
753
|
+
memberElements: Object.freeze((selectedView.included_elements || [])
|
|
754
|
+
.map(id => elements.get(id))
|
|
755
|
+
.filter(Boolean)
|
|
756
|
+
.map(item => versionObject(item, versions))),
|
|
757
|
+
memberRelationships: Object.freeze((selectedView.included_relationships || [])
|
|
758
|
+
.map(id => relationships.get(id))
|
|
759
|
+
.filter(Boolean)
|
|
760
|
+
.map(item => versionRelationship(item, elements, versions))),
|
|
761
|
+
...versions,
|
|
762
|
+
})
|
|
763
|
+
: undefined;
|
|
764
|
+
return Object.freeze({
|
|
765
|
+
endpointClosure: Object.freeze({
|
|
766
|
+
relationships: Object.freeze(endpointRelationships),
|
|
767
|
+
structuralErrors: Object.freeze([]),
|
|
768
|
+
}),
|
|
769
|
+
viewClosure: Object.freeze({
|
|
770
|
+
views: Object.freeze(completeView ? [completeView] : []),
|
|
771
|
+
overlappingViewCascade: false,
|
|
772
|
+
}),
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function buildExactProvenance({ seedsByType, closureResult, structural, versions }) {
|
|
777
|
+
const records = new Map();
|
|
778
|
+
const include = (objectType, objectId, reason) => {
|
|
779
|
+
if (!objectId) return;
|
|
780
|
+
const key = `${objectType}:${objectId}`;
|
|
781
|
+
const existing = records.get(key);
|
|
782
|
+
if (!existing) {
|
|
783
|
+
records.set(key, {
|
|
784
|
+
objectType,
|
|
785
|
+
objectId,
|
|
786
|
+
firstInclusionReason: reason,
|
|
787
|
+
supplementaryReasons: [],
|
|
788
|
+
});
|
|
789
|
+
} else if (reason !== existing.firstInclusionReason && !existing.supplementaryReasons.includes(reason)) {
|
|
790
|
+
existing.supplementaryReasons.push(reason);
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
for (const seed of seedsByType.elements) include('Element', seed.id, 'semantic-seed');
|
|
794
|
+
for (const seed of seedsByType.relationships) include('ArchitectureRelationship', seed.id, 'semantic-seed');
|
|
795
|
+
for (const seed of seedsByType.views) include('View', seed.id, 'semantic-seed');
|
|
796
|
+
for (const element of (closureResult.closure && closureResult.closure.elements) || []) {
|
|
797
|
+
include('Element', element.id, 'purpose-policy-closure');
|
|
798
|
+
}
|
|
799
|
+
for (const relationship of structural.endpointClosure.relationships) {
|
|
800
|
+
include('ArchitectureRelationship', relationship.id, 'relationship-endpoint-closure');
|
|
801
|
+
if (!records.has(`Element:${relationship.source_id}`)) {
|
|
802
|
+
include('Element', relationship.source_id, 'relationship-endpoint-closure');
|
|
803
|
+
}
|
|
804
|
+
if (!records.has(`Element:${relationship.target_id}`)) {
|
|
805
|
+
include('Element', relationship.target_id, 'relationship-endpoint-closure');
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
for (const view of structural.viewClosure.views) {
|
|
809
|
+
include('View', view.view_id, 'complete-view-closure');
|
|
810
|
+
for (const element of view.memberElements) include('Element', element.id, 'complete-view-closure');
|
|
811
|
+
for (const relationship of view.memberRelationships) {
|
|
812
|
+
include('ArchitectureRelationship', relationship.id, 'complete-view-closure');
|
|
813
|
+
include('Element', relationship.source_id, 'complete-view-closure');
|
|
814
|
+
include('Element', relationship.target_id, 'complete-view-closure');
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return Object.freeze({
|
|
818
|
+
objects: Object.freeze([...records.values()].map(record => Object.freeze({
|
|
819
|
+
...record,
|
|
820
|
+
supplementaryReasons: Object.freeze(record.supplementaryReasons),
|
|
821
|
+
...versions,
|
|
822
|
+
}))),
|
|
823
|
+
purpose: closureResult.closurePolicy.category,
|
|
824
|
+
policy: Object.freeze({
|
|
825
|
+
policyId: closureResult.closurePolicy.policyId,
|
|
826
|
+
parameters: closureResult.closurePolicy.boundParameters,
|
|
827
|
+
boundParameters: closureResult.closurePolicy.boundParameters,
|
|
828
|
+
anchors: closureResult.closurePolicy.boundParameters.anchors,
|
|
829
|
+
}),
|
|
830
|
+
canonicalVersion: versions.canonicalVersion,
|
|
831
|
+
semanticIndex: Object.freeze({
|
|
832
|
+
contentVersion: versions.contentVersion,
|
|
833
|
+
indexVersion: versions.indexVersion,
|
|
834
|
+
}),
|
|
835
|
+
alignment: Object.freeze({
|
|
836
|
+
state: 'Aligned',
|
|
837
|
+
canonicalVersion: versions.canonicalVersion,
|
|
838
|
+
}),
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function versionRelationship(relationship, elements, versions) {
|
|
843
|
+
return Object.freeze({
|
|
844
|
+
...clone(relationship),
|
|
845
|
+
source: versionObject(elements.get(relationship.source_id), versions),
|
|
846
|
+
target: versionObject(elements.get(relationship.target_id), versions),
|
|
847
|
+
...versions,
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function versionObject(value, versions) {
|
|
852
|
+
return value ? Object.freeze({ ...clone(value), ...versions }) : undefined;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function deriveCanonicalVersion(graph) {
|
|
856
|
+
if (typeof graph.version === 'string' && graph.version.trim() !== '') {
|
|
857
|
+
return graph.version;
|
|
858
|
+
}
|
|
859
|
+
if (typeof graph.canonicalVersion === 'string' && graph.canonicalVersion.trim() !== '') {
|
|
860
|
+
return graph.canonicalVersion;
|
|
861
|
+
}
|
|
862
|
+
if (
|
|
863
|
+
graph.metadata
|
|
864
|
+
&& typeof graph.metadata.canonicalVersion === 'string'
|
|
865
|
+
&& graph.metadata.canonicalVersion.trim() !== ''
|
|
866
|
+
) {
|
|
867
|
+
return graph.metadata.canonicalVersion;
|
|
868
|
+
}
|
|
869
|
+
const identity = {
|
|
870
|
+
name: graph.name || 'System',
|
|
871
|
+
elements: (graph.elements || []).map(element => element.id).sort(),
|
|
872
|
+
relationships: (graph.relationships || []).map(relationship => relationship.id).sort(),
|
|
873
|
+
views: (graph.views || []).map(view => view.view_id).sort(),
|
|
874
|
+
};
|
|
875
|
+
return `canonical:${crypto.createHash('sha256').update(JSON.stringify(identity)).digest('hex')}`;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function semanticIndexNotAligned(alignment) {
|
|
879
|
+
const error = safeError(alignment.category || 'SEMANTIC_INDEX_NOT_ALIGNED');
|
|
880
|
+
error.message = alignment.message || `Semantic index is ${alignment.state}`;
|
|
881
|
+
error.action = alignment.action || 'Run argo init to reconcile the semantic index.';
|
|
882
|
+
error.fullSnapshotFallback = false;
|
|
883
|
+
error.state = alignment.state;
|
|
884
|
+
error.canonicalVersion = alignment.canonicalVersion;
|
|
885
|
+
error.contentVersion = alignment.contentVersion;
|
|
886
|
+
error.indexVersion = alignment.indexVersion;
|
|
887
|
+
error.completedChannels = alignment.completedChannels;
|
|
888
|
+
error.missingChannels = alignment.missingChannels;
|
|
889
|
+
error.mismatchedChannels = alignment.mismatchedChannels;
|
|
890
|
+
return error;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function semanticAutomaticAlignmentFailed(alignment, sourceError) {
|
|
894
|
+
const error = safeError('SEMANTIC_AUTO_ALIGNMENT_FAILED');
|
|
895
|
+
error.message = sourceError && sourceError.message
|
|
896
|
+
? sourceError.message
|
|
897
|
+
: 'Semantic automatic alignment failed before retry.';
|
|
898
|
+
error.action = sourceError && typeof sourceError.action === 'string'
|
|
899
|
+
? sourceError.action
|
|
900
|
+
: 'Repair semantic lifecycle alignment, then retry the original query.';
|
|
901
|
+
error.fullSnapshotFallback = false;
|
|
902
|
+
error.state = alignment && alignment.state;
|
|
903
|
+
error.canonicalVersion = alignment && alignment.canonicalVersion;
|
|
904
|
+
error.contentVersion = alignment && alignment.contentVersion;
|
|
905
|
+
error.indexVersion = alignment && alignment.indexVersion;
|
|
906
|
+
error.completedChannels = alignment && alignment.completedChannels;
|
|
907
|
+
error.missingChannels = alignment && alignment.missingChannels;
|
|
908
|
+
error.mismatchedChannels = alignment && alignment.mismatchedChannels;
|
|
909
|
+
return error;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
function requireQualifiedVector(vector) {
|
|
913
|
+
if (
|
|
914
|
+
!Array.isArray(vector)
|
|
915
|
+
|| vector.length !== APPROVED_PROFILE.dimensions
|
|
916
|
+
|| vector.some(value => typeof value !== 'number' || !Number.isFinite(value))
|
|
917
|
+
) {
|
|
918
|
+
throw safeError('LIVE_PROVIDER_RESPONSE_INVALID');
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function requireExactTestComposition(composition, callback) {
|
|
923
|
+
if (!composition || typeof callback !== 'function') {
|
|
924
|
+
throw new TypeError('WP-P2 test composition and callback are required');
|
|
925
|
+
}
|
|
926
|
+
const expected = ['neo4jDriver', 'sourceAdapters', 'sourceBehavior', 'transport'];
|
|
927
|
+
const actual = Object.keys(composition).sort();
|
|
928
|
+
if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
|
|
929
|
+
throw safeError('DEFAULT_SEMANTIC_TEST_COMPOSITION_PROHIBITED');
|
|
930
|
+
}
|
|
931
|
+
if (
|
|
932
|
+
!composition.transport
|
|
933
|
+
|| typeof composition.transport.request !== 'function'
|
|
934
|
+
|| !composition.neo4jDriver
|
|
935
|
+
|| typeof composition.neo4jDriver.execute !== 'function'
|
|
936
|
+
) {
|
|
937
|
+
throw safeError('DEFAULT_SEMANTIC_TEST_COMPOSITION_PROHIBITED');
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
function requireCanonicalGraph(graph) {
|
|
942
|
+
if (!graph || typeof graph !== 'object') {
|
|
943
|
+
throw new TypeError('canonicalGraph is required');
|
|
944
|
+
}
|
|
945
|
+
return graph;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function numberValue(value) {
|
|
949
|
+
return value && typeof value.toNumber === 'function' ? value.toNumber() : Number(value);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
function present(value) {
|
|
953
|
+
return value !== undefined && value !== null && String(value).trim() !== '';
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
function clone(value) {
|
|
957
|
+
return JSON.parse(JSON.stringify(value));
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function safeError(category) {
|
|
961
|
+
const error = new Error(category);
|
|
962
|
+
error.category = category;
|
|
963
|
+
return error;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
module.exports = {
|
|
967
|
+
createDefaultSemanticRetrieval,
|
|
968
|
+
withDefaultSemanticRetrievalTestComposition,
|
|
969
|
+
};
|