@kernel.chat/kbot-finance 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +188 -0
- package/RFC-content-addressed-mcp.md +240 -0
- package/dist/adapters/edgar/client.d.ts +11 -0
- package/dist/adapters/edgar/client.d.ts.map +1 -0
- package/dist/adapters/edgar/client.js +56 -0
- package/dist/adapters/edgar/client.js.map +1 -0
- package/dist/adapters/edgar/commands.d.ts +27 -0
- package/dist/adapters/edgar/commands.d.ts.map +1 -0
- package/dist/adapters/edgar/commands.js +56 -0
- package/dist/adapters/edgar/commands.js.map +1 -0
- package/dist/adapters/edgar/index.d.ts +4 -0
- package/dist/adapters/edgar/index.d.ts.map +1 -0
- package/dist/adapters/edgar/index.js +4 -0
- package/dist/adapters/edgar/index.js.map +1 -0
- package/dist/adapters/edgar/types.d.ts +70 -0
- package/dist/adapters/edgar/types.d.ts.map +1 -0
- package/dist/adapters/edgar/types.js +23 -0
- package/dist/adapters/edgar/types.js.map +1 -0
- package/dist/adapters/polymarket/client.d.ts +7 -0
- package/dist/adapters/polymarket/client.d.ts.map +1 -0
- package/dist/adapters/polymarket/client.js +58 -0
- package/dist/adapters/polymarket/client.js.map +1 -0
- package/dist/adapters/polymarket/commands.d.ts +30 -0
- package/dist/adapters/polymarket/commands.d.ts.map +1 -0
- package/dist/adapters/polymarket/commands.js +67 -0
- package/dist/adapters/polymarket/commands.js.map +1 -0
- package/dist/adapters/polymarket/index.d.ts +4 -0
- package/dist/adapters/polymarket/index.d.ts.map +1 -0
- package/dist/adapters/polymarket/index.js +4 -0
- package/dist/adapters/polymarket/index.js.map +1 -0
- package/dist/adapters/polymarket/types.d.ts +58 -0
- package/dist/adapters/polymarket/types.d.ts.map +1 -0
- package/dist/adapters/polymarket/types.js +12 -0
- package/dist/adapters/polymarket/types.js.map +1 -0
- package/dist/audit-log.d.ts +65 -0
- package/dist/audit-log.d.ts.map +1 -0
- package/dist/audit-log.js +96 -0
- package/dist/audit-log.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +44 -0
- package/dist/cli.js.map +1 -0
- package/dist/demo.d.ts +11 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +133 -0
- package/dist/demo.js.map +1 -0
- package/dist/envelope.d.ts +71 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +83 -0
- package/dist/envelope.js.map +1 -0
- package/dist/exporters/annex-iv.d.ts +40 -0
- package/dist/exporters/annex-iv.d.ts.map +1 -0
- package/dist/exporters/annex-iv.js +154 -0
- package/dist/exporters/annex-iv.js.map +1 -0
- package/dist/governance.d.ts +55 -0
- package/dist/governance.d.ts.map +1 -0
- package/dist/governance.js +73 -0
- package/dist/governance.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/kbot-tool.d.ts +31 -0
- package/dist/kbot-tool.d.ts.map +1 -0
- package/dist/kbot-tool.js +325 -0
- package/dist/kbot-tool.js.map +1 -0
- package/dist/mcp-server.d.ts +25 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +80 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/tools/edgar-query.d.ts +36 -0
- package/dist/tools/edgar-query.d.ts.map +1 -0
- package/dist/tools/edgar-query.js +108 -0
- package/dist/tools/edgar-query.js.map +1 -0
- package/dist/tools/polymarket-query.d.ts +55 -0
- package/dist/tools/polymarket-query.d.ts.map +1 -0
- package/dist/tools/polymarket-query.js +128 -0
- package/dist/tools/polymarket-query.js.map +1 -0
- package/dist/verifier/eu-rts6.d.ts +3 -0
- package/dist/verifier/eu-rts6.d.ts.map +1 -0
- package/dist/verifier/eu-rts6.js +45 -0
- package/dist/verifier/eu-rts6.js.map +1 -0
- package/dist/verifier/index.d.ts +67 -0
- package/dist/verifier/index.d.ts.map +1 -0
- package/dist/verifier/index.js +22 -0
- package/dist/verifier/index.js.map +1 -0
- package/dist/verifier/kelly-cap.d.ts +19 -0
- package/dist/verifier/kelly-cap.d.ts.map +1 -0
- package/dist/verifier/kelly-cap.js +64 -0
- package/dist/verifier/kelly-cap.js.map +1 -0
- package/dist/verifier/model-version.d.ts +3 -0
- package/dist/verifier/model-version.d.ts.map +1 -0
- package/dist/verifier/model-version.js +28 -0
- package/dist/verifier/model-version.js.map +1 -0
- package/dist/verifier/position-limit.d.ts +21 -0
- package/dist/verifier/position-limit.d.ts.map +1 -0
- package/dist/verifier/position-limit.js +42 -0
- package/dist/verifier/position-limit.js.map +1 -0
- package/package.json +101 -0
package/dist/demo.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end demo of the kbot-finance architecture.
|
|
3
|
+
*
|
|
4
|
+
* Run with: npm run demo
|
|
5
|
+
*
|
|
6
|
+
* Hits the live Polymarket Gamma API. No keys required. The Replit
|
|
7
|
+
* entrypoint runs this on first launch so visitors see the full
|
|
8
|
+
* envelope + verifier + audit-log flow light up.
|
|
9
|
+
*/
|
|
10
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { AppendOnlyAuditLog, makePositionLimitRule, makeKellyCapRule, polymarketQuery, runVerifier, } from "./index.js";
|
|
14
|
+
const SESSION_ID = `demo-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
15
|
+
async function main() {
|
|
16
|
+
const banner = (s) => {
|
|
17
|
+
process.stdout.write(`\n${"=".repeat(72)}\n${s}\n${"=".repeat(72)}\n`);
|
|
18
|
+
};
|
|
19
|
+
banner("kbot-finance v0.1 — audit-grade AI infrastructure for capital markets");
|
|
20
|
+
process.stdout.write(`session_id: ${SESSION_ID}\n` +
|
|
21
|
+
`architecture: deterministic engine + AI intelligence + human governance\n` +
|
|
22
|
+
`engine for this demo: Polymarket Gamma (https://gamma-api.polymarket.com)\n`);
|
|
23
|
+
const dir = await mkdtemp(join(tmpdir(), "kbot-finance-demo-"));
|
|
24
|
+
const audit_path = join(dir, "audit.jsonl");
|
|
25
|
+
const auditLog = await AppendOnlyAuditLog.open(audit_path);
|
|
26
|
+
process.stdout.write(`audit log: ${audit_path}\n`);
|
|
27
|
+
// Compose a minimal global ruleset. v0.1 ships two rules; later jurisdictions
|
|
28
|
+
// layer more rules on top.
|
|
29
|
+
const rules = [
|
|
30
|
+
makePositionLimitRule({ default_max_size: 10_000, default_max_notional: 50_000 }),
|
|
31
|
+
makeKellyCapRule({ kelly_fraction: 0.5, bankroll: 100_000 }),
|
|
32
|
+
];
|
|
33
|
+
banner("Step 1 — query Polymarket: top 3 active markets by 24h volume");
|
|
34
|
+
const result = await polymarketQuery({
|
|
35
|
+
mode: "list_active",
|
|
36
|
+
limit: 3,
|
|
37
|
+
data_as_of: new Date().toISOString(),
|
|
38
|
+
}, {
|
|
39
|
+
auditLog,
|
|
40
|
+
rules,
|
|
41
|
+
verifierContext: {
|
|
42
|
+
session_id: SESSION_ID,
|
|
43
|
+
state: {},
|
|
44
|
+
jurisdiction: "US",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
if (!result.ok) {
|
|
48
|
+
process.stdout.write(`FAIL at ${result.stage}: ${JSON.stringify(result.detail)}\n`);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
process.stdout.write(`request_hash: ${result.response.request_hash}\n`);
|
|
53
|
+
process.stdout.write(`engine_version: ${result.response.engine_version}\n`);
|
|
54
|
+
process.stdout.write(`produced_at: ${result.response.produced_at}\n`);
|
|
55
|
+
process.stdout.write(`byte_identical_replayable: ${result.response.byte_identical_replayable} ` +
|
|
56
|
+
`(false because Gamma is live HTTPS; replay needs an indexer pinned to block)\n`);
|
|
57
|
+
for (const m of result.response.value.markets) {
|
|
58
|
+
process.stdout.write(`\n ${m.question ?? "(no question)"}\n`);
|
|
59
|
+
if (m.outcomes && m.outcome_prices) {
|
|
60
|
+
for (let i = 0; i < m.outcomes.length; i++) {
|
|
61
|
+
const price = m.outcome_prices[i];
|
|
62
|
+
process.stdout.write(` ${m.outcomes[i]}: ${price !== undefined ? (price * 100).toFixed(1) + "%" : "—"}\n`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
process.stdout.write(` 24h volume: $${(m.volume_24h ?? 0).toFixed(0)}\n`);
|
|
66
|
+
}
|
|
67
|
+
banner("Step 2 — verifier rejects an oversized trade proposal");
|
|
68
|
+
// The AI proposes a hypothetical trade; the verifier checks it against every
|
|
69
|
+
// applicable rule BEFORE any engine call. Half-Kelly + position limits both fire.
|
|
70
|
+
const proposed_trade = {
|
|
71
|
+
instrument_id: result.response.value.markets[0]?.id ?? "demo-market",
|
|
72
|
+
size: 50_000, // exceeds default_max_size (10_000)
|
|
73
|
+
notional: 75_000, // exceeds default_max_notional (50_000)
|
|
74
|
+
edge_probability: 0.55, // p=0.55, b=1 → Kelly = 0.1 → half-Kelly cap = 5,000
|
|
75
|
+
payoff_b: 1.0,
|
|
76
|
+
};
|
|
77
|
+
const verdict = runVerifier(rules, {
|
|
78
|
+
operation: "polymarket.trade",
|
|
79
|
+
inputs: proposed_trade,
|
|
80
|
+
materiality: "material",
|
|
81
|
+
}, { session_id: SESSION_ID, state: {}, jurisdiction: "US" });
|
|
82
|
+
await auditLog.append({
|
|
83
|
+
action: "verifier_check",
|
|
84
|
+
subject: "polymarket.trade",
|
|
85
|
+
session_id: SESSION_ID,
|
|
86
|
+
payload: verdict,
|
|
87
|
+
});
|
|
88
|
+
process.stdout.write(`verifier ok: ${verdict.ok}\n`);
|
|
89
|
+
for (const check of verdict.checks) {
|
|
90
|
+
if (check.result.pass) {
|
|
91
|
+
process.stdout.write(` ✓ ${check.rule_id}: pass\n`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
process.stdout.write(` ✗ ${check.rule_id}: ${check.result.reason.code} — ${check.result.reason.summary}\n`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
banner("Step 3 — audit log integrity check");
|
|
98
|
+
const integrity = await AppendOnlyAuditLog.verify(audit_path);
|
|
99
|
+
if (integrity.ok) {
|
|
100
|
+
process.stdout.write("audit log: HASH CHAIN INTACT — every entry verified\n");
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
process.stdout.write(`audit log: BROKEN at seq=${integrity.broken_at_seq}\n`);
|
|
104
|
+
process.exitCode = 1;
|
|
105
|
+
}
|
|
106
|
+
banner("Audit log contents");
|
|
107
|
+
const log_content = await readFile(audit_path, "utf8");
|
|
108
|
+
const lines = log_content.split("\n").filter((l) => l.length > 0);
|
|
109
|
+
process.stdout.write(`entries written: ${lines.length}\n\n`);
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const entry = JSON.parse(line);
|
|
112
|
+
process.stdout.write(` [${entry.seq}] ${entry.action.padEnd(16)} ${entry.subject.padEnd(30)} hash=${entry.self_hash.slice(0, 12)}…\n`);
|
|
113
|
+
}
|
|
114
|
+
banner("Demo complete");
|
|
115
|
+
process.stdout.write(`\nWhat just happened:\n` +
|
|
116
|
+
` 1. AI agent requested a Polymarket query inside a content-addressed envelope.\n` +
|
|
117
|
+
` 2. Regulatory verifier ran every active rule against the request.\n` +
|
|
118
|
+
` 3. Engine (Gamma API) was called; result sealed with request_hash.\n` +
|
|
119
|
+
` 4. Audit log recorded verifier check + engine request + engine response.\n` +
|
|
120
|
+
` 5. Verifier successfully blocked an oversized request without reaching the engine.\n` +
|
|
121
|
+
` 6. Audit log hash-chain integrity verified end-to-end.\n` +
|
|
122
|
+
`\nThe AI never produced a price. The engine did. Every step is replayable.\n`);
|
|
123
|
+
// Clean up the temp audit log and force exit so Node's fetch keepalive
|
|
124
|
+
// doesn't hold the event loop open in Replit.
|
|
125
|
+
await rm(dir, { recursive: true, force: true });
|
|
126
|
+
}
|
|
127
|
+
main()
|
|
128
|
+
.then(() => process.exit(0))
|
|
129
|
+
.catch((e) => {
|
|
130
|
+
process.stderr.write(`fatal: ${e.message}\n`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=demo.js.map
|
package/dist/demo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-addressed envelope for engine calls.
|
|
3
|
+
*
|
|
4
|
+
* The single load-bearing primitive of the audit substrate. Every engine
|
|
5
|
+
* request resolves to a deterministic SHA-256 hash over canonicalized inputs;
|
|
6
|
+
* identical hash → identical result, byte-for-byte. The AI layer cannot
|
|
7
|
+
* produce a number — it can only request one inside an envelope, and the
|
|
8
|
+
* envelope is the only thing regulators replay.
|
|
9
|
+
*
|
|
10
|
+
* This is the gap in current MCP. We ship it as a wrapper now and propose
|
|
11
|
+
* the spec extension separately.
|
|
12
|
+
*/
|
|
13
|
+
export interface ContentAddressedRequest {
|
|
14
|
+
/** Logical operation, e.g. "polymarket.get_market", "alts.nav_compute". */
|
|
15
|
+
readonly operation: string;
|
|
16
|
+
/** Pinned engine version, e.g. "polymarket-adapter@0.1.0". */
|
|
17
|
+
readonly engine_version: string;
|
|
18
|
+
/** SHA-256 of the JSON schema used to validate `inputs`. */
|
|
19
|
+
readonly schema_hash: string;
|
|
20
|
+
/** Operation inputs. Will be canonicalized before hashing. */
|
|
21
|
+
readonly inputs: JsonValue;
|
|
22
|
+
/** As-of timestamp (ISO 8601, UTC) for the market data snapshot. */
|
|
23
|
+
readonly data_as_of: string;
|
|
24
|
+
/** Optional deterministic seed for any Monte Carlo paths. */
|
|
25
|
+
readonly deterministic_seed?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ContentAddressedResponse<T = JsonValue> {
|
|
28
|
+
/** SHA-256 hash of the canonical request — the replay key. */
|
|
29
|
+
readonly request_hash: string;
|
|
30
|
+
/** Engine version that produced this response. Must match the request. */
|
|
31
|
+
readonly engine_version: string;
|
|
32
|
+
/** ISO 8601 timestamp when the engine produced this result. */
|
|
33
|
+
readonly produced_at: string;
|
|
34
|
+
/** Hardware-determinism honesty flag. False if running on non-deterministic GPU/etc. */
|
|
35
|
+
readonly byte_identical_replayable: boolean;
|
|
36
|
+
/** The actual numerical/structured payload. */
|
|
37
|
+
readonly value: T;
|
|
38
|
+
}
|
|
39
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
40
|
+
readonly [key: string]: JsonValue;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Canonical JSON serialization (RFC 8785 JCS, simplified).
|
|
44
|
+
*
|
|
45
|
+
* Sorts object keys lexicographically. Numbers are emitted in the shortest
|
|
46
|
+
* round-trip form. Strings are JSON-escaped. This is the foundation of
|
|
47
|
+
* deterministic content hashing — two callers producing the same logical
|
|
48
|
+
* request must produce byte-identical canonical bytes.
|
|
49
|
+
*/
|
|
50
|
+
export declare function canonicalize(value: JsonValue): string;
|
|
51
|
+
/** SHA-256 of a string, hex-encoded. */
|
|
52
|
+
export declare function sha256(input: string): string;
|
|
53
|
+
/** Compute the content-addressed hash of a request. */
|
|
54
|
+
export declare function requestHash(request: ContentAddressedRequest): string;
|
|
55
|
+
/**
|
|
56
|
+
* Wrap an engine call: compute the hash, invoke the engine, return the
|
|
57
|
+
* envelope. The engine function must be deterministic given the same
|
|
58
|
+
* canonicalized inputs — if it isn't, the replay primitive is a lie.
|
|
59
|
+
*/
|
|
60
|
+
export declare function sealEnvelope<T>(request: ContentAddressedRequest, engine: (req: ContentAddressedRequest) => Promise<T>, options?: {
|
|
61
|
+
byte_identical_replayable: boolean;
|
|
62
|
+
}): Promise<ContentAddressedResponse<T>>;
|
|
63
|
+
/**
|
|
64
|
+
* Generate a deterministic seed from a string source. Useful when the AI
|
|
65
|
+
* layer needs to commit to a seed before the engine call — the seed itself
|
|
66
|
+
* is content-addressed so the agent can't retroactively pick a favourable one.
|
|
67
|
+
*/
|
|
68
|
+
export declare function deriveSeed(source: string): string;
|
|
69
|
+
/** Generate a fresh random seed for cases where determinism is not yet required. */
|
|
70
|
+
export declare function freshSeed(): string;
|
|
71
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,SAAS;IACrD,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC;IAC5C,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAE1C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAsBrD;AAED,wCAAwC;AACxC,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAcpE;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,OAAO,EAAE,uBAAuB,EAChC,MAAM,EAAE,CAAC,GAAG,EAAE,uBAAuB,KAAK,OAAO,CAAC,CAAC,CAAC,EACpD,OAAO,GAAE;IAAE,yBAAyB,EAAE,OAAO,CAAA;CAAyC,GACrF,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAStC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,oFAAoF;AACpF,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
|
package/dist/envelope.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical JSON serialization (RFC 8785 JCS, simplified).
|
|
4
|
+
*
|
|
5
|
+
* Sorts object keys lexicographically. Numbers are emitted in the shortest
|
|
6
|
+
* round-trip form. Strings are JSON-escaped. This is the foundation of
|
|
7
|
+
* deterministic content hashing — two callers producing the same logical
|
|
8
|
+
* request must produce byte-identical canonical bytes.
|
|
9
|
+
*/
|
|
10
|
+
export function canonicalize(value) {
|
|
11
|
+
if (value === null)
|
|
12
|
+
return "null";
|
|
13
|
+
if (typeof value === "boolean")
|
|
14
|
+
return value ? "true" : "false";
|
|
15
|
+
if (typeof value === "number") {
|
|
16
|
+
if (!Number.isFinite(value)) {
|
|
17
|
+
throw new Error(`canonicalize: non-finite number is not representable: ${value}`);
|
|
18
|
+
}
|
|
19
|
+
return JSON.stringify(value);
|
|
20
|
+
}
|
|
21
|
+
if (typeof value === "string")
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
return "[" + value.map(canonicalize).join(",") + "]";
|
|
25
|
+
}
|
|
26
|
+
const keys = Object.keys(value).sort();
|
|
27
|
+
const parts = keys.map((k) => {
|
|
28
|
+
const v = value[k];
|
|
29
|
+
if (v === undefined) {
|
|
30
|
+
throw new Error(`canonicalize: undefined values not permitted (key: ${k})`);
|
|
31
|
+
}
|
|
32
|
+
return JSON.stringify(k) + ":" + canonicalize(v);
|
|
33
|
+
});
|
|
34
|
+
return "{" + parts.join(",") + "}";
|
|
35
|
+
}
|
|
36
|
+
/** SHA-256 of a string, hex-encoded. */
|
|
37
|
+
export function sha256(input) {
|
|
38
|
+
return createHash("sha256").update(input, "utf8").digest("hex");
|
|
39
|
+
}
|
|
40
|
+
/** Compute the content-addressed hash of a request. */
|
|
41
|
+
export function requestHash(request) {
|
|
42
|
+
// The hash is over the canonicalized request envelope. We exclude any
|
|
43
|
+
// future fields by being explicit about what enters the hash.
|
|
44
|
+
const hashable = {
|
|
45
|
+
operation: request.operation,
|
|
46
|
+
engine_version: request.engine_version,
|
|
47
|
+
schema_hash: request.schema_hash,
|
|
48
|
+
inputs: request.inputs,
|
|
49
|
+
data_as_of: request.data_as_of,
|
|
50
|
+
...(request.deterministic_seed !== undefined
|
|
51
|
+
? { deterministic_seed: request.deterministic_seed }
|
|
52
|
+
: {}),
|
|
53
|
+
};
|
|
54
|
+
return sha256(canonicalize(hashable));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Wrap an engine call: compute the hash, invoke the engine, return the
|
|
58
|
+
* envelope. The engine function must be deterministic given the same
|
|
59
|
+
* canonicalized inputs — if it isn't, the replay primitive is a lie.
|
|
60
|
+
*/
|
|
61
|
+
export async function sealEnvelope(request, engine, options = { byte_identical_replayable: false }) {
|
|
62
|
+
const value = await engine(request);
|
|
63
|
+
return {
|
|
64
|
+
request_hash: requestHash(request),
|
|
65
|
+
engine_version: request.engine_version,
|
|
66
|
+
produced_at: new Date().toISOString(),
|
|
67
|
+
byte_identical_replayable: options.byte_identical_replayable,
|
|
68
|
+
value: value,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generate a deterministic seed from a string source. Useful when the AI
|
|
73
|
+
* layer needs to commit to a seed before the engine call — the seed itself
|
|
74
|
+
* is content-addressed so the agent can't retroactively pick a favourable one.
|
|
75
|
+
*/
|
|
76
|
+
export function deriveSeed(source) {
|
|
77
|
+
return sha256(`seed:${source}`).slice(0, 32);
|
|
78
|
+
}
|
|
79
|
+
/** Generate a fresh random seed for cases where determinism is not yet required. */
|
|
80
|
+
export function freshSeed() {
|
|
81
|
+
return randomBytes(16).toString("hex");
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EU AI Act Annex IV technical documentation exporter.
|
|
3
|
+
*
|
|
4
|
+
* Walks the kbot-finance audit log and emits a markdown bundle aligned to
|
|
5
|
+
* the structure required by EU AI Act Article 11 / Annex IV. The same
|
|
6
|
+
* bundle satisfies Fed SR 26-02 technical documentation requirements
|
|
7
|
+
* because both regimes converge on the same artifact set.
|
|
8
|
+
*
|
|
9
|
+
* v0.1 emits a single markdown document. v0.2 will emit a structured
|
|
10
|
+
* directory (model card, training-data manifest, evaluation logs,
|
|
11
|
+
* deployment config, prompt templates, drift reports, incident records)
|
|
12
|
+
* matching the AI Act's Annex IV sections 1-9 verbatim.
|
|
13
|
+
*
|
|
14
|
+
* This is the artifact compliance teams buy from the platform; the
|
|
15
|
+
* audit log is the raw material, the exporter is the user-visible
|
|
16
|
+
* deliverable.
|
|
17
|
+
*/
|
|
18
|
+
export interface AnnexIvBundle {
|
|
19
|
+
readonly format: "markdown";
|
|
20
|
+
readonly content: string;
|
|
21
|
+
readonly meta: {
|
|
22
|
+
readonly generated_at: string;
|
|
23
|
+
readonly audit_log_path: string;
|
|
24
|
+
readonly audit_log_intact: boolean;
|
|
25
|
+
readonly entry_count: number;
|
|
26
|
+
readonly first_seq: number | null;
|
|
27
|
+
readonly last_seq: number | null;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read a JSONL audit log and emit an Annex IV-shaped markdown bundle.
|
|
32
|
+
* Returns the rendered string plus a small metadata block — caller writes
|
|
33
|
+
* the bundle to disk, e-mails it, or uploads to a regulator portal.
|
|
34
|
+
*/
|
|
35
|
+
export declare function exportAnnexIv(audit_log_path: string, options?: {
|
|
36
|
+
system_name?: string;
|
|
37
|
+
deployer?: string;
|
|
38
|
+
jurisdiction?: "EU" | "US" | "UK" | "SG" | "HK" | "UAE" | "GLOBAL";
|
|
39
|
+
}): Promise<AnnexIvBundle>;
|
|
40
|
+
//# sourceMappingURL=annex-iv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annex-iv.d.ts","sourceRoot":"","sources":["../../src/exporters/annex-iv.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;QACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC;CACH;AA0DD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,QAAQ,CAAC;CAC/D,GACL,OAAO,CAAC,aAAa,CAAC,CAyIxB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { AppendOnlyAuditLog } from "../audit-log.js";
|
|
3
|
+
function aggregate(entries) {
|
|
4
|
+
const operations = new Map();
|
|
5
|
+
const rule_failures = new Map();
|
|
6
|
+
const incidents = [];
|
|
7
|
+
const engine_versions = new Set();
|
|
8
|
+
const jurisdictions = new Set();
|
|
9
|
+
const sessions = new Set();
|
|
10
|
+
for (const e of entries) {
|
|
11
|
+
operations.set(e.subject, (operations.get(e.subject) ?? 0) + 1);
|
|
12
|
+
if (e.action === "incident")
|
|
13
|
+
incidents.push(e);
|
|
14
|
+
if (e.action === "verifier_check") {
|
|
15
|
+
const p = e.payload;
|
|
16
|
+
if (p.checks) {
|
|
17
|
+
for (const c of p.checks) {
|
|
18
|
+
if (!c.result.pass) {
|
|
19
|
+
const key = `${c.rule_id}/${c.result.reason?.code ?? "unknown"}`;
|
|
20
|
+
rule_failures.set(key, (rule_failures.get(key) ?? 0) + 1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (e.action === "engine_response") {
|
|
26
|
+
const p = e.payload;
|
|
27
|
+
if (typeof p.engine_version === "string")
|
|
28
|
+
engine_versions.add(p.engine_version);
|
|
29
|
+
}
|
|
30
|
+
sessions.add(e.session_id);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
entries: entries.slice(),
|
|
34
|
+
operations,
|
|
35
|
+
rule_failures,
|
|
36
|
+
incidents,
|
|
37
|
+
engine_versions,
|
|
38
|
+
jurisdictions,
|
|
39
|
+
sessions,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function formatNumber(n) {
|
|
43
|
+
return n.toLocaleString("en-US");
|
|
44
|
+
}
|
|
45
|
+
function section(title, body) {
|
|
46
|
+
return `## ${title}\n\n${body}\n`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read a JSONL audit log and emit an Annex IV-shaped markdown bundle.
|
|
50
|
+
* Returns the rendered string plus a small metadata block — caller writes
|
|
51
|
+
* the bundle to disk, e-mails it, or uploads to a regulator portal.
|
|
52
|
+
*/
|
|
53
|
+
export async function exportAnnexIv(audit_log_path, options = {}) {
|
|
54
|
+
const integrity = await AppendOnlyAuditLog.verify(audit_log_path);
|
|
55
|
+
const raw = await readFile(audit_log_path, "utf8").catch(() => "");
|
|
56
|
+
const lines = raw.split("\n").filter((l) => l.length > 0);
|
|
57
|
+
const entries = lines.map((l) => JSON.parse(l));
|
|
58
|
+
const agg = aggregate(entries);
|
|
59
|
+
const first = entries[0];
|
|
60
|
+
const last = entries[entries.length - 1];
|
|
61
|
+
const system_name = options.system_name ?? "kbot-finance AI Intelligence Layer";
|
|
62
|
+
const deployer = options.deployer ?? "(deployer not specified)";
|
|
63
|
+
const jurisdiction = options.jurisdiction ?? "EU";
|
|
64
|
+
const header = `# Annex IV Technical Documentation Pack
|
|
65
|
+
|
|
66
|
+
**System name:** ${system_name}
|
|
67
|
+
**Deployer:** ${deployer}
|
|
68
|
+
**Jurisdiction filed under:** ${jurisdiction}
|
|
69
|
+
**Generated:** ${new Date().toISOString()}
|
|
70
|
+
**Audit log:** ${audit_log_path}
|
|
71
|
+
**Hash chain integrity:** ${integrity.ok ? "INTACT" : `BROKEN at seq=${integrity.ok ? "" : integrity.broken_at_seq}`}
|
|
72
|
+
**Period covered:** ${first?.timestamp ?? "(empty)"} → ${last?.timestamp ?? "(empty)"}
|
|
73
|
+
**Entries:** ${formatNumber(entries.length)}
|
|
74
|
+
`;
|
|
75
|
+
const sec1 = section("1. General description of the AI system", `An AI-orchestration ("Intelligence") layer that issues content-addressed engine requests on behalf of authenticated callers. The system **never produces a financial number itself** — numbers are produced by deterministic engine adapters wrapped in SHA-256-hashed request envelopes. Each response carries a \`request_hash\` that uniquely identifies the call and is reproducible from the canonicalized inputs.
|
|
76
|
+
|
|
77
|
+
The system operates in the seconds-to-minutes latency band; sub-millisecond execution paths are explicitly out of scope.
|
|
78
|
+
|
|
79
|
+
Engine adapters wired into this deployment:
|
|
80
|
+
${[...agg.engine_versions].sort().map((v) => `- ${v}`).join("\n") || "- (none recorded)"}
|
|
81
|
+
`);
|
|
82
|
+
const opLines = [...agg.operations.entries()]
|
|
83
|
+
.sort((a, b) => b[1] - a[1])
|
|
84
|
+
.map(([op, n]) => `- ${op}: ${formatNumber(n)} entries`)
|
|
85
|
+
.join("\n");
|
|
86
|
+
const sec2 = section("2. Detailed description of elements and process of development", `Engine adapters expose typed read/write operations; the AI orchestration layer composes them through a content-addressed envelope. Every operation is governed by a regulatory verifier that evaluates jurisdiction-aware rules-as-code before the engine is invoked. Operation traffic in the audited period:
|
|
87
|
+
|
|
88
|
+
${opLines || "- (no operations recorded)"}
|
|
89
|
+
`);
|
|
90
|
+
const sec3 = section("3. Detailed description of monitoring, functioning and control", `Every request and response is logged into a hash-chained append-only audit log (\`AppendOnlyAuditLog\`). Each entry includes \`prev_hash\`, \`self_hash\`, and a strictly monotonic \`seq\`. The chain is verifiable by walking the log and recomputing entry hashes (\`AppendOnlyAuditLog.verify\`). Drift, hallucination, and incident reports flow into the same log under action codes \`incident\`, \`replay_mismatch\`.
|
|
91
|
+
|
|
92
|
+
Hash chain integrity at time of export: **${integrity.ok ? "INTACT" : "BROKEN"}**.
|
|
93
|
+
`);
|
|
94
|
+
const ruleLines = [...agg.rule_failures.entries()]
|
|
95
|
+
.sort((a, b) => b[1] - a[1])
|
|
96
|
+
.map(([k, n]) => `- ${k}: ${formatNumber(n)} occurrences`)
|
|
97
|
+
.join("\n");
|
|
98
|
+
const sec4 = section("4. Risk management system", `A pre-action regulatory verifier evaluates rules-as-code before any engine call. Failures emit adverse-action-style reason codes patterned on ECOA. The verifier never short-circuits — every applicable rule runs so the audit log records the full evaluation, not just the first failure.
|
|
99
|
+
|
|
100
|
+
Verifier rejections during the audited period:
|
|
101
|
+
|
|
102
|
+
${ruleLines || "- (no verifier rejections recorded)"}
|
|
103
|
+
|
|
104
|
+
Material-gate approval tokens (HMAC-SHA256-signed; Ed25519 in v0.2) bind every approver decision to the exact \`request_hash\` they signed off on. Tokens cannot be replayed across requests, sessions, or materiality classes.
|
|
105
|
+
`);
|
|
106
|
+
const sec5 = section("5. Description of any changes to the system through its lifecycle", `Engine adapters and verifier rules are versioned independently. The audit log records every engine_version observed during the audited period (see §1). Adapter upgrades are non-breaking when they preserve the same \`engine_version\` namespace; breaking upgrades produce a new version string and therefore a new \`request_hash\` for any otherwise-identical request.
|
|
107
|
+
|
|
108
|
+
No retraining cycles occur within the kbot-finance substrate itself; AI model versions are external dependencies whose lineage is captured in \`model_version\` fields on each request envelope (enforced by \`rule.model_version_pinned\`).
|
|
109
|
+
`);
|
|
110
|
+
const sec6 = section("6. List of harmonised standards / common specifications applied", `- IEEE 754-2019 floating-point arithmetic (numerical determinism preconditions)
|
|
111
|
+
- RFC 8785 JSON Canonicalization Scheme (canonical input hashing)
|
|
112
|
+
- SHA-256 (content addressing, audit-log chain)
|
|
113
|
+
- HMAC-SHA256 (approval token signing, v0.1)
|
|
114
|
+
- ISO 8601 UTC timestamps
|
|
115
|
+
- FINOS AI Governance Framework v2.0 risk catalog
|
|
116
|
+
- Mapped to: EU AI Act Art. 11-15, Fed SR 26-02, ESMA MiFID II RTS 6 (Article 9 self-assessment), FINRA 2026 ROR GenAI section, FCA SS1/23.
|
|
117
|
+
`);
|
|
118
|
+
const incidentLines = agg.incidents.length === 0
|
|
119
|
+
? "- (no incidents recorded)"
|
|
120
|
+
: agg.incidents.map((i) => `- ${i.timestamp} seq=${i.seq} subject=${i.subject} payload=${JSON.stringify(i.payload).slice(0, 200)}`).join("\n");
|
|
121
|
+
const sec7 = section("7. EU declaration of conformity / serious-incident records", `Serious-incident reports flow through the same audit log under action=\`incident\`. The reportable surface satisfies Reg S-P 72-hour notification timelines and AI Act Art. 73 serious-incident reporting through the same plumbing — incidents are not parallel records, they are entries in the chain.
|
|
122
|
+
|
|
123
|
+
Incidents observed during the audited period:
|
|
124
|
+
|
|
125
|
+
${incidentLines}
|
|
126
|
+
`);
|
|
127
|
+
const sec8 = section("8. Records of post-market monitoring", `Drift, hallucination, and verifier-rejection rates are computable from this log directly (see §4). Long-term retention is configured to the longest applicable bar: 10 years post-decommission for high-risk AI Act systems (Art. 19); 6 years for Exchange Act 17a-4 records; 5 years for Advisers Act 204-2 / MiFID II.
|
|
128
|
+
`);
|
|
129
|
+
const content = header +
|
|
130
|
+
"\n---\n\n" +
|
|
131
|
+
sec1 +
|
|
132
|
+
sec2 +
|
|
133
|
+
sec3 +
|
|
134
|
+
sec4 +
|
|
135
|
+
sec5 +
|
|
136
|
+
sec6 +
|
|
137
|
+
sec7 +
|
|
138
|
+
sec8 +
|
|
139
|
+
"\n---\n\n" +
|
|
140
|
+
`*Generated by @kernel.chat/kbot-finance Annex IV exporter. Audit log integrity verifiable via \`AppendOnlyAuditLog.verify("${audit_log_path}")\`.*\n`;
|
|
141
|
+
return {
|
|
142
|
+
format: "markdown",
|
|
143
|
+
content,
|
|
144
|
+
meta: {
|
|
145
|
+
generated_at: new Date().toISOString(),
|
|
146
|
+
audit_log_path,
|
|
147
|
+
audit_log_intact: integrity.ok,
|
|
148
|
+
entry_count: entries.length,
|
|
149
|
+
first_seq: first?.seq ?? null,
|
|
150
|
+
last_seq: last?.seq ?? null,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=annex-iv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annex-iv.js","sourceRoot":"","sources":["../../src/exporters/annex-iv.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Material-gate approval tokens.
|
|
3
|
+
*
|
|
4
|
+
* Any action tagged `material: true` requires a signed approval token from
|
|
5
|
+
* an authorized human approver before the engine executes. The token binds:
|
|
6
|
+
*
|
|
7
|
+
* - approver identity
|
|
8
|
+
* - the exact action envelope the approver saw
|
|
9
|
+
* - timestamp
|
|
10
|
+
* - a cryptographic signature (HMAC-SHA256 for v0.1; Ed25519 in v0.2)
|
|
11
|
+
*
|
|
12
|
+
* v0.1 uses a shared secret per approver because it's the smallest landing
|
|
13
|
+
* artifact. v0.2 replaces it with public-key signatures so approvers can
|
|
14
|
+
* sign offline and the system only verifies.
|
|
15
|
+
*/
|
|
16
|
+
export interface ApprovalRequest {
|
|
17
|
+
/** Action being approved — typically a content-addressed request_hash. */
|
|
18
|
+
readonly request_hash: string;
|
|
19
|
+
/** Human-readable summary of what the approver is signing off on. */
|
|
20
|
+
readonly summary: string;
|
|
21
|
+
/** Session ID. */
|
|
22
|
+
readonly session_id: string;
|
|
23
|
+
/** Materiality classification, e.g. "trade.execute", "model.deploy". */
|
|
24
|
+
readonly materiality: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ApprovalToken {
|
|
27
|
+
readonly request_hash: string;
|
|
28
|
+
readonly summary: string;
|
|
29
|
+
readonly session_id: string;
|
|
30
|
+
readonly materiality: string;
|
|
31
|
+
readonly approver_id: string;
|
|
32
|
+
readonly approved_at: string;
|
|
33
|
+
readonly signature: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Approver — issues signed approval tokens. In production this is a separate
|
|
37
|
+
* service held by compliance; for v0.1 it's an in-process module.
|
|
38
|
+
*/
|
|
39
|
+
export declare class Approver {
|
|
40
|
+
private readonly approver_id;
|
|
41
|
+
private readonly secret;
|
|
42
|
+
constructor(approver_id: string, secret: Buffer);
|
|
43
|
+
approve(request: ApprovalRequest): ApprovalToken;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Verify an approval token. Returns true iff the signature matches and the
|
|
47
|
+
* approver is in the provided trust set.
|
|
48
|
+
*/
|
|
49
|
+
export declare function verifyApproval(token: ApprovalToken, trusted: ReadonlyMap<string, Buffer>, request: ApprovalRequest): {
|
|
50
|
+
ok: true;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
reason: string;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=governance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governance.d.ts","sourceRoot":"","sources":["../src/governance.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kBAAkB;IAClB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAeD;;;GAGG;AACH,qBAAa,QAAQ;IAEjB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM;IAGjC,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa;CAYjD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,OAAO,EAAE,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA2B9C"}
|