@haaaiawd/second-nature 0.1.16 → 0.1.18

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.
Files changed (188) hide show
  1. package/index.js +855 -851
  2. package/openclaw.plugin.json +29 -29
  3. package/package.json +52 -52
  4. package/runtime/cli/commands/index.d.ts +14 -14
  5. package/runtime/cli/commands/index.js +193 -193
  6. package/runtime/cli/explain/explain-surface-subject.d.ts +8 -8
  7. package/runtime/cli/explain/explain-surface-subject.js +9 -9
  8. package/runtime/cli/explain/format-explanation.d.ts +12 -12
  9. package/runtime/cli/explain/format-explanation.js +12 -12
  10. package/runtime/cli/explain/resolve-subject.js +41 -41
  11. package/runtime/cli/host-capability/classify-delivery.d.ts +14 -14
  12. package/runtime/cli/host-capability/classify-delivery.js +20 -20
  13. package/runtime/cli/host-capability/probe-host-capability.d.ts +2 -2
  14. package/runtime/cli/host-capability/probe-host-capability.js +58 -58
  15. package/runtime/cli/host-capability/record-host-capability.d.ts +6 -6
  16. package/runtime/cli/host-capability/record-host-capability.js +14 -14
  17. package/runtime/cli/host-capability/types.d.ts +71 -71
  18. package/runtime/cli/host-capability/types.js +6 -6
  19. package/runtime/cli/host-smoke/run-host-smoke.d.ts +2 -2
  20. package/runtime/cli/host-smoke/run-host-smoke.js +40 -40
  21. package/runtime/cli/host-smoke/types.d.ts +35 -35
  22. package/runtime/cli/host-smoke/types.js +6 -6
  23. package/runtime/cli/index.js +58 -54
  24. package/runtime/cli/ops/heartbeat-surface.d.ts +38 -35
  25. package/runtime/cli/ops/heartbeat-surface.js +73 -71
  26. package/runtime/cli/ops/ops-router.d.ts +19 -16
  27. package/runtime/cli/ops/ops-router.js +89 -87
  28. package/runtime/cli/ops/show-operator-fallback.d.ts +13 -13
  29. package/runtime/cli/ops/show-operator-fallback.js +22 -22
  30. package/runtime/cli/ops/workspace-heartbeat-runner.d.ts +19 -10
  31. package/runtime/cli/ops/workspace-heartbeat-runner.js +39 -26
  32. package/runtime/cli/read-models/index.d.ts +29 -29
  33. package/runtime/cli/read-models/index.js +256 -256
  34. package/runtime/cli/read-models/operator-explain-map.d.ts +6 -6
  35. package/runtime/cli/read-models/operator-explain-map.js +10 -10
  36. package/runtime/cli/read-models/types.d.ts +79 -79
  37. package/runtime/cli/runtime/runtime-artifact-boundary.d.ts +28 -28
  38. package/runtime/cli/runtime/runtime-artifact-boundary.js +94 -94
  39. package/runtime/connectors/base/contract.d.ts +87 -87
  40. package/runtime/connectors/base/execution-policy.d.ts +47 -47
  41. package/runtime/connectors/base/execution-policy.js +82 -82
  42. package/runtime/connectors/base/index.d.ts +8 -8
  43. package/runtime/connectors/base/index.js +8 -8
  44. package/runtime/connectors/base/manifest.d.ts +64 -64
  45. package/runtime/connectors/base/manifest.js +86 -86
  46. package/runtime/connectors/base/map-life-evidence.d.ts +16 -16
  47. package/runtime/connectors/base/map-life-evidence.js +79 -79
  48. package/runtime/connectors/base/policy-layer.d.ts +29 -29
  49. package/runtime/connectors/base/policy-layer.js +198 -198
  50. package/runtime/connectors/base/route-planner.js +99 -99
  51. package/runtime/connectors/index.d.ts +5 -5
  52. package/runtime/connectors/index.js +5 -5
  53. package/runtime/connectors/near-real/near-real-connector-smoke.d.ts +19 -19
  54. package/runtime/connectors/near-real/near-real-connector-smoke.js +152 -152
  55. package/runtime/core/second-nature/heartbeat/heartbeat-executor.js +114 -114
  56. package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +63 -63
  57. package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +139 -139
  58. package/runtime/core/second-nature/heartbeat/index.d.ts +8 -8
  59. package/runtime/core/second-nature/heartbeat/index.js +7 -7
  60. package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.d.ts +21 -21
  61. package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.js +35 -35
  62. package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +28 -28
  63. package/runtime/core/second-nature/heartbeat/runtime-snapshot.js +35 -35
  64. package/runtime/core/second-nature/heartbeat/signal.d.ts +42 -42
  65. package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +51 -51
  66. package/runtime/core/second-nature/index.d.ts +22 -22
  67. package/runtime/core/second-nature/index.js +22 -22
  68. package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +100 -100
  69. package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +144 -144
  70. package/runtime/core/second-nature/orchestrator/guard-layer.d.ts +8 -8
  71. package/runtime/core/second-nature/orchestrator/guard-layer.js +110 -110
  72. package/runtime/core/second-nature/orchestrator/intent-planner.d.ts +13 -13
  73. package/runtime/core/second-nature/orchestrator/intent-planner.js +199 -199
  74. package/runtime/core/second-nature/orchestrator/lease-manager.d.ts +14 -14
  75. package/runtime/core/second-nature/orchestrator/lease-manager.js +58 -58
  76. package/runtime/core/second-nature/outreach/build-outreach-draft-request.d.ts +6 -6
  77. package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +63 -63
  78. package/runtime/core/second-nature/outreach/delivery-target.d.ts +26 -26
  79. package/runtime/core/second-nature/outreach/delivery-target.js +70 -70
  80. package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +38 -38
  81. package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +119 -119
  82. package/runtime/core/second-nature/outreach/judge-input-from-snapshot.d.ts +7 -7
  83. package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +45 -45
  84. package/runtime/core/second-nature/outreach/judge-outreach.d.ts +40 -40
  85. package/runtime/core/second-nature/outreach/judge-outreach.js +121 -121
  86. package/runtime/core/second-nature/quiet/run-source-backed-quiet.d.ts +21 -21
  87. package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +123 -123
  88. package/runtime/core/second-nature/rhythm/planner-rhythm-window.d.ts +15 -15
  89. package/runtime/core/second-nature/rhythm/planner-rhythm-window.js +52 -52
  90. package/runtime/core/second-nature/rhythm/policy-bridge.d.ts +19 -19
  91. package/runtime/core/second-nature/rhythm/policy-bridge.js +34 -34
  92. package/runtime/core/second-nature/runtime/service-entry.js +45 -45
  93. package/runtime/core/second-nature/types.d.ts +51 -51
  94. package/runtime/guidance/draft-outreach-message.d.ts +7 -7
  95. package/runtime/guidance/draft-outreach-message.js +42 -42
  96. package/runtime/guidance/evidence-guidance.d.ts +40 -40
  97. package/runtime/guidance/evidence-guidance.js +52 -52
  98. package/runtime/guidance/index.d.ts +11 -11
  99. package/runtime/guidance/index.js +11 -11
  100. package/runtime/guidance/outreach-draft-schema.d.ts +228 -228
  101. package/runtime/guidance/outreach-draft-schema.js +80 -80
  102. package/runtime/observability/audit/append-only-audit-store.d.ts +14 -14
  103. package/runtime/observability/audit/append-only-audit-store.js +21 -21
  104. package/runtime/observability/audit/audit-envelope.d.ts +51 -51
  105. package/runtime/observability/audit/audit-envelope.js +130 -130
  106. package/runtime/observability/audit/verify-audit-hash-chain.d.ts +23 -23
  107. package/runtime/observability/audit/verify-audit-hash-chain.js +83 -83
  108. package/runtime/observability/db/index.js +124 -124
  109. package/runtime/observability/db/schema/host-capability-reports.d.ts +180 -180
  110. package/runtime/observability/db/schema/host-capability-reports.js +12 -12
  111. package/runtime/observability/db/schema/index.d.ts +947 -947
  112. package/runtime/observability/db/schema/index.js +71 -71
  113. package/runtime/observability/index.d.ts +20 -19
  114. package/runtime/observability/index.js +19 -18
  115. package/runtime/observability/query/explain-query.d.ts +48 -48
  116. package/runtime/observability/query/explain-query.js +114 -114
  117. package/runtime/observability/query/export-audit-bundle.d.ts +22 -22
  118. package/runtime/observability/query/export-audit-bundle.js +27 -27
  119. package/runtime/observability/services/decision-ledger.d.ts +46 -46
  120. package/runtime/observability/services/decision-ledger.js +161 -161
  121. package/runtime/observability/services/governance-audit.d.ts +41 -41
  122. package/runtime/observability/services/governance-audit.js +163 -163
  123. package/runtime/observability/services/governance-plane-recorder.d.ts +47 -47
  124. package/runtime/observability/services/governance-plane-recorder.js +55 -55
  125. package/runtime/observability/services/lived-experience-audit.d.ts +97 -97
  126. package/runtime/observability/services/lived-experience-audit.js +162 -162
  127. package/runtime/observability/services/runtime-decision-recorder.d.ts +29 -0
  128. package/runtime/observability/services/runtime-decision-recorder.js +94 -0
  129. package/runtime/storage/bootstrap/native-sqlite-probe.d.ts +7 -7
  130. package/runtime/storage/bootstrap/native-sqlite-probe.js +28 -28
  131. package/runtime/storage/bootstrap/repair-gate.d.ts +17 -17
  132. package/runtime/storage/bootstrap/repair-gate.js +71 -71
  133. package/runtime/storage/bootstrap/storage-mode-smoke.d.ts +38 -38
  134. package/runtime/storage/bootstrap/storage-mode-smoke.js +85 -85
  135. package/runtime/storage/db/index.js +154 -154
  136. package/runtime/storage/db/schema/delivery-attempts.d.ts +199 -199
  137. package/runtime/storage/db/schema/delivery-attempts.js +13 -13
  138. package/runtime/storage/db/schema/index.d.ts +9 -9
  139. package/runtime/storage/db/schema/index.js +9 -9
  140. package/runtime/storage/db/schema/life-evidence-index.d.ts +161 -161
  141. package/runtime/storage/db/schema/life-evidence-index.js +11 -11
  142. package/runtime/storage/db/schema/operator-fallback-artifacts.d.ts +161 -161
  143. package/runtime/storage/db/schema/operator-fallback-artifacts.js +11 -11
  144. package/runtime/storage/db/schema/policies.d.ts +98 -98
  145. package/runtime/storage/db/schema/policies.js +8 -8
  146. package/runtime/storage/delivery/query-delivery-attempts.d.ts +3 -3
  147. package/runtime/storage/delivery/query-delivery-attempts.js +32 -32
  148. package/runtime/storage/delivery/types.d.ts +27 -27
  149. package/runtime/storage/delivery/types.js +1 -1
  150. package/runtime/storage/delivery/write-delivery-attempt.d.ts +6 -6
  151. package/runtime/storage/delivery/write-delivery-attempt.js +36 -36
  152. package/runtime/storage/fallback/load-operator-fallback.d.ts +14 -14
  153. package/runtime/storage/fallback/load-operator-fallback.js +47 -47
  154. package/runtime/storage/fallback/operator-fallback-types.d.ts +9 -9
  155. package/runtime/storage/fallback/operator-fallback-types.js +1 -1
  156. package/runtime/storage/fallback/operator-fallback-view.d.ts +11 -11
  157. package/runtime/storage/fallback/operator-fallback-view.js +1 -1
  158. package/runtime/storage/fallback/write-operator-fallback.d.ts +6 -6
  159. package/runtime/storage/fallback/write-operator-fallback.js +21 -21
  160. package/runtime/storage/index.d.ts +37 -37
  161. package/runtime/storage/index.js +30 -30
  162. package/runtime/storage/life-evidence/append-life-evidence.d.ts +7 -7
  163. package/runtime/storage/life-evidence/append-life-evidence.js +64 -64
  164. package/runtime/storage/life-evidence/types.d.ts +45 -45
  165. package/runtime/storage/life-evidence/types.js +6 -6
  166. package/runtime/storage/quiet/persist-quiet-artifact.d.ts +7 -7
  167. package/runtime/storage/quiet/persist-quiet-artifact.js +22 -22
  168. package/runtime/storage/quiet/quiet-artifact-types.d.ts +18 -18
  169. package/runtime/storage/quiet/quiet-artifact-types.js +1 -1
  170. package/runtime/storage/quiet/quiet-artifact-writer.d.ts +15 -15
  171. package/runtime/storage/quiet/quiet-artifact-writer.js +56 -56
  172. package/runtime/storage/repositories/credential-repository.js +30 -30
  173. package/runtime/storage/rhythm/rhythm-policy-snapshot.d.ts +10 -10
  174. package/runtime/storage/rhythm/rhythm-policy-snapshot.js +34 -34
  175. package/runtime/storage/services/credential-vault.d.ts +13 -13
  176. package/runtime/storage/services/credential-vault.js +116 -116
  177. package/runtime/storage/snapshots/continuity-snapshot.d.ts +9 -9
  178. package/runtime/storage/snapshots/continuity-snapshot.js +41 -41
  179. package/runtime/storage/snapshots/life-evidence-snapshot.d.ts +6 -6
  180. package/runtime/storage/snapshots/life-evidence-snapshot.js +114 -114
  181. package/runtime/storage/snapshots/types.d.ts +58 -58
  182. package/runtime/storage/snapshots/types.js +1 -1
  183. package/runtime/storage/state-api.js +104 -104
  184. package/runtime/storage/user-interest/load-user-interest-snapshot.d.ts +2 -2
  185. package/runtime/storage/user-interest/load-user-interest-snapshot.js +150 -150
  186. package/runtime/storage/user-interest/types.d.ts +25 -25
  187. package/runtime/storage/user-interest/types.js +1 -1
  188. package/workspace-ops-bridge.js +81 -80
@@ -1,27 +1,27 @@
1
- /**
2
- * Redacted audit export bundle for operator / retention tooling (T5.3.1).
3
- *
4
- * Core logic: load range, attach export metadata; payloads are already redacted at envelope build time.
5
- *
6
- * Dependencies: same range loader pattern as verifyAuditHashChain.
7
- *
8
- * Test coverage: tests/integration/observability/explain-query-export.test.ts
9
- */
10
- import * as crypto from "node:crypto";
11
- function summarize(events) {
12
- const ids = new Set();
13
- for (const e of events) {
14
- ids.add(e.redaction.manifestId);
15
- }
16
- return { eventCount: events.length, manifestIds: [...ids] };
17
- }
18
- export async function exportAuditBundle(range, deps) {
19
- const events = [...(await deps.loadRange(range.from, range.to, range.families))].sort((a, b) => a.sequence - b.sequence);
20
- return {
21
- bundleId: crypto.randomUUID(),
22
- generatedAt: new Date().toISOString(),
23
- range,
24
- events,
25
- redactionSummary: summarize(events),
26
- };
27
- }
1
+ /**
2
+ * Redacted audit export bundle for operator / retention tooling (T5.3.1).
3
+ *
4
+ * Core logic: load range, attach export metadata; payloads are already redacted at envelope build time.
5
+ *
6
+ * Dependencies: same range loader pattern as verifyAuditHashChain.
7
+ *
8
+ * Test coverage: tests/integration/observability/explain-query-export.test.ts
9
+ */
10
+ import * as crypto from "node:crypto";
11
+ function summarize(events) {
12
+ const ids = new Set();
13
+ for (const e of events) {
14
+ ids.add(e.redaction.manifestId);
15
+ }
16
+ return { eventCount: events.length, manifestIds: [...ids] };
17
+ }
18
+ export async function exportAuditBundle(range, deps) {
19
+ const events = [...(await deps.loadRange(range.from, range.to, range.families))].sort((a, b) => a.sequence - b.sequence);
20
+ return {
21
+ bundleId: crypto.randomUUID(),
22
+ generatedAt: new Date().toISOString(),
23
+ range,
24
+ events,
25
+ redactionSummary: summarize(events),
26
+ };
27
+ }
@@ -1,46 +1,46 @@
1
- import type { ObservabilityDatabase } from "../db/index.js";
2
- import type { DecisionRecord } from "../../shared/types/continuity.js";
3
- export interface QuietLifecycleEvent {
4
- id: string;
5
- tickId: string;
6
- eventType: "quiet.entered" | "quiet.skipped" | "quiet.interrupted" | "quiet.resumed" | "quiet.suppressed";
7
- reason?: string;
8
- suppressedBy?: string;
9
- reflectionCandidates?: string[];
10
- createdAt: string;
11
- }
12
- export interface OutreachDecision {
13
- id: string;
14
- tickId: string;
15
- eventType: "outreach.considered" | "outreach.denied" | "outreach.deferred" | "outreach.sent";
16
- platformId?: string;
17
- targetUserId?: string;
18
- valueScore?: number;
19
- suppressionReason?: string;
20
- messagePreview?: string;
21
- createdAt: string;
22
- }
23
- export interface HeartbeatDecisionEvent {
24
- id: string;
25
- tickId: string;
26
- traceId: string;
27
- runtimeScope: "rhythm" | "user_task" | "user_reply";
28
- triggerSource: "heartbeat_bridge" | "user_task" | "user_reply" | "interrupt" | "resume";
29
- decisionStatus: "heartbeat_ok" | "intent_selected" | "denied" | "deferred" | "runtime_carrier_only" | "delivery_unavailable";
30
- reasons: string[];
31
- intentId?: string;
32
- mode: "active" | "quiet" | "maintenance_only" | "paused_for_interrupt";
33
- createdAt: string;
34
- }
35
- export declare class DecisionLedger {
36
- private db;
37
- constructor(db: ObservabilityDatabase);
38
- recordDecision(record: DecisionRecord): Promise<void>;
39
- recordHeartbeatDecision(event: HeartbeatDecisionEvent): Promise<void>;
40
- recordQuietLifecycle(event: QuietLifecycleEvent): Promise<void>;
41
- recordOutreachDecision(event: OutreachDecision): Promise<void>;
42
- queryByTickId(tickId: string): Promise<DecisionRecord[]>;
43
- queryByTraceId(traceId: string): Promise<DecisionRecord | null>;
44
- queryByIntentId(intentId: string): Promise<DecisionRecord[]>;
45
- private mapToDecisionRecord;
46
- }
1
+ import type { ObservabilityDatabase } from "../db/index.js";
2
+ import type { DecisionRecord } from "../../shared/types/continuity.js";
3
+ export interface QuietLifecycleEvent {
4
+ id: string;
5
+ tickId: string;
6
+ eventType: "quiet.entered" | "quiet.skipped" | "quiet.interrupted" | "quiet.resumed" | "quiet.suppressed";
7
+ reason?: string;
8
+ suppressedBy?: string;
9
+ reflectionCandidates?: string[];
10
+ createdAt: string;
11
+ }
12
+ export interface OutreachDecision {
13
+ id: string;
14
+ tickId: string;
15
+ eventType: "outreach.considered" | "outreach.denied" | "outreach.deferred" | "outreach.sent";
16
+ platformId?: string;
17
+ targetUserId?: string;
18
+ valueScore?: number;
19
+ suppressionReason?: string;
20
+ messagePreview?: string;
21
+ createdAt: string;
22
+ }
23
+ export interface HeartbeatDecisionEvent {
24
+ id: string;
25
+ tickId: string;
26
+ traceId: string;
27
+ runtimeScope: "rhythm" | "user_task" | "user_reply";
28
+ triggerSource: "heartbeat_bridge" | "user_task" | "user_reply" | "interrupt" | "resume";
29
+ decisionStatus: "heartbeat_ok" | "intent_selected" | "denied" | "deferred" | "runtime_carrier_only" | "delivery_unavailable";
30
+ reasons: string[];
31
+ intentId?: string;
32
+ mode: "active" | "quiet" | "maintenance_only" | "paused_for_interrupt";
33
+ createdAt: string;
34
+ }
35
+ export declare class DecisionLedger {
36
+ private db;
37
+ constructor(db: ObservabilityDatabase);
38
+ recordDecision(record: DecisionRecord): Promise<void>;
39
+ recordHeartbeatDecision(event: HeartbeatDecisionEvent): Promise<void>;
40
+ recordQuietLifecycle(event: QuietLifecycleEvent): Promise<void>;
41
+ recordOutreachDecision(event: OutreachDecision): Promise<void>;
42
+ queryByTickId(tickId: string): Promise<DecisionRecord[]>;
43
+ queryByTraceId(traceId: string): Promise<DecisionRecord | null>;
44
+ queryByIntentId(intentId: string): Promise<DecisionRecord[]>;
45
+ private mapToDecisionRecord;
46
+ }
@@ -1,161 +1,161 @@
1
- import { eq } from "drizzle-orm";
2
- import { decisionLedger } from "../db/schema/index.js";
3
- import { redactEvent } from "../redaction/manifest.js";
4
- import { persistRedactionManifest } from "./redaction-store.js";
5
- export class DecisionLedger {
6
- db;
7
- constructor(db) {
8
- this.db = db;
9
- }
10
- async recordDecision(record) {
11
- const { redacted, manifest } = redactEvent(record);
12
- await this.db.db.insert(decisionLedger).values({
13
- id: redacted.id,
14
- tickId: redacted.tickId,
15
- traceId: redacted.traceId,
16
- intentId: redacted.intentId ?? null,
17
- platformId: redacted.platformId ?? null,
18
- verdict: redacted.verdict,
19
- mode: redacted.mode,
20
- reasons: JSON.stringify(redacted.reasons),
21
- reasonCodes: JSON.stringify(redacted.reasonCodes),
22
- decisionBasis: redacted.decisionBasis,
23
- evidenceRefs: JSON.stringify(redacted.evidenceRefs),
24
- modelEvalRef: redacted.modelEvalRef ?? null,
25
- createdAt: redacted.createdAt,
26
- });
27
- await persistRedactionManifest(this.db, redacted.id, "decision.recorded", manifest);
28
- }
29
- async recordHeartbeatDecision(event) {
30
- const { redacted, manifest } = redactEvent(event);
31
- // Map decisionStatus to existing verdict field without changing business semantics
32
- const verdict = mapHeartbeatStatusToVerdict(redacted.decisionStatus);
33
- await this.db.db.insert(decisionLedger).values({
34
- id: redacted.id,
35
- tickId: redacted.tickId,
36
- traceId: redacted.traceId,
37
- intentId: redacted.intentId ?? null,
38
- platformId: null,
39
- verdict,
40
- mode: redacted.mode,
41
- reasons: JSON.stringify(redacted.reasons),
42
- reasonCodes: JSON.stringify(["heartbeat_decision"]),
43
- decisionBasis: "rule_only",
44
- evidenceRefs: JSON.stringify([
45
- `scope:${redacted.runtimeScope}`,
46
- `trigger:${redacted.triggerSource}`,
47
- `status:${redacted.decisionStatus}`,
48
- ].filter(Boolean)),
49
- modelEvalRef: null,
50
- createdAt: redacted.createdAt,
51
- });
52
- await persistRedactionManifest(this.db, redacted.id, "heartbeat.decision", manifest);
53
- }
54
- async recordQuietLifecycle(event) {
55
- const { redacted, manifest } = redactEvent(event);
56
- await this.db.db.insert(decisionLedger).values({
57
- id: redacted.id,
58
- tickId: redacted.tickId,
59
- traceId: `quiet-${redacted.eventType}-${redacted.id}`,
60
- intentId: null,
61
- platformId: null,
62
- verdict: "allow",
63
- mode: "quiet",
64
- reasons: JSON.stringify([redacted.eventType, redacted.reason ?? ""].filter(Boolean)),
65
- reasonCodes: JSON.stringify(["quiet_lifecycle"]),
66
- decisionBasis: "rule_only",
67
- evidenceRefs: JSON.stringify(redacted.reflectionCandidates ?? []),
68
- modelEvalRef: null,
69
- createdAt: redacted.createdAt,
70
- });
71
- await persistRedactionManifest(this.db, redacted.id, redacted.eventType, manifest);
72
- }
73
- async recordOutreachDecision(event) {
74
- const { redacted, manifest } = redactEvent(event);
75
- const verdict = redacted.eventType === "outreach.sent"
76
- ? "allow"
77
- : redacted.eventType === "outreach.deferred" || redacted.eventType === "outreach.considered"
78
- ? "defer"
79
- : "deny";
80
- await this.db.db.insert(decisionLedger).values({
81
- id: redacted.id,
82
- tickId: redacted.tickId,
83
- traceId: `outreach-${redacted.eventType}-${redacted.id}`,
84
- intentId: null,
85
- platformId: redacted.platformId ?? null,
86
- verdict,
87
- mode: "active",
88
- reasons: JSON.stringify([
89
- redacted.eventType,
90
- redacted.valueScore?.toString() ?? "",
91
- redacted.suppressionReason ?? "",
92
- ].filter(Boolean)),
93
- reasonCodes: JSON.stringify(["outreach_decision"]),
94
- decisionBasis: "score_based",
95
- evidenceRefs: JSON.stringify([redacted.targetUserId ?? ""].filter(Boolean)),
96
- modelEvalRef: null,
97
- createdAt: redacted.createdAt,
98
- });
99
- await persistRedactionManifest(this.db, redacted.id, redacted.eventType, manifest);
100
- }
101
- async queryByTickId(tickId) {
102
- const results = await this.db.db
103
- .select()
104
- .from(decisionLedger)
105
- .where(eq(decisionLedger.tickId, tickId));
106
- return results.map(this.mapToDecisionRecord);
107
- }
108
- async queryByTraceId(traceId) {
109
- const results = await this.db.db
110
- .select()
111
- .from(decisionLedger)
112
- .where(eq(decisionLedger.traceId, traceId))
113
- .limit(1);
114
- return results[0] ? this.mapToDecisionRecord(results[0]) : null;
115
- }
116
- async queryByIntentId(intentId) {
117
- const results = await this.db.db
118
- .select()
119
- .from(decisionLedger)
120
- .where(eq(decisionLedger.intentId, intentId));
121
- return results.map(this.mapToDecisionRecord);
122
- }
123
- mapToDecisionRecord(row) {
124
- return {
125
- id: row.id,
126
- tickId: row.tickId,
127
- traceId: row.traceId,
128
- intentId: row.intentId ?? undefined,
129
- platformId: row.platformId ?? undefined,
130
- verdict: row.verdict,
131
- mode: row.mode,
132
- reasons: JSON.parse(row.reasons),
133
- reasonCodes: JSON.parse(row.reasonCodes),
134
- decisionBasis: row.decisionBasis,
135
- evidenceRefs: JSON.parse(row.evidenceRefs),
136
- modelEvalRef: row.modelEvalRef ?? undefined,
137
- createdAt: row.createdAt,
138
- };
139
- }
140
- }
141
- /**
142
- * Map heartbeat decision status to existing verdict field.
143
- * This preserves the existing DecisionRecord semantics while allowing
144
- * heartbeat-specific status to be recoverable from evidenceRefs.
145
- */
146
- function mapHeartbeatStatusToVerdict(status) {
147
- switch (status) {
148
- case "intent_selected":
149
- return "allow";
150
- case "denied":
151
- return "deny";
152
- case "deferred":
153
- return "defer";
154
- case "heartbeat_ok":
155
- return "defer";
156
- case "runtime_carrier_only":
157
- return "defer";
158
- case "delivery_unavailable":
159
- return "deny";
160
- }
161
- }
1
+ import { eq } from "drizzle-orm";
2
+ import { decisionLedger } from "../db/schema/index.js";
3
+ import { redactEvent } from "../redaction/manifest.js";
4
+ import { persistRedactionManifest } from "./redaction-store.js";
5
+ export class DecisionLedger {
6
+ db;
7
+ constructor(db) {
8
+ this.db = db;
9
+ }
10
+ async recordDecision(record) {
11
+ const { redacted, manifest } = redactEvent(record);
12
+ await this.db.db.insert(decisionLedger).values({
13
+ id: redacted.id,
14
+ tickId: redacted.tickId,
15
+ traceId: redacted.traceId,
16
+ intentId: redacted.intentId ?? null,
17
+ platformId: redacted.platformId ?? null,
18
+ verdict: redacted.verdict,
19
+ mode: redacted.mode,
20
+ reasons: JSON.stringify(redacted.reasons),
21
+ reasonCodes: JSON.stringify(redacted.reasonCodes),
22
+ decisionBasis: redacted.decisionBasis,
23
+ evidenceRefs: JSON.stringify(redacted.evidenceRefs),
24
+ modelEvalRef: redacted.modelEvalRef ?? null,
25
+ createdAt: redacted.createdAt,
26
+ });
27
+ await persistRedactionManifest(this.db, redacted.id, "decision.recorded", manifest);
28
+ }
29
+ async recordHeartbeatDecision(event) {
30
+ const { redacted, manifest } = redactEvent(event);
31
+ // Map decisionStatus to existing verdict field without changing business semantics
32
+ const verdict = mapHeartbeatStatusToVerdict(redacted.decisionStatus);
33
+ await this.db.db.insert(decisionLedger).values({
34
+ id: redacted.id,
35
+ tickId: redacted.tickId,
36
+ traceId: redacted.traceId,
37
+ intentId: redacted.intentId ?? null,
38
+ platformId: null,
39
+ verdict,
40
+ mode: redacted.mode,
41
+ reasons: JSON.stringify(redacted.reasons),
42
+ reasonCodes: JSON.stringify(["heartbeat_decision"]),
43
+ decisionBasis: "rule_only",
44
+ evidenceRefs: JSON.stringify([
45
+ `scope:${redacted.runtimeScope}`,
46
+ `trigger:${redacted.triggerSource}`,
47
+ `status:${redacted.decisionStatus}`,
48
+ ].filter(Boolean)),
49
+ modelEvalRef: null,
50
+ createdAt: redacted.createdAt,
51
+ });
52
+ await persistRedactionManifest(this.db, redacted.id, "heartbeat.decision", manifest);
53
+ }
54
+ async recordQuietLifecycle(event) {
55
+ const { redacted, manifest } = redactEvent(event);
56
+ await this.db.db.insert(decisionLedger).values({
57
+ id: redacted.id,
58
+ tickId: redacted.tickId,
59
+ traceId: `quiet-${redacted.eventType}-${redacted.id}`,
60
+ intentId: null,
61
+ platformId: null,
62
+ verdict: "allow",
63
+ mode: "quiet",
64
+ reasons: JSON.stringify([redacted.eventType, redacted.reason ?? ""].filter(Boolean)),
65
+ reasonCodes: JSON.stringify(["quiet_lifecycle"]),
66
+ decisionBasis: "rule_only",
67
+ evidenceRefs: JSON.stringify(redacted.reflectionCandidates ?? []),
68
+ modelEvalRef: null,
69
+ createdAt: redacted.createdAt,
70
+ });
71
+ await persistRedactionManifest(this.db, redacted.id, redacted.eventType, manifest);
72
+ }
73
+ async recordOutreachDecision(event) {
74
+ const { redacted, manifest } = redactEvent(event);
75
+ const verdict = redacted.eventType === "outreach.sent"
76
+ ? "allow"
77
+ : redacted.eventType === "outreach.deferred" || redacted.eventType === "outreach.considered"
78
+ ? "defer"
79
+ : "deny";
80
+ await this.db.db.insert(decisionLedger).values({
81
+ id: redacted.id,
82
+ tickId: redacted.tickId,
83
+ traceId: `outreach-${redacted.eventType}-${redacted.id}`,
84
+ intentId: null,
85
+ platformId: redacted.platformId ?? null,
86
+ verdict,
87
+ mode: "active",
88
+ reasons: JSON.stringify([
89
+ redacted.eventType,
90
+ redacted.valueScore?.toString() ?? "",
91
+ redacted.suppressionReason ?? "",
92
+ ].filter(Boolean)),
93
+ reasonCodes: JSON.stringify(["outreach_decision"]),
94
+ decisionBasis: "score_based",
95
+ evidenceRefs: JSON.stringify([redacted.targetUserId ?? ""].filter(Boolean)),
96
+ modelEvalRef: null,
97
+ createdAt: redacted.createdAt,
98
+ });
99
+ await persistRedactionManifest(this.db, redacted.id, redacted.eventType, manifest);
100
+ }
101
+ async queryByTickId(tickId) {
102
+ const results = await this.db.db
103
+ .select()
104
+ .from(decisionLedger)
105
+ .where(eq(decisionLedger.tickId, tickId));
106
+ return results.map(this.mapToDecisionRecord);
107
+ }
108
+ async queryByTraceId(traceId) {
109
+ const results = await this.db.db
110
+ .select()
111
+ .from(decisionLedger)
112
+ .where(eq(decisionLedger.traceId, traceId))
113
+ .limit(1);
114
+ return results[0] ? this.mapToDecisionRecord(results[0]) : null;
115
+ }
116
+ async queryByIntentId(intentId) {
117
+ const results = await this.db.db
118
+ .select()
119
+ .from(decisionLedger)
120
+ .where(eq(decisionLedger.intentId, intentId));
121
+ return results.map(this.mapToDecisionRecord);
122
+ }
123
+ mapToDecisionRecord(row) {
124
+ return {
125
+ id: row.id,
126
+ tickId: row.tickId,
127
+ traceId: row.traceId,
128
+ intentId: row.intentId ?? undefined,
129
+ platformId: row.platformId ?? undefined,
130
+ verdict: row.verdict,
131
+ mode: row.mode,
132
+ reasons: JSON.parse(row.reasons),
133
+ reasonCodes: JSON.parse(row.reasonCodes),
134
+ decisionBasis: row.decisionBasis,
135
+ evidenceRefs: JSON.parse(row.evidenceRefs),
136
+ modelEvalRef: row.modelEvalRef ?? undefined,
137
+ createdAt: row.createdAt,
138
+ };
139
+ }
140
+ }
141
+ /**
142
+ * Map heartbeat decision status to existing verdict field.
143
+ * This preserves the existing DecisionRecord semantics while allowing
144
+ * heartbeat-specific status to be recoverable from evidenceRefs.
145
+ */
146
+ function mapHeartbeatStatusToVerdict(status) {
147
+ switch (status) {
148
+ case "intent_selected":
149
+ return "allow";
150
+ case "denied":
151
+ return "deny";
152
+ case "deferred":
153
+ return "defer";
154
+ case "heartbeat_ok":
155
+ return "defer";
156
+ case "runtime_carrier_only":
157
+ return "defer";
158
+ case "delivery_unavailable":
159
+ return "deny";
160
+ }
161
+ }
@@ -1,41 +1,41 @@
1
- import type { ObservabilityDatabase } from "../db/index.js";
2
- import type { AnchorChangeAudit } from "../../shared/types/continuity.js";
3
- export interface CredentialLifecycleAudit {
4
- id: string;
5
- platformId: string;
6
- credentialId: string;
7
- statusFrom?: string;
8
- statusTo: string;
9
- verificationDeadline?: string;
10
- attemptsRemaining?: number;
11
- explanationCapsule: string;
12
- createdAt: string;
13
- }
14
- export declare class GovernanceAudit {
15
- private db;
16
- constructor(db: ObservabilityDatabase);
17
- recordAnchorChangeAudit(event: AnchorChangeAudit): Promise<void>;
18
- /**
19
- * Generic governance-plane events (T5.1.2): fallback_written, effect_commit_advanced, connector_failure, etc.
20
- * traceId is stored on target_asset_id for explain/trace correlation until a dedicated column exists.
21
- */
22
- recordOperationalGovernanceEvent(input: {
23
- id: string;
24
- eventType: string;
25
- traceId: string;
26
- statusTo: string;
27
- reason: string;
28
- assetPath?: string;
29
- supportingSources?: string[];
30
- createdAt?: string;
31
- }): Promise<void>;
32
- recordCredentialLifecycle(event: CredentialLifecycleAudit): Promise<void>;
33
- recordProposalApply(proposalId: string, targetAssetId: string, assetPath: string, beforeHash: string | undefined, afterHash: string | undefined, supportingSources: string[], reason: string): Promise<void>;
34
- recordProposalReject(proposalId: string, targetAssetId: string, assetPath: string, reason: string): Promise<void>;
35
- queryByProposalId(proposalId: string): Promise<AnchorChangeAudit[]>;
36
- queryByAssetId(assetId: string): Promise<AnchorChangeAudit[]>;
37
- queryByEventType(eventType: string): Promise<AnchorChangeAudit[]>;
38
- queryCredentialByPlatform(platformId: string): Promise<CredentialLifecycleAudit[]>;
39
- private mapToAnchorAudit;
40
- private mapToCredentialAudit;
41
- }
1
+ import type { ObservabilityDatabase } from "../db/index.js";
2
+ import type { AnchorChangeAudit } from "../../shared/types/continuity.js";
3
+ export interface CredentialLifecycleAudit {
4
+ id: string;
5
+ platformId: string;
6
+ credentialId: string;
7
+ statusFrom?: string;
8
+ statusTo: string;
9
+ verificationDeadline?: string;
10
+ attemptsRemaining?: number;
11
+ explanationCapsule: string;
12
+ createdAt: string;
13
+ }
14
+ export declare class GovernanceAudit {
15
+ private db;
16
+ constructor(db: ObservabilityDatabase);
17
+ recordAnchorChangeAudit(event: AnchorChangeAudit): Promise<void>;
18
+ /**
19
+ * Generic governance-plane events (T5.1.2): fallback_written, effect_commit_advanced, connector_failure, etc.
20
+ * traceId is stored on target_asset_id for explain/trace correlation until a dedicated column exists.
21
+ */
22
+ recordOperationalGovernanceEvent(input: {
23
+ id: string;
24
+ eventType: string;
25
+ traceId: string;
26
+ statusTo: string;
27
+ reason: string;
28
+ assetPath?: string;
29
+ supportingSources?: string[];
30
+ createdAt?: string;
31
+ }): Promise<void>;
32
+ recordCredentialLifecycle(event: CredentialLifecycleAudit): Promise<void>;
33
+ recordProposalApply(proposalId: string, targetAssetId: string, assetPath: string, beforeHash: string | undefined, afterHash: string | undefined, supportingSources: string[], reason: string): Promise<void>;
34
+ recordProposalReject(proposalId: string, targetAssetId: string, assetPath: string, reason: string): Promise<void>;
35
+ queryByProposalId(proposalId: string): Promise<AnchorChangeAudit[]>;
36
+ queryByAssetId(assetId: string): Promise<AnchorChangeAudit[]>;
37
+ queryByEventType(eventType: string): Promise<AnchorChangeAudit[]>;
38
+ queryCredentialByPlatform(platformId: string): Promise<CredentialLifecycleAudit[]>;
39
+ private mapToAnchorAudit;
40
+ private mapToCredentialAudit;
41
+ }