archgraph-argo 0.24.1 → 0.24.3

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.
@@ -25,6 +25,7 @@ Non-negotiable red lines (MUST). Never skip, simplify, or silently violate them;
25
25
  9. Never duplicate: reuse is the default; a create blocked as an exact or semantic duplicate must be reused, or explicitly overridden with `onConflict: "allowDuplicate"` + justification. See `<GraphDeduplication>`.
26
26
  10. Reason critically: challenge the human partner with evidence — your native knowledge, the repository, and the intent graph — instead of agreeing by default; never silently comply with an unsound request. See `<CriticalReasoningGuideline>`.
27
27
  11. Never lose content silently: writes that reduce existing content must be lossless (merge/delta) or explicitly acknowledged (`acknowledgeLoss`), and destructive removals are tombstoned. See `<LosslessWrite>`.
28
+ 12. Federate by reference, never by copy: register/discover/authorize/read through the federation center (graph MCP surface); a read returns a reference, not a copy; cross-member access is denied by default. See `<FederationGuideline>`.
28
29
  </CoreRules>
29
30
 
30
31
  <Ontology>
@@ -170,6 +171,17 @@ Use `queryNeo4jGraph` for structural/type lookups. It never mutates the canonica
170
171
  3. Semantic/context reads (`getSystemArchitecture`, `getIntentElementContext`, `getArchitectureViewContext`) are the PRIORITY path; Cypher is the SECONDARY path per `<QueryPriorityGuideline>`.
171
172
  </GraphQueryGuideline>
172
173
 
174
+ <FederationGuideline>
175
+ When your project participates in a federation, act through the federation center (one central platform reached over the graph MCP):
176
+ 1. Register or exit: register your project with the center to join; deregister it to leave. Do this as the project's own Agent together with your human partner — no separate external approval is required.
177
+ 2. Discover before relying: query the center for the members that exist and what each offers (purpose, capabilities, open interfaces).
178
+ 3. Authorize before you read: read another member's opened content only after that member explicitly authorizes you; access is denied by default, assume no trust between members.
179
+ 4. Reference, not a copy: a read returns a reference, not a copy of another member's content; never persist a copy. The center holds only federation metadata (membership, interfaces, grants); each member's own graph stays the single source of truth.
180
+ 5. Never merge graphs: members stay independent; keep your own graph sovereign.
181
+ 6. One center: use the single federation center; if it is unreachable, fall back to locally cached discovery/grants and say so.
182
+ 7. Surface: do register / deregister / discover / authorize / read through the center's graph MCP tools; never reach the center by a file or SQL path.
183
+ </FederationGuideline>
184
+
173
185
  <Attention>
174
186
  Confirm the ARGO MCP server is serving this repository's graph (design/KG/SystemArchitecture.json), not another graph. If it is not, stop and report to your human partner before doing anything else.
175
187
  </Attention>
@@ -85,32 +85,35 @@ const CHANNELS = Object.freeze([
85
85
  indexName: 'argo_production_semantic_view_vector',
86
86
  }),
87
87
  ]);
88
+ // Project an explicit metadata allowlist instead of properties(node): Neo4j map
89
+ // projection `.*` lets an existing property win, so properties(node) / node{.*, vector:null}
90
+ // would still ship the 1536-dim vector; the read path only consumes canonicalIdentity, channel, searchText and score.
88
91
  const VECTOR_QUERY_CYPHER = [
89
92
  'CALL db.index.vector.queryNodes($indexName, $topK, $vector)',
90
93
  'YIELD node, score',
91
94
  'WHERE node.channel = $channel',
92
- 'RETURN properties(node) AS record, score',
95
+ 'RETURN {canonicalIdentity: node.canonicalIdentity, channel: node.channel, searchText: node.searchText, dimensions: node.dimensions, provider: node.provider, model: node.model, modelVersion: node.modelVersion, canonicalVersion: node.canonicalVersion, contentVersion: node.contentVersion, indexVersion: node.indexVersion} AS record, score',
93
96
  'ORDER BY score DESC',
94
97
  ].join('\n');
95
98
  const VECTOR_QUERY_CYPHER_SCOPED = [
96
99
  'CALL db.index.vector.queryNodes($indexName, $topK, $vector)',
97
100
  'YIELD node, score',
98
101
  'WHERE node.channel = $channel AND node.canonicalIdentity IN $canonicalIdentities',
99
- 'RETURN properties(node) AS record, score',
102
+ 'RETURN {canonicalIdentity: node.canonicalIdentity, channel: node.channel, searchText: node.searchText, dimensions: node.dimensions, provider: node.provider, model: node.model, modelVersion: node.modelVersion, canonicalVersion: node.canonicalVersion, contentVersion: node.contentVersion, indexVersion: node.indexVersion} AS record, score',
100
103
  'ORDER BY score DESC',
101
104
  ].join('\n');
102
105
  const LEXICAL_QUERY_CYPHER = [
103
106
  'CALL db.index.fulltext.queryNodes($indexName, $queryText, { limit: $topK })',
104
107
  'YIELD node, score',
105
108
  'WHERE node.channel = $channel',
106
- 'RETURN properties(node) AS record, score',
109
+ 'RETURN {canonicalIdentity: node.canonicalIdentity, channel: node.channel, searchText: node.searchText, dimensions: node.dimensions, provider: node.provider, model: node.model, modelVersion: node.modelVersion, canonicalVersion: node.canonicalVersion, contentVersion: node.contentVersion, indexVersion: node.indexVersion} AS record, score',
107
110
  'ORDER BY score DESC',
108
111
  ].join('\n');
109
112
  const LEXICAL_QUERY_CYPHER_SCOPED = [
110
113
  'CALL db.index.fulltext.queryNodes($indexName, $queryText, { limit: $topK })',
111
114
  'YIELD node, score',
112
115
  'WHERE node.channel = $channel AND node.canonicalIdentity IN $canonicalIdentities',
113
- 'RETURN properties(node) AS record, score',
116
+ 'RETURN {canonicalIdentity: node.canonicalIdentity, channel: node.channel, searchText: node.searchText, dimensions: node.dimensions, provider: node.provider, model: node.model, modelVersion: node.modelVersion, canonicalVersion: node.canonicalVersion, contentVersion: node.contentVersion, indexVersion: node.indexVersion} AS record, score',
114
117
  'ORDER BY score DESC',
115
118
  ].join('\n');
116
119
  const READINESS_QUERY_CYPHER = [
@@ -149,6 +152,12 @@ function resolveTopK() {
149
152
  const k = envNumber('ARGO_SEMANTIC_TOP_K', DEFAULT_TOP_K);
150
153
  return Number.isInteger(k) && k > 0 ? k : DEFAULT_TOP_K;
151
154
  }
155
+ // The single production seed gate: a retrieved record becomes a seed only when
156
+ // its TRUE vector similarity reaches the purpose-aware threshold. Exposed so
157
+ // acceptance tests exercise the exact predicate the retrieval runtime uses.
158
+ function isSeedAboveThreshold(score, threshold) {
159
+ return Number.isFinite(score) && Number.isFinite(threshold) && score >= threshold;
160
+ }
152
161
  const testCompositionStorage = new AsyncLocalStorage();
153
162
 
154
163
  function createDefaultSemanticRetrieval(dependencies = {}) {
@@ -828,7 +837,7 @@ async function exhaustChannel({
828
837
  for (const raw of newlyVisible) {
829
838
  if (accepted.length >= effectiveMax) break;
830
839
  const record = normalizeVectorRecord(raw, channel);
831
- if (record && record.score >= effectiveThreshold && !seen.has(record.id)) {
840
+ if (record && isSeedAboveThreshold(record.score, effectiveThreshold) && !seen.has(record.id)) {
832
841
  seen.add(record.id);
833
842
  accepted.push(Object.freeze(record));
834
843
  }
@@ -1238,8 +1247,11 @@ module.exports = {
1238
1247
  memoryThresholdFor,
1239
1248
  auditThresholdFor,
1240
1249
  resolveTopK,
1250
+ isSeedAboveThreshold,
1241
1251
  scopeCanonicalIdentitiesForChannel,
1242
1252
  bareCanonicalId,
1243
1253
  normalizeVectorRecord,
1254
+ exhaustChannel,
1255
+ exhaustLexicalChannel,
1244
1256
  AUDIT_PURPOSES,
1245
1257
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archgraph-argo",
3
- "version": "0.24.1",
3
+ "version": "0.24.3",
4
4
  "description": "Deploy the ArchGraph ARGO toolchain, skills, and rules (schema, scripts, argo-init skill, global rule) with one command.",
5
5
  "license": "MIT",
6
6
  "bin": {