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,30 @@
|
|
|
1
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/mcp-tools.test.ts","timestamp":1779154995196}
|
|
2
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/mcp-tools.test.ts","timestamp":1779155000177}
|
|
3
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/mcp-tools.test.ts","timestamp":1779155004124}
|
|
4
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/.github/workflows/v3-ci.yml","timestamp":1779155058730}
|
|
5
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/.github/workflows/v3-ci.yml","timestamp":1779155073299}
|
|
6
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/browser-causal-adapter.ts","timestamp":1779155171818}
|
|
7
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/index.ts","timestamp":1779155174932}
|
|
8
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/browser-causal-adapter.test.ts","timestamp":1779155203499}
|
|
9
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/index.ts","timestamp":1779155205959}
|
|
10
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/federation-trust-adapter.ts","timestamp":1779155250109}
|
|
11
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/cost-attribution-adapter.ts","timestamp":1779155268574}
|
|
12
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/observability-span-adapter.ts","timestamp":1779155285631}
|
|
13
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/index.ts","timestamp":1779155291726}
|
|
14
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/phase3-adapters.test.ts","timestamp":1779155320194}
|
|
15
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/knowledge-graph-adapter.ts","timestamp":1779155358150}
|
|
16
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/rag-memory-adapter.ts","timestamp":1779155374761}
|
|
17
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/index.ts","timestamp":1779155379146}
|
|
18
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/phase4-adapters.test.ts","timestamp":1779155401684}
|
|
19
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/aidefence-suspicion-adapter.ts","timestamp":1779155607985}
|
|
20
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/jujutsu-blast-radius-adapter.ts","timestamp":1779155622800}
|
|
21
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/infrastructure/jl-embed.ts","timestamp":1779155641351}
|
|
22
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/mcp-tools/index.ts","timestamp":1779155648400}
|
|
23
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/mcp-tools/index.ts","timestamp":1779155664743}
|
|
24
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/adapters/index.ts","timestamp":1779155669573}
|
|
25
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/index.ts","timestamp":1779155672340}
|
|
26
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/phase6-adapters.test.ts","timestamp":1779155710143}
|
|
27
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/domain/signed-artifact.ts","timestamp":1779155976116}
|
|
28
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/infrastructure/witness-signer.ts","timestamp":1779156003682}
|
|
29
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/src/index.ts","timestamp":1779156008672}
|
|
30
|
+
{"type":"edit","file":"/Users/cohen/Projects/ruflo/plugins/ruflo-graph-intelligence/tests/phase7-signed-artifact.test.ts","timestamp":1779156040832}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIDefence Suspicion Adapter (Wedge 10, ADR-123 Phase 6)
|
|
3
|
+
*
|
|
4
|
+
* `ruflo-aidefence` flags syscalls / agent actions as suspicious. This
|
|
5
|
+
* adapter exports the call-graph so suspicion propagates from the flagged
|
|
6
|
+
* leaf node back through callers via single-entry PR. `α=0.95` (high
|
|
7
|
+
* decay — suspicion travels far) by convention.
|
|
8
|
+
*/
|
|
9
|
+
import type { SparseMatrix } from '../domain/types.js';
|
|
10
|
+
import type { SublinearAdapter, AdapterRegistry } from '../domain/adapter.js';
|
|
11
|
+
export interface CallEdge {
|
|
12
|
+
callerId: string;
|
|
13
|
+
calleeId: string;
|
|
14
|
+
/** Optional weight — calls per session. Default 1. */
|
|
15
|
+
weight?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface AIDefenceSource {
|
|
18
|
+
listCallEdges(): Promise<readonly CallEdge[]>;
|
|
19
|
+
}
|
|
20
|
+
export interface AIDefenceAdapterOptions {
|
|
21
|
+
source: AIDefenceSource;
|
|
22
|
+
/** DD safety margin. Default 0.25. */
|
|
23
|
+
ddSafetyMargin?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const AIDEFENCE_CALL_GRAPH_ID = "ruflo-aidefence:call-graph";
|
|
26
|
+
export declare class AIDefenceSuspicionAdapter implements SublinearAdapter {
|
|
27
|
+
readonly graphId = "ruflo-aidefence:call-graph";
|
|
28
|
+
readonly ownerPlugin = "ruflo-aidefence";
|
|
29
|
+
readonly requiresPreprocessing = false;
|
|
30
|
+
private readonly source;
|
|
31
|
+
private readonly ddSafetyMargin;
|
|
32
|
+
constructor(options: AIDefenceAdapterOptions);
|
|
33
|
+
exportAsSparseMatrix(options?: {
|
|
34
|
+
nodeFilter?: ReadonlySet<string>;
|
|
35
|
+
}): Promise<SparseMatrix>;
|
|
36
|
+
}
|
|
37
|
+
export declare function registerAIDefenceSuspicionAdapter(options: AIDefenceAdapterOptions & {
|
|
38
|
+
registry?: AdapterRegistry;
|
|
39
|
+
}): AIDefenceSuspicionAdapter;
|
|
40
|
+
//# sourceMappingURL=aidefence-suspicion-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aidefence-suspicion-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/aidefence-suspicion-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG9E,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,IAAI,OAAO,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,eAAe,CAAC;IACxB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,uBAAuB,+BAA+B,CAAC;AAEpE,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,QAAQ,CAAC,OAAO,gCAA2B;IAC3C,QAAQ,CAAC,WAAW,qBAAqB;IACzC,QAAQ,CAAC,qBAAqB,SAAS;IAEvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,OAAO,EAAE,uBAAuB;IAKtC,oBAAoB,CAAC,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAwClG;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,uBAAuB,GAAG;IAAE,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAE,GAChE,yBAAyB,CAI3B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIDefence Suspicion Adapter (Wedge 10, ADR-123 Phase 6)
|
|
3
|
+
*
|
|
4
|
+
* `ruflo-aidefence` flags syscalls / agent actions as suspicious. This
|
|
5
|
+
* adapter exports the call-graph so suspicion propagates from the flagged
|
|
6
|
+
* leaf node back through callers via single-entry PR. `α=0.95` (high
|
|
7
|
+
* decay — suspicion travels far) by convention.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { getRegistry } from '../domain/adapter.js';
|
|
11
|
+
export const AIDEFENCE_CALL_GRAPH_ID = 'ruflo-aidefence:call-graph';
|
|
12
|
+
export class AIDefenceSuspicionAdapter {
|
|
13
|
+
graphId = AIDEFENCE_CALL_GRAPH_ID;
|
|
14
|
+
ownerPlugin = 'ruflo-aidefence';
|
|
15
|
+
requiresPreprocessing = false;
|
|
16
|
+
source;
|
|
17
|
+
ddSafetyMargin;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.source = options.source;
|
|
20
|
+
this.ddSafetyMargin = options.ddSafetyMargin ?? 0.25;
|
|
21
|
+
}
|
|
22
|
+
async exportAsSparseMatrix(options) {
|
|
23
|
+
const edges = await this.source.listCallEdges();
|
|
24
|
+
const idSet = new Set();
|
|
25
|
+
for (const e of edges) {
|
|
26
|
+
idSet.add(e.callerId);
|
|
27
|
+
idSet.add(e.calleeId);
|
|
28
|
+
}
|
|
29
|
+
if (options?.nodeFilter) {
|
|
30
|
+
for (const n of [...idSet])
|
|
31
|
+
if (!options.nodeFilter.has(n))
|
|
32
|
+
idSet.delete(n);
|
|
33
|
+
}
|
|
34
|
+
const nodes = [...idSet].sort();
|
|
35
|
+
const nodeIndex = {};
|
|
36
|
+
nodes.forEach((n, i) => (nodeIndex[n] = i));
|
|
37
|
+
// Suspicion flows from callee BACK to caller, so edges are reversed:
|
|
38
|
+
// a callee that's flagged should bump suspicion on its caller.
|
|
39
|
+
const entries = [];
|
|
40
|
+
const rowSums = new Array(nodes.length).fill(0);
|
|
41
|
+
for (const e of edges) {
|
|
42
|
+
// Reverse direction: from callee → caller
|
|
43
|
+
const r = nodeIndex[e.calleeId];
|
|
44
|
+
const c = nodeIndex[e.callerId];
|
|
45
|
+
if (r === undefined || c === undefined || r === c)
|
|
46
|
+
continue;
|
|
47
|
+
const w = Math.max(0, e.weight ?? 1);
|
|
48
|
+
entries.push({ row: r, col: c, value: w });
|
|
49
|
+
rowSums[r] += w;
|
|
50
|
+
}
|
|
51
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
52
|
+
entries.push({ row: i, col: i, value: rowSums[i] + this.ddSafetyMargin });
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
graphId: this.graphId,
|
|
56
|
+
size: nodes.length,
|
|
57
|
+
entries,
|
|
58
|
+
nodeIndex,
|
|
59
|
+
indexNode: nodes,
|
|
60
|
+
capturedAt: new Date().toISOString(),
|
|
61
|
+
contentHash: hashContent(this.graphId, entries),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function registerAIDefenceSuspicionAdapter(options) {
|
|
66
|
+
const adapter = new AIDefenceSuspicionAdapter(options);
|
|
67
|
+
(options.registry ?? getRegistry()).register(adapter);
|
|
68
|
+
return adapter;
|
|
69
|
+
}
|
|
70
|
+
function hashContent(graphId, entries) {
|
|
71
|
+
const h = createHash('sha256');
|
|
72
|
+
h.update(graphId);
|
|
73
|
+
for (const e of entries)
|
|
74
|
+
h.update(`|${e.row},${e.col},${e.value.toFixed(8)}`);
|
|
75
|
+
return h.digest('hex');
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=aidefence-suspicion-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aidefence-suspicion-adapter.js","sourceRoot":"","sources":["../../src/adapters/aidefence-suspicion-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Causal-Recovery Adapter (Wedge 1, ADR-123 Phase 2)
|
|
3
|
+
*
|
|
4
|
+
* Exports the ADR-122 Phase 2 selector-break events as a SparseMatrix so
|
|
5
|
+
* `sublinear/page-rank-entry` can score a single element-ref's causal
|
|
6
|
+
* brittleness in O(log N) instead of the current O(N) `breakCount / attempts`
|
|
7
|
+
* ratio.
|
|
8
|
+
*
|
|
9
|
+
* The matrix `M` is built per-origin: rows + columns are union of
|
|
10
|
+
* - all element-refs that have ever appeared
|
|
11
|
+
* - all selector strings that have ever been retried
|
|
12
|
+
* Off-diagonal entry M[i,j] = number of times row-event preceded column-event
|
|
13
|
+
* on the same DOM mutation lineage (weight ≥ 1). Diagonal entry M[i,i] = 1 + Σ
|
|
14
|
+
* |off-diagonals on row i|, so the matrix is strictly diagonally-dominant.
|
|
15
|
+
*
|
|
16
|
+
* The adapter is **dependency-injection-friendly**: callers pass a
|
|
17
|
+
* `BreakEventSource` (a structural type matching the slice of ADR-122's
|
|
18
|
+
* CausalRecoveryService surface we actually need) so this plugin does NOT
|
|
19
|
+
* hard-import @claude-flow/browser. Phase 2 of *this* plugin ships the
|
|
20
|
+
* adapter; the browser package only needs to call `registerBrowserCausalAdapter()`
|
|
21
|
+
* at its plugin-init time.
|
|
22
|
+
*/
|
|
23
|
+
import type { SparseMatrix } from '../domain/types.js';
|
|
24
|
+
import type { SublinearAdapter } from '../domain/adapter.js';
|
|
25
|
+
/**
|
|
26
|
+
* The slice of @claude-flow/browser's CausalRecoveryService surface we depend on.
|
|
27
|
+
* Defined structurally so we don't need a hard import.
|
|
28
|
+
*/
|
|
29
|
+
export interface BreakEventSource {
|
|
30
|
+
/** All recorded break events for an origin, in chronological order. */
|
|
31
|
+
listBreaks(origin: string): Promise<readonly BreakEventLike[]>;
|
|
32
|
+
}
|
|
33
|
+
/** Minimal break-event shape we read. Compatible with ADR-122 Phase 2. */
|
|
34
|
+
export interface BreakEventLike {
|
|
35
|
+
id: string;
|
|
36
|
+
origin: string;
|
|
37
|
+
selector: string;
|
|
38
|
+
/** Optional last-known role+name fuzzy-match keys (Phase 2 records both). */
|
|
39
|
+
lastKnownRole?: string;
|
|
40
|
+
lastKnownName?: string;
|
|
41
|
+
/** When the break was first observed (ISO). */
|
|
42
|
+
timestamp: string;
|
|
43
|
+
}
|
|
44
|
+
export interface BrowserCausalAdapterOptions {
|
|
45
|
+
/** Origin (e.g. `https://example.com`) — one adapter instance per origin. */
|
|
46
|
+
origin: string;
|
|
47
|
+
/** Event source. */
|
|
48
|
+
source: BreakEventSource;
|
|
49
|
+
/** Adjacency-weighting half-life in milliseconds. Default 24h. */
|
|
50
|
+
halfLifeMs?: number;
|
|
51
|
+
/** Diagonal-dominance margin to keep DD even under heavy noise. Default 0.5. */
|
|
52
|
+
ddSafetyMargin?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Identifier convention so consumers can address per-origin graphs:
|
|
56
|
+
* `browser:causal:<origin>` — e.g. `browser:causal:https://example.com`
|
|
57
|
+
*/
|
|
58
|
+
export declare function browserCausalGraphId(origin: string): string;
|
|
59
|
+
export declare class BrowserCausalAdapter implements SublinearAdapter {
|
|
60
|
+
readonly graphId: string;
|
|
61
|
+
readonly ownerPlugin = "@claude-flow/browser";
|
|
62
|
+
private readonly origin;
|
|
63
|
+
private readonly source;
|
|
64
|
+
private readonly halfLifeMs;
|
|
65
|
+
private readonly ddSafetyMargin;
|
|
66
|
+
constructor(options: BrowserCausalAdapterOptions);
|
|
67
|
+
exportAsSparseMatrix(options?: {
|
|
68
|
+
since?: string;
|
|
69
|
+
nodeFilter?: ReadonlySet<string>;
|
|
70
|
+
}): Promise<SparseMatrix>;
|
|
71
|
+
readonly requiresPreprocessing = false;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Convenience entry point — instantiate + register in one call.
|
|
75
|
+
*
|
|
76
|
+
* Intended to be invoked from @claude-flow/browser's init code:
|
|
77
|
+
* import { registerBrowserCausalAdapter } from 'ruflo-graph-intelligence/adapters';
|
|
78
|
+
* registerBrowserCausalAdapter({ origin: 'https://example.com', source: causalService });
|
|
79
|
+
*/
|
|
80
|
+
export declare function registerBrowserCausalAdapter(options: BrowserCausalAdapterOptions & {
|
|
81
|
+
registry?: import('../domain/adapter.js').AdapterRegistry;
|
|
82
|
+
}): BrowserCausalAdapter;
|
|
83
|
+
//# sourceMappingURL=browser-causal-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-causal-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/browser-causal-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC;CAChE;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,qBAAa,oBAAqB,YAAW,gBAAgB;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,0BAA0B;IAE9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,OAAO,EAAE,2BAA2B;IAQ1C,oBAAoB,CAAC,OAAO,CAAC,EAAE;QACnC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;KAClC,GAAG,OAAO,CAAC,YAAY,CAAC;IA6DzB,QAAQ,CAAC,qBAAqB,SAAS;CACxC;AAwBD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,2BAA2B,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,sBAAsB,EAAE,eAAe,CAAA;CAAE,GACnG,oBAAoB,CAUtB"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Causal-Recovery Adapter (Wedge 1, ADR-123 Phase 2)
|
|
3
|
+
*
|
|
4
|
+
* Exports the ADR-122 Phase 2 selector-break events as a SparseMatrix so
|
|
5
|
+
* `sublinear/page-rank-entry` can score a single element-ref's causal
|
|
6
|
+
* brittleness in O(log N) instead of the current O(N) `breakCount / attempts`
|
|
7
|
+
* ratio.
|
|
8
|
+
*
|
|
9
|
+
* The matrix `M` is built per-origin: rows + columns are union of
|
|
10
|
+
* - all element-refs that have ever appeared
|
|
11
|
+
* - all selector strings that have ever been retried
|
|
12
|
+
* Off-diagonal entry M[i,j] = number of times row-event preceded column-event
|
|
13
|
+
* on the same DOM mutation lineage (weight ≥ 1). Diagonal entry M[i,i] = 1 + Σ
|
|
14
|
+
* |off-diagonals on row i|, so the matrix is strictly diagonally-dominant.
|
|
15
|
+
*
|
|
16
|
+
* The adapter is **dependency-injection-friendly**: callers pass a
|
|
17
|
+
* `BreakEventSource` (a structural type matching the slice of ADR-122's
|
|
18
|
+
* CausalRecoveryService surface we actually need) so this plugin does NOT
|
|
19
|
+
* hard-import @claude-flow/browser. Phase 2 of *this* plugin ships the
|
|
20
|
+
* adapter; the browser package only needs to call `registerBrowserCausalAdapter()`
|
|
21
|
+
* at its plugin-init time.
|
|
22
|
+
*/
|
|
23
|
+
import { createHash } from 'node:crypto';
|
|
24
|
+
/**
|
|
25
|
+
* Identifier convention so consumers can address per-origin graphs:
|
|
26
|
+
* `browser:causal:<origin>` — e.g. `browser:causal:https://example.com`
|
|
27
|
+
*/
|
|
28
|
+
export function browserCausalGraphId(origin) {
|
|
29
|
+
return `browser:causal:${origin}`;
|
|
30
|
+
}
|
|
31
|
+
export class BrowserCausalAdapter {
|
|
32
|
+
graphId;
|
|
33
|
+
ownerPlugin = '@claude-flow/browser';
|
|
34
|
+
origin;
|
|
35
|
+
source;
|
|
36
|
+
halfLifeMs;
|
|
37
|
+
ddSafetyMargin;
|
|
38
|
+
constructor(options) {
|
|
39
|
+
this.origin = options.origin;
|
|
40
|
+
this.source = options.source;
|
|
41
|
+
this.halfLifeMs = options.halfLifeMs ?? 24 * 60 * 60 * 1000;
|
|
42
|
+
this.ddSafetyMargin = options.ddSafetyMargin ?? 0.5;
|
|
43
|
+
this.graphId = browserCausalGraphId(this.origin);
|
|
44
|
+
}
|
|
45
|
+
async exportAsSparseMatrix(options) {
|
|
46
|
+
const events = await this.source.listBreaks(this.origin);
|
|
47
|
+
const cutoff = options?.since ? Date.parse(options.since) : -Infinity;
|
|
48
|
+
const filtered = events.filter((e) => Date.parse(e.timestamp) >= cutoff);
|
|
49
|
+
// Node set: union of selectors + (role:name) fuzzy keys
|
|
50
|
+
const nodeIds = new Set();
|
|
51
|
+
for (const e of filtered) {
|
|
52
|
+
nodeIds.add(e.selector);
|
|
53
|
+
if (e.lastKnownRole && e.lastKnownName) {
|
|
54
|
+
nodeIds.add(`role:${e.lastKnownRole}:${e.lastKnownName}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (options?.nodeFilter) {
|
|
58
|
+
for (const n of [...nodeIds])
|
|
59
|
+
if (!options.nodeFilter.has(n))
|
|
60
|
+
nodeIds.delete(n);
|
|
61
|
+
}
|
|
62
|
+
const nodes = [...nodeIds].sort();
|
|
63
|
+
const nodeIndex = {};
|
|
64
|
+
nodes.forEach((n, i) => (nodeIndex[n] = i));
|
|
65
|
+
// Build adjacency: row = source event's selector, col = "next" event's selector
|
|
66
|
+
// within the same chronological neighbourhood. Time-decayed weight.
|
|
67
|
+
const weights = new Map(); // key = "row:col"
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
for (let i = 0; i < filtered.length - 1; i++) {
|
|
70
|
+
const a = filtered[i];
|
|
71
|
+
const b = filtered[i + 1];
|
|
72
|
+
const decay = Math.exp(-(now - Date.parse(a.timestamp)) / this.halfLifeMs);
|
|
73
|
+
const keys = pairKeys(a, b);
|
|
74
|
+
for (const k of keys)
|
|
75
|
+
weights.set(k, (weights.get(k) ?? 0) + decay);
|
|
76
|
+
}
|
|
77
|
+
// Emit off-diagonal entries, then add a diagonal that guarantees DD.
|
|
78
|
+
const entries = [];
|
|
79
|
+
const rowSums = new Array(nodes.length).fill(0);
|
|
80
|
+
for (const [key, w] of weights) {
|
|
81
|
+
const [from, to] = key.split('::');
|
|
82
|
+
const rIdx = nodeIndex[from];
|
|
83
|
+
const cIdx = nodeIndex[to];
|
|
84
|
+
if (rIdx === undefined || cIdx === undefined)
|
|
85
|
+
continue;
|
|
86
|
+
if (rIdx === cIdx)
|
|
87
|
+
continue;
|
|
88
|
+
entries.push({ row: rIdx, col: cIdx, value: w });
|
|
89
|
+
rowSums[rIdx] += Math.abs(w);
|
|
90
|
+
}
|
|
91
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
92
|
+
const diag = rowSums[i] + this.ddSafetyMargin;
|
|
93
|
+
entries.push({ row: i, col: i, value: Math.max(1, diag) });
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
graphId: this.graphId,
|
|
97
|
+
size: nodes.length,
|
|
98
|
+
entries,
|
|
99
|
+
nodeIndex,
|
|
100
|
+
indexNode: nodes,
|
|
101
|
+
capturedAt: new Date().toISOString(),
|
|
102
|
+
contentHash: hashContent(this.graphId, entries),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
requiresPreprocessing = false;
|
|
106
|
+
}
|
|
107
|
+
function pairKeys(a, b) {
|
|
108
|
+
const keys = [`${a.selector}::${b.selector}`];
|
|
109
|
+
if (a.lastKnownRole && a.lastKnownName) {
|
|
110
|
+
const key = `role:${a.lastKnownRole}:${a.lastKnownName}`;
|
|
111
|
+
keys.push(`${key}::${b.selector}`);
|
|
112
|
+
}
|
|
113
|
+
if (b.lastKnownRole && b.lastKnownName) {
|
|
114
|
+
const key = `role:${b.lastKnownRole}:${b.lastKnownName}`;
|
|
115
|
+
keys.push(`${a.selector}::${key}`);
|
|
116
|
+
}
|
|
117
|
+
return keys;
|
|
118
|
+
}
|
|
119
|
+
function hashContent(graphId, entries) {
|
|
120
|
+
const h = createHash('sha256');
|
|
121
|
+
h.update(graphId);
|
|
122
|
+
for (const e of entries) {
|
|
123
|
+
h.update(`|${e.row},${e.col},${e.value.toFixed(8)}`);
|
|
124
|
+
}
|
|
125
|
+
return h.digest('hex');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Convenience entry point — instantiate + register in one call.
|
|
129
|
+
*
|
|
130
|
+
* Intended to be invoked from @claude-flow/browser's init code:
|
|
131
|
+
* import { registerBrowserCausalAdapter } from 'ruflo-graph-intelligence/adapters';
|
|
132
|
+
* registerBrowserCausalAdapter({ origin: 'https://example.com', source: causalService });
|
|
133
|
+
*/
|
|
134
|
+
export function registerBrowserCausalAdapter(options) {
|
|
135
|
+
const adapter = new BrowserCausalAdapter(options);
|
|
136
|
+
const registry = options.registry ?? import('../domain/adapter.js').then((m) => m.getRegistry());
|
|
137
|
+
// Synchronous registration when registry is supplied; lazy fallback otherwise.
|
|
138
|
+
if (typeof registry.register === 'function') {
|
|
139
|
+
registry.register(adapter);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
registry.then((r) => r.register(adapter));
|
|
143
|
+
}
|
|
144
|
+
return adapter;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=browser-causal-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-causal-adapter.js","sourceRoot":"","sources":["../../src/adapters/browser-causal-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Attribution Adapter (Wedge 6, ADR-123 Phase 3)
|
|
3
|
+
*
|
|
4
|
+
* `ruflo-cost-tracker` records token usage per session in a causation graph:
|
|
5
|
+
* user-prompt → spawned-agent → MCP-call → model-invocation → tokens-USD
|
|
6
|
+
*
|
|
7
|
+
* This adapter exports that graph so `sublinear/page-rank-entry` answers
|
|
8
|
+
* "which root prompt caused the most downstream spend" in O(log traces)
|
|
9
|
+
* rather than O(traces) walks. Costs are one-way edges → asymmetric matrix.
|
|
10
|
+
*/
|
|
11
|
+
import type { SparseMatrix } from '../domain/types.js';
|
|
12
|
+
import type { SublinearAdapter, AdapterRegistry } from '../domain/adapter.js';
|
|
13
|
+
export interface CostCausationEdge {
|
|
14
|
+
/** Parent node — typically a prompt id or upstream agent id. */
|
|
15
|
+
parentId: string;
|
|
16
|
+
/** Child node — typically a spawned agent / MCP call / model invocation id. */
|
|
17
|
+
childId: string;
|
|
18
|
+
/** USD cost attributed to the child as caused by this parent. */
|
|
19
|
+
costUsd: number;
|
|
20
|
+
}
|
|
21
|
+
export interface CostCausationSource {
|
|
22
|
+
/** All causation edges for a session (or globally). */
|
|
23
|
+
listCausationEdges(sessionId?: string): Promise<readonly CostCausationEdge[]>;
|
|
24
|
+
}
|
|
25
|
+
export interface CostAttributionAdapterOptions {
|
|
26
|
+
source: CostCausationSource;
|
|
27
|
+
/** Restrict to a specific session id. */
|
|
28
|
+
sessionId?: string;
|
|
29
|
+
/** DD safety margin. Default 0.25. */
|
|
30
|
+
ddSafetyMargin?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function costAttributionGraphId(sessionId?: string): string;
|
|
33
|
+
export declare class CostAttributionAdapter implements SublinearAdapter {
|
|
34
|
+
readonly graphId: string;
|
|
35
|
+
readonly ownerPlugin = "ruflo-cost-tracker";
|
|
36
|
+
readonly requiresPreprocessing = false;
|
|
37
|
+
private readonly source;
|
|
38
|
+
private readonly sessionId?;
|
|
39
|
+
private readonly ddSafetyMargin;
|
|
40
|
+
constructor(options: CostAttributionAdapterOptions);
|
|
41
|
+
exportAsSparseMatrix(options?: {
|
|
42
|
+
nodeFilter?: ReadonlySet<string>;
|
|
43
|
+
}): Promise<SparseMatrix>;
|
|
44
|
+
}
|
|
45
|
+
export declare function registerCostAttributionAdapter(options: CostAttributionAdapterOptions & {
|
|
46
|
+
registry?: AdapterRegistry;
|
|
47
|
+
}): CostAttributionAdapter;
|
|
48
|
+
//# sourceMappingURL=cost-attribution-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-attribution-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/cost-attribution-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG9E,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,mBAAmB,CAAC;IAC5B,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,wBAAwB;IAC5C,QAAQ,CAAC,qBAAqB,SAAS;IAEvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,OAAO,EAAE,6BAA6B;IAO5C,oBAAoB,CAAC,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAiDlG;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,6BAA6B,GAAG;IAAE,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAE,GACtE,sBAAsB,CAIxB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Attribution Adapter (Wedge 6, ADR-123 Phase 3)
|
|
3
|
+
*
|
|
4
|
+
* `ruflo-cost-tracker` records token usage per session in a causation graph:
|
|
5
|
+
* user-prompt → spawned-agent → MCP-call → model-invocation → tokens-USD
|
|
6
|
+
*
|
|
7
|
+
* This adapter exports that graph so `sublinear/page-rank-entry` answers
|
|
8
|
+
* "which root prompt caused the most downstream spend" in O(log traces)
|
|
9
|
+
* rather than O(traces) walks. Costs are one-way edges → asymmetric matrix.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { getRegistry } from '../domain/adapter.js';
|
|
13
|
+
export function costAttributionGraphId(sessionId) {
|
|
14
|
+
return sessionId ? `ruflo-cost-tracker:causation:${sessionId}` : 'ruflo-cost-tracker:causation:global';
|
|
15
|
+
}
|
|
16
|
+
export class CostAttributionAdapter {
|
|
17
|
+
graphId;
|
|
18
|
+
ownerPlugin = 'ruflo-cost-tracker';
|
|
19
|
+
requiresPreprocessing = false;
|
|
20
|
+
source;
|
|
21
|
+
sessionId;
|
|
22
|
+
ddSafetyMargin;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.source = options.source;
|
|
25
|
+
this.sessionId = options.sessionId;
|
|
26
|
+
this.ddSafetyMargin = options.ddSafetyMargin ?? 0.25;
|
|
27
|
+
this.graphId = costAttributionGraphId(this.sessionId);
|
|
28
|
+
}
|
|
29
|
+
async exportAsSparseMatrix(options) {
|
|
30
|
+
const edges = await this.source.listCausationEdges(this.sessionId);
|
|
31
|
+
const nodeSet = new Set();
|
|
32
|
+
for (const e of edges) {
|
|
33
|
+
nodeSet.add(e.parentId);
|
|
34
|
+
nodeSet.add(e.childId);
|
|
35
|
+
}
|
|
36
|
+
if (options?.nodeFilter) {
|
|
37
|
+
for (const n of [...nodeSet])
|
|
38
|
+
if (!options.nodeFilter.has(n))
|
|
39
|
+
nodeSet.delete(n);
|
|
40
|
+
}
|
|
41
|
+
const nodes = [...nodeSet].sort();
|
|
42
|
+
const nodeIndex = {};
|
|
43
|
+
nodes.forEach((n, i) => (nodeIndex[n] = i));
|
|
44
|
+
// Normalise costs into [0, 1] per row so PageRank semantics make sense
|
|
45
|
+
// (we're after the *share of blame*, not the raw dollar amount).
|
|
46
|
+
const rawRowSums = new Array(nodes.length).fill(0);
|
|
47
|
+
for (const e of edges) {
|
|
48
|
+
const r = nodeIndex[e.parentId];
|
|
49
|
+
if (r === undefined)
|
|
50
|
+
continue;
|
|
51
|
+
rawRowSums[r] += Math.max(0, e.costUsd);
|
|
52
|
+
}
|
|
53
|
+
const entries = [];
|
|
54
|
+
const rowSums = new Array(nodes.length).fill(0);
|
|
55
|
+
for (const e of edges) {
|
|
56
|
+
const r = nodeIndex[e.parentId];
|
|
57
|
+
const c = nodeIndex[e.childId];
|
|
58
|
+
if (r === undefined || c === undefined || r === c)
|
|
59
|
+
continue;
|
|
60
|
+
const denom = rawRowSums[r];
|
|
61
|
+
if (denom === 0)
|
|
62
|
+
continue;
|
|
63
|
+
const w = Math.max(0, e.costUsd) / denom;
|
|
64
|
+
if (w === 0)
|
|
65
|
+
continue;
|
|
66
|
+
entries.push({ row: r, col: c, value: w });
|
|
67
|
+
rowSums[r] += w;
|
|
68
|
+
}
|
|
69
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
70
|
+
entries.push({ row: i, col: i, value: rowSums[i] + this.ddSafetyMargin });
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
graphId: this.graphId,
|
|
74
|
+
size: nodes.length,
|
|
75
|
+
entries,
|
|
76
|
+
nodeIndex,
|
|
77
|
+
indexNode: nodes,
|
|
78
|
+
capturedAt: new Date().toISOString(),
|
|
79
|
+
contentHash: hashContent(this.graphId, entries),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function registerCostAttributionAdapter(options) {
|
|
84
|
+
const adapter = new CostAttributionAdapter(options);
|
|
85
|
+
(options.registry ?? getRegistry()).register(adapter);
|
|
86
|
+
return adapter;
|
|
87
|
+
}
|
|
88
|
+
function hashContent(graphId, entries) {
|
|
89
|
+
const h = createHash('sha256');
|
|
90
|
+
h.update(graphId);
|
|
91
|
+
for (const e of entries)
|
|
92
|
+
h.update(`|${e.row},${e.col},${e.value.toFixed(8)}`);
|
|
93
|
+
return h.digest('hex');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=cost-attribution-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-attribution-adapter.js","sourceRoot":"","sources":["../../src/adapters/cost-attribution-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Trust Adapter (Wedge 3, ADR-123 Phase 3)
|
|
3
|
+
*
|
|
4
|
+
* `ruflo-federation` ships a peer trust mesh (ADR-097/104/105/111). This
|
|
5
|
+
* adapter exports the mesh as a SparseMatrix so `sublinear/page-rank-entry`
|
|
6
|
+
* computes transitive trust `(I − αT)τ = e` in O(log peers) instead of
|
|
7
|
+
* O(peers²) closure walks. Trust is one-way → the matrix is asymmetric
|
|
8
|
+
* (per upstream 2025 asymmetric-DD result, this is in-scope for sublinear).
|
|
9
|
+
*/
|
|
10
|
+
import type { SparseMatrix } from '../domain/types.js';
|
|
11
|
+
import type { SublinearAdapter, AdapterRegistry } from '../domain/adapter.js';
|
|
12
|
+
export interface PeerTrustEdge {
|
|
13
|
+
/** Peer the trust comes from. */
|
|
14
|
+
fromPeer: string;
|
|
15
|
+
/** Peer the trust is directed at. */
|
|
16
|
+
toPeer: string;
|
|
17
|
+
/** Confidence in [0, 1] — typically derived from signed-message hit rate. */
|
|
18
|
+
confidence: number;
|
|
19
|
+
/** When the edge was last updated. */
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
export interface PeerTrustSource {
|
|
23
|
+
/** All trust edges currently in the local view of the mesh. */
|
|
24
|
+
listTrustEdges(): Promise<readonly PeerTrustEdge[]>;
|
|
25
|
+
}
|
|
26
|
+
export interface FederationTrustAdapterOptions {
|
|
27
|
+
source: PeerTrustSource;
|
|
28
|
+
/** Edge-staleness cutoff in milliseconds. Default 7 days. */
|
|
29
|
+
freshnessMs?: number;
|
|
30
|
+
/** Diagonal-dominance safety margin. Default 0.25. */
|
|
31
|
+
ddSafetyMargin?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare const FEDERATION_TRUST_GRAPH_ID = "ruflo-federation:trust-mesh";
|
|
34
|
+
export declare class FederationTrustAdapter implements SublinearAdapter {
|
|
35
|
+
readonly graphId = "ruflo-federation:trust-mesh";
|
|
36
|
+
readonly ownerPlugin = "ruflo-federation";
|
|
37
|
+
readonly requiresPreprocessing = false;
|
|
38
|
+
private readonly source;
|
|
39
|
+
private readonly freshnessMs;
|
|
40
|
+
private readonly ddSafetyMargin;
|
|
41
|
+
constructor(options: FederationTrustAdapterOptions);
|
|
42
|
+
exportAsSparseMatrix(options?: {
|
|
43
|
+
nodeFilter?: ReadonlySet<string>;
|
|
44
|
+
}): Promise<SparseMatrix>;
|
|
45
|
+
}
|
|
46
|
+
export declare function registerFederationTrustAdapter(options: FederationTrustAdapterOptions & {
|
|
47
|
+
registry?: AdapterRegistry;
|
|
48
|
+
}): FederationTrustAdapter;
|
|
49
|
+
//# sourceMappingURL=federation-trust-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federation-trust-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/federation-trust-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG9E,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,cAAc,IAAI,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,eAAe,CAAC;IACxB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAEvE,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,QAAQ,CAAC,OAAO,iCAA6B;IAC7C,QAAQ,CAAC,WAAW,sBAAsB;IAC1C,QAAQ,CAAC,qBAAqB,SAAS;IAEvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,OAAO,EAAE,6BAA6B;IAM5C,oBAAoB,CAAC,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CA4ClG;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,6BAA6B,GAAG;IAAE,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAE,GACtE,sBAAsB,CAIxB"}
|