ruflo-graph-intelligence 0.1.0-alpha.1
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/.claude-flow/data/pending-insights.jsonl +30 -0
- package/dist/adapters/aidefence-suspicion-adapter.d.ts +40 -0
- package/dist/adapters/aidefence-suspicion-adapter.d.ts.map +1 -0
- package/dist/adapters/aidefence-suspicion-adapter.js +77 -0
- package/dist/adapters/aidefence-suspicion-adapter.js.map +1 -0
- package/dist/adapters/browser-causal-adapter.d.ts +83 -0
- package/dist/adapters/browser-causal-adapter.d.ts.map +1 -0
- package/dist/adapters/browser-causal-adapter.js +146 -0
- package/dist/adapters/browser-causal-adapter.js.map +1 -0
- package/dist/adapters/cost-attribution-adapter.d.ts +48 -0
- package/dist/adapters/cost-attribution-adapter.d.ts.map +1 -0
- package/dist/adapters/cost-attribution-adapter.js +95 -0
- package/dist/adapters/cost-attribution-adapter.js.map +1 -0
- package/dist/adapters/federation-trust-adapter.d.ts +49 -0
- package/dist/adapters/federation-trust-adapter.d.ts.map +1 -0
- package/dist/adapters/federation-trust-adapter.js +82 -0
- package/dist/adapters/federation-trust-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +16 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/jujutsu-blast-radius-adapter.d.ts +46 -0
- package/dist/adapters/jujutsu-blast-radius-adapter.d.ts.map +1 -0
- package/dist/adapters/jujutsu-blast-radius-adapter.js +80 -0
- package/dist/adapters/jujutsu-blast-radius-adapter.js.map +1 -0
- package/dist/adapters/knowledge-graph-adapter.d.ts +41 -0
- package/dist/adapters/knowledge-graph-adapter.d.ts.map +1 -0
- package/dist/adapters/knowledge-graph-adapter.js +83 -0
- package/dist/adapters/knowledge-graph-adapter.js.map +1 -0
- package/dist/adapters/observability-span-adapter.d.ts +45 -0
- package/dist/adapters/observability-span-adapter.d.ts.map +1 -0
- package/dist/adapters/observability-span-adapter.js +97 -0
- package/dist/adapters/observability-span-adapter.js.map +1 -0
- package/dist/adapters/portfolio-cg-adapter.d.ts +60 -0
- package/dist/adapters/portfolio-cg-adapter.d.ts.map +1 -0
- package/dist/adapters/portfolio-cg-adapter.js +102 -0
- package/dist/adapters/portfolio-cg-adapter.js.map +1 -0
- package/dist/adapters/rag-memory-adapter.d.ts +49 -0
- package/dist/adapters/rag-memory-adapter.d.ts.map +1 -0
- package/dist/adapters/rag-memory-adapter.js +86 -0
- package/dist/adapters/rag-memory-adapter.js.map +1 -0
- package/dist/application/federation-client.d.ts +54 -0
- package/dist/application/federation-client.d.ts.map +1 -0
- package/dist/application/federation-client.js +101 -0
- package/dist/application/federation-client.js.map +1 -0
- package/dist/application/federation-server.d.ts +38 -0
- package/dist/application/federation-server.d.ts.map +1 -0
- package/dist/application/federation-server.js +127 -0
- package/dist/application/federation-server.js.map +1 -0
- package/dist/application/streaming-bridge.d.ts +62 -0
- package/dist/application/streaming-bridge.d.ts.map +1 -0
- package/dist/application/streaming-bridge.js +101 -0
- package/dist/application/streaming-bridge.js.map +1 -0
- package/dist/domain/adapter.d.ts +58 -0
- package/dist/domain/adapter.d.ts.map +1 -0
- package/dist/domain/adapter.js +43 -0
- package/dist/domain/adapter.js.map +1 -0
- package/dist/domain/federation-protocol.d.ts +857 -0
- package/dist/domain/federation-protocol.d.ts.map +1 -0
- package/dist/domain/federation-protocol.js +72 -0
- package/dist/domain/federation-protocol.js.map +1 -0
- package/dist/domain/signed-artifact.d.ts +429 -0
- package/dist/domain/signed-artifact.d.ts.map +1 -0
- package/dist/domain/signed-artifact.js +57 -0
- package/dist/domain/signed-artifact.js.map +1 -0
- package/dist/domain/types.d.ts +329 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +165 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/jl-embed.d.ts +27 -0
- package/dist/infrastructure/jl-embed.d.ts.map +1 -0
- package/dist/infrastructure/jl-embed.js +79 -0
- package/dist/infrastructure/jl-embed.js.map +1 -0
- package/dist/infrastructure/solver-bridge.d.ts +73 -0
- package/dist/infrastructure/solver-bridge.d.ts.map +1 -0
- package/dist/infrastructure/solver-bridge.js +359 -0
- package/dist/infrastructure/solver-bridge.js.map +1 -0
- package/dist/infrastructure/witness-signer.d.ts +44 -0
- package/dist/infrastructure/witness-signer.d.ts.map +1 -0
- package/dist/infrastructure/witness-signer.js +158 -0
- package/dist/infrastructure/witness-signer.js.map +1 -0
- package/dist/mcp-tools/index.d.ts +27 -0
- package/dist/mcp-tools/index.d.ts.map +1 -0
- package/dist/mcp-tools/index.js +292 -0
- package/dist/mcp-tools/index.js.map +1 -0
- package/package.json +55 -0
- package/ruvector.db +0 -0
- package/src/adapters/aidefence-suspicion-adapter.ts +102 -0
- package/src/adapters/browser-causal-adapter.ts +193 -0
- package/src/adapters/cost-attribution-adapter.ts +123 -0
- package/src/adapters/federation-trust-adapter.ts +116 -0
- package/src/adapters/index.ts +87 -0
- package/src/adapters/jujutsu-blast-radius-adapter.ts +107 -0
- package/src/adapters/knowledge-graph-adapter.ts +110 -0
- package/src/adapters/observability-span-adapter.ts +123 -0
- package/src/adapters/portfolio-cg-adapter.ts +140 -0
- package/src/adapters/rag-memory-adapter.ts +117 -0
- package/src/application/federation-client.ts +147 -0
- package/src/application/federation-server.ts +158 -0
- package/src/application/streaming-bridge.ts +137 -0
- package/src/domain/adapter.ts +92 -0
- package/src/domain/federation-protocol.ts +95 -0
- package/src/domain/signed-artifact.ts +80 -0
- package/src/domain/types.ts +215 -0
- package/src/index.ts +105 -0
- package/src/infrastructure/jl-embed.ts +98 -0
- package/src/infrastructure/solver-bridge.ts +389 -0
- package/src/infrastructure/witness-signer.ts +209 -0
- package/src/mcp-tools/index.ts +316 -0
- package/tests/adapter-registry.test.ts +69 -0
- package/tests/browser-causal-adapter.test.ts +174 -0
- package/tests/mcp-tools.test.ts +169 -0
- package/tests/phase3-adapters.test.ts +206 -0
- package/tests/phase4-adapters.test.ts +158 -0
- package/tests/phase5-portfolio.test.ts +122 -0
- package/tests/phase6-adapters.test.ts +224 -0
- package/tests/phase6_5-streaming.test.ts +135 -0
- package/tests/phase7-signed-artifact.test.ts +238 -0
- package/tests/phase8-federation.test.ts +194 -0
- package/tests/solver-bridge.test.ts +255 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signed PageRank Artifact (Phase 7 — beyond-SOTA, ADR-123)
|
|
3
|
+
*
|
|
4
|
+
* RuFlo gains a primitive no competing memory framework can ship: a portable,
|
|
5
|
+
* Ed25519-signed PageRank result that carries enough metadata for a remote
|
|
6
|
+
* peer to verify provenance + budget compliance + input stability without
|
|
7
|
+
* trusting the producer. Federation peers exchange these instead of
|
|
8
|
+
* re-walking graphs.
|
|
9
|
+
*
|
|
10
|
+
* Schema mirrors the ADR-123 Architecture diagram with the upstream 1.7.0
|
|
11
|
+
* additions: `complexity_class` (budget compliance) + `coherence_score`
|
|
12
|
+
* (DD-margin at compute time).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import {
|
|
17
|
+
ComplexityClassSchema,
|
|
18
|
+
PageRankResultSchema,
|
|
19
|
+
type PageRankResult,
|
|
20
|
+
} from './types.js';
|
|
21
|
+
|
|
22
|
+
export const ARTIFACT_ENVELOPE_VERSION = '1.0.0';
|
|
23
|
+
export const ARTIFACT_ENVELOPE_KIND = 'pagerank';
|
|
24
|
+
|
|
25
|
+
export const SignedPageRankPayloadSchema = z.object({
|
|
26
|
+
envelopeVersion: z.literal(ARTIFACT_ENVELOPE_VERSION),
|
|
27
|
+
kind: z.literal(ARTIFACT_ENVELOPE_KIND),
|
|
28
|
+
installationId: z.string().min(1),
|
|
29
|
+
/** Witness key ID (key version, not key identity per ADR-103). */
|
|
30
|
+
witnessKeyId: z.string().min(1),
|
|
31
|
+
/** Ed25519 public key (hex, 32 bytes). */
|
|
32
|
+
publicKey: z.string().regex(/^[0-9a-f]{64}$/),
|
|
33
|
+
/** Adapter graph id (e.g. `ruflo-federation:trust-mesh`). */
|
|
34
|
+
graphId: z.string().min(1),
|
|
35
|
+
/** SHA-256 of the input matrix's `contentHash`. */
|
|
36
|
+
graphHash: z.string().regex(/^[0-9a-f]{64}$/),
|
|
37
|
+
/** Wall-clock at compute time. */
|
|
38
|
+
graphTimestamp: z.string(),
|
|
39
|
+
algorithm: z.enum(['forward-push', 'backward-push', 'bidirectional', 'cg', 'neumann']),
|
|
40
|
+
alpha: z.number().positive().lt(1),
|
|
41
|
+
epsilon: z.number().positive(),
|
|
42
|
+
/** Query node — None for full-vector artifacts. */
|
|
43
|
+
queryNode: z.string().optional(),
|
|
44
|
+
/** Seed nodes (PPR). Empty for plain PR. */
|
|
45
|
+
seedNodes: z.array(z.string()),
|
|
46
|
+
/** Result (single-entry or full-vector). */
|
|
47
|
+
result: PageRankResultSchema,
|
|
48
|
+
/** Class the solver actually achieved (echoes result.complexityClass). */
|
|
49
|
+
complexityClass: ComplexityClassSchema,
|
|
50
|
+
/** Coherence margin at compute time (echoes result.coherence.score). */
|
|
51
|
+
coherenceScore: z.number(),
|
|
52
|
+
/** Hash of `result` (echoes result.resultHash). */
|
|
53
|
+
resultHash: z.string().regex(/^[0-9a-f]{64}$/),
|
|
54
|
+
/** When the envelope was sealed. */
|
|
55
|
+
sealedAt: z.string(),
|
|
56
|
+
/** Solver version used. */
|
|
57
|
+
solverVersion: z.string().default('sublinear-time-solver@1.7.0'),
|
|
58
|
+
});
|
|
59
|
+
export type SignedPageRankPayload = z.infer<typeof SignedPageRankPayloadSchema>;
|
|
60
|
+
|
|
61
|
+
export const SignedPageRankEnvelopeSchema = z.object({
|
|
62
|
+
payload: SignedPageRankPayloadSchema,
|
|
63
|
+
signature: z.string().regex(/^[0-9a-f]{128}$/),
|
|
64
|
+
algorithm: z.literal('ed25519'),
|
|
65
|
+
});
|
|
66
|
+
export type SignedPageRankEnvelope = z.infer<typeof SignedPageRankEnvelopeSchema>;
|
|
67
|
+
|
|
68
|
+
export interface ArtifactVerificationResult {
|
|
69
|
+
valid: boolean;
|
|
70
|
+
signatureValid: boolean;
|
|
71
|
+
schemaValid: boolean;
|
|
72
|
+
/** True iff graphHash + resultHash + signature all check out. */
|
|
73
|
+
integrityValid: boolean;
|
|
74
|
+
publicKey?: string;
|
|
75
|
+
/** Complexity class echo — callers can budget against this. */
|
|
76
|
+
complexityClass?: PageRankResult['complexityClass'];
|
|
77
|
+
/** Coherence margin echo — callers can sanity-check input stability. */
|
|
78
|
+
coherenceScore?: number;
|
|
79
|
+
reason?: string;
|
|
80
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ruflo-graph-intelligence — Domain Types (ADR-123)
|
|
3
|
+
*
|
|
4
|
+
* Core type contract: SparseMatrix shape, ComplexityClass budget, coherence
|
|
5
|
+
* threshold, signed PR artifact envelope. These are the wire types every
|
|
6
|
+
* adapter, MCP tool, and federation peer agrees on.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// SparseMatrix — the adapter handover shape
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
export const SparseEntrySchema = z.object({
|
|
16
|
+
row: z.number().int().nonnegative(),
|
|
17
|
+
col: z.number().int().nonnegative(),
|
|
18
|
+
value: z.number().finite(),
|
|
19
|
+
});
|
|
20
|
+
export type SparseEntry = z.infer<typeof SparseEntrySchema>;
|
|
21
|
+
|
|
22
|
+
export const SparseMatrixSchema = z.object({
|
|
23
|
+
/** Stable identifier — e.g. "ruflo-federation:trust-mesh:2026-05-19T01:00:00Z". */
|
|
24
|
+
graphId: z.string().min(1),
|
|
25
|
+
/** Number of rows / columns (square). */
|
|
26
|
+
size: z.number().int().positive(),
|
|
27
|
+
/** Non-zero entries. */
|
|
28
|
+
entries: z.array(SparseEntrySchema),
|
|
29
|
+
/** Node-id → row-index lookup so callers can talk in domain identifiers. */
|
|
30
|
+
nodeIndex: z.record(z.number().int().nonnegative()),
|
|
31
|
+
/** Reverse lookup row-index → node-id. */
|
|
32
|
+
indexNode: z.array(z.string()),
|
|
33
|
+
/** When the snapshot was taken (ISO). */
|
|
34
|
+
capturedAt: z.string(),
|
|
35
|
+
/** Optional content hash for memoization + signed-artifact integrity. */
|
|
36
|
+
contentHash: z.string().regex(/^[0-9a-f]{64}$/).optional(),
|
|
37
|
+
});
|
|
38
|
+
export type SparseMatrix = z.infer<typeof SparseMatrixSchema>;
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Complexity class — runtime governance budget
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 12-tier upstream `sublinear-time-solver@1.7.0` taxonomy. Ordered.
|
|
46
|
+
* Lower-cost classes are at the top; Adaptive wraps a (default, worst) pair.
|
|
47
|
+
*/
|
|
48
|
+
export const ComplexityClassSchema = z.enum([
|
|
49
|
+
'constant', // O(1)
|
|
50
|
+
'logarithmic', // O(log n)
|
|
51
|
+
'polylogarithmic', // O((log n)^k)
|
|
52
|
+
'sublinear', // O(n^α) for α < 1
|
|
53
|
+
'linear', // O(n)
|
|
54
|
+
'linearithmic', // O(n log n)
|
|
55
|
+
'polynomial', // O(n^k)
|
|
56
|
+
'exponential', // O(2^n)
|
|
57
|
+
'doubleExponential',// O(2^(2^n))
|
|
58
|
+
'adaptive', // see adaptiveBound
|
|
59
|
+
'unknown',
|
|
60
|
+
'unbounded',
|
|
61
|
+
]);
|
|
62
|
+
export type ComplexityClass = z.infer<typeof ComplexityClassSchema>;
|
|
63
|
+
|
|
64
|
+
/** For Adaptive: default + worst-case both reported. */
|
|
65
|
+
export interface AdaptiveBound {
|
|
66
|
+
default: ComplexityClass;
|
|
67
|
+
worst: ComplexityClass;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Ordering — index = cost rank, so `rank('logarithmic') < rank('linear')`. */
|
|
71
|
+
const COMPLEXITY_RANK: Record<ComplexityClass, number> = {
|
|
72
|
+
constant: 0,
|
|
73
|
+
logarithmic: 1,
|
|
74
|
+
polylogarithmic: 2,
|
|
75
|
+
sublinear: 3,
|
|
76
|
+
linear: 4,
|
|
77
|
+
linearithmic: 5,
|
|
78
|
+
polynomial: 6,
|
|
79
|
+
exponential: 7,
|
|
80
|
+
doubleExponential: 8,
|
|
81
|
+
adaptive: 4, // worst-case treated as Linear for budget comparisons by default
|
|
82
|
+
unknown: 8,
|
|
83
|
+
unbounded: 9,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** Is `actual` within `budget`? */
|
|
87
|
+
export function fitsBudget(actual: ComplexityClass, budget: ComplexityClass): boolean {
|
|
88
|
+
return COMPLEXITY_RANK[actual] <= COMPLEXITY_RANK[budget];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Pi-Zero-safe ≈ at most polylogarithmic. */
|
|
92
|
+
export function isEdgeSafe(c: ComplexityClass): boolean {
|
|
93
|
+
return COMPLEXITY_RANK[c] <= COMPLEXITY_RANK['polylogarithmic'];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Coherence — DD margin for graph stability monitoring
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
export const CoherenceReportSchema = z.object({
|
|
101
|
+
/** Per-row margin (min over rows of (|diag| − Σ|off|) / |diag|). Range (−∞, 1]. */
|
|
102
|
+
score: z.number(),
|
|
103
|
+
/** Did the matrix pass the configured threshold? */
|
|
104
|
+
passed: z.boolean(),
|
|
105
|
+
/** Threshold used. 0 = gate disabled (wire-compatible default). */
|
|
106
|
+
threshold: z.number(),
|
|
107
|
+
});
|
|
108
|
+
export type CoherenceReport = z.infer<typeof CoherenceReportSchema>;
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// PageRank query + result
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
export const PageRankQuerySchema = z.object({
|
|
115
|
+
graphId: z.string(),
|
|
116
|
+
/** Single-entry query — the node we want the PR score for. */
|
|
117
|
+
nodeId: z.string(),
|
|
118
|
+
/** Damping factor. Default 0.85. */
|
|
119
|
+
alpha: z.number().positive().lt(1).default(0.85),
|
|
120
|
+
/** ε convergence target. Default 1e-3. */
|
|
121
|
+
epsilon: z.number().positive().default(1e-3),
|
|
122
|
+
/** For personalized PR — seed nodes weighted as the restart distribution. */
|
|
123
|
+
seedNodes: z.array(z.string()).default([]),
|
|
124
|
+
/** Budget gate. Default `linear` (tier-2-safe). */
|
|
125
|
+
maxComplexityClass: ComplexityClassSchema.default('linear'),
|
|
126
|
+
/** DD-margin floor. 0 = disabled. */
|
|
127
|
+
coherenceThreshold: z.number().default(0),
|
|
128
|
+
});
|
|
129
|
+
export type PageRankQuery = z.infer<typeof PageRankQuerySchema>;
|
|
130
|
+
|
|
131
|
+
export const PageRankResultSchema = z.object({
|
|
132
|
+
graphId: z.string(),
|
|
133
|
+
nodeId: z.string(),
|
|
134
|
+
score: z.number(),
|
|
135
|
+
alpha: z.number(),
|
|
136
|
+
epsilon: z.number(),
|
|
137
|
+
iterations: z.number().int().nonnegative(),
|
|
138
|
+
/** Class the solver actually used. */
|
|
139
|
+
complexityClass: ComplexityClassSchema,
|
|
140
|
+
/** Coherence report attached at compute time. */
|
|
141
|
+
coherence: CoherenceReportSchema,
|
|
142
|
+
computedAt: z.string(),
|
|
143
|
+
/** Hash of (graphId, nodeId, alpha, epsilon, seedNodes, score). Stable for memoization. */
|
|
144
|
+
resultHash: z.string().regex(/^[0-9a-f]{64}$/),
|
|
145
|
+
});
|
|
146
|
+
export type PageRankResult = z.infer<typeof PageRankResultSchema>;
|
|
147
|
+
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// Solve (full vector)
|
|
150
|
+
// ============================================================================
|
|
151
|
+
|
|
152
|
+
export const SolveQuerySchema = z.object({
|
|
153
|
+
graphId: z.string(),
|
|
154
|
+
rhs: z.array(z.number()),
|
|
155
|
+
algorithm: z.enum(['cg', 'neumann', 'random-walk']).default('cg'),
|
|
156
|
+
maxComplexityClass: ComplexityClassSchema.default('linear'),
|
|
157
|
+
coherenceThreshold: z.number().default(0),
|
|
158
|
+
});
|
|
159
|
+
export type SolveQuery = z.infer<typeof SolveQuerySchema>;
|
|
160
|
+
|
|
161
|
+
export const SolveResultSchema = z.object({
|
|
162
|
+
graphId: z.string(),
|
|
163
|
+
x: z.array(z.number()),
|
|
164
|
+
residualNorm: z.number(),
|
|
165
|
+
iterations: z.number().int().nonnegative(),
|
|
166
|
+
complexityClass: ComplexityClassSchema,
|
|
167
|
+
coherence: CoherenceReportSchema,
|
|
168
|
+
computedAt: z.string(),
|
|
169
|
+
});
|
|
170
|
+
export type SolveResult = z.infer<typeof SolveResultSchema>;
|
|
171
|
+
|
|
172
|
+
// ============================================================================
|
|
173
|
+
// Incremental solve (Wedge 12 — streaming)
|
|
174
|
+
// ============================================================================
|
|
175
|
+
|
|
176
|
+
export const SparseDeltaSchema = z.object({
|
|
177
|
+
indices: z.array(z.number().int().nonnegative()),
|
|
178
|
+
values: z.array(z.number()),
|
|
179
|
+
});
|
|
180
|
+
export type SparseDelta = z.infer<typeof SparseDeltaSchema>;
|
|
181
|
+
|
|
182
|
+
export const SolveOnChangeQuerySchema = z.object({
|
|
183
|
+
graphId: z.string(),
|
|
184
|
+
prevSolution: z.array(z.number()),
|
|
185
|
+
delta: SparseDeltaSchema,
|
|
186
|
+
algorithm: z.enum(['cg', 'neumann']).default('cg'),
|
|
187
|
+
maxComplexityClass: ComplexityClassSchema.default('linear'),
|
|
188
|
+
});
|
|
189
|
+
export type SolveOnChangeQuery = z.infer<typeof SolveOnChangeQuerySchema>;
|
|
190
|
+
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// Structured errors
|
|
193
|
+
// ============================================================================
|
|
194
|
+
|
|
195
|
+
export const GraphIntelErrorKindSchema = z.enum([
|
|
196
|
+
'complexity-budget-exceeded',
|
|
197
|
+
'coherence-rejected',
|
|
198
|
+
'graph-not-found',
|
|
199
|
+
'invalid-input',
|
|
200
|
+
'solver-failed',
|
|
201
|
+
'not-applicable',
|
|
202
|
+
]);
|
|
203
|
+
export type GraphIntelErrorKind = z.infer<typeof GraphIntelErrorKindSchema>;
|
|
204
|
+
|
|
205
|
+
export interface GraphIntelError {
|
|
206
|
+
kind: GraphIntelErrorKind;
|
|
207
|
+
message: string;
|
|
208
|
+
recoverable: boolean;
|
|
209
|
+
/** If `complexity-budget-exceeded`: what class was needed vs requested. */
|
|
210
|
+
requiredClass?: ComplexityClass;
|
|
211
|
+
requestedClass?: ComplexityClass;
|
|
212
|
+
/** If `coherence-rejected`: actual vs threshold. */
|
|
213
|
+
coherence?: number;
|
|
214
|
+
threshold?: number;
|
|
215
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ruflo-graph-intelligence — RuFlo Graph Intelligence Engine (ADR-123)
|
|
3
|
+
*
|
|
4
|
+
* Real-time relationship intelligence with complexity-aware execution.
|
|
5
|
+
*
|
|
6
|
+
* Three-layer architecture:
|
|
7
|
+
* Neural Layer — adaptive learning (existing — @claude-flow/neural)
|
|
8
|
+
* Graph Intelligence — relationship reasoning (this plugin)
|
|
9
|
+
* Complexity Layer — runtime governance (this plugin)
|
|
10
|
+
*
|
|
11
|
+
* Built on `sublinear-time-solver@1.7.0`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Domain
|
|
15
|
+
export * from './domain/types.js';
|
|
16
|
+
export {
|
|
17
|
+
AdapterRegistry,
|
|
18
|
+
getRegistry,
|
|
19
|
+
resetRegistry,
|
|
20
|
+
noopUnsubscribe,
|
|
21
|
+
type SublinearAdapter,
|
|
22
|
+
} from './domain/adapter.js';
|
|
23
|
+
|
|
24
|
+
// Infrastructure
|
|
25
|
+
export {
|
|
26
|
+
coherenceScore,
|
|
27
|
+
checkCoherence,
|
|
28
|
+
singleEntryPageRank,
|
|
29
|
+
conjugateGradient,
|
|
30
|
+
neumann,
|
|
31
|
+
solveOnChange,
|
|
32
|
+
hashResult,
|
|
33
|
+
observedComplexity,
|
|
34
|
+
runPageRank,
|
|
35
|
+
runSolve,
|
|
36
|
+
runSolveOnChange,
|
|
37
|
+
} from './infrastructure/solver-bridge.js';
|
|
38
|
+
|
|
39
|
+
// MCP tools
|
|
40
|
+
export { graphIntelligenceTools, type MCPTool } from './mcp-tools/index.js';
|
|
41
|
+
|
|
42
|
+
// Adapters (per-wedge integrations)
|
|
43
|
+
export * from './adapters/index.js';
|
|
44
|
+
|
|
45
|
+
// JL embedding (ADR-121 follow-up)
|
|
46
|
+
export { jlEmbed, computeTargetDim, type JLEmbedOptions, type JLEmbedResult } from './infrastructure/jl-embed.js';
|
|
47
|
+
|
|
48
|
+
// Streaming bridge (Wedge 12)
|
|
49
|
+
export {
|
|
50
|
+
StreamingBridge,
|
|
51
|
+
type StreamingBridgeOptions,
|
|
52
|
+
type StreamingUpdate,
|
|
53
|
+
} from './application/streaming-bridge.js';
|
|
54
|
+
|
|
55
|
+
// Federation protocol (Phase 8 — beyond-SOTA)
|
|
56
|
+
export {
|
|
57
|
+
PrArtifactRequestSchema,
|
|
58
|
+
PrArtifactResponseSchema,
|
|
59
|
+
PrArtifactDeltaSchema,
|
|
60
|
+
PrArtifactStaleSchema,
|
|
61
|
+
FederationMessageSchema,
|
|
62
|
+
type PrArtifactRequest,
|
|
63
|
+
type PrArtifactResponse,
|
|
64
|
+
type PrArtifactDelta,
|
|
65
|
+
type PrArtifactStale,
|
|
66
|
+
type FederationMessage,
|
|
67
|
+
type FederationTransport,
|
|
68
|
+
} from './domain/federation-protocol.js';
|
|
69
|
+
export {
|
|
70
|
+
FederationServer,
|
|
71
|
+
type FederationServerOptions,
|
|
72
|
+
} from './application/federation-server.js';
|
|
73
|
+
export {
|
|
74
|
+
FederationClient,
|
|
75
|
+
inProcessTransport,
|
|
76
|
+
type FederationClientOptions,
|
|
77
|
+
type FetchPrResult,
|
|
78
|
+
} from './application/federation-client.js';
|
|
79
|
+
|
|
80
|
+
// Signed PR artifacts (Phase 7 — beyond-SOTA)
|
|
81
|
+
export {
|
|
82
|
+
ARTIFACT_ENVELOPE_VERSION,
|
|
83
|
+
ARTIFACT_ENVELOPE_KIND,
|
|
84
|
+
SignedPageRankEnvelopeSchema,
|
|
85
|
+
SignedPageRankPayloadSchema,
|
|
86
|
+
type SignedPageRankEnvelope,
|
|
87
|
+
type SignedPageRankPayload,
|
|
88
|
+
type ArtifactVerificationResult,
|
|
89
|
+
} from './domain/signed-artifact.js';
|
|
90
|
+
export {
|
|
91
|
+
generateWitnessKey,
|
|
92
|
+
loadWitnessKey,
|
|
93
|
+
resolveWitnessKey,
|
|
94
|
+
sealArtifact,
|
|
95
|
+
verifyArtifact,
|
|
96
|
+
canonicalJSON,
|
|
97
|
+
sha256Hex,
|
|
98
|
+
type WitnessKey,
|
|
99
|
+
type SealArtifactInput,
|
|
100
|
+
} from './infrastructure/witness-signer.js';
|
|
101
|
+
|
|
102
|
+
// Default export
|
|
103
|
+
import { graphIntelligenceTools } from './mcp-tools/index.js';
|
|
104
|
+
import { getRegistry } from './domain/adapter.js';
|
|
105
|
+
export default { tools: graphIntelligenceTools, registry: getRegistry };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Johnson-Lindenstrauss embedding (Wedge: ADR-121 follow-up, ADR-123 Phase 6)
|
|
3
|
+
*
|
|
4
|
+
* Replaces `@claude-flow/embeddings`' hand-rolled hand-rolled JL with a
|
|
5
|
+
* tested implementation that obeys the Achlioptas / Dasgupta-Gupta bound
|
|
6
|
+
* `target_dim ≤ original_dim − 1`. Matches the upstream
|
|
7
|
+
* `sublinear-time-solver@1.7.0` JL contract.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createHash } from 'node:crypto';
|
|
11
|
+
|
|
12
|
+
/** Deterministic Gaussian RNG seeded by content hash so embeddings are reproducible. */
|
|
13
|
+
function* gaussianStream(seed: string): IterableIterator<number> {
|
|
14
|
+
// Box-Muller from a deterministic PRNG seeded by the hash.
|
|
15
|
+
let counter = 0;
|
|
16
|
+
while (true) {
|
|
17
|
+
const h = createHash('sha256').update(seed + ':' + counter++).digest();
|
|
18
|
+
// Two 32-bit floats in [0,1) per hash
|
|
19
|
+
const u1 = (h.readUInt32BE(0) >>> 0) / 0x100000000;
|
|
20
|
+
const u2 = (h.readUInt32BE(4) >>> 0) / 0x100000000;
|
|
21
|
+
const r = Math.sqrt(-2 * Math.log(Math.max(u1, 1e-12)));
|
|
22
|
+
const theta = 2 * Math.PI * u2;
|
|
23
|
+
yield r * Math.cos(theta);
|
|
24
|
+
yield r * Math.sin(theta);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Cap target dim at `n − 1` (Achlioptas / Dasgupta-Gupta). */
|
|
29
|
+
export function computeTargetDim(originalDim: number, requestedDim: number, epsilon: number): number {
|
|
30
|
+
const cap = Math.max(1, originalDim - 1);
|
|
31
|
+
const k = Math.min(cap, requestedDim);
|
|
32
|
+
// Documentation: the literature bound is k ≥ 4 log(n) / ε². We honour the
|
|
33
|
+
// user's requested target unless it exceeds the cap.
|
|
34
|
+
return Math.max(1, Math.min(cap, k));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface JLEmbedOptions {
|
|
38
|
+
targetDim: number;
|
|
39
|
+
epsilon?: number;
|
|
40
|
+
/** Seed for the projection matrix. Default 'ruflo-jl-v1' so it's reproducible. */
|
|
41
|
+
seed?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface JLEmbedResult {
|
|
45
|
+
projected: number[][];
|
|
46
|
+
targetDim: number;
|
|
47
|
+
/** ε from the input, echoed for reporting. */
|
|
48
|
+
epsilon: number;
|
|
49
|
+
/** Confirmed within k ≤ n − 1 bound. */
|
|
50
|
+
withinAchlioptasBound: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Project a list of vectors to `targetDim` via a random Gaussian matrix. */
|
|
54
|
+
export function jlEmbed(vectors: number[][], options: JLEmbedOptions): JLEmbedResult {
|
|
55
|
+
if (vectors.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
projected: [],
|
|
58
|
+
targetDim: 0,
|
|
59
|
+
epsilon: options.epsilon ?? 0.1,
|
|
60
|
+
withinAchlioptasBound: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const originalDim = vectors[0]!.length;
|
|
64
|
+
const target = computeTargetDim(originalDim, options.targetDim, options.epsilon ?? 0.1);
|
|
65
|
+
const seed = options.seed ?? 'ruflo-jl-v1';
|
|
66
|
+
|
|
67
|
+
// Construct the k × n projection matrix R, then project each vector.
|
|
68
|
+
const stream = gaussianStream(seed);
|
|
69
|
+
const R = new Array<Float64Array>(target);
|
|
70
|
+
for (let i = 0; i < target; i++) {
|
|
71
|
+
const row = new Float64Array(originalDim);
|
|
72
|
+
for (let j = 0; j < originalDim; j++) row[j] = stream.next().value as number;
|
|
73
|
+
R[i] = row;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Scaling: each entry has Var = 1, so multiply by 1/√k to keep ‖Rv‖² ≈ ‖v‖²
|
|
77
|
+
const scale = 1 / Math.sqrt(target);
|
|
78
|
+
const projected: number[][] = [];
|
|
79
|
+
for (const v of vectors) {
|
|
80
|
+
if (v.length !== originalDim) {
|
|
81
|
+
throw new Error(`jlEmbed: vector dim ${v.length} ≠ expected ${originalDim}`);
|
|
82
|
+
}
|
|
83
|
+
const out = new Array<number>(target);
|
|
84
|
+
for (let i = 0; i < target; i++) {
|
|
85
|
+
let s = 0;
|
|
86
|
+
const row = R[i]!;
|
|
87
|
+
for (let j = 0; j < originalDim; j++) s += row[j]! * v[j]!;
|
|
88
|
+
out[i] = s * scale;
|
|
89
|
+
}
|
|
90
|
+
projected.push(out);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
projected,
|
|
94
|
+
targetDim: target,
|
|
95
|
+
epsilon: options.epsilon ?? 0.1,
|
|
96
|
+
withinAchlioptasBound: target <= Math.max(1, originalDim - 1),
|
|
97
|
+
};
|
|
98
|
+
}
|