archgraph-argo 0.10.42 → 0.10.44
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 -201
- package/argo/package.json +8 -8
- package/argo/rules/archgraph.instructions.md +8 -0
- package/argo/schema/ImplementationToCodingHandoff.schema.json +251 -251
- package/argo/schema/ImplementationToIntentTraceProposal.schema.json +180 -180
- package/argo/schema/IntentToImplementationHandoff.schema.json +74 -74
- package/argo/schema/SystemArchitecture.schema.json +378 -378
- package/argo/schema/archimate3.2.md +7153 -7153
- package/argo/scripts/archimate32-rules.js +12301 -12301
- package/argo/scripts/generateArchitectureDiffPlantuml.js +466 -466
- package/argo/scripts/graph-rag/ARCHITECTURE.md +192 -192
- package/argo/scripts/graph-rag/canonicalProjectionAuthority.js +45 -45
- package/argo/scripts/graph-rag/embeddingQualificationGate.js +59 -59
- package/argo/scripts/graph-rag/externalProductionConfig.js +74 -74
- package/argo/scripts/graph-rag/liveEmbeddingProviderClient.js +49 -49
- package/argo/scripts/graph-rag/neo4jNativeRetrieval.js +37 -37
- package/argo/scripts/graph-rag/semantic-persistence/ARCHITECTURE.md +51 -51
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticCheckpointStore.js +99 -99
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticProjectionStore.js +171 -171
- package/argo/scripts/graph-rag/semanticOperatorError.js +38 -38
- package/argo/scripts/graph-rag/semanticOperatorJourney.js +459 -459
- package/argo/scripts/graph-rag/semanticReadinessAttestationStore.js +398 -398
- package/argo/scripts/graph-rag/systemMetadataCommandAdapter.js +269 -269
- package/argo/scripts/graph-semantics.js +220 -220
- package/argo/scripts/repositoryArgoEnvironment.js +101 -101
- package/argo/scripts/runArchitectureTests.js +583 -583
- package/argo/scripts/semanticOperatorJourneyCli.js +91 -91
- package/argo/scripts/syncSystemArchitectureToNeo4j.js +66 -66
- package/argo/scripts/test-executors/_template.js +58 -58
- package/argo/scripts/test-executors/default.js +199 -199
- package/argo/scripts/validateStageHandoff.js +458 -458
- package/argo/scripts/validateSystemArchitecture.js +253 -253
- package/argo/scripts/validateTraceProposal.js +181 -181
- package/bin/argo-deploy.js +12 -12
- package/install-argo.ps1 +27 -8
- package/package.json +1 -1
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
const CHECKPOINT_LABEL = 'ArgoProductionSemanticCheckpoint';
|
|
2
|
-
|
|
3
|
-
function createProductionSemanticCheckpointStore(dependencies = {}) {
|
|
4
|
-
const { driver } = dependencies;
|
|
5
|
-
if (!driver || (typeof driver.execute !== 'function' && typeof driver.session !== 'function')) {
|
|
6
|
-
throw new TypeError('driver.execute or driver.session is required');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return Object.freeze({
|
|
10
|
-
async readCheckpoint(channel) {
|
|
11
|
-
if (typeof driver.execute === 'function') {
|
|
12
|
-
const result = await driver.execute(Object.freeze({
|
|
13
|
-
kind: 'semantic-checkpoint-read',
|
|
14
|
-
channel,
|
|
15
|
-
}));
|
|
16
|
-
return result && result.checkpoint ? cloneCheckpoint(result.checkpoint) : undefined;
|
|
17
|
-
}
|
|
18
|
-
return withSession(driver, dependencies.configuration, async session => {
|
|
19
|
-
const result = await executeRead(
|
|
20
|
-
session,
|
|
21
|
-
`MATCH (checkpoint:${CHECKPOINT_LABEL} {channel: $channel}) RETURN checkpoint.payload AS payload`,
|
|
22
|
-
{ channel },
|
|
23
|
-
);
|
|
24
|
-
const record = result.records && result.records[0];
|
|
25
|
-
const payload = record && typeof record.get === 'function' ? record.get('payload') : record && record.payload;
|
|
26
|
-
return typeof payload === 'string' ? cloneCheckpoint(JSON.parse(payload)) : undefined;
|
|
27
|
-
});
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
async writeCheckpoint(checkpoint) {
|
|
31
|
-
const durableCheckpoint = cloneCheckpoint(checkpoint);
|
|
32
|
-
if (typeof driver.execute === 'function') {
|
|
33
|
-
const result = await driver.execute(Object.freeze({
|
|
34
|
-
kind: 'semantic-checkpoint-write',
|
|
35
|
-
checkpoint: durableCheckpoint,
|
|
36
|
-
}));
|
|
37
|
-
return result && result.checkpoint ? cloneCheckpoint(result.checkpoint) : durableCheckpoint;
|
|
38
|
-
}
|
|
39
|
-
await withSession(driver, dependencies.configuration, session => executeWrite(
|
|
40
|
-
session,
|
|
41
|
-
[
|
|
42
|
-
`MERGE (checkpoint:${CHECKPOINT_LABEL} {channel: $channel})`,
|
|
43
|
-
'SET checkpoint.canonicalVersion = $canonicalVersion, checkpoint.payload = $payload',
|
|
44
|
-
'RETURN checkpoint.payload AS payload',
|
|
45
|
-
].join('\n'),
|
|
46
|
-
{
|
|
47
|
-
channel: durableCheckpoint.channel,
|
|
48
|
-
canonicalVersion: durableCheckpoint.canonicalVersion,
|
|
49
|
-
payload: JSON.stringify(durableCheckpoint),
|
|
50
|
-
},
|
|
51
|
-
));
|
|
52
|
-
return durableCheckpoint;
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
async close() {
|
|
56
|
-
if (typeof driver.close === 'function') {
|
|
57
|
-
await driver.close();
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function withSession(driver, configuration, action) {
|
|
64
|
-
const database = configuration && configuration.neo4jDatabase;
|
|
65
|
-
const session = driver.session(database === undefined ? undefined : { database });
|
|
66
|
-
try {
|
|
67
|
-
return await action(session);
|
|
68
|
-
} finally {
|
|
69
|
-
if (session && typeof session.close === 'function') {
|
|
70
|
-
await session.close();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function executeWrite(session, query, parameters) {
|
|
76
|
-
if (typeof session.executeWrite === 'function') {
|
|
77
|
-
return session.executeWrite(transaction => transaction.run(query, parameters));
|
|
78
|
-
}
|
|
79
|
-
return session.run(query, parameters);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function executeRead(session, query, parameters) {
|
|
83
|
-
if (typeof session.executeRead === 'function') {
|
|
84
|
-
return session.executeRead(transaction => transaction.run(query, parameters));
|
|
85
|
-
}
|
|
86
|
-
return session.run(query, parameters);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function cloneCheckpoint(checkpoint) {
|
|
90
|
-
return Object.freeze({
|
|
91
|
-
...checkpoint,
|
|
92
|
-
completedCanonicalIdentities: Object.freeze([...(checkpoint.completedCanonicalIdentities || [])]),
|
|
93
|
-
isolatedFailures: Object.freeze((checkpoint.isolatedFailures || []).map(failure => Object.freeze({ ...failure }))),
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
module.exports = {
|
|
98
|
-
createProductionSemanticCheckpointStore,
|
|
99
|
-
};
|
|
1
|
+
const CHECKPOINT_LABEL = 'ArgoProductionSemanticCheckpoint';
|
|
2
|
+
|
|
3
|
+
function createProductionSemanticCheckpointStore(dependencies = {}) {
|
|
4
|
+
const { driver } = dependencies;
|
|
5
|
+
if (!driver || (typeof driver.execute !== 'function' && typeof driver.session !== 'function')) {
|
|
6
|
+
throw new TypeError('driver.execute or driver.session is required');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return Object.freeze({
|
|
10
|
+
async readCheckpoint(channel) {
|
|
11
|
+
if (typeof driver.execute === 'function') {
|
|
12
|
+
const result = await driver.execute(Object.freeze({
|
|
13
|
+
kind: 'semantic-checkpoint-read',
|
|
14
|
+
channel,
|
|
15
|
+
}));
|
|
16
|
+
return result && result.checkpoint ? cloneCheckpoint(result.checkpoint) : undefined;
|
|
17
|
+
}
|
|
18
|
+
return withSession(driver, dependencies.configuration, async session => {
|
|
19
|
+
const result = await executeRead(
|
|
20
|
+
session,
|
|
21
|
+
`MATCH (checkpoint:${CHECKPOINT_LABEL} {channel: $channel}) RETURN checkpoint.payload AS payload`,
|
|
22
|
+
{ channel },
|
|
23
|
+
);
|
|
24
|
+
const record = result.records && result.records[0];
|
|
25
|
+
const payload = record && typeof record.get === 'function' ? record.get('payload') : record && record.payload;
|
|
26
|
+
return typeof payload === 'string' ? cloneCheckpoint(JSON.parse(payload)) : undefined;
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
async writeCheckpoint(checkpoint) {
|
|
31
|
+
const durableCheckpoint = cloneCheckpoint(checkpoint);
|
|
32
|
+
if (typeof driver.execute === 'function') {
|
|
33
|
+
const result = await driver.execute(Object.freeze({
|
|
34
|
+
kind: 'semantic-checkpoint-write',
|
|
35
|
+
checkpoint: durableCheckpoint,
|
|
36
|
+
}));
|
|
37
|
+
return result && result.checkpoint ? cloneCheckpoint(result.checkpoint) : durableCheckpoint;
|
|
38
|
+
}
|
|
39
|
+
await withSession(driver, dependencies.configuration, session => executeWrite(
|
|
40
|
+
session,
|
|
41
|
+
[
|
|
42
|
+
`MERGE (checkpoint:${CHECKPOINT_LABEL} {channel: $channel})`,
|
|
43
|
+
'SET checkpoint.canonicalVersion = $canonicalVersion, checkpoint.payload = $payload',
|
|
44
|
+
'RETURN checkpoint.payload AS payload',
|
|
45
|
+
].join('\n'),
|
|
46
|
+
{
|
|
47
|
+
channel: durableCheckpoint.channel,
|
|
48
|
+
canonicalVersion: durableCheckpoint.canonicalVersion,
|
|
49
|
+
payload: JSON.stringify(durableCheckpoint),
|
|
50
|
+
},
|
|
51
|
+
));
|
|
52
|
+
return durableCheckpoint;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
async close() {
|
|
56
|
+
if (typeof driver.close === 'function') {
|
|
57
|
+
await driver.close();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function withSession(driver, configuration, action) {
|
|
64
|
+
const database = configuration && configuration.neo4jDatabase;
|
|
65
|
+
const session = driver.session(database === undefined ? undefined : { database });
|
|
66
|
+
try {
|
|
67
|
+
return await action(session);
|
|
68
|
+
} finally {
|
|
69
|
+
if (session && typeof session.close === 'function') {
|
|
70
|
+
await session.close();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function executeWrite(session, query, parameters) {
|
|
76
|
+
if (typeof session.executeWrite === 'function') {
|
|
77
|
+
return session.executeWrite(transaction => transaction.run(query, parameters));
|
|
78
|
+
}
|
|
79
|
+
return session.run(query, parameters);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function executeRead(session, query, parameters) {
|
|
83
|
+
if (typeof session.executeRead === 'function') {
|
|
84
|
+
return session.executeRead(transaction => transaction.run(query, parameters));
|
|
85
|
+
}
|
|
86
|
+
return session.run(query, parameters);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function cloneCheckpoint(checkpoint) {
|
|
90
|
+
return Object.freeze({
|
|
91
|
+
...checkpoint,
|
|
92
|
+
completedCanonicalIdentities: Object.freeze([...(checkpoint.completedCanonicalIdentities || [])]),
|
|
93
|
+
isolatedFailures: Object.freeze((checkpoint.isolatedFailures || []).map(failure => Object.freeze({ ...failure }))),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
createProductionSemanticCheckpointStore,
|
|
99
|
+
};
|
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
const {
|
|
2
|
-
evaluateEmbeddingQualification,
|
|
3
|
-
} = require('../embeddingQualificationGate.js');
|
|
4
|
-
|
|
5
|
-
const CHANNELS = new Set(['Element', 'ArchitectureRelationship', 'View']);
|
|
6
|
-
const STRING_METADATA_FIELDS = Object.freeze([
|
|
7
|
-
'canonicalIdentity',
|
|
8
|
-
'canonicalVersion',
|
|
9
|
-
'contentVersion',
|
|
10
|
-
'indexVersion',
|
|
11
|
-
'provider',
|
|
12
|
-
'model',
|
|
13
|
-
'modelVersion',
|
|
14
|
-
]);
|
|
15
|
-
|
|
16
|
-
function createProductionSemanticProjectionStore(dependencies = {}) {
|
|
17
|
-
const {
|
|
18
|
-
persistenceAdapter,
|
|
19
|
-
canonicalAuthority,
|
|
20
|
-
configuration,
|
|
21
|
-
qualification,
|
|
22
|
-
} = dependencies;
|
|
23
|
-
requireAdapter(persistenceAdapter);
|
|
24
|
-
if (!canonicalAuthority || typeof canonicalAuthority.assertProjectionOnly !== 'function') {
|
|
25
|
-
throw new TypeError('canonicalAuthority.assertProjectionOnly is required');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function requireReleaseGates() {
|
|
29
|
-
requireExternalConfiguration(configuration);
|
|
30
|
-
const approved = evaluateEmbeddingQualification(qualification);
|
|
31
|
-
canonicalAuthority.assertProjectionOnly();
|
|
32
|
-
return approved;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return Object.freeze({
|
|
36
|
-
async upsertRecords(records) {
|
|
37
|
-
const supplied = requireArray(records, 'records');
|
|
38
|
-
rejectRunIds(supplied);
|
|
39
|
-
const approved = requireReleaseGates();
|
|
40
|
-
const validated = supplied.map(record => validateRecord(record, approved));
|
|
41
|
-
await persistenceAdapter.upsertRecords(validated);
|
|
42
|
-
return Object.freeze({ count: validated.length });
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
async deleteTombstones(tombstones) {
|
|
46
|
-
const supplied = requireArray(tombstones, 'tombstones');
|
|
47
|
-
rejectRunIds(supplied);
|
|
48
|
-
requireReleaseGates();
|
|
49
|
-
const validated = supplied.map(validateTombstone);
|
|
50
|
-
await persistenceAdapter.deleteTombstones(validated);
|
|
51
|
-
return Object.freeze({ count: validated.length });
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
async readRecords() {
|
|
55
|
-
requireReleaseGates();
|
|
56
|
-
const records = await persistenceAdapter.readRecords();
|
|
57
|
-
return Object.freeze((records || []).map(record => Object.freeze({
|
|
58
|
-
...record,
|
|
59
|
-
...(Array.isArray(record.vector) ? { vector: Object.freeze([...record.vector]) } : {}),
|
|
60
|
-
})));
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
async close() {
|
|
64
|
-
await persistenceAdapter.close();
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function requireAdapter(adapter) {
|
|
70
|
-
for (const method of ['upsertRecords', 'deleteTombstones', 'readRecords', 'close']) {
|
|
71
|
-
if (!adapter || typeof adapter[method] !== 'function') {
|
|
72
|
-
throw new TypeError(`persistenceAdapter.${method} is required`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function requireExternalConfiguration(configuration) {
|
|
78
|
-
const supplied = configuration && typeof configuration === 'object' ? configuration : {};
|
|
79
|
-
const required = [
|
|
80
|
-
['neo4jDatabaseUrl', 'neo4jUri'],
|
|
81
|
-
['neo4jDatabaseUsername', 'neo4jUsername'],
|
|
82
|
-
['neo4jDatabasePassword', 'neo4jPassword'],
|
|
83
|
-
['embeddingCredential'],
|
|
84
|
-
];
|
|
85
|
-
for (const alternatives of required) {
|
|
86
|
-
const value = alternatives.map(field => supplied[field]).find(isNonBlankString);
|
|
87
|
-
if (value === undefined) {
|
|
88
|
-
throw categoryError('EXTERNAL_CREDENTIALS_REQUIRED', alternatives[0]);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function validateRecord(record, qualification) {
|
|
94
|
-
if (!record || typeof record !== 'object') {
|
|
95
|
-
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'record');
|
|
96
|
-
}
|
|
97
|
-
for (const field of STRING_METADATA_FIELDS) {
|
|
98
|
-
if (!isNonBlankString(record[field])) {
|
|
99
|
-
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', field);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (!CHANNELS.has(record.channel)) {
|
|
103
|
-
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'channel');
|
|
104
|
-
}
|
|
105
|
-
if (!Number.isInteger(record.dimensions) || record.dimensions <= 0) {
|
|
106
|
-
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'dimensions');
|
|
107
|
-
}
|
|
108
|
-
if (
|
|
109
|
-
!Array.isArray(record.vector)
|
|
110
|
-
|| record.vector.length !== record.dimensions
|
|
111
|
-
|| record.vector.some(value => typeof value !== 'number' || !Number.isFinite(value))
|
|
112
|
-
) {
|
|
113
|
-
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'vector');
|
|
114
|
-
}
|
|
115
|
-
if (
|
|
116
|
-
record.provider !== qualification.provider
|
|
117
|
-
|| record.model !== qualification.model
|
|
118
|
-
|| record.modelVersion !== qualification.version
|
|
119
|
-
|| record.dimensions !== qualification.dimensions
|
|
120
|
-
) {
|
|
121
|
-
throw categoryError('SP02_SEMANTIC_RECORD_QUALIFICATION_MISMATCH', 'qualification');
|
|
122
|
-
}
|
|
123
|
-
return Object.freeze({
|
|
124
|
-
...record,
|
|
125
|
-
vector: Object.freeze([...record.vector]),
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function validateTombstone(tombstone) {
|
|
130
|
-
if (
|
|
131
|
-
!tombstone
|
|
132
|
-
|| !isNonBlankString(tombstone.canonicalIdentity)
|
|
133
|
-
|| !CHANNELS.has(tombstone.channel)
|
|
134
|
-
|| !isNonBlankString(tombstone.canonicalVersion)
|
|
135
|
-
) {
|
|
136
|
-
throw categoryError('SP02_TOMBSTONE_METADATA_INVALID', 'tombstone');
|
|
137
|
-
}
|
|
138
|
-
return Object.freeze({
|
|
139
|
-
canonicalIdentity: tombstone.canonicalIdentity.trim(),
|
|
140
|
-
channel: tombstone.channel,
|
|
141
|
-
canonicalVersion: tombstone.canonicalVersion.trim(),
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function rejectRunIds(records) {
|
|
146
|
-
if (records.some(record => record && Object.prototype.hasOwnProperty.call(record, 'runId'))) {
|
|
147
|
-
throw categoryError('SP02_PRODUCTION_RUNID_PROHIBITED', 'runId');
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function requireArray(value, field) {
|
|
152
|
-
if (!Array.isArray(value)) {
|
|
153
|
-
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', field);
|
|
154
|
-
}
|
|
155
|
-
return value;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function isNonBlankString(value) {
|
|
159
|
-
return typeof value === 'string' && value.trim() !== '';
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function categoryError(category, field) {
|
|
163
|
-
const error = new Error(category);
|
|
164
|
-
error.category = category;
|
|
165
|
-
error.field = field;
|
|
166
|
-
return error;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
module.exports = {
|
|
170
|
-
createProductionSemanticProjectionStore,
|
|
171
|
-
};
|
|
1
|
+
const {
|
|
2
|
+
evaluateEmbeddingQualification,
|
|
3
|
+
} = require('../embeddingQualificationGate.js');
|
|
4
|
+
|
|
5
|
+
const CHANNELS = new Set(['Element', 'ArchitectureRelationship', 'View']);
|
|
6
|
+
const STRING_METADATA_FIELDS = Object.freeze([
|
|
7
|
+
'canonicalIdentity',
|
|
8
|
+
'canonicalVersion',
|
|
9
|
+
'contentVersion',
|
|
10
|
+
'indexVersion',
|
|
11
|
+
'provider',
|
|
12
|
+
'model',
|
|
13
|
+
'modelVersion',
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
function createProductionSemanticProjectionStore(dependencies = {}) {
|
|
17
|
+
const {
|
|
18
|
+
persistenceAdapter,
|
|
19
|
+
canonicalAuthority,
|
|
20
|
+
configuration,
|
|
21
|
+
qualification,
|
|
22
|
+
} = dependencies;
|
|
23
|
+
requireAdapter(persistenceAdapter);
|
|
24
|
+
if (!canonicalAuthority || typeof canonicalAuthority.assertProjectionOnly !== 'function') {
|
|
25
|
+
throw new TypeError('canonicalAuthority.assertProjectionOnly is required');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function requireReleaseGates() {
|
|
29
|
+
requireExternalConfiguration(configuration);
|
|
30
|
+
const approved = evaluateEmbeddingQualification(qualification);
|
|
31
|
+
canonicalAuthority.assertProjectionOnly();
|
|
32
|
+
return approved;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return Object.freeze({
|
|
36
|
+
async upsertRecords(records) {
|
|
37
|
+
const supplied = requireArray(records, 'records');
|
|
38
|
+
rejectRunIds(supplied);
|
|
39
|
+
const approved = requireReleaseGates();
|
|
40
|
+
const validated = supplied.map(record => validateRecord(record, approved));
|
|
41
|
+
await persistenceAdapter.upsertRecords(validated);
|
|
42
|
+
return Object.freeze({ count: validated.length });
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
async deleteTombstones(tombstones) {
|
|
46
|
+
const supplied = requireArray(tombstones, 'tombstones');
|
|
47
|
+
rejectRunIds(supplied);
|
|
48
|
+
requireReleaseGates();
|
|
49
|
+
const validated = supplied.map(validateTombstone);
|
|
50
|
+
await persistenceAdapter.deleteTombstones(validated);
|
|
51
|
+
return Object.freeze({ count: validated.length });
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
async readRecords() {
|
|
55
|
+
requireReleaseGates();
|
|
56
|
+
const records = await persistenceAdapter.readRecords();
|
|
57
|
+
return Object.freeze((records || []).map(record => Object.freeze({
|
|
58
|
+
...record,
|
|
59
|
+
...(Array.isArray(record.vector) ? { vector: Object.freeze([...record.vector]) } : {}),
|
|
60
|
+
})));
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
async close() {
|
|
64
|
+
await persistenceAdapter.close();
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function requireAdapter(adapter) {
|
|
70
|
+
for (const method of ['upsertRecords', 'deleteTombstones', 'readRecords', 'close']) {
|
|
71
|
+
if (!adapter || typeof adapter[method] !== 'function') {
|
|
72
|
+
throw new TypeError(`persistenceAdapter.${method} is required`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function requireExternalConfiguration(configuration) {
|
|
78
|
+
const supplied = configuration && typeof configuration === 'object' ? configuration : {};
|
|
79
|
+
const required = [
|
|
80
|
+
['neo4jDatabaseUrl', 'neo4jUri'],
|
|
81
|
+
['neo4jDatabaseUsername', 'neo4jUsername'],
|
|
82
|
+
['neo4jDatabasePassword', 'neo4jPassword'],
|
|
83
|
+
['embeddingCredential'],
|
|
84
|
+
];
|
|
85
|
+
for (const alternatives of required) {
|
|
86
|
+
const value = alternatives.map(field => supplied[field]).find(isNonBlankString);
|
|
87
|
+
if (value === undefined) {
|
|
88
|
+
throw categoryError('EXTERNAL_CREDENTIALS_REQUIRED', alternatives[0]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function validateRecord(record, qualification) {
|
|
94
|
+
if (!record || typeof record !== 'object') {
|
|
95
|
+
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'record');
|
|
96
|
+
}
|
|
97
|
+
for (const field of STRING_METADATA_FIELDS) {
|
|
98
|
+
if (!isNonBlankString(record[field])) {
|
|
99
|
+
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', field);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!CHANNELS.has(record.channel)) {
|
|
103
|
+
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'channel');
|
|
104
|
+
}
|
|
105
|
+
if (!Number.isInteger(record.dimensions) || record.dimensions <= 0) {
|
|
106
|
+
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'dimensions');
|
|
107
|
+
}
|
|
108
|
+
if (
|
|
109
|
+
!Array.isArray(record.vector)
|
|
110
|
+
|| record.vector.length !== record.dimensions
|
|
111
|
+
|| record.vector.some(value => typeof value !== 'number' || !Number.isFinite(value))
|
|
112
|
+
) {
|
|
113
|
+
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', 'vector');
|
|
114
|
+
}
|
|
115
|
+
if (
|
|
116
|
+
record.provider !== qualification.provider
|
|
117
|
+
|| record.model !== qualification.model
|
|
118
|
+
|| record.modelVersion !== qualification.version
|
|
119
|
+
|| record.dimensions !== qualification.dimensions
|
|
120
|
+
) {
|
|
121
|
+
throw categoryError('SP02_SEMANTIC_RECORD_QUALIFICATION_MISMATCH', 'qualification');
|
|
122
|
+
}
|
|
123
|
+
return Object.freeze({
|
|
124
|
+
...record,
|
|
125
|
+
vector: Object.freeze([...record.vector]),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function validateTombstone(tombstone) {
|
|
130
|
+
if (
|
|
131
|
+
!tombstone
|
|
132
|
+
|| !isNonBlankString(tombstone.canonicalIdentity)
|
|
133
|
+
|| !CHANNELS.has(tombstone.channel)
|
|
134
|
+
|| !isNonBlankString(tombstone.canonicalVersion)
|
|
135
|
+
) {
|
|
136
|
+
throw categoryError('SP02_TOMBSTONE_METADATA_INVALID', 'tombstone');
|
|
137
|
+
}
|
|
138
|
+
return Object.freeze({
|
|
139
|
+
canonicalIdentity: tombstone.canonicalIdentity.trim(),
|
|
140
|
+
channel: tombstone.channel,
|
|
141
|
+
canonicalVersion: tombstone.canonicalVersion.trim(),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function rejectRunIds(records) {
|
|
146
|
+
if (records.some(record => record && Object.prototype.hasOwnProperty.call(record, 'runId'))) {
|
|
147
|
+
throw categoryError('SP02_PRODUCTION_RUNID_PROHIBITED', 'runId');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function requireArray(value, field) {
|
|
152
|
+
if (!Array.isArray(value)) {
|
|
153
|
+
throw categoryError('SP02_SEMANTIC_RECORD_METADATA_INVALID', field);
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function isNonBlankString(value) {
|
|
159
|
+
return typeof value === 'string' && value.trim() !== '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function categoryError(category, field) {
|
|
163
|
+
const error = new Error(category);
|
|
164
|
+
error.category = category;
|
|
165
|
+
error.field = field;
|
|
166
|
+
return error;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = {
|
|
170
|
+
createProductionSemanticProjectionStore,
|
|
171
|
+
};
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
function semanticOperatorErrorPayload(error) {
|
|
2
|
-
return Object.freeze({
|
|
3
|
-
category: typeof error.category === 'string' ? error.category : 'SEMANTIC_OPERATOR_ERROR',
|
|
4
|
-
state: typeof error.state === 'string' ? error.state : null,
|
|
5
|
-
verified: error.verified === true,
|
|
6
|
-
canonicalVersion: typeof error.canonicalVersion === 'string' ? error.canonicalVersion : null,
|
|
7
|
-
contentVersion: typeof error.contentVersion === 'string' ? error.contentVersion : null,
|
|
8
|
-
indexVersion: typeof error.indexVersion === 'string' ? error.indexVersion : null,
|
|
9
|
-
completedChannels: Array.isArray(error.completedChannels) ? [...error.completedChannels] : [],
|
|
10
|
-
missingChannels: Array.isArray(error.missingChannels) ? [...error.missingChannels] : [],
|
|
11
|
-
mismatchedChannels: Array.isArray(error.mismatchedChannels) ? [...error.mismatchedChannels] : [],
|
|
12
|
-
fullSnapshotFallback: false,
|
|
13
|
-
action: typeof error.action === 'string' ? error.action : 'Correct readiness and retry',
|
|
14
|
-
...(typeof error.field === 'string' ? { field: error.field } : {}),
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function semanticOperatorErrorResult(error) {
|
|
19
|
-
const payload = Object.freeze({
|
|
20
|
-
status: 'failed',
|
|
21
|
-
error: semanticOperatorErrorPayload(error),
|
|
22
|
-
});
|
|
23
|
-
return Object.freeze({
|
|
24
|
-
...payload,
|
|
25
|
-
content: Object.freeze([
|
|
26
|
-
Object.freeze({
|
|
27
|
-
type: 'text',
|
|
28
|
-
text: JSON.stringify(payload),
|
|
29
|
-
}),
|
|
30
|
-
]),
|
|
31
|
-
isError: true,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = {
|
|
36
|
-
semanticOperatorErrorPayload,
|
|
37
|
-
semanticOperatorErrorResult,
|
|
38
|
-
};
|
|
1
|
+
function semanticOperatorErrorPayload(error) {
|
|
2
|
+
return Object.freeze({
|
|
3
|
+
category: typeof error.category === 'string' ? error.category : 'SEMANTIC_OPERATOR_ERROR',
|
|
4
|
+
state: typeof error.state === 'string' ? error.state : null,
|
|
5
|
+
verified: error.verified === true,
|
|
6
|
+
canonicalVersion: typeof error.canonicalVersion === 'string' ? error.canonicalVersion : null,
|
|
7
|
+
contentVersion: typeof error.contentVersion === 'string' ? error.contentVersion : null,
|
|
8
|
+
indexVersion: typeof error.indexVersion === 'string' ? error.indexVersion : null,
|
|
9
|
+
completedChannels: Array.isArray(error.completedChannels) ? [...error.completedChannels] : [],
|
|
10
|
+
missingChannels: Array.isArray(error.missingChannels) ? [...error.missingChannels] : [],
|
|
11
|
+
mismatchedChannels: Array.isArray(error.mismatchedChannels) ? [...error.mismatchedChannels] : [],
|
|
12
|
+
fullSnapshotFallback: false,
|
|
13
|
+
action: typeof error.action === 'string' ? error.action : 'Correct readiness and retry',
|
|
14
|
+
...(typeof error.field === 'string' ? { field: error.field } : {}),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function semanticOperatorErrorResult(error) {
|
|
19
|
+
const payload = Object.freeze({
|
|
20
|
+
status: 'failed',
|
|
21
|
+
error: semanticOperatorErrorPayload(error),
|
|
22
|
+
});
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
...payload,
|
|
25
|
+
content: Object.freeze([
|
|
26
|
+
Object.freeze({
|
|
27
|
+
type: 'text',
|
|
28
|
+
text: JSON.stringify(payload),
|
|
29
|
+
}),
|
|
30
|
+
]),
|
|
31
|
+
isError: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
semanticOperatorErrorPayload,
|
|
37
|
+
semanticOperatorErrorResult,
|
|
38
|
+
};
|