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.
Files changed (54) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +115 -0
  3. package/argo/package.json +8 -0
  4. package/argo/rules/intent-architecture-global-rule.md +45 -0
  5. package/argo/schema/ImplementationToCodingHandoff.schema.json +252 -0
  6. package/argo/schema/ImplementationToIntentTraceProposal.schema.json +180 -0
  7. package/argo/schema/IntentToImplementationHandoff.schema.json +75 -0
  8. package/argo/schema/SystemArchitecture.schema.json +378 -0
  9. package/argo/schema/archimate3.2.pdf +0 -0
  10. package/argo/scripts/ARCHITECTURE.md +57 -0
  11. package/argo/scripts/archimate32-rules.js +12301 -0
  12. package/argo/scripts/argo-mcp-server.js +629 -0
  13. package/argo/scripts/argo-paths.js +77 -0
  14. package/argo/scripts/ensureArgoHarnessEnvironment.js +340 -0
  15. package/argo/scripts/generateArchitectureDiffPlantuml.js +466 -0
  16. package/argo/scripts/graph-rag/ARCHITECTURE.md +192 -0
  17. package/argo/scripts/graph-rag/canonicalProjectionAuthority.js +45 -0
  18. package/argo/scripts/graph-rag/defaultSemanticRetrieval.js +969 -0
  19. package/argo/scripts/graph-rag/embeddingQualificationGate.js +59 -0
  20. package/argo/scripts/graph-rag/externalProductionConfig.js +74 -0
  21. package/argo/scripts/graph-rag/liveEmbeddingIndexGate.js +129 -0
  22. package/argo/scripts/graph-rag/liveEmbeddingNeo4jBoundary.js +137 -0
  23. package/argo/scripts/graph-rag/liveEmbeddingProviderClient.js +49 -0
  24. package/argo/scripts/graph-rag/liveEmbeddingProviderConfig.js +481 -0
  25. package/argo/scripts/graph-rag/mutationEmbeddingVectorLifecycle.js +1261 -0
  26. package/argo/scripts/graph-rag/neo4jNativeRetrieval.js +37 -0
  27. package/argo/scripts/graph-rag/productionGraphRagRuntime.js +1624 -0
  28. package/argo/scripts/graph-rag/semantic-persistence/ARCHITECTURE.md +51 -0
  29. package/argo/scripts/graph-rag/semantic-persistence/productionSemanticBackfill.js +241 -0
  30. package/argo/scripts/graph-rag/semantic-persistence/productionSemanticCheckpointStore.js +99 -0
  31. package/argo/scripts/graph-rag/semantic-persistence/productionSemanticNeo4jAdapter.js +149 -0
  32. package/argo/scripts/graph-rag/semantic-persistence/productionSemanticProjectionStore.js +171 -0
  33. package/argo/scripts/graph-rag/semanticOperatorError.js +38 -0
  34. package/argo/scripts/graph-rag/semanticOperatorJourney.js +459 -0
  35. package/argo/scripts/graph-rag/semanticReadinessAttestationStore.js +398 -0
  36. package/argo/scripts/graph-rag/systemMetadataCommandAdapter.js +269 -0
  37. package/argo/scripts/graph-semantics.js +220 -0
  38. package/argo/scripts/neo4j-system-architecture-store.js +777 -0
  39. package/argo/scripts/repositoryArgoEnvironment.js +101 -0
  40. package/argo/scripts/runArchitectureTests.js +583 -0
  41. package/argo/scripts/semanticOperatorJourneyCli.js +91 -0
  42. package/argo/scripts/syncSystemArchitectureToNeo4j.js +67 -0
  43. package/argo/scripts/systemarchitecture-mcp-server.js +2965 -0
  44. package/argo/scripts/test-executors/_template.js +58 -0
  45. package/argo/scripts/test-executors/default.js +199 -0
  46. package/argo/scripts/validateStageHandoff.js +459 -0
  47. package/argo/scripts/validateSystemArchitecture.js +254 -0
  48. package/argo/scripts/validateTraceProposal.js +181 -0
  49. package/argo/scripts/validator-mcp-server.js +377 -0
  50. package/argo/skills/argo-init/SKILL.md +110 -0
  51. package/bin/argo-deploy.js +12 -0
  52. package/install-argo.ps1 +112 -0
  53. package/package.json +28 -0
  54. 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
+ };