@hardkas/query 0.7.1-alpha → 0.7.4-alpha
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/dist/index.d.ts +1 -0
- package/dist/index.js +298 -111
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -127,7 +127,9 @@ var FilesystemQueryBackend = class {
|
|
|
127
127
|
return { applied: 0 };
|
|
128
128
|
}
|
|
129
129
|
async executeRawSql(_sql) {
|
|
130
|
-
throw new Error(
|
|
130
|
+
throw new Error(
|
|
131
|
+
"Raw SQL execution not supported by Filesystem backend. Use SQLite backend."
|
|
132
|
+
);
|
|
131
133
|
}
|
|
132
134
|
async scanFiles(dir) {
|
|
133
135
|
const results = [];
|
|
@@ -419,7 +421,9 @@ function formatWhyBlock(block) {
|
|
|
419
421
|
}
|
|
420
422
|
if (block.evidence.length > 0) {
|
|
421
423
|
lines.push("");
|
|
422
|
-
lines.push(
|
|
424
|
+
lines.push(
|
|
425
|
+
` Evidence Refs: ${block.evidence.map((e) => `${e.type}:${e.value.slice(0, 12)}...`).join(", ")}`
|
|
426
|
+
);
|
|
423
427
|
}
|
|
424
428
|
return lines.join("\n");
|
|
425
429
|
}
|
|
@@ -438,7 +442,18 @@ var ArtifactQueryAdapter = class {
|
|
|
438
442
|
return ["list", "inspect", "diff", "verify"];
|
|
439
443
|
}
|
|
440
444
|
supportedFilters() {
|
|
441
|
-
return [
|
|
445
|
+
return [
|
|
446
|
+
"schema",
|
|
447
|
+
"version",
|
|
448
|
+
"networkId",
|
|
449
|
+
"mode",
|
|
450
|
+
"from.address",
|
|
451
|
+
"to.address",
|
|
452
|
+
"amountSompi",
|
|
453
|
+
"status",
|
|
454
|
+
"contentHash",
|
|
455
|
+
"createdAt"
|
|
456
|
+
];
|
|
442
457
|
}
|
|
443
458
|
async execute(request) {
|
|
444
459
|
switch (request.op) {
|
|
@@ -487,12 +502,16 @@ var ArtifactQueryAdapter = class {
|
|
|
487
502
|
const paged = sorted.slice(request.offset, request.offset + request.limit);
|
|
488
503
|
let why;
|
|
489
504
|
if (request.explain) {
|
|
490
|
-
why = paged.map(
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
505
|
+
why = paged.map(
|
|
506
|
+
(item) => explainIntegrity(item, {
|
|
507
|
+
ok: true,
|
|
508
|
+
hashMatch: true,
|
|
509
|
+
schemaValid: KNOWN_SCHEMAS.has(
|
|
510
|
+
item.schema
|
|
511
|
+
),
|
|
512
|
+
errors: []
|
|
513
|
+
})
|
|
514
|
+
);
|
|
496
515
|
}
|
|
497
516
|
return {
|
|
498
517
|
domain: "artifacts",
|
|
@@ -516,7 +535,8 @@ var ArtifactQueryAdapter = class {
|
|
|
516
535
|
async executeInspect(request) {
|
|
517
536
|
const start = Date.now();
|
|
518
537
|
const target = request.params["target"];
|
|
519
|
-
if (!target)
|
|
538
|
+
if (!target)
|
|
539
|
+
throw new Error("inspect requires params.target (content hash or file path)");
|
|
520
540
|
const filePath = await this.resolveTarget(target);
|
|
521
541
|
const raw = await this.readJsonSafe(filePath);
|
|
522
542
|
if (!raw) throw new Error(`Cannot read artifact at: ${filePath}`);
|
|
@@ -550,8 +570,13 @@ var ArtifactQueryAdapter = class {
|
|
|
550
570
|
integrity: {
|
|
551
571
|
ok: integrityResult.ok && hashMatch,
|
|
552
572
|
hashMatch,
|
|
553
|
-
schemaValid: KNOWN_SCHEMAS.has(
|
|
554
|
-
|
|
573
|
+
schemaValid: KNOWN_SCHEMAS.has(
|
|
574
|
+
item.schema
|
|
575
|
+
),
|
|
576
|
+
errors: [
|
|
577
|
+
...integrityResult.issues.map((i) => i.message),
|
|
578
|
+
...semanticResult.issues.map((i) => i.message)
|
|
579
|
+
]
|
|
555
580
|
},
|
|
556
581
|
economics,
|
|
557
582
|
staleness,
|
|
@@ -584,7 +609,8 @@ var ArtifactQueryAdapter = class {
|
|
|
584
609
|
const start = Date.now();
|
|
585
610
|
const leftPath = request.params["left"];
|
|
586
611
|
const rightPath = request.params["right"];
|
|
587
|
-
if (!leftPath || !rightPath)
|
|
612
|
+
if (!leftPath || !rightPath)
|
|
613
|
+
throw new Error("diff requires params.left and params.right");
|
|
588
614
|
const leftRaw = await this.readJsonSafe(leftPath);
|
|
589
615
|
const rightRaw = await this.readJsonSafe(rightPath);
|
|
590
616
|
if (!leftRaw) throw new Error(`Cannot read left artifact: ${leftPath}`);
|
|
@@ -653,7 +679,8 @@ var ArtifactQueryAdapter = class {
|
|
|
653
679
|
for (const entry of entries) {
|
|
654
680
|
const full = path2.join(dir, entry.name);
|
|
655
681
|
if (entry.isDirectory()) {
|
|
656
|
-
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "keystores")
|
|
682
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "keystores")
|
|
683
|
+
continue;
|
|
657
684
|
await this.walkDir(full, out);
|
|
658
685
|
} else if (entry.name.endsWith(".json") && !entry.name.endsWith(".enc.json")) {
|
|
659
686
|
out.push(full);
|
|
@@ -738,7 +765,8 @@ import { deterministicCompare } from "@hardkas/core";
|
|
|
738
765
|
var VALID_TRANSITIONS2 = {
|
|
739
766
|
"hardkas.snapshot": ["hardkas.txPlan"],
|
|
740
767
|
"hardkas.txPlan": ["hardkas.signedTx"],
|
|
741
|
-
"hardkas.signedTx": ["hardkas.txReceipt"]
|
|
768
|
+
"hardkas.signedTx": ["hardkas.signedTx", "hardkas.txReceipt"],
|
|
769
|
+
"hardkas.workflow.v1": ["hardkas.txPlan", "hardkas.signedTx", "hardkas.txReceipt"]
|
|
742
770
|
};
|
|
743
771
|
var LineageQueryAdapter = class {
|
|
744
772
|
domain = "lineage";
|
|
@@ -771,8 +799,24 @@ var LineageQueryAdapter = class {
|
|
|
771
799
|
// -------------------------------------------------------------------------
|
|
772
800
|
async executeChain(request) {
|
|
773
801
|
const start = Date.now();
|
|
774
|
-
|
|
775
|
-
if (!anchor)
|
|
802
|
+
let anchor = request.params["anchor"];
|
|
803
|
+
if (!anchor)
|
|
804
|
+
throw new Error("chain requires params.anchor (contentHash or artifactId)");
|
|
805
|
+
if (typeof anchor === "string") {
|
|
806
|
+
try {
|
|
807
|
+
const path7 = await import("path");
|
|
808
|
+
const fs7 = await import("fs");
|
|
809
|
+
const resolvedPath = path7.resolve(this.rootDir, anchor);
|
|
810
|
+
if (fs7.existsSync(resolvedPath) && fs7.statSync(resolvedPath).isFile()) {
|
|
811
|
+
const content = fs7.readFileSync(resolvedPath, "utf-8");
|
|
812
|
+
const json = JSON.parse(content);
|
|
813
|
+
if (json) {
|
|
814
|
+
anchor = json.lineage?.artifactId || json.artifactId || json.planId || json.signedId || json.txId || json.contentHash || anchor;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
} catch (e) {
|
|
818
|
+
}
|
|
819
|
+
}
|
|
776
820
|
const direction = request.params["direction"] ?? "ancestors";
|
|
777
821
|
const graph = await this.buildGraph();
|
|
778
822
|
const anchorNode = graph.byArtifactId.get(anchor) ?? graph.byContentHash.get(anchor);
|
|
@@ -910,30 +954,46 @@ var LineageQueryAdapter = class {
|
|
|
910
954
|
const byContentHash = /* @__PURE__ */ new Map();
|
|
911
955
|
const children = /* @__PURE__ */ new Map();
|
|
912
956
|
const docs = await this.backend.findArtifacts();
|
|
957
|
+
const VALID_SCHEMAS = [
|
|
958
|
+
"hardkas.txPlan",
|
|
959
|
+
"hardkas.signedTx",
|
|
960
|
+
"hardkas.txReceipt",
|
|
961
|
+
"hardkas.workflow.v1",
|
|
962
|
+
"hardkas.snapshot"
|
|
963
|
+
];
|
|
913
964
|
for (const doc of docs) {
|
|
914
965
|
const raw = doc.payload;
|
|
915
|
-
if (!raw?.schema || !raw.
|
|
966
|
+
if (!raw?.schema || !VALID_SCHEMAS.includes(raw.schema)) continue;
|
|
916
967
|
const node = {
|
|
917
968
|
contentHash: doc.contentHash,
|
|
918
969
|
schema: doc.schema,
|
|
919
|
-
artifactId: raw.lineage.artifactId || "",
|
|
920
|
-
parentArtifactId: raw.lineage.
|
|
921
|
-
rootArtifactId: raw.lineage.rootArtifactId || "",
|
|
922
|
-
lineageId: raw.lineage
|
|
923
|
-
sequence: raw.lineage
|
|
970
|
+
artifactId: raw.lineage?.artifactId || raw.artifactId || raw.planId || raw.signedId || raw.txId || doc.contentHash || "",
|
|
971
|
+
parentArtifactId: raw.lineage?.parentArtifactId || raw.sourcePlanId || raw.sourceSignedId,
|
|
972
|
+
rootArtifactId: raw.lineage?.rootArtifactId || raw.rootArtifactId || raw.artifactId || raw.planId || raw.signedId || raw.txId || doc.contentHash || "",
|
|
973
|
+
lineageId: raw.lineage?.lineageId || "",
|
|
974
|
+
sequence: raw.lineage?.sequence,
|
|
924
975
|
filePath: doc.path,
|
|
925
976
|
networkId: doc.networkId,
|
|
926
977
|
mode: doc.mode,
|
|
927
|
-
createdAt: doc.createdAt || ""
|
|
978
|
+
createdAt: doc.createdAt || "",
|
|
979
|
+
workflowId: raw.schema === "hardkas.workflow.v1" ? void 0 : raw.workflowId
|
|
928
980
|
};
|
|
929
981
|
nodes.push(node);
|
|
930
982
|
if (node.artifactId) byArtifactId.set(node.artifactId, node);
|
|
983
|
+
if (raw.planId) byArtifactId.set(raw.planId, node);
|
|
984
|
+
if (raw.signedId) byArtifactId.set(raw.signedId, node);
|
|
985
|
+
if (raw.txId) byArtifactId.set(raw.txId, node);
|
|
931
986
|
if (node.contentHash) byContentHash.set(node.contentHash, node);
|
|
932
987
|
if (node.parentArtifactId) {
|
|
933
988
|
const existing = children.get(node.parentArtifactId) ?? [];
|
|
934
989
|
existing.push(node);
|
|
935
990
|
children.set(node.parentArtifactId, existing);
|
|
936
991
|
}
|
|
992
|
+
if (node.workflowId) {
|
|
993
|
+
const existing = children.get(node.workflowId) ?? [];
|
|
994
|
+
existing.push(node);
|
|
995
|
+
children.set(node.workflowId, existing);
|
|
996
|
+
}
|
|
937
997
|
}
|
|
938
998
|
return { nodes, byArtifactId, byContentHash, children, totalFiles: docs.length };
|
|
939
999
|
}
|
|
@@ -941,44 +1001,59 @@ var LineageQueryAdapter = class {
|
|
|
941
1001
|
// Graph Traversal
|
|
942
1002
|
// -------------------------------------------------------------------------
|
|
943
1003
|
walkAncestors(node, graph, nodes, transitions) {
|
|
944
|
-
const
|
|
945
|
-
let current = node;
|
|
1004
|
+
const queue = [node];
|
|
946
1005
|
const visited = /* @__PURE__ */ new Set();
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1006
|
+
const queued = /* @__PURE__ */ new Set([node.artifactId]);
|
|
1007
|
+
nodes.push(node);
|
|
1008
|
+
while (queue.length > 0) {
|
|
1009
|
+
const current = queue.shift();
|
|
1010
|
+
visited.add(current.artifactId);
|
|
1011
|
+
const parentIds = [];
|
|
1012
|
+
if (current.parentArtifactId) parentIds.push(current.parentArtifactId);
|
|
1013
|
+
if (current.workflowId) parentIds.push(current.workflowId);
|
|
1014
|
+
for (const parentId of parentIds) {
|
|
1015
|
+
const parent = graph.byArtifactId.get(parentId) ?? graph.byContentHash.get(parentId);
|
|
1016
|
+
if (!parent) continue;
|
|
1017
|
+
if (!queued.has(parent.artifactId)) {
|
|
1018
|
+
queued.add(parent.artifactId);
|
|
1019
|
+
nodes.unshift(parent);
|
|
1020
|
+
queue.push(parent);
|
|
1021
|
+
const allowed = VALID_TRANSITIONS2[parent.schema] ?? [];
|
|
1022
|
+
transitions.unshift({
|
|
1023
|
+
from: parent,
|
|
1024
|
+
to: current,
|
|
1025
|
+
valid: allowed.includes(current.schema),
|
|
1026
|
+
rule: allowed.includes(current.schema) ? `${parent.schema} \u2192 ${current.schema} (valid)` : `${parent.schema} \u2192 ${current.schema} (INVALID)`
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
960
1030
|
}
|
|
961
|
-
nodes.push(...chain);
|
|
962
1031
|
}
|
|
963
1032
|
walkDescendants(node, graph, nodes, transitions) {
|
|
964
1033
|
const queue = [node];
|
|
965
1034
|
const visited = /* @__PURE__ */ new Set();
|
|
1035
|
+
const queued = /* @__PURE__ */ new Set([node.artifactId]);
|
|
966
1036
|
nodes.push(node);
|
|
967
1037
|
while (queue.length > 0) {
|
|
968
1038
|
const current = queue.shift();
|
|
969
|
-
if (visited.has(current.artifactId)) continue;
|
|
970
1039
|
visited.add(current.artifactId);
|
|
971
|
-
const kids =
|
|
1040
|
+
const kids = [
|
|
1041
|
+
...graph.children.get(current.artifactId) ?? [],
|
|
1042
|
+
...current.contentHash ? graph.children.get(current.contentHash) ?? [] : []
|
|
1043
|
+
];
|
|
972
1044
|
for (const child of kids) {
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1045
|
+
if (!queued.has(child.artifactId)) {
|
|
1046
|
+
queued.add(child.artifactId);
|
|
1047
|
+
nodes.push(child);
|
|
1048
|
+
queue.push(child);
|
|
1049
|
+
const allowed = VALID_TRANSITIONS2[current.schema] ?? [];
|
|
1050
|
+
transitions.push({
|
|
1051
|
+
from: current,
|
|
1052
|
+
to: child,
|
|
1053
|
+
valid: allowed.includes(child.schema),
|
|
1054
|
+
rule: allowed.includes(child.schema) ? `${current.schema} \u2192 ${child.schema} (valid)` : `${current.schema} \u2192 ${child.schema} (INVALID)`
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
982
1057
|
}
|
|
983
1058
|
}
|
|
984
1059
|
}
|
|
@@ -1000,7 +1075,8 @@ var LineageQueryAdapter = class {
|
|
|
1000
1075
|
for (const entry of entries) {
|
|
1001
1076
|
const full = path3.join(dir, entry.name);
|
|
1002
1077
|
if (entry.isDirectory()) {
|
|
1003
|
-
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "keystores")
|
|
1078
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "keystores")
|
|
1079
|
+
continue;
|
|
1004
1080
|
await this.walkDir(full, out);
|
|
1005
1081
|
} else if (entry.name.endsWith(".json") && !entry.name.endsWith(".enc.json")) {
|
|
1006
1082
|
out.push(full);
|
|
@@ -1033,7 +1109,15 @@ var ReplayQueryAdapter = class {
|
|
|
1033
1109
|
return ["list", "summary", "divergences", "invariants"];
|
|
1034
1110
|
}
|
|
1035
1111
|
supportedFilters() {
|
|
1036
|
-
return [
|
|
1112
|
+
return [
|
|
1113
|
+
"txId",
|
|
1114
|
+
"status",
|
|
1115
|
+
"networkId",
|
|
1116
|
+
"mode",
|
|
1117
|
+
"daaScore",
|
|
1118
|
+
"from.address",
|
|
1119
|
+
"to.address"
|
|
1120
|
+
];
|
|
1037
1121
|
}
|
|
1038
1122
|
async execute(request) {
|
|
1039
1123
|
switch (request.op) {
|
|
@@ -1096,7 +1180,8 @@ var ReplayQueryAdapter = class {
|
|
|
1096
1180
|
const txId = request.params["txId"];
|
|
1097
1181
|
if (!txId) throw new Error("summary requires params.txId");
|
|
1098
1182
|
const receipt = await this.backend.getArtifact(txId);
|
|
1099
|
-
if (!receipt || receipt.schema !== "hardkas.txReceipt")
|
|
1183
|
+
if (!receipt || receipt.schema !== "hardkas.txReceipt")
|
|
1184
|
+
throw new Error(`Receipt not found for txId: ${txId}`);
|
|
1100
1185
|
const traces = await this.backend.findTraces({ txId });
|
|
1101
1186
|
const trace = traces[0];
|
|
1102
1187
|
const item = toSummary(receipt.payload, trace?.payload);
|
|
@@ -1209,7 +1294,8 @@ var ReplayQueryAdapter = class {
|
|
|
1209
1294
|
const txId = request.params["txId"];
|
|
1210
1295
|
if (!txId) throw new Error("invariants requires params.txId");
|
|
1211
1296
|
const doc = await this.backend.getArtifact(txId);
|
|
1212
|
-
if (!doc || doc.schema !== "hardkas.txReceipt")
|
|
1297
|
+
if (!doc || doc.schema !== "hardkas.txReceipt")
|
|
1298
|
+
throw new Error(`Receipt not found for txId: ${txId}`);
|
|
1213
1299
|
const receipt = doc.payload;
|
|
1214
1300
|
const issues = [];
|
|
1215
1301
|
const planIntegrity = receipt.contentHash ? computeContentHashSafe(receipt) === receipt.contentHash : true;
|
|
@@ -1342,10 +1428,30 @@ function explainDivergence(d) {
|
|
|
1342
1428
|
function explainInvariants(result) {
|
|
1343
1429
|
const causalChain = [];
|
|
1344
1430
|
let order = 1;
|
|
1345
|
-
causalChain.push({
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1431
|
+
causalChain.push({
|
|
1432
|
+
order: order++,
|
|
1433
|
+
assertion: result.planIntegrity ? "Plan integrity is OK" : "Plan integrity FAILED",
|
|
1434
|
+
evidence: `planIntegrity=${result.planIntegrity}`,
|
|
1435
|
+
rule: "SHA-256 canonical consistency"
|
|
1436
|
+
});
|
|
1437
|
+
causalChain.push({
|
|
1438
|
+
order: order++,
|
|
1439
|
+
assertion: result.receiptReproducible ? "Receipt is reproducible" : "Receipt is NOT reproducible",
|
|
1440
|
+
evidence: `receiptReproducible=${result.receiptReproducible}`,
|
|
1441
|
+
rule: "Replay evidence requirements"
|
|
1442
|
+
});
|
|
1443
|
+
causalChain.push({
|
|
1444
|
+
order: order++,
|
|
1445
|
+
assertion: result.stateTransitionValid ? "State transition is valid" : "State transition INVALID",
|
|
1446
|
+
evidence: `stateTransitionValid=${result.stateTransitionValid}`,
|
|
1447
|
+
rule: "Status/State alignment"
|
|
1448
|
+
});
|
|
1449
|
+
causalChain.push({
|
|
1450
|
+
order: order++,
|
|
1451
|
+
assertion: result.utxoConservation ? "UTXO conservation holds" : "UTXO conservation VIOLATED",
|
|
1452
|
+
evidence: `utxoConservation=${result.utxoConservation}`,
|
|
1453
|
+
rule: "Value conservation policy"
|
|
1454
|
+
});
|
|
1349
1455
|
const allOk = result.planIntegrity && result.receiptReproducible && result.stateTransitionValid && result.utxoConservation;
|
|
1350
1456
|
return {
|
|
1351
1457
|
question: `Are replay invariants satisfied for tx ${result.txId.slice(0, 16)}...?`,
|
|
@@ -1420,7 +1526,10 @@ var DagQueryAdapter = class {
|
|
|
1420
1526
|
deterministic: true,
|
|
1421
1527
|
queryHash: computeQueryHash(paged),
|
|
1422
1528
|
why,
|
|
1423
|
-
annotations: {
|
|
1529
|
+
annotations: {
|
|
1530
|
+
executedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1531
|
+
executionMs: Date.now() - start
|
|
1532
|
+
}
|
|
1424
1533
|
};
|
|
1425
1534
|
}
|
|
1426
1535
|
// -------------------------------------------------------------------------
|
|
@@ -1456,7 +1565,10 @@ var DagQueryAdapter = class {
|
|
|
1456
1565
|
deterministic: true,
|
|
1457
1566
|
queryHash: computeQueryHash(paged),
|
|
1458
1567
|
why,
|
|
1459
|
-
annotations: {
|
|
1568
|
+
annotations: {
|
|
1569
|
+
executedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1570
|
+
executionMs: Date.now() - start
|
|
1571
|
+
}
|
|
1460
1572
|
};
|
|
1461
1573
|
}
|
|
1462
1574
|
// -------------------------------------------------------------------------
|
|
@@ -1508,7 +1620,10 @@ var DagQueryAdapter = class {
|
|
|
1508
1620
|
deterministic: true,
|
|
1509
1621
|
queryHash: computeQueryHash(entries),
|
|
1510
1622
|
why,
|
|
1511
|
-
annotations: {
|
|
1623
|
+
annotations: {
|
|
1624
|
+
executedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1625
|
+
executionMs: Date.now() - start
|
|
1626
|
+
}
|
|
1512
1627
|
};
|
|
1513
1628
|
}
|
|
1514
1629
|
// -------------------------------------------------------------------------
|
|
@@ -1542,7 +1657,10 @@ var DagQueryAdapter = class {
|
|
|
1542
1657
|
truncated: false,
|
|
1543
1658
|
deterministic: true,
|
|
1544
1659
|
queryHash: computeQueryHash([result]),
|
|
1545
|
-
annotations: {
|
|
1660
|
+
annotations: {
|
|
1661
|
+
executedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1662
|
+
executionMs: Date.now() - start
|
|
1663
|
+
}
|
|
1546
1664
|
};
|
|
1547
1665
|
}
|
|
1548
1666
|
// -------------------------------------------------------------------------
|
|
@@ -1608,7 +1726,10 @@ var DagQueryAdapter = class {
|
|
|
1608
1726
|
deterministic: true,
|
|
1609
1727
|
queryHash: computeQueryHash(paged),
|
|
1610
1728
|
why,
|
|
1611
|
-
annotations: {
|
|
1729
|
+
annotations: {
|
|
1730
|
+
executedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1731
|
+
executionMs: Date.now() - start
|
|
1732
|
+
}
|
|
1612
1733
|
};
|
|
1613
1734
|
}
|
|
1614
1735
|
// -------------------------------------------------------------------------
|
|
@@ -1683,7 +1804,12 @@ function explainDisplacement(d, _dag) {
|
|
|
1683
1804
|
answer: d.reason,
|
|
1684
1805
|
evidence: [{ type: "txId", value: d.txId }],
|
|
1685
1806
|
causalChain: [
|
|
1686
|
-
{
|
|
1807
|
+
{
|
|
1808
|
+
order: 1,
|
|
1809
|
+
assertion: "Tx in displaced set",
|
|
1810
|
+
evidence: "dag.displacedTxIds includes txId",
|
|
1811
|
+
rule: "DAG reorganization"
|
|
1812
|
+
},
|
|
1687
1813
|
{ order: 2, assertion: "Status: displaced", evidence: d.reason }
|
|
1688
1814
|
],
|
|
1689
1815
|
model: "deterministic-light-model",
|
|
@@ -1700,8 +1826,16 @@ function explainTxHistory(entry, _dag) {
|
|
|
1700
1826
|
{ type: "blockId", value: entry.blockId }
|
|
1701
1827
|
],
|
|
1702
1828
|
causalChain: [
|
|
1703
|
-
{
|
|
1704
|
-
|
|
1829
|
+
{
|
|
1830
|
+
order: 1,
|
|
1831
|
+
assertion: `In block ${entry.blockId}`,
|
|
1832
|
+
evidence: `daaScore=${entry.daaScore}`
|
|
1833
|
+
},
|
|
1834
|
+
{
|
|
1835
|
+
order: 2,
|
|
1836
|
+
assertion: entry.inSinkPath ? "In selected sink path" : "Not in sink path",
|
|
1837
|
+
evidence: `selectedPathToSink.includes("${entry.blockId}")`
|
|
1838
|
+
}
|
|
1705
1839
|
],
|
|
1706
1840
|
model: "deterministic-light-model",
|
|
1707
1841
|
confidence: "definitive"
|
|
@@ -1716,7 +1850,12 @@ function explainAnomaly(a, _dag) {
|
|
|
1716
1850
|
answer: a.description,
|
|
1717
1851
|
evidence,
|
|
1718
1852
|
causalChain: [
|
|
1719
|
-
{
|
|
1853
|
+
{
|
|
1854
|
+
order: 1,
|
|
1855
|
+
assertion: a.description,
|
|
1856
|
+
evidence: `Anomaly: ${a.kind}`,
|
|
1857
|
+
rule: "DAG invariant check"
|
|
1858
|
+
}
|
|
1720
1859
|
],
|
|
1721
1860
|
model: "deterministic-light-model",
|
|
1722
1861
|
confidence: "definitive"
|
|
@@ -1784,18 +1923,32 @@ var EventsQueryAdapter = class {
|
|
|
1784
1923
|
executionMs: Date.now() - start,
|
|
1785
1924
|
filesScanned: backendUsed === "sqlite" ? 0 : 1
|
|
1786
1925
|
},
|
|
1787
|
-
why: request.explain ? [
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1926
|
+
why: request.explain ? [
|
|
1927
|
+
{
|
|
1928
|
+
question: "How were events loaded and linked?",
|
|
1929
|
+
answer: `Loaded ${total} events matching filters. Causal links (correlation/causation) available in payload.`,
|
|
1930
|
+
evidence: [],
|
|
1931
|
+
causalChain: [
|
|
1932
|
+
{
|
|
1933
|
+
order: 1,
|
|
1934
|
+
assertion: `Source: ${backendUsed}`,
|
|
1935
|
+
evidence: "Event stream processed"
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
order: 2,
|
|
1939
|
+
assertion: `Filters: ${effectiveFilters.length} applied`,
|
|
1940
|
+
evidence: effectiveFilters.map((f) => `${f.field} ${f.op} ${f.value}`).join(", ") || "none"
|
|
1941
|
+
},
|
|
1942
|
+
{
|
|
1943
|
+
order: 3,
|
|
1944
|
+
assertion: "Ordering: timestamp ASC",
|
|
1945
|
+
evidence: "Deterministic stream sorting"
|
|
1946
|
+
}
|
|
1947
|
+
],
|
|
1948
|
+
model: "events-causality",
|
|
1949
|
+
confidence: "definitive"
|
|
1950
|
+
}
|
|
1951
|
+
] : void 0
|
|
1799
1952
|
};
|
|
1800
1953
|
}
|
|
1801
1954
|
async loadEvents() {
|
|
@@ -1856,29 +2009,46 @@ var TxQueryAdapter = class {
|
|
|
1856
2009
|
const roles = new Set(artifacts.map((a) => a.role));
|
|
1857
2010
|
if (!roles.has("plan")) warnings.push("Missing tx plan artifact");
|
|
1858
2011
|
if (!roles.has("signed")) warnings.push("Missing signed tx artifact");
|
|
1859
|
-
if (!roles.has("receipt"))
|
|
2012
|
+
if (!roles.has("receipt"))
|
|
2013
|
+
warnings.push("Missing tx receipt artifact (may not exist yet)");
|
|
1860
2014
|
const complete = roles.has("plan") && roles.has("signed");
|
|
1861
2015
|
const result = {
|
|
1862
2016
|
txId,
|
|
1863
2017
|
artifacts,
|
|
1864
|
-
events: events.sort(
|
|
2018
|
+
events: events.sort(
|
|
2019
|
+
(a, b) => deterministicCompare5(a.timestamp, b.timestamp) || deterministicCompare5(a.eventId, b.eventId)
|
|
2020
|
+
),
|
|
1865
2021
|
warnings,
|
|
1866
2022
|
complete
|
|
1867
2023
|
};
|
|
1868
2024
|
let why;
|
|
1869
2025
|
if (request.explain) {
|
|
1870
|
-
why = [
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
2026
|
+
why = [
|
|
2027
|
+
{
|
|
2028
|
+
question: `Causal aggregation for transaction ${txId}?`,
|
|
2029
|
+
answer: complete ? `Found ${artifacts.length} artifact(s) and ${events.length} event(s). Workflow is consistent.` : `Aggregation incomplete: ${warnings.join(". ")}.`,
|
|
2030
|
+
evidence: [{ type: "txId", value: txId }],
|
|
2031
|
+
causalChain: [
|
|
2032
|
+
{
|
|
2033
|
+
order: 1,
|
|
2034
|
+
assertion: `Artifacts linked: ${artifacts.length}`,
|
|
2035
|
+
evidence: artifacts.map((a) => a.role).join(", ")
|
|
2036
|
+
},
|
|
2037
|
+
{
|
|
2038
|
+
order: 2,
|
|
2039
|
+
assertion: `Events linked: ${events.length}`,
|
|
2040
|
+
evidence: "Events found in stream"
|
|
2041
|
+
},
|
|
2042
|
+
{
|
|
2043
|
+
order: 3,
|
|
2044
|
+
assertion: `Completeness check: ${complete}`,
|
|
2045
|
+
evidence: warnings.join("; ") || "all required roles found"
|
|
2046
|
+
}
|
|
2047
|
+
],
|
|
2048
|
+
model: "tx-causality",
|
|
2049
|
+
confidence: "definitive"
|
|
2050
|
+
}
|
|
2051
|
+
];
|
|
1882
2052
|
}
|
|
1883
2053
|
return {
|
|
1884
2054
|
domain: "tx",
|
|
@@ -1949,18 +2119,21 @@ var QueryEngine = class _QueryEngine {
|
|
|
1949
2119
|
const { HardkasStore, SqliteQueryBackend, HardkasIndexer } = await import("@hardkas/query-store");
|
|
1950
2120
|
const store = new HardkasStore({ dbPath });
|
|
1951
2121
|
if (options.autoSync) {
|
|
1952
|
-
await withLock(
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
2122
|
+
await withLock(
|
|
2123
|
+
{
|
|
2124
|
+
rootDir: options.artifactDir,
|
|
2125
|
+
name: "query-store",
|
|
2126
|
+
command: "query-engine-auto-sync",
|
|
2127
|
+
wait: options.waitLock ?? false,
|
|
2128
|
+
timeoutMs: 5e3
|
|
2129
|
+
// Short timeout for auto-sync
|
|
2130
|
+
},
|
|
2131
|
+
async () => {
|
|
2132
|
+
store.connect({ autoMigrate: true });
|
|
2133
|
+
const indexer = new HardkasIndexer(store.getDatabase());
|
|
2134
|
+
await indexer.sync();
|
|
2135
|
+
}
|
|
2136
|
+
);
|
|
1964
2137
|
} else {
|
|
1965
2138
|
store.connect();
|
|
1966
2139
|
}
|
|
@@ -1980,11 +2153,23 @@ var QueryEngine = class _QueryEngine {
|
|
|
1980
2153
|
constructor(options) {
|
|
1981
2154
|
this.backend = options.backend || new FilesystemQueryBackend(options.artifactDir);
|
|
1982
2155
|
this.adapters = /* @__PURE__ */ new Map();
|
|
1983
|
-
this.adapters.set(
|
|
1984
|
-
|
|
1985
|
-
|
|
2156
|
+
this.adapters.set(
|
|
2157
|
+
"artifacts",
|
|
2158
|
+
new ArtifactQueryAdapter(options.artifactDir, this.backend)
|
|
2159
|
+
);
|
|
2160
|
+
this.adapters.set(
|
|
2161
|
+
"lineage",
|
|
2162
|
+
new LineageQueryAdapter(options.artifactDir, this.backend)
|
|
2163
|
+
);
|
|
2164
|
+
this.adapters.set(
|
|
2165
|
+
"replay",
|
|
2166
|
+
new ReplayQueryAdapter(options.artifactDir, this.backend)
|
|
2167
|
+
);
|
|
1986
2168
|
this.adapters.set("dag", new DagQueryAdapter(options.artifactDir, this.backend));
|
|
1987
|
-
this.adapters.set(
|
|
2169
|
+
this.adapters.set(
|
|
2170
|
+
"events",
|
|
2171
|
+
new EventsQueryAdapter(options.artifactDir, this.backend)
|
|
2172
|
+
);
|
|
1988
2173
|
this.adapters.set("tx", new TxQueryAdapter(options.artifactDir, this.backend));
|
|
1989
2174
|
}
|
|
1990
2175
|
/**
|
|
@@ -2013,7 +2198,9 @@ var QueryEngine = class _QueryEngine {
|
|
|
2013
2198
|
rowsRead: result.items.length,
|
|
2014
2199
|
scannedFiles: result.annotations.filesScanned || 0,
|
|
2015
2200
|
freshness,
|
|
2016
|
-
warnings: freshness === "stale" ? [
|
|
2201
|
+
warnings: freshness === "stale" ? [
|
|
2202
|
+
"Index is STALE. mtime mismatch detected. Run 'hardkas query store rebuild'."
|
|
2203
|
+
] : []
|
|
2017
2204
|
};
|
|
2018
2205
|
}
|
|
2019
2206
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardkas/query",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4-alpha",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"picocolors": "^1.1.1",
|
|
17
|
-
"@hardkas/core": "0.7.
|
|
18
|
-
"@hardkas/
|
|
19
|
-
"@hardkas/
|
|
17
|
+
"@hardkas/core": "0.7.4-alpha",
|
|
18
|
+
"@hardkas/query-store": "0.7.4-alpha",
|
|
19
|
+
"@hardkas/artifacts": "0.7.4-alpha"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"tsup": "^8.3.5",
|