@haaaiawd/second-nature 0.1.8 → 0.1.10
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/index.js +281 -69
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/runtime/cli/commands/index.d.ts +2 -0
- package/runtime/cli/commands/index.js +61 -6
- package/runtime/cli/explain/explain-surface-subject.d.ts +8 -0
- package/runtime/cli/explain/explain-surface-subject.js +9 -0
- package/runtime/cli/explain/format-explanation.d.ts +2 -0
- package/runtime/cli/explain/format-explanation.js +2 -0
- package/runtime/cli/explain/resolve-subject.js +15 -0
- package/runtime/cli/host-capability/classify-delivery.d.ts +14 -0
- package/runtime/cli/host-capability/classify-delivery.js +20 -0
- package/runtime/cli/host-capability/probe-host-capability.d.ts +2 -0
- package/runtime/cli/host-capability/probe-host-capability.js +58 -0
- package/runtime/cli/host-capability/record-host-capability.d.ts +6 -0
- package/runtime/cli/host-capability/record-host-capability.js +14 -0
- package/runtime/cli/host-capability/types.d.ts +71 -0
- package/runtime/cli/host-capability/types.js +6 -0
- package/runtime/cli/host-smoke/run-host-smoke.d.ts +2 -0
- package/runtime/cli/host-smoke/run-host-smoke.js +40 -0
- package/runtime/cli/host-smoke/types.d.ts +35 -0
- package/runtime/cli/host-smoke/types.js +6 -0
- package/runtime/cli/index.js +18 -0
- package/runtime/cli/ops/heartbeat-surface.d.ts +35 -0
- package/runtime/cli/ops/heartbeat-surface.js +71 -0
- package/runtime/cli/ops/ops-router.d.ts +16 -0
- package/runtime/cli/ops/ops-router.js +83 -0
- package/runtime/cli/ops/show-operator-fallback.d.ts +13 -0
- package/runtime/cli/ops/show-operator-fallback.js +22 -0
- package/runtime/cli/ops/workspace-heartbeat-runner.d.ts +10 -0
- package/runtime/cli/ops/workspace-heartbeat-runner.js +26 -0
- package/runtime/cli/read-models/index.d.ts +11 -2
- package/runtime/cli/read-models/index.js +50 -0
- package/runtime/cli/read-models/operator-explain-map.d.ts +6 -0
- package/runtime/cli/read-models/operator-explain-map.js +10 -0
- package/runtime/cli/read-models/types.d.ts +5 -1
- package/runtime/cli/runtime/runtime-artifact-boundary.d.ts +28 -0
- package/runtime/cli/runtime/runtime-artifact-boundary.js +94 -0
- package/runtime/connectors/base/contract.d.ts +6 -0
- package/runtime/connectors/base/execution-policy.d.ts +47 -0
- package/runtime/connectors/base/execution-policy.js +82 -0
- package/runtime/connectors/base/index.d.ts +2 -0
- package/runtime/connectors/base/index.js +2 -0
- package/runtime/connectors/base/manifest.d.ts +55 -2
- package/runtime/connectors/base/manifest.js +50 -0
- package/runtime/connectors/base/map-life-evidence.d.ts +16 -0
- package/runtime/connectors/base/map-life-evidence.js +79 -0
- package/runtime/connectors/base/policy-layer.d.ts +2 -0
- package/runtime/connectors/base/policy-layer.js +16 -0
- package/runtime/connectors/base/route-planner.js +1 -0
- package/runtime/connectors/index.d.ts +1 -0
- package/runtime/connectors/index.js +1 -0
- package/runtime/connectors/near-real/near-real-connector-smoke.d.ts +19 -0
- package/runtime/connectors/near-real/near-real-connector-smoke.js +152 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-executor.js +2 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +37 -16
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +95 -29
- package/runtime/core/second-nature/heartbeat/index.d.ts +4 -1
- package/runtime/core/second-nature/heartbeat/index.js +4 -1
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.d.ts +21 -0
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.js +35 -0
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +28 -0
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.js +35 -0
- package/runtime/core/second-nature/heartbeat/signal.d.ts +9 -2
- package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +19 -1
- package/runtime/core/second-nature/index.d.ts +8 -0
- package/runtime/core/second-nature/index.js +8 -0
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +1 -1
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +9 -4
- package/runtime/core/second-nature/orchestrator/guard-layer.d.ts +6 -0
- package/runtime/core/second-nature/orchestrator/guard-layer.js +76 -20
- package/runtime/core/second-nature/orchestrator/intent-planner.d.ts +10 -0
- package/runtime/core/second-nature/orchestrator/intent-planner.js +135 -28
- package/runtime/core/second-nature/orchestrator/lease-manager.d.ts +1 -1
- package/runtime/core/second-nature/orchestrator/lease-manager.js +1 -1
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.d.ts +6 -0
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +63 -0
- package/runtime/core/second-nature/outreach/delivery-target.d.ts +26 -0
- package/runtime/core/second-nature/outreach/delivery-target.js +70 -0
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +38 -0
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +119 -0
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.d.ts +7 -0
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +45 -0
- package/runtime/core/second-nature/outreach/judge-outreach.d.ts +40 -0
- package/runtime/core/second-nature/outreach/judge-outreach.js +121 -0
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.d.ts +21 -0
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +123 -0
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.d.ts +15 -0
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.js +52 -0
- package/runtime/core/second-nature/rhythm/policy-bridge.d.ts +19 -0
- package/runtime/core/second-nature/rhythm/policy-bridge.js +34 -0
- package/runtime/core/second-nature/types.d.ts +16 -2
- package/runtime/guidance/draft-outreach-message.d.ts +7 -0
- package/runtime/guidance/draft-outreach-message.js +42 -0
- package/runtime/guidance/evidence-guidance.d.ts +40 -0
- package/runtime/guidance/evidence-guidance.js +52 -0
- package/runtime/guidance/index.d.ts +3 -0
- package/runtime/guidance/index.js +3 -0
- package/runtime/guidance/outreach-draft-schema.d.ts +228 -0
- package/runtime/guidance/outreach-draft-schema.js +80 -0
- package/runtime/observability/audit/append-only-audit-store.d.ts +14 -0
- package/runtime/observability/audit/append-only-audit-store.js +21 -0
- package/runtime/observability/audit/audit-envelope.d.ts +51 -0
- package/runtime/observability/audit/audit-envelope.js +130 -0
- package/runtime/observability/audit/verify-audit-hash-chain.d.ts +23 -0
- package/runtime/observability/audit/verify-audit-hash-chain.js +83 -0
- package/runtime/observability/db/index.js +11 -0
- package/runtime/observability/db/schema/host-capability-reports.d.ts +180 -0
- package/runtime/observability/db/schema/host-capability-reports.js +12 -0
- package/runtime/observability/db/schema/index.d.ts +1 -0
- package/runtime/observability/db/schema/index.js +1 -0
- package/runtime/observability/index.d.ts +7 -0
- package/runtime/observability/index.js +7 -0
- package/runtime/observability/query/explain-query.d.ts +48 -0
- package/runtime/observability/query/explain-query.js +114 -0
- package/runtime/observability/query/export-audit-bundle.d.ts +22 -0
- package/runtime/observability/query/export-audit-bundle.js +27 -0
- package/runtime/observability/services/decision-ledger.d.ts +1 -1
- package/runtime/observability/services/decision-ledger.js +4 -0
- package/runtime/observability/services/governance-audit.d.ts +14 -0
- package/runtime/observability/services/governance-audit.js +25 -1
- package/runtime/observability/services/governance-plane-recorder.d.ts +47 -0
- package/runtime/observability/services/governance-plane-recorder.js +55 -0
- package/runtime/observability/services/lived-experience-audit.d.ts +97 -0
- package/runtime/observability/services/lived-experience-audit.js +162 -0
- package/runtime/storage/bootstrap/native-sqlite-probe.d.ts +7 -0
- package/runtime/storage/bootstrap/native-sqlite-probe.js +28 -0
- package/runtime/storage/bootstrap/repair-gate.d.ts +17 -0
- package/runtime/storage/bootstrap/repair-gate.js +71 -0
- package/runtime/storage/bootstrap/storage-mode-smoke.d.ts +38 -0
- package/runtime/storage/bootstrap/storage-mode-smoke.js +85 -0
- package/runtime/storage/db/index.js +49 -0
- package/runtime/storage/db/schema/delivery-attempts.d.ts +199 -0
- package/runtime/storage/db/schema/delivery-attempts.js +13 -0
- package/runtime/storage/db/schema/index.d.ts +3 -0
- package/runtime/storage/db/schema/index.js +3 -0
- package/runtime/storage/db/schema/life-evidence-index.d.ts +161 -0
- package/runtime/storage/db/schema/life-evidence-index.js +11 -0
- package/runtime/storage/db/schema/operator-fallback-artifacts.d.ts +161 -0
- package/runtime/storage/db/schema/operator-fallback-artifacts.js +11 -0
- package/runtime/storage/db/schema/policies.d.ts +17 -0
- package/runtime/storage/db/schema/policies.js +1 -0
- package/runtime/storage/delivery/query-delivery-attempts.d.ts +3 -0
- package/runtime/storage/delivery/query-delivery-attempts.js +32 -0
- package/runtime/storage/delivery/types.d.ts +27 -0
- package/runtime/storage/delivery/types.js +1 -0
- package/runtime/storage/delivery/write-delivery-attempt.d.ts +6 -0
- package/runtime/storage/delivery/write-delivery-attempt.js +36 -0
- package/runtime/storage/fallback/load-operator-fallback.d.ts +14 -0
- package/runtime/storage/fallback/load-operator-fallback.js +47 -0
- package/runtime/storage/fallback/operator-fallback-types.d.ts +9 -0
- package/runtime/storage/fallback/operator-fallback-types.js +1 -0
- package/runtime/storage/fallback/operator-fallback-view.d.ts +11 -0
- package/runtime/storage/fallback/operator-fallback-view.js +1 -0
- package/runtime/storage/fallback/write-operator-fallback.d.ts +6 -0
- package/runtime/storage/fallback/write-operator-fallback.js +21 -0
- package/runtime/storage/index.d.ts +21 -0
- package/runtime/storage/index.js +14 -0
- package/runtime/storage/life-evidence/append-life-evidence.d.ts +7 -0
- package/runtime/storage/life-evidence/append-life-evidence.js +64 -0
- package/runtime/storage/life-evidence/types.d.ts +45 -0
- package/runtime/storage/life-evidence/types.js +6 -0
- package/runtime/storage/quiet/persist-quiet-artifact.d.ts +7 -0
- package/runtime/storage/quiet/persist-quiet-artifact.js +22 -0
- package/runtime/storage/quiet/quiet-artifact-types.d.ts +18 -0
- package/runtime/storage/quiet/quiet-artifact-types.js +1 -0
- package/runtime/storage/quiet/quiet-artifact-writer.d.ts +15 -0
- package/runtime/storage/quiet/quiet-artifact-writer.js +56 -0
- package/runtime/storage/repositories/credential-repository.js +12 -1
- package/runtime/storage/rhythm/rhythm-policy-snapshot.d.ts +10 -0
- package/runtime/storage/rhythm/rhythm-policy-snapshot.js +34 -0
- package/runtime/storage/services/credential-vault.d.ts +5 -0
- package/runtime/storage/services/credential-vault.js +47 -9
- package/runtime/storage/snapshots/continuity-snapshot.d.ts +9 -0
- package/runtime/storage/snapshots/continuity-snapshot.js +41 -0
- package/runtime/storage/snapshots/life-evidence-snapshot.d.ts +6 -0
- package/runtime/storage/snapshots/life-evidence-snapshot.js +114 -0
- package/runtime/storage/snapshots/types.d.ts +58 -0
- package/runtime/storage/snapshots/types.js +1 -0
- package/runtime/storage/state-api.js +11 -4
- package/runtime/storage/user-interest/load-user-interest-snapshot.d.ts +2 -0
- package/runtime/storage/user-interest/load-user-interest-snapshot.js +150 -0
- package/runtime/storage/user-interest/types.d.ts +25 -0
- package/runtime/storage/user-interest/types.js +1 -0
- package/workspace-ops-bridge.js +78 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type RedactionManifest as FieldRedactionManifest } from "../redaction/manifest.js";
|
|
2
|
+
export type AuditPlane = "decision" | "delivery" | "source_coverage" | "governance" | "telemetry";
|
|
3
|
+
export type AuditEventFamily = "heartbeat.decision" | "delivery" | "source_coverage" | "guidance.grounding" | "host_capability" | "connector.attempt" | "state.governance";
|
|
4
|
+
export type AuditEnvelopeSensitivity = "public" | "internal" | "private" | "credential" | "sensitive";
|
|
5
|
+
export interface AuditRedactionManifest {
|
|
6
|
+
manifestId: string;
|
|
7
|
+
maskedPaths: string[];
|
|
8
|
+
erasedPaths: string[];
|
|
9
|
+
hashedPaths: string[];
|
|
10
|
+
contentRefPaths: string[];
|
|
11
|
+
sensitivity: AuditEnvelopeSensitivity;
|
|
12
|
+
}
|
|
13
|
+
export interface AuditIntegrity {
|
|
14
|
+
previousHash?: string;
|
|
15
|
+
recordHash: string;
|
|
16
|
+
schemaVersion: "observability.v5";
|
|
17
|
+
}
|
|
18
|
+
export interface AuditEnvelope<TPayload> {
|
|
19
|
+
eventId: string;
|
|
20
|
+
family: AuditEventFamily;
|
|
21
|
+
plane: AuditPlane;
|
|
22
|
+
traceId: string;
|
|
23
|
+
sequence: number;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
payload: TPayload;
|
|
26
|
+
redaction: AuditRedactionManifest;
|
|
27
|
+
integrity: AuditIntegrity;
|
|
28
|
+
}
|
|
29
|
+
export interface RedactAuditEventResult<TPayload> {
|
|
30
|
+
payload: TPayload;
|
|
31
|
+
redaction: AuditRedactionManifest;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Apply field redaction rules and lift manifests to audit path vocabulary (observability-system.detail §2).
|
|
35
|
+
*/
|
|
36
|
+
export declare function redactAuditEvent<TPayload extends object>(payload: TPayload): RedactAuditEventResult<TPayload>;
|
|
37
|
+
export interface BuildAuditEnvelopeInput<TPayload extends object> {
|
|
38
|
+
family: AuditEventFamily;
|
|
39
|
+
plane: AuditPlane;
|
|
40
|
+
traceId: string;
|
|
41
|
+
sequence: number;
|
|
42
|
+
payload: TPayload;
|
|
43
|
+
previousHash?: string;
|
|
44
|
+
eventId?: string;
|
|
45
|
+
createdAt?: string;
|
|
46
|
+
}
|
|
47
|
+
/** Recompute integrity hash for an existing envelope (T5.2.2 / verifyAuditHashChain). */
|
|
48
|
+
export declare function computeAuditRecordHash(envelope: AuditEnvelope<unknown>): string;
|
|
49
|
+
export declare function buildAuditEnvelope<TPayload extends object>(input: BuildAuditEnvelopeInput<TPayload>): AuditEnvelope<TPayload>;
|
|
50
|
+
/** @internal Maps legacy field manifest to audit manifest for persistence helpers. */
|
|
51
|
+
export declare function auditManifestFromFieldManifest(manifest: FieldRedactionManifest): AuditRedactionManifest;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit envelope construction + redaction for observability-system v5.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: redact structured payloads, attach RedactionManifest (L0/L1 contract paths),
|
|
5
|
+
* compute hash-chain fields for append-only ledger rows.
|
|
6
|
+
*
|
|
7
|
+
* Dependencies: observability redactEvent (field-level); maps to envelope redaction paths.
|
|
8
|
+
*
|
|
9
|
+
* Boundaries: persistence is delegated to AppendOnlyAuditStore / DB adapters.
|
|
10
|
+
*
|
|
11
|
+
* Test coverage: tests/unit/observability/audit-envelope.test.ts
|
|
12
|
+
*/
|
|
13
|
+
import * as crypto from "node:crypto";
|
|
14
|
+
import { redactEvent } from "../redaction/manifest.js";
|
|
15
|
+
function fieldPathToAuditPath(field) {
|
|
16
|
+
if (field.startsWith("/")) {
|
|
17
|
+
return field;
|
|
18
|
+
}
|
|
19
|
+
return `/payload/${field.replace(/\./g, "/")}`;
|
|
20
|
+
}
|
|
21
|
+
function mapSensitivity(level) {
|
|
22
|
+
switch (level) {
|
|
23
|
+
case "public":
|
|
24
|
+
return "public";
|
|
25
|
+
case "internal":
|
|
26
|
+
return "internal";
|
|
27
|
+
case "confidential":
|
|
28
|
+
return "private";
|
|
29
|
+
case "restricted":
|
|
30
|
+
return "sensitive";
|
|
31
|
+
default:
|
|
32
|
+
return "internal";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Apply field redaction rules and lift manifests to audit path vocabulary (observability-system.detail §2).
|
|
37
|
+
*/
|
|
38
|
+
export function redactAuditEvent(payload) {
|
|
39
|
+
const { redacted, manifest } = redactEvent(payload);
|
|
40
|
+
const redaction = {
|
|
41
|
+
manifestId: manifest.id,
|
|
42
|
+
maskedPaths: manifest.maskedFields.map(fieldPathToAuditPath),
|
|
43
|
+
erasedPaths: manifest.erasedFields.map(fieldPathToAuditPath),
|
|
44
|
+
hashedPaths: manifest.hashedFields.map(fieldPathToAuditPath),
|
|
45
|
+
contentRefPaths: [],
|
|
46
|
+
sensitivity: mapSensitivity(manifest.sensitivityLevel),
|
|
47
|
+
};
|
|
48
|
+
return { payload: redacted, redaction };
|
|
49
|
+
}
|
|
50
|
+
function stableStringify(value) {
|
|
51
|
+
if (value === null || typeof value !== "object") {
|
|
52
|
+
return JSON.stringify(value);
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(value)) {
|
|
55
|
+
return `[${value.map((v) => stableStringify(v)).join(",")}]`;
|
|
56
|
+
}
|
|
57
|
+
const obj = value;
|
|
58
|
+
const keys = Object.keys(obj).sort();
|
|
59
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(",")}}`;
|
|
60
|
+
}
|
|
61
|
+
function hashRecord(input) {
|
|
62
|
+
const canonical = stableStringify({
|
|
63
|
+
eventId: input.eventId,
|
|
64
|
+
family: input.family,
|
|
65
|
+
plane: input.plane,
|
|
66
|
+
traceId: input.traceId,
|
|
67
|
+
sequence: input.sequence,
|
|
68
|
+
createdAt: input.createdAt,
|
|
69
|
+
payload: input.payload,
|
|
70
|
+
redaction: input.redaction,
|
|
71
|
+
previousHash: input.previousHash ?? null,
|
|
72
|
+
});
|
|
73
|
+
return crypto.createHash("sha256").update(canonical, "utf8").digest("hex");
|
|
74
|
+
}
|
|
75
|
+
/** Recompute integrity hash for an existing envelope (T5.2.2 / verifyAuditHashChain). */
|
|
76
|
+
export function computeAuditRecordHash(envelope) {
|
|
77
|
+
return hashRecord({
|
|
78
|
+
eventId: envelope.eventId,
|
|
79
|
+
family: envelope.family,
|
|
80
|
+
plane: envelope.plane,
|
|
81
|
+
traceId: envelope.traceId,
|
|
82
|
+
sequence: envelope.sequence,
|
|
83
|
+
createdAt: envelope.createdAt,
|
|
84
|
+
payload: envelope.payload,
|
|
85
|
+
redaction: envelope.redaction,
|
|
86
|
+
previousHash: envelope.integrity.previousHash,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export function buildAuditEnvelope(input) {
|
|
90
|
+
const { payload, redaction } = redactAuditEvent(input.payload);
|
|
91
|
+
const eventId = input.eventId ?? crypto.randomUUID();
|
|
92
|
+
const createdAt = input.createdAt ?? new Date().toISOString();
|
|
93
|
+
const recordHash = hashRecord({
|
|
94
|
+
eventId,
|
|
95
|
+
family: input.family,
|
|
96
|
+
plane: input.plane,
|
|
97
|
+
traceId: input.traceId,
|
|
98
|
+
sequence: input.sequence,
|
|
99
|
+
createdAt,
|
|
100
|
+
payload,
|
|
101
|
+
redaction,
|
|
102
|
+
previousHash: input.previousHash,
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
eventId,
|
|
106
|
+
family: input.family,
|
|
107
|
+
plane: input.plane,
|
|
108
|
+
traceId: input.traceId,
|
|
109
|
+
sequence: input.sequence,
|
|
110
|
+
createdAt,
|
|
111
|
+
payload,
|
|
112
|
+
redaction,
|
|
113
|
+
integrity: {
|
|
114
|
+
previousHash: input.previousHash,
|
|
115
|
+
recordHash,
|
|
116
|
+
schemaVersion: "observability.v5",
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** @internal Maps legacy field manifest to audit manifest for persistence helpers. */
|
|
121
|
+
export function auditManifestFromFieldManifest(manifest) {
|
|
122
|
+
return {
|
|
123
|
+
manifestId: manifest.id,
|
|
124
|
+
maskedPaths: manifest.maskedFields.map(fieldPathToAuditPath),
|
|
125
|
+
erasedPaths: manifest.erasedFields.map(fieldPathToAuditPath),
|
|
126
|
+
hashedPaths: manifest.hashedFields.map(fieldPathToAuditPath),
|
|
127
|
+
contentRefPaths: [],
|
|
128
|
+
sensitivity: mapSensitivity(manifest.sensitivityLevel),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AppendOnlyAuditStore } from "./append-only-audit-store.js";
|
|
2
|
+
import { type AuditEnvelope, type AuditEventFamily } from "./audit-envelope.js";
|
|
3
|
+
export interface AuditExportRange {
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
families?: AuditEventFamily[];
|
|
7
|
+
}
|
|
8
|
+
export type AuditHashChainVerificationStatus = "pass" | "broken" | "incomplete";
|
|
9
|
+
export interface AuditHashChainVerificationReport {
|
|
10
|
+
reportId: string;
|
|
11
|
+
generatedAt: string;
|
|
12
|
+
range: AuditExportRange;
|
|
13
|
+
checkedEventCount: number;
|
|
14
|
+
status: AuditHashChainVerificationStatus;
|
|
15
|
+
brokenAtEventIds: string[];
|
|
16
|
+
reasons: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface VerifyAuditHashChainDeps {
|
|
19
|
+
loadRange(from: string, to: string, families?: AuditEventFamily[]): Promise<readonly AuditEnvelope<unknown>[]>;
|
|
20
|
+
}
|
|
21
|
+
export declare function verifyAuditHashChain(range: AuditExportRange, deps: VerifyAuditHashChainDeps): Promise<AuditHashChainVerificationReport>;
|
|
22
|
+
/** In-memory adapter: filter `AppendOnlyAuditStore.list()` by createdAt + optional families. */
|
|
23
|
+
export declare function createAppendOnlyAuditStoreRangeLoader(store: AppendOnlyAuditStore): VerifyAuditHashChainDeps;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Range-based hash-chain verification for append-only audit rows (T5.2.2 / INT-S3).
|
|
3
|
+
*
|
|
4
|
+
* Core logic: load events in [from, to], order by sequence, recompute recordHash and
|
|
5
|
+
* verify previousHash links between consecutive **loaded** rows only (partial ranges
|
|
6
|
+
* may start mid-chain; parent outside the slice is not validated). Empty or invalid
|
|
7
|
+
* ranges yield incomplete (T5.2.2 / task verification plan).
|
|
8
|
+
*
|
|
9
|
+
* Dependencies: computeAuditRecordHash from audit-envelope; callers supply loadRange via deps.
|
|
10
|
+
*
|
|
11
|
+
* Test coverage: tests/unit/observability/verify-audit-hash-chain.test.ts
|
|
12
|
+
*/
|
|
13
|
+
import * as crypto from "node:crypto";
|
|
14
|
+
import { computeAuditRecordHash } from "./audit-envelope.js";
|
|
15
|
+
function unique(ids) {
|
|
16
|
+
return [...new Set(ids)];
|
|
17
|
+
}
|
|
18
|
+
export async function verifyAuditHashChain(range, deps) {
|
|
19
|
+
const generatedAt = new Date().toISOString();
|
|
20
|
+
const reportId = crypto.randomUUID();
|
|
21
|
+
if (range.from > range.to) {
|
|
22
|
+
return {
|
|
23
|
+
reportId,
|
|
24
|
+
generatedAt,
|
|
25
|
+
range,
|
|
26
|
+
checkedEventCount: 0,
|
|
27
|
+
status: "incomplete",
|
|
28
|
+
brokenAtEventIds: [],
|
|
29
|
+
reasons: ["invalid_range_from_after_to"],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const raw = await deps.loadRange(range.from, range.to, range.families);
|
|
33
|
+
const events = [...raw].sort((a, b) => a.sequence - b.sequence);
|
|
34
|
+
if (events.length === 0) {
|
|
35
|
+
return {
|
|
36
|
+
reportId,
|
|
37
|
+
generatedAt,
|
|
38
|
+
range,
|
|
39
|
+
checkedEventCount: 0,
|
|
40
|
+
status: "incomplete",
|
|
41
|
+
brokenAtEventIds: [],
|
|
42
|
+
reasons: ["range_empty"],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const brokenAtEventIds = [];
|
|
46
|
+
for (let i = 0; i < events.length; i += 1) {
|
|
47
|
+
const event = events[i];
|
|
48
|
+
const expected = computeAuditRecordHash(event);
|
|
49
|
+
if (event.integrity.recordHash !== expected) {
|
|
50
|
+
brokenAtEventIds.push(event.eventId);
|
|
51
|
+
}
|
|
52
|
+
const prev = events[i - 1];
|
|
53
|
+
if (prev && event.integrity.previousHash !== prev.integrity.recordHash) {
|
|
54
|
+
brokenAtEventIds.push(event.eventId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const uniq = unique(brokenAtEventIds);
|
|
58
|
+
const broken = uniq.length > 0;
|
|
59
|
+
return {
|
|
60
|
+
reportId,
|
|
61
|
+
generatedAt,
|
|
62
|
+
range,
|
|
63
|
+
checkedEventCount: events.length,
|
|
64
|
+
status: broken ? "broken" : "pass",
|
|
65
|
+
brokenAtEventIds: uniq,
|
|
66
|
+
reasons: broken ? ["hash_chain_broken"] : ["hash_chain_valid"],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** In-memory adapter: filter `AppendOnlyAuditStore.list()` by createdAt + optional families. */
|
|
70
|
+
export function createAppendOnlyAuditStoreRangeLoader(store) {
|
|
71
|
+
return {
|
|
72
|
+
async loadRange(from, to, families) {
|
|
73
|
+
const fams = families?.length ? new Set(families) : undefined;
|
|
74
|
+
return store.list().filter((e) => {
|
|
75
|
+
if (e.createdAt < from || e.createdAt > to)
|
|
76
|
+
return false;
|
|
77
|
+
if (fams && !fams.has(e.family))
|
|
78
|
+
return false;
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -72,6 +72,17 @@ const OBSERVABILITY_SCHEMA_SQL = `
|
|
|
72
72
|
created_at TEXT NOT NULL
|
|
73
73
|
);
|
|
74
74
|
CREATE INDEX IF NOT EXISTS redact_event_idx ON redaction_manifest(event_id);
|
|
75
|
+
CREATE TABLE IF NOT EXISTS host_capability_reports (
|
|
76
|
+
report_id TEXT PRIMARY KEY,
|
|
77
|
+
generated_at TEXT NOT NULL,
|
|
78
|
+
host_version TEXT,
|
|
79
|
+
observed_version TEXT,
|
|
80
|
+
doc_checked_at TEXT NOT NULL,
|
|
81
|
+
doc_links_json TEXT NOT NULL,
|
|
82
|
+
delivery_target TEXT NOT NULL,
|
|
83
|
+
conflict_records_json TEXT NOT NULL,
|
|
84
|
+
full_report_json TEXT NOT NULL
|
|
85
|
+
);
|
|
75
86
|
`;
|
|
76
87
|
function resolveDbPath(filename) {
|
|
77
88
|
if (path.isAbsolute(filename) || filename === ":memory:") {
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
export declare const hostCapabilityReports: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
2
|
+
name: "host_capability_reports";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
reportId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
6
|
+
name: "report_id";
|
|
7
|
+
tableName: "host_capability_reports";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "SQLiteText";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: [string, ...string[]];
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {
|
|
22
|
+
length: number | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
generatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
25
|
+
name: "generated_at";
|
|
26
|
+
tableName: "host_capability_reports";
|
|
27
|
+
dataType: "string";
|
|
28
|
+
columnType: "SQLiteText";
|
|
29
|
+
data: string;
|
|
30
|
+
driverParam: string;
|
|
31
|
+
notNull: true;
|
|
32
|
+
hasDefault: false;
|
|
33
|
+
isPrimaryKey: false;
|
|
34
|
+
isAutoincrement: false;
|
|
35
|
+
hasRuntimeDefault: false;
|
|
36
|
+
enumValues: [string, ...string[]];
|
|
37
|
+
baseColumn: never;
|
|
38
|
+
identity: undefined;
|
|
39
|
+
generated: undefined;
|
|
40
|
+
}, {}, {
|
|
41
|
+
length: number | undefined;
|
|
42
|
+
}>;
|
|
43
|
+
hostVersion: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
44
|
+
name: "host_version";
|
|
45
|
+
tableName: "host_capability_reports";
|
|
46
|
+
dataType: "string";
|
|
47
|
+
columnType: "SQLiteText";
|
|
48
|
+
data: string;
|
|
49
|
+
driverParam: string;
|
|
50
|
+
notNull: false;
|
|
51
|
+
hasDefault: false;
|
|
52
|
+
isPrimaryKey: false;
|
|
53
|
+
isAutoincrement: false;
|
|
54
|
+
hasRuntimeDefault: false;
|
|
55
|
+
enumValues: [string, ...string[]];
|
|
56
|
+
baseColumn: never;
|
|
57
|
+
identity: undefined;
|
|
58
|
+
generated: undefined;
|
|
59
|
+
}, {}, {
|
|
60
|
+
length: number | undefined;
|
|
61
|
+
}>;
|
|
62
|
+
observedVersion: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
63
|
+
name: "observed_version";
|
|
64
|
+
tableName: "host_capability_reports";
|
|
65
|
+
dataType: "string";
|
|
66
|
+
columnType: "SQLiteText";
|
|
67
|
+
data: string;
|
|
68
|
+
driverParam: string;
|
|
69
|
+
notNull: false;
|
|
70
|
+
hasDefault: false;
|
|
71
|
+
isPrimaryKey: false;
|
|
72
|
+
isAutoincrement: false;
|
|
73
|
+
hasRuntimeDefault: false;
|
|
74
|
+
enumValues: [string, ...string[]];
|
|
75
|
+
baseColumn: never;
|
|
76
|
+
identity: undefined;
|
|
77
|
+
generated: undefined;
|
|
78
|
+
}, {}, {
|
|
79
|
+
length: number | undefined;
|
|
80
|
+
}>;
|
|
81
|
+
docCheckedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
82
|
+
name: "doc_checked_at";
|
|
83
|
+
tableName: "host_capability_reports";
|
|
84
|
+
dataType: "string";
|
|
85
|
+
columnType: "SQLiteText";
|
|
86
|
+
data: string;
|
|
87
|
+
driverParam: string;
|
|
88
|
+
notNull: true;
|
|
89
|
+
hasDefault: false;
|
|
90
|
+
isPrimaryKey: false;
|
|
91
|
+
isAutoincrement: false;
|
|
92
|
+
hasRuntimeDefault: false;
|
|
93
|
+
enumValues: [string, ...string[]];
|
|
94
|
+
baseColumn: never;
|
|
95
|
+
identity: undefined;
|
|
96
|
+
generated: undefined;
|
|
97
|
+
}, {}, {
|
|
98
|
+
length: number | undefined;
|
|
99
|
+
}>;
|
|
100
|
+
docLinksJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
101
|
+
name: "doc_links_json";
|
|
102
|
+
tableName: "host_capability_reports";
|
|
103
|
+
dataType: "string";
|
|
104
|
+
columnType: "SQLiteText";
|
|
105
|
+
data: string;
|
|
106
|
+
driverParam: string;
|
|
107
|
+
notNull: true;
|
|
108
|
+
hasDefault: false;
|
|
109
|
+
isPrimaryKey: false;
|
|
110
|
+
isAutoincrement: false;
|
|
111
|
+
hasRuntimeDefault: false;
|
|
112
|
+
enumValues: [string, ...string[]];
|
|
113
|
+
baseColumn: never;
|
|
114
|
+
identity: undefined;
|
|
115
|
+
generated: undefined;
|
|
116
|
+
}, {}, {
|
|
117
|
+
length: number | undefined;
|
|
118
|
+
}>;
|
|
119
|
+
deliveryTarget: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
120
|
+
name: "delivery_target";
|
|
121
|
+
tableName: "host_capability_reports";
|
|
122
|
+
dataType: "string";
|
|
123
|
+
columnType: "SQLiteText";
|
|
124
|
+
data: string;
|
|
125
|
+
driverParam: string;
|
|
126
|
+
notNull: true;
|
|
127
|
+
hasDefault: false;
|
|
128
|
+
isPrimaryKey: false;
|
|
129
|
+
isAutoincrement: false;
|
|
130
|
+
hasRuntimeDefault: false;
|
|
131
|
+
enumValues: [string, ...string[]];
|
|
132
|
+
baseColumn: never;
|
|
133
|
+
identity: undefined;
|
|
134
|
+
generated: undefined;
|
|
135
|
+
}, {}, {
|
|
136
|
+
length: number | undefined;
|
|
137
|
+
}>;
|
|
138
|
+
conflictRecordsJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
139
|
+
name: "conflict_records_json";
|
|
140
|
+
tableName: "host_capability_reports";
|
|
141
|
+
dataType: "string";
|
|
142
|
+
columnType: "SQLiteText";
|
|
143
|
+
data: string;
|
|
144
|
+
driverParam: string;
|
|
145
|
+
notNull: true;
|
|
146
|
+
hasDefault: false;
|
|
147
|
+
isPrimaryKey: false;
|
|
148
|
+
isAutoincrement: false;
|
|
149
|
+
hasRuntimeDefault: false;
|
|
150
|
+
enumValues: [string, ...string[]];
|
|
151
|
+
baseColumn: never;
|
|
152
|
+
identity: undefined;
|
|
153
|
+
generated: undefined;
|
|
154
|
+
}, {}, {
|
|
155
|
+
length: number | undefined;
|
|
156
|
+
}>;
|
|
157
|
+
fullReportJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
158
|
+
name: "full_report_json";
|
|
159
|
+
tableName: "host_capability_reports";
|
|
160
|
+
dataType: "string";
|
|
161
|
+
columnType: "SQLiteText";
|
|
162
|
+
data: string;
|
|
163
|
+
driverParam: string;
|
|
164
|
+
notNull: true;
|
|
165
|
+
hasDefault: false;
|
|
166
|
+
isPrimaryKey: false;
|
|
167
|
+
isAutoincrement: false;
|
|
168
|
+
hasRuntimeDefault: false;
|
|
169
|
+
enumValues: [string, ...string[]];
|
|
170
|
+
baseColumn: never;
|
|
171
|
+
identity: undefined;
|
|
172
|
+
generated: undefined;
|
|
173
|
+
}, {}, {
|
|
174
|
+
length: number | undefined;
|
|
175
|
+
}>;
|
|
176
|
+
};
|
|
177
|
+
dialect: "sqlite";
|
|
178
|
+
}>;
|
|
179
|
+
export type HostCapabilityReportRow = typeof hostCapabilityReports.$inferSelect;
|
|
180
|
+
export type NewHostCapabilityReportRow = typeof hostCapabilityReports.$inferInsert;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
2
|
+
export const hostCapabilityReports = sqliteTable("host_capability_reports", {
|
|
3
|
+
reportId: text("report_id").primaryKey(),
|
|
4
|
+
generatedAt: text("generated_at").notNull(),
|
|
5
|
+
hostVersion: text("host_version"),
|
|
6
|
+
observedVersion: text("observed_version"),
|
|
7
|
+
docCheckedAt: text("doc_checked_at").notNull(),
|
|
8
|
+
docLinksJson: text("doc_links_json").notNull(),
|
|
9
|
+
deliveryTarget: text("delivery_target").notNull(),
|
|
10
|
+
conflictRecordsJson: text("conflict_records_json").notNull(),
|
|
11
|
+
fullReportJson: text("full_report_json").notNull(),
|
|
12
|
+
});
|
|
@@ -944,3 +944,4 @@ export type GovernanceAuditDb = typeof governanceAudit.$inferSelect;
|
|
|
944
944
|
export type NewGovernanceAuditDb = typeof governanceAudit.$inferInsert;
|
|
945
945
|
export type RedactionManifestDb = typeof redactionManifest.$inferSelect;
|
|
946
946
|
export type NewRedactionManifestDb = typeof redactionManifest.$inferInsert;
|
|
947
|
+
export { hostCapabilityReports, type HostCapabilityReportRow, type NewHostCapabilityReportRow, } from "./host-capability-reports.js";
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
export { createObservabilityDatabase, type ObservabilityDatabase } from "./db/index.js";
|
|
2
2
|
export * as obsSchema from "./db/schema/index.js";
|
|
3
|
+
export { buildAuditEnvelope, computeAuditRecordHash, redactAuditEvent, auditManifestFromFieldManifest, type AuditEnvelope, type AuditEnvelopeSensitivity, type AuditEventFamily, type AuditPlane, type AuditRedactionManifest, type AuditIntegrity, type BuildAuditEnvelopeInput, type RedactAuditEventResult, } from "./audit/audit-envelope.js";
|
|
4
|
+
export { AppendOnlyAuditStore } from "./audit/append-only-audit-store.js";
|
|
5
|
+
export { verifyAuditHashChain, createAppendOnlyAuditStoreRangeLoader, type AuditExportRange, type AuditHashChainVerificationReport, type AuditHashChainVerificationStatus, type VerifyAuditHashChainDeps, } from "./audit/verify-audit-hash-chain.js";
|
|
3
6
|
export { REDACTION_CONFIG, DEFAULT_REDACTION_POLICY, getFieldRedactionRule, type RedactionPolicy, type RedactionRule, type SensitivityLevel, } from "./redaction/policy.js";
|
|
4
7
|
export { redactEvent, createEmptyManifest, mergeManifests, type RedactionManifest, type RedactionResult, } from "./redaction/manifest.js";
|
|
5
8
|
export { DecisionLedger, type QuietLifecycleEvent, type OutreachDecision, type HeartbeatDecisionEvent } from "./services/decision-ledger.js";
|
|
6
9
|
export { GovernanceAudit, type CredentialLifecycleAudit } from "./services/governance-audit.js";
|
|
7
10
|
export { ExecutionTelemetry, type ExecutionAttemptInput } from "./services/execution-telemetry.js";
|
|
11
|
+
export { LivedExperienceAuditRecorder, createLivedExperienceAuditRecorder, type DecisionTracePayload, type DeliveryAuditPayload, type DeliveryAuditStatus, type ExplainLinkageSummary, type GuidanceGroundingAuditPayload, type SourceCoverageAuditPayload, } from "./services/lived-experience-audit.js";
|
|
12
|
+
export { GovernancePlaneRecorder, createGovernancePlaneRecorder, type AuditAppendAck, type ConnectorAttemptAudit, type ConnectorAttemptOutcome, type StateGovernanceAudit, type StateGovernanceKind, } from "./services/governance-plane-recorder.js";
|
|
13
|
+
export { queryExplain, type ExplainQuery, type OperatorExplainReadModel, type RedactedExplainEvent, } from "./query/explain-query.js";
|
|
14
|
+
export { exportAuditBundle, type AuditBundle, type AuditBundleExportRange, type AuditRedactionSummary, type ExportAuditBundleDeps } from "./query/export-audit-bundle.js";
|
|
8
15
|
export { EvidenceQueryEngine, } from "./query/evidence-query-engine.js";
|
|
9
16
|
export type { EvidenceQuery, EvidenceBundle, EvidenceResolutionPlan, GovernanceEvidenceRecord, ResolvedContentRef, ExplanationCapsule, } from "./query/compose-evidence.js";
|
|
10
17
|
export { projectReflectionAudit, type ReflectionAudit, type ReflectionAuditProjection, } from "./projections/reflection-audit.js";
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
export { createObservabilityDatabase } from "./db/index.js";
|
|
2
2
|
export * as obsSchema from "./db/schema/index.js";
|
|
3
|
+
export { buildAuditEnvelope, computeAuditRecordHash, redactAuditEvent, auditManifestFromFieldManifest, } from "./audit/audit-envelope.js";
|
|
4
|
+
export { AppendOnlyAuditStore } from "./audit/append-only-audit-store.js";
|
|
5
|
+
export { verifyAuditHashChain, createAppendOnlyAuditStoreRangeLoader, } from "./audit/verify-audit-hash-chain.js";
|
|
3
6
|
export { REDACTION_CONFIG, DEFAULT_REDACTION_POLICY, getFieldRedactionRule, } from "./redaction/policy.js";
|
|
4
7
|
export { redactEvent, createEmptyManifest, mergeManifests, } from "./redaction/manifest.js";
|
|
5
8
|
export { DecisionLedger } from "./services/decision-ledger.js";
|
|
6
9
|
export { GovernanceAudit } from "./services/governance-audit.js";
|
|
7
10
|
export { ExecutionTelemetry } from "./services/execution-telemetry.js";
|
|
11
|
+
export { LivedExperienceAuditRecorder, createLivedExperienceAuditRecorder, } from "./services/lived-experience-audit.js";
|
|
12
|
+
export { GovernancePlaneRecorder, createGovernancePlaneRecorder, } from "./services/governance-plane-recorder.js";
|
|
13
|
+
export { queryExplain, } from "./query/explain-query.js";
|
|
14
|
+
export { exportAuditBundle } from "./query/export-audit-bundle.js";
|
|
8
15
|
export { EvidenceQueryEngine, } from "./query/evidence-query-engine.js";
|
|
9
16
|
export { projectReflectionAudit, } from "./projections/reflection-audit.js";
|
|
10
17
|
export { projectOutreachQualityAudit, } from "./projections/outreach-quality-audit.js";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operator explain query over append-only audit envelopes (T5.3.1).
|
|
3
|
+
*
|
|
4
|
+
* Core logic: resolve subject to matching envelopes, compose summary + no-user-visible-contact warnings,
|
|
5
|
+
* expose minimal redacted event list for JSON-first read models.
|
|
6
|
+
*
|
|
7
|
+
* Dependencies: AppendOnlyAuditStore list; audit-envelope types; delivery audit payload shape from lived-experience-audit.
|
|
8
|
+
*
|
|
9
|
+
* Test coverage: tests/integration/observability/explain-query-export.test.ts
|
|
10
|
+
*/
|
|
11
|
+
import type { AppendOnlyAuditStore } from "../audit/append-only-audit-store.js";
|
|
12
|
+
import type { DeliveryAuditPayload } from "../services/lived-experience-audit.js";
|
|
13
|
+
export type ExplainQuery = {
|
|
14
|
+
kind: "decision";
|
|
15
|
+
decisionId: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "fallback";
|
|
18
|
+
fallbackRef: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "report";
|
|
21
|
+
reportId: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "delivery";
|
|
24
|
+
auditId: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "source_ref";
|
|
27
|
+
sourceRefId: string;
|
|
28
|
+
};
|
|
29
|
+
export interface RedactedExplainEvent {
|
|
30
|
+
eventId: string;
|
|
31
|
+
family: string;
|
|
32
|
+
plane: string;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
/** Minimal safe summary — no raw recipient / tokens */
|
|
35
|
+
summary: string;
|
|
36
|
+
}
|
|
37
|
+
export interface OperatorExplainReadModel {
|
|
38
|
+
query: ExplainQuery;
|
|
39
|
+
summary: string;
|
|
40
|
+
warnings: string[];
|
|
41
|
+
deliveryStatus?: DeliveryAuditPayload["status"];
|
|
42
|
+
relatedEventIds: string[];
|
|
43
|
+
events: RedactedExplainEvent[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Query explain read model from an in-memory append-only audit slice (tests / local tooling).
|
|
47
|
+
*/
|
|
48
|
+
export declare function queryExplain(query: ExplainQuery, store: AppendOnlyAuditStore): OperatorExplainReadModel;
|