@haaaiawd/second-nature 0.2.9 → 0.2.13

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 (115) hide show
  1. package/index.js +102 -6
  2. package/openclaw.plugin.json +2 -5
  3. package/package.json +1 -1
  4. package/runtime/cli/commands/index.js +85 -11
  5. package/runtime/cli/host-capability/host-discovery-port.d.ts +85 -0
  6. package/runtime/cli/host-capability/host-discovery-port.js +137 -0
  7. package/runtime/cli/host-capability/probe-host-capability.js +1 -1
  8. package/runtime/cli/host-capability/types.d.ts +2 -7
  9. package/runtime/cli/host-capability/types.js +0 -5
  10. package/runtime/cli/ops/heartbeat-surface.d.ts +5 -3
  11. package/runtime/cli/ops/heartbeat-surface.js +38 -8
  12. package/runtime/cli/ops/ops-router.d.ts +6 -2
  13. package/runtime/cli/ops/ops-router.js +1275 -1147
  14. package/runtime/cli/ops/workspace-heartbeat-runner.js +2 -5
  15. package/runtime/connectors/base/normalized-evidence-content.d.ts +4 -0
  16. package/runtime/connectors/base/normalized-evidence-content.js +21 -2
  17. package/runtime/connectors/evidence-normalizer.js +32 -1
  18. package/runtime/connectors/manifest/manifest-schema.d.ts +2 -2
  19. package/runtime/connectors/registry/dynamic-connector-registry.js +16 -1
  20. package/runtime/connectors/services/connector-executor-adapter.js +54 -35
  21. package/runtime/core/second-nature/action/action-closure-recorder.d.ts +4 -0
  22. package/runtime/core/second-nature/action/action-closure-recorder.js +51 -38
  23. package/runtime/core/second-nature/action/action-proposal-builder.js +8 -34
  24. package/runtime/core/second-nature/action/policy-bound-dispatch.d.ts +2 -0
  25. package/runtime/core/second-nature/action/policy-bound-dispatch.js +10 -5
  26. package/runtime/core/second-nature/control-plane/accepted-projection-loader.js +1 -11
  27. package/runtime/core/second-nature/control-plane/cycle-finalizer.d.ts +82 -0
  28. package/runtime/core/second-nature/control-plane/cycle-finalizer.js +187 -0
  29. package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.d.ts +1 -0
  30. package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.js +23 -15
  31. package/runtime/core/second-nature/control-plane/real-runtime-spine.d.ts +2 -0
  32. package/runtime/core/second-nature/control-plane/real-runtime-spine.js +2 -1
  33. package/runtime/core/second-nature/guidance/guidance-proposal-consumer.d.ts +2 -1
  34. package/runtime/core/second-nature/guidance/guidance-proposal-consumer.js +4 -2
  35. package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +4 -3
  36. package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +3 -2
  37. package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +3 -2
  38. package/runtime/core/second-nature/orchestrator/intent-planner.js +4 -2
  39. package/runtime/core/second-nature/orchestrator/narrative-update.js +1 -2
  40. package/runtime/core/second-nature/orchestrator/platform-capability-router.d.ts +2 -2
  41. package/runtime/core/second-nature/orchestrator/platform-capability-router.js +1 -1
  42. package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +2 -3
  43. package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +2 -2
  44. package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +6 -1
  45. package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +3 -14
  46. package/runtime/core/second-nature/outreach/judge-outreach.d.ts +6 -5
  47. package/runtime/core/second-nature/perception/judgment-engine.js +10 -16
  48. package/runtime/core/second-nature/perception/perception-builder.js +15 -11
  49. package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +13 -15
  50. package/runtime/core/second-nature/quiet-dream/daily-rhythm-scheduler.js +40 -16
  51. package/runtime/core/second-nature/quiet-dream/dream-consolidation-runner.d.ts +5 -1
  52. package/runtime/core/second-nature/quiet-dream/dream-consolidation-runner.js +68 -29
  53. package/runtime/core/second-nature/quiet-dream/dream-scheduler.js +2 -3
  54. package/runtime/core/second-nature/quiet-dream/memory-projection-lifecycle.js +2 -13
  55. package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.d.ts +1 -0
  56. package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.js +34 -11
  57. package/runtime/core/second-nature/types.d.ts +2 -9
  58. package/runtime/dream/dream-engine.js +11 -4
  59. package/runtime/guidance/outreach-draft-schema.d.ts +12 -12
  60. package/runtime/guidance/persona-selection.js +5 -0
  61. package/runtime/guidance/template-registry.js +6 -1
  62. package/runtime/guidance/types.d.ts +2 -2
  63. package/runtime/observability/causal-loop-health.d.ts +2 -1
  64. package/runtime/observability/causal-loop-health.js +7 -0
  65. package/runtime/observability/living-loop-health-gate.js +2 -8
  66. package/runtime/observability/loop-stage-event-sink.js +6 -2
  67. package/runtime/observability/loop-status.d.ts +2 -0
  68. package/runtime/observability/loop-status.js +14 -1
  69. package/runtime/observability/services/heartbeat-digest-assembler.d.ts +3 -0
  70. package/runtime/observability/services/heartbeat-digest-assembler.js +9 -0
  71. package/runtime/observability/services/lived-experience-audit.d.ts +7 -7
  72. package/runtime/shared/degraded-status-classifier.d.ts +16 -0
  73. package/runtime/shared/degraded-status-classifier.js +68 -0
  74. package/runtime/shared/evidence-level-classifier.d.ts +61 -0
  75. package/runtime/shared/evidence-level-classifier.js +116 -0
  76. package/runtime/shared/provenance-tier.d.ts +37 -0
  77. package/runtime/shared/provenance-tier.js +97 -0
  78. package/runtime/shared/serialization.d.ts +17 -0
  79. package/runtime/shared/serialization.js +27 -0
  80. package/runtime/shared/setup-ack.d.ts +54 -0
  81. package/runtime/shared/setup-ack.js +108 -0
  82. package/runtime/shared/source-ref-compat.d.ts +26 -0
  83. package/runtime/shared/source-ref-compat.js +64 -0
  84. package/runtime/shared/types/goal.d.ts +4 -4
  85. package/runtime/shared/types/goal.js +1 -1
  86. package/runtime/shared/types/index.d.ts +1 -0
  87. package/runtime/shared/types/index.js +1 -3
  88. package/runtime/shared/types/source-ref.d.ts +2 -2
  89. package/runtime/shared/types/v7-entities.d.ts +5 -5
  90. package/runtime/shared/types/v7-entities.js +1 -1
  91. package/runtime/shared/types/v8-contracts.d.ts +13 -2
  92. package/runtime/storage/db/index.js +60 -12
  93. package/runtime/storage/db/migrations/index.js +4 -0
  94. package/runtime/storage/db/migrations/v8-004-schema-closure.d.ts +19 -0
  95. package/runtime/storage/db/migrations/v8-004-schema-closure.js +74 -0
  96. package/runtime/storage/db/migrations/v8-005-single-status-schema.d.ts +11 -0
  97. package/runtime/storage/db/migrations/v8-005-single-status-schema.js +16 -0
  98. package/runtime/storage/db/migrations/v8-006-loop-stage-event-proof-trace-columns.d.ts +9 -0
  99. package/runtime/storage/db/migrations/v8-006-loop-stage-event-proof-trace-columns.js +15 -0
  100. package/runtime/storage/db/schema/v8-entities.d.ts +65 -84
  101. package/runtime/storage/db/schema/v8-entities.js +8 -7
  102. package/runtime/storage/delivery/types.d.ts +2 -2
  103. package/runtime/storage/fallback/load-operator-fallback.d.ts +2 -2
  104. package/runtime/storage/fallback/operator-fallback-types.d.ts +2 -2
  105. package/runtime/storage/fallback/operator-fallback-view.d.ts +2 -2
  106. package/runtime/storage/index.d.ts +1 -1
  107. package/runtime/storage/life-evidence/types.d.ts +5 -5
  108. package/runtime/storage/quiet/quiet-artifact-types.d.ts +4 -4
  109. package/runtime/storage/quiet/quiet-artifact-writer.d.ts +2 -2
  110. package/runtime/storage/services/write-validation-gate.d.ts +1 -1
  111. package/runtime/storage/services/write-validation-gate.js +15 -3
  112. package/runtime/storage/snapshots/types.d.ts +8 -8
  113. package/runtime/storage/user-interest/types.d.ts +3 -3
  114. package/runtime/storage/v8-state-stores.d.ts +15 -3
  115. package/runtime/storage/v8-state-stores.js +60 -39
@@ -0,0 +1,64 @@
1
+ export function sourceRefFamilyFromLegacyKind(kind) {
2
+ switch (kind) {
3
+ case "connector_result":
4
+ return "connector_result";
5
+ case "decision_record":
6
+ return "judgment";
7
+ case "platform_item":
8
+ case "user_anchor":
9
+ return "evidence";
10
+ case "workspace_artifact":
11
+ case "host_report":
12
+ case "fallback_artifact":
13
+ default:
14
+ return "audit";
15
+ }
16
+ }
17
+ export function legacyKindFromSourceRef(ref) {
18
+ // Check family first so canonical connector_result refs with platform://
19
+ // URIs are not incorrectly downgraded to "platform_item".
20
+ if (ref.family === "connector_result") {
21
+ return "connector_result";
22
+ }
23
+ if (ref.uri.startsWith("platform://")) {
24
+ return "platform_item";
25
+ }
26
+ if (ref.uri.startsWith("goal://") || ref.uri.startsWith("workspace://")) {
27
+ return "workspace_artifact";
28
+ }
29
+ if (ref.id.startsWith("anchor:") || ref.id.startsWith("curated:") || /(?:USER|MEMORY)\.md$/i.test(ref.uri)) {
30
+ return "user_anchor";
31
+ }
32
+ switch (ref.family) {
33
+ case "judgment":
34
+ return "decision_record";
35
+ case "evidence":
36
+ case "perception":
37
+ return "platform_item";
38
+ case "audit":
39
+ case "action_closure":
40
+ case "quiet_review":
41
+ case "dream_run":
42
+ case "memory_projection":
43
+ case "projection":
44
+ case "tool_experience":
45
+ default:
46
+ return "workspace_artifact";
47
+ }
48
+ }
49
+ export function toCanonicalSourceRef(ref) {
50
+ return {
51
+ id: ref.id,
52
+ uri: ref.uri,
53
+ family: sourceRefFamilyFromLegacyKind(ref.kind),
54
+ redactionClass: "none",
55
+ };
56
+ }
57
+ export function makeCanonicalSourceRef(input) {
58
+ return {
59
+ id: input.id,
60
+ family: input.family,
61
+ uri: input.uri,
62
+ redactionClass: input.redactionClass ?? "none",
63
+ };
64
+ }
@@ -7,7 +7,7 @@
7
7
  * - `status` supports full v7 lifecycle including paused → expired/replaced.
8
8
  *
9
9
  * Dependencies:
10
- * - `SourceRef` from `./source-ref.js` for grounding.
10
+ * - `SourceRefTuple` from `./source-ref.js` for grounding.
11
11
  *
12
12
  * Boundary:
13
13
  * - Used by state-memory (GoalLifecycleStore), control-plane
@@ -17,7 +17,7 @@
17
17
  * Test coverage: tests/unit/shared/v7-entities.test.ts (invalid kind
18
18
  * `@ts-expect-error` compile guard).
19
19
  */
20
- import type { SourceRef } from "./source-ref.js";
20
+ import type { SourceRefTuple } from "./source-ref.js";
21
21
  export type AgentGoalKind = "short_term" | "long_term" | "habit" | "maintenance" | "passive_sensing" | "outreach" | "exploration";
22
22
  export type AgentGoalStatus = "proposal" | "accepted" | "rejected" | "completed" | "paused" | "expired" | "replaced";
23
23
  export type AgentGoalOrigin = "owner_set" | "agent_proposed" | "policy_seeded";
@@ -32,7 +32,7 @@ export interface AgentGoal {
32
32
  completionCriteria: string;
33
33
  risk: "low" | "medium" | "high";
34
34
  priorityHint: number;
35
- sourceRefs: SourceRef;
35
+ sourceRefs: SourceRefTuple;
36
36
  acceptedBy?: "owner" | "policy_allowlist";
37
37
  expiresAt?: string;
38
38
  createdAt: string;
@@ -48,7 +48,7 @@ export interface AgentGoalWrite {
48
48
  completionCriteria: string;
49
49
  risk: "low" | "medium" | "high";
50
50
  priorityHint: number;
51
- sourceRefs: SourceRef;
51
+ sourceRefs: SourceRefTuple;
52
52
  acceptedBy?: "owner" | "policy_allowlist";
53
53
  expiresAt?: string;
54
54
  createdAt: string;
@@ -7,7 +7,7 @@
7
7
  * - `status` supports full v7 lifecycle including paused → expired/replaced.
8
8
  *
9
9
  * Dependencies:
10
- * - `SourceRef` from `./source-ref.js` for grounding.
10
+ * - `SourceRefTuple` from `./source-ref.js` for grounding.
11
11
  *
12
12
  * Boundary:
13
13
  * - Used by state-memory (GoalLifecycleStore), control-plane
@@ -4,3 +4,4 @@ export * from "./outreach.js";
4
4
  export * from "./source-ref.js";
5
5
  export * from "./goal.js";
6
6
  export * from "./v7-entities.js";
7
+ export * from "./v8-contracts.js";
@@ -4,6 +4,4 @@ export * from "./outreach.js";
4
4
  export * from "./source-ref.js";
5
5
  export * from "./goal.js";
6
6
  export * from "./v7-entities.js";
7
- // v8-contracts intentionally NOT re-exported from index to avoid SourceRef
8
- // name collision with v7 tuple type. v8 consumers import directly from
9
- // `./v8-contracts.js`.
7
+ export * from "./v8-contracts.js";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SourceRef — v7 non-empty tuple for source grounding.
2
+ * SourceRefTuple — v7 non-empty tuple for source grounding.
3
3
  *
4
4
  * Core logic: Every fact claim must carry at least one source reference.
5
5
  * DR-025 enforces non-empty at compile time. Empty array assignments are
@@ -11,4 +11,4 @@
11
11
  * Test coverage: tests/unit/shared/v7-entities.test.ts (compile-time
12
12
  * `@ts-expect-error` guard for empty tuple).
13
13
  */
14
- export type SourceRef = readonly [string, ...string[]];
14
+ export type SourceRefTuple = readonly [string, ...string[]];
@@ -12,7 +12,7 @@
12
12
  * - ADR-002/003/007/008 — entity semantics
13
13
  *
14
14
  * Dependencies:
15
- * - `SourceRef` from `./source-ref.js`
15
+ * - `SourceRefTuple` from `./source-ref.js`
16
16
  * - `AgentGoal` from `./goal.js`
17
17
  *
18
18
  * Boundary:
@@ -24,7 +24,7 @@
24
24
  *
25
25
  * Test coverage: tests/unit/shared/v7-entities.test.ts
26
26
  */
27
- import type { SourceRef } from "./source-ref.js";
27
+ import type { SourceRefTuple } from "./source-ref.js";
28
28
  import type { AgentGoal } from "./goal.js";
29
29
  export interface PlatformHandle {
30
30
  platformId: string;
@@ -60,7 +60,7 @@ export interface ToolExperience {
60
60
  failureClass?: string;
61
61
  latencyMs: number;
62
62
  evidenceQuality: number;
63
- sourceRefs: SourceRef;
63
+ sourceRefs: SourceRefTuple;
64
64
  triggerSource: ToolExperienceTriggerSource;
65
65
  createdAt: string;
66
66
  }
@@ -97,7 +97,7 @@ export interface QuietClaim {
97
97
  claimId: string;
98
98
  kind: QuietClaimKind;
99
99
  text: string;
100
- sourceRefs: SourceRef;
100
+ sourceRefs: SourceRefTuple;
101
101
  confidence: number;
102
102
  createdAt: string;
103
103
  }
@@ -107,7 +107,7 @@ export interface DailyDiary {
107
107
  observedToday: string[];
108
108
  notableSignals: string[];
109
109
  tomorrowDirection: string;
110
- sourceRefs: SourceRef;
110
+ sourceRefs: SourceRefTuple;
111
111
  createdAt: string;
112
112
  }
113
113
  export type DreamOutputStatus = "candidate" | "accepted" | "archived" | "partial";
@@ -12,7 +12,7 @@
12
12
  * - ADR-002/003/007/008 — entity semantics
13
13
  *
14
14
  * Dependencies:
15
- * - `SourceRef` from `./source-ref.js`
15
+ * - `SourceRefTuple` from `./source-ref.js`
16
16
  * - `AgentGoal` from `./goal.js`
17
17
  *
18
18
  * Boundary:
@@ -38,6 +38,12 @@ export interface SourceRef {
38
38
  resolveStatus?: SourceResolveStatus;
39
39
  resolveFailureReason?: string;
40
40
  }
41
+ export interface ProvenanceBundle {
42
+ sourceRefs: SourceRef[];
43
+ proofRefs: SourceRef[];
44
+ traceRefs: SourceRef[];
45
+ }
46
+ export type ProvenanceTier = "source" | "proof" | "trace";
41
47
  export type HeartbeatCycleStatus = "started" | "completed" | "failed" | "degraded";
42
48
  export interface HeartbeatCycleTrace {
43
49
  cycleId: string;
@@ -59,11 +65,14 @@ export interface LoopStageEvent {
59
65
  status: LoopStageEventStatus;
60
66
  reason?: V8ReasonCode;
61
67
  sourceRefs: SourceRef[];
68
+ proofRefs?: SourceRef[];
69
+ traceRefs?: SourceRef[];
62
70
  redactionClass: RedactionClass;
63
71
  occurredAt: string;
64
72
  expectedDownstreamByCycle?: number;
65
73
  payloadJson?: string;
66
74
  }
75
+ export type EvidenceLevel = "carrier_ack" | "contract_smoke" | "state_present" | "real_runtime" | "durable_verified";
67
76
  export type MemoryReviewClosureSubtype = "remember_for_review";
68
77
  export interface MemoryReviewCandidateClosure {
69
78
  closureSubtype: MemoryReviewClosureSubtype;
@@ -75,12 +84,14 @@ export interface MemoryReviewCandidateClosure {
75
84
  sourceRefs: [SourceRef, ...SourceRef[]];
76
85
  }
77
86
  export interface DegradedOperationResult {
78
- status: "degraded" | "blocked";
87
+ status: "empty" | "partial" | "blocked" | "unavailable" | "unsafe";
79
88
  reason: V8ReasonCode;
80
89
  ownerStage: LoopStage;
81
90
  sourceRefs: SourceRef[];
91
+ proofRefs?: SourceRef[];
92
+ traceRefs?: SourceRef[];
82
93
  operatorNextAction: string;
83
94
  retryable: boolean;
84
95
  }
85
- export type V8ReasonCode = "quiet_completed" | "quiet_empty_input" | "quiet_state_unreadable" | "quiet_validation_failed" | "quiet_redaction_blocked" | "dream_scheduled" | "dream_scheduled_stalled" | "dream_scheduler_unavailable" | "dream_started" | "dream_completed" | "dream_failed" | "dream_blocked_redaction" | "dream_rules_only" | "dream_model_timeout" | "projection_candidate_created" | "projection_accepted" | "projection_rejected" | "projection_superseded" | "projection_topic_matched" | "proposal_created" | "proposal_no_action" | "proposal_missing_source_refs" | "proposal_risk_blocked" | "policy_allowed" | "policy_deferred_owner_confirmation" | "policy_downgraded_to_draft" | "policy_denied_missing_permission" | "policy_denied_high_risk" | "policy_denied_breaker_open" | "guidance_unavailable" | "closure_completed" | "closure_no_action" | "closure_denied" | "closure_deferred" | "closure_downgraded" | "closure_downgraded_without_draft" | "closure_failed" | "perception_rules_only" | "perception_contract_drift" | "evidence_batch_empty" | "evidence_batch_truncated" | "evidence_content_missing" | "judgment_low_confidence" | "judgment_missing_source_refs" | "source_refs_unresolved" | "state_unreadable" | "stage_event_missing" | "ingestion_no_data" | "ingestion_empty" | "ingestion_state_unreadable" | "ingestion_connector_failed" | "execution_completed" | "execution_failed" | "execution_timeout" | "execution_unavailable";
96
+ export type V8ReasonCode = "quiet_completed" | "quiet_empty_input" | "quiet_state_unreadable" | "quiet_validation_failed" | "quiet_redaction_blocked" | "dream_scheduled" | "dream_scheduled_stalled" | "dream_scheduler_unavailable" | "dream_started" | "dream_completed" | "dream_failed" | "dream_blocked_redaction" | "dream_blocked_no_content" | "dream_blocked_private_redacted" | "dream_blocked_credential" | "dream_blocked_validation_failed" | "dream_interval_active" | "dream_rules_only" | "dream_model_timeout" | "projection_candidate_created" | "projection_accepted" | "projection_rejected" | "projection_superseded" | "projection_topic_matched" | "proposal_created" | "proposal_no_action" | "proposal_missing_source_refs" | "proposal_risk_blocked" | "policy_allowed" | "policy_deferred_owner_confirmation" | "policy_downgraded_to_draft" | "policy_denied_missing_permission" | "policy_denied_high_risk" | "policy_denied_breaker_open" | "guidance_unavailable" | "closure_completed" | "closure_no_action" | "closure_denied" | "closure_deferred" | "closure_downgraded" | "closure_downgraded_without_draft" | "closure_failed" | "closure_idempotency_conflict" | "closure_unavailable" | "perception_rules_only" | "perception_contract_drift" | "evidence_batch_empty" | "evidence_batch_truncated" | "evidence_content_missing" | "judgment_low_confidence" | "judgment_missing_source_refs" | "source_refs_unresolved" | "state_unreadable" | "stage_event_missing" | "ingestion_no_data" | "ingestion_empty" | "ingestion_state_unreadable" | "ingestion_connector_failed" | "execution_completed" | "execution_failed" | "execution_timeout" | "execution_unavailable";
86
97
  export declare const ACTION_KIND_REGISTRY: Readonly<Record<PlatformNeutralActionKind, ActionKindMetadata>>;
@@ -233,9 +233,10 @@ const STATE_SCHEMA_SQL = `
233
233
  reason TEXT,
234
234
  next_state TEXT,
235
235
  source_refs_json TEXT NOT NULL,
236
+ proof_refs_json TEXT,
237
+ trace_refs_json TEXT,
236
238
  redaction_class TEXT NOT NULL DEFAULT 'none',
237
- payload_json TEXT,
238
- lifecycle_status TEXT NOT NULL DEFAULT 'closed'
239
+ payload_json TEXT
239
240
  );
240
241
  CREATE TABLE IF NOT EXISTS quiet_daily_review (
241
242
  id TEXT PRIMARY KEY,
@@ -257,8 +258,7 @@ const STATE_SCHEMA_SQL = `
257
258
  reason TEXT,
258
259
  source_refs_json TEXT NOT NULL,
259
260
  redaction_class TEXT NOT NULL DEFAULT 'none',
260
- payload_json TEXT,
261
- lifecycle_status TEXT NOT NULL DEFAULT 'pending'
261
+ payload_json TEXT
262
262
  );
263
263
  CREATE TABLE IF NOT EXISTS long_term_memory_projection (
264
264
  id TEXT PRIMARY KEY,
@@ -268,8 +268,7 @@ const STATE_SCHEMA_SQL = `
268
268
  status TEXT NOT NULL DEFAULT 'candidate',
269
269
  source_refs_json TEXT NOT NULL,
270
270
  redaction_class TEXT NOT NULL DEFAULT 'none',
271
- payload_json TEXT,
272
- lifecycle_status TEXT NOT NULL DEFAULT 'candidate'
271
+ payload_json TEXT
273
272
  );
274
273
  CREATE TABLE IF NOT EXISTS heartbeat_cycle_trace (
275
274
  id TEXT PRIMARY KEY,
@@ -282,8 +281,7 @@ const STATE_SCHEMA_SQL = `
282
281
  status TEXT NOT NULL,
283
282
  source_refs_json TEXT,
284
283
  redaction_class TEXT NOT NULL DEFAULT 'none',
285
- payload_json TEXT,
286
- lifecycle_status TEXT NOT NULL DEFAULT 'started'
284
+ payload_json TEXT
287
285
  );
288
286
  CREATE TABLE IF NOT EXISTS loop_stage_event (
289
287
  id TEXT PRIMARY KEY,
@@ -293,11 +291,12 @@ const STATE_SCHEMA_SQL = `
293
291
  status TEXT NOT NULL,
294
292
  reason TEXT,
295
293
  source_refs_json TEXT NOT NULL,
294
+ proof_refs_json TEXT,
295
+ trace_refs_json TEXT,
296
296
  redaction_class TEXT NOT NULL DEFAULT 'none',
297
297
  occurred_at TEXT NOT NULL,
298
298
  expected_downstream_by_cycle INTEGER,
299
- payload_json TEXT,
300
- lifecycle_status TEXT NOT NULL DEFAULT 'started'
299
+ payload_json TEXT
301
300
  );
302
301
  CREATE TABLE IF NOT EXISTS impulse_context_artifact (
303
302
  id TEXT PRIMARY KEY,
@@ -366,14 +365,23 @@ function bootstrapStateSchema(sqlite) {
366
365
  runMigrations(sqlite, ALL_MIGRATIONS);
367
366
  }
368
367
  function applyStateSchemaMigrations(sqlite) {
369
- const migrations = [
368
+ // Defensive column/index additions for DBs that were initialized before
369
+ // v8-004-schema-closure. Fresh DBs already have these from bootstrap SQL.
370
+ // Each statement is wrapped individually so duplicate-column errors are
371
+ // harmless and do not block startup.
372
+ const addColumnMigrations = [
370
373
  "ALTER TABLE policy_records ADD COLUMN outreach_daily_budget INTEGER NOT NULL DEFAULT 2",
371
374
  "ALTER TABLE action_closure_record ADD COLUMN platform_id TEXT",
372
375
  "ALTER TABLE action_closure_record ADD COLUMN capability_id TEXT",
376
+ "ALTER TABLE quiet_daily_review ADD COLUMN closure_refs_json TEXT",
373
377
  "ALTER TABLE connector_cooldown_state ADD COLUMN terminal_count INTEGER NOT NULL DEFAULT 0",
378
+ "ALTER TABLE loop_stage_event ADD COLUMN proof_refs_json TEXT",
379
+ "ALTER TABLE loop_stage_event ADD COLUMN trace_refs_json TEXT",
380
+ "ALTER TABLE action_closure_record ADD COLUMN proof_refs_json TEXT",
381
+ "ALTER TABLE action_closure_record ADD COLUMN trace_refs_json TEXT",
374
382
  "CREATE INDEX IF NOT EXISTS connector_cooldown_state_platform_capability_idx ON connector_cooldown_state(platform_id, capability_id)",
375
383
  ];
376
- for (const sql of migrations) {
384
+ for (const sql of addColumnMigrations) {
377
385
  try {
378
386
  sqlite.exec(sql);
379
387
  }
@@ -381,6 +389,46 @@ function applyStateSchemaMigrations(sqlite) {
381
389
  /* duplicate column / already migrated */
382
390
  }
383
391
  }
392
+ // DROP COLUMN requires SQLite ≥ 3.35.0. Guard against older native
393
+ // bindings where the statement would silently fail (caught by try/catch)
394
+ // yet leave lifecycle_status in place while the Drizzle schema no longer
395
+ // declares it, masking an incomplete cleanup.
396
+ const vResult = sqlite.exec("SELECT sqlite_version() AS ver");
397
+ const ver = String(vResult[0]?.values[0]?.[0] ?? "0.0.0");
398
+ const [major, minor] = ver.split(".").map(Number);
399
+ const supportsDropColumn = major > 3 || (major === 3 && minor >= 35);
400
+ const dropColumnTables = [
401
+ "action_closure_record",
402
+ "dream_consolidation_run",
403
+ "long_term_memory_projection",
404
+ "heartbeat_cycle_trace",
405
+ "loop_stage_event",
406
+ ];
407
+ for (const table of dropColumnTables) {
408
+ try {
409
+ if (supportsDropColumn) {
410
+ sqlite.exec(`ALTER TABLE ${table} DROP COLUMN lifecycle_status`);
411
+ }
412
+ else {
413
+ // Rebuild the table without lifecycle_status for SQLite < 3.35.0.
414
+ const info = sqlite.exec(`PRAGMA table_info(${table})`);
415
+ if (!info[0])
416
+ continue;
417
+ const nameIdx = info[0].columns.indexOf("name");
418
+ const allNames = info[0].values.map((row) => String(row[nameIdx]));
419
+ const kept = allNames.filter((n) => n !== "lifecycle_status");
420
+ if (kept.length === allNames.length)
421
+ continue; // column already absent
422
+ const colList = kept.join(", ");
423
+ sqlite.exec(`CREATE TABLE ${table}_backup AS SELECT ${colList} FROM ${table}`);
424
+ sqlite.exec(`DROP TABLE ${table}`);
425
+ sqlite.exec(`ALTER TABLE ${table}_backup RENAME TO ${table}`);
426
+ }
427
+ }
428
+ catch {
429
+ /* column already removed or table missing */
430
+ }
431
+ }
384
432
  }
385
433
  export function createStateDatabase(filename = "state.db") {
386
434
  const dbPath = resolveDbPath(filename);
@@ -8,6 +8,8 @@ import { V7_004_BEHAVIOR_PROMOTION } from "./v7-004-behavior-promotion.js";
8
8
  import { V8_001_LIVING_PERCEPTION_LOOP } from "./v8-001-living-perception-loop.js";
9
9
  import { V8_002_PERCEPTION_CONTRACT_ALIGNMENT } from "./v8-002-perception-contract-alignment.js";
10
10
  import { V8_003_QUIET_CLOSURE_REFS } from "./v8-003-quiet-closure-refs.js";
11
+ import { V8_004_SCHEMA_CLOSURE } from "./v8-004-schema-closure.js";
12
+ import { V8_005_SINGLE_STATUS_SCHEMA } from "./v8-005-single-status-schema.js";
11
13
  export const ALL_MIGRATIONS = [
12
14
  V7_001_FOUNDATION,
13
15
  V7_002_EFFECT_COMMIT_LEDGER,
@@ -16,4 +18,6 @@ export const ALL_MIGRATIONS = [
16
18
  V8_001_LIVING_PERCEPTION_LOOP,
17
19
  V8_002_PERCEPTION_CONTRACT_ALIGNMENT,
18
20
  V8_003_QUIET_CLOSURE_REFS,
21
+ V8_004_SCHEMA_CLOSURE,
22
+ V8_005_SINGLE_STATUS_SCHEMA,
19
23
  ];
@@ -0,0 +1,19 @@
1
+ /**
2
+ * v8-004 Schema Closure — brings pre-existing v8 DBs up to the current bootstrap schema.
3
+ *
4
+ * Problem: v8-001 created the first v8 tables, but daily_rhythm_state,
5
+ * impulse_context_artifact, connector_cooldown_state, and several columns
6
+ * (action_closure_record.platform_id/capability_id,
7
+ * quiet_daily_review.closure_refs_json, connector_cooldown_state.terminal_count)
8
+ * were added later only in the bootstrap SQL. DBs initialized before those
9
+ * bootstrap changes would miss tables/columns and break at runtime.
10
+ *
11
+ * Strategy:
12
+ * - CREATE TABLE IF NOT EXISTS for the three tables (idempotent on fresh DBs).
13
+ * - Column-level fixes are handled by the defensive applyStateSchemaMigrations
14
+ * helper in db/index.ts, because SQLite cannot conditionally ADD COLUMN.
15
+ *
16
+ * Resolves T-SMS.R.2.
17
+ */
18
+ import type { Migration } from "../migration-runner.js";
19
+ export declare const V8_004_SCHEMA_CLOSURE: Migration;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * v8-004 Schema Closure — brings pre-existing v8 DBs up to the current bootstrap schema.
3
+ *
4
+ * Problem: v8-001 created the first v8 tables, but daily_rhythm_state,
5
+ * impulse_context_artifact, connector_cooldown_state, and several columns
6
+ * (action_closure_record.platform_id/capability_id,
7
+ * quiet_daily_review.closure_refs_json, connector_cooldown_state.terminal_count)
8
+ * were added later only in the bootstrap SQL. DBs initialized before those
9
+ * bootstrap changes would miss tables/columns and break at runtime.
10
+ *
11
+ * Strategy:
12
+ * - CREATE TABLE IF NOT EXISTS for the three tables (idempotent on fresh DBs).
13
+ * - Column-level fixes are handled by the defensive applyStateSchemaMigrations
14
+ * helper in db/index.ts, because SQLite cannot conditionally ADD COLUMN.
15
+ *
16
+ * Resolves T-SMS.R.2.
17
+ */
18
+ export const V8_004_SCHEMA_CLOSURE = {
19
+ version: 8,
20
+ label: "v8-schema-closure",
21
+ sql: `
22
+ CREATE TABLE IF NOT EXISTS daily_rhythm_state (
23
+ id TEXT PRIMARY KEY,
24
+ day TEXT NOT NULL,
25
+ quiet_status TEXT NOT NULL DEFAULT 'not_due',
26
+ dream_status TEXT NOT NULL DEFAULT 'not_due',
27
+ quiet_reason TEXT,
28
+ dream_reason TEXT,
29
+ quiet_completed_at TEXT,
30
+ dream_completed_at TEXT,
31
+ source_refs_json TEXT NOT NULL,
32
+ payload_json TEXT,
33
+ updated_at TEXT NOT NULL
34
+ );
35
+
36
+ CREATE TABLE IF NOT EXISTS impulse_context_artifact (
37
+ id TEXT PRIMARY KEY,
38
+ created_at TEXT NOT NULL,
39
+ updated_at TEXT NOT NULL,
40
+ scene_type TEXT NOT NULL,
41
+ capability_intent TEXT,
42
+ platform_id TEXT,
43
+ capability_class TEXT,
44
+ impulse_source TEXT NOT NULL,
45
+ impulse_text TEXT,
46
+ atmosphere_text TEXT,
47
+ expression_boundary_constraints_json TEXT,
48
+ expression_boundary_style TEXT,
49
+ freshness_version INTEGER NOT NULL DEFAULT 1,
50
+ source_refs_json TEXT NOT NULL,
51
+ redaction_class TEXT NOT NULL DEFAULT 'none',
52
+ payload_json TEXT,
53
+ lifecycle_status TEXT NOT NULL DEFAULT 'active'
54
+ );
55
+
56
+ CREATE TABLE IF NOT EXISTS connector_cooldown_state (
57
+ id TEXT PRIMARY KEY,
58
+ platform_id TEXT NOT NULL,
59
+ capability_id TEXT NOT NULL,
60
+ failure_class TEXT NOT NULL,
61
+ retry_after_ms INTEGER,
62
+ blocked_until TEXT NOT NULL,
63
+ failure_count INTEGER NOT NULL DEFAULT 1,
64
+ terminal_count INTEGER NOT NULL DEFAULT 0,
65
+ source_refs_json TEXT NOT NULL,
66
+ redaction_class TEXT NOT NULL DEFAULT 'none',
67
+ payload_json TEXT,
68
+ created_at TEXT NOT NULL,
69
+ updated_at TEXT NOT NULL
70
+ );
71
+ CREATE INDEX IF NOT EXISTS connector_cooldown_state_platform_capability_idx
72
+ ON connector_cooldown_state(platform_id, capability_id);
73
+ `,
74
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * v8-005 Single Status Schema — records Wave 114 status-column cleanup.
3
+ *
4
+ * SQLite cannot safely run `DROP COLUMN IF EXISTS`; the actual idempotent
5
+ * column removal lives in applyStateSchemaMigrations where each statement is
6
+ * isolated. This migration marks the schema version after that defensive pass.
7
+ *
8
+ * Resolves T-SMS.R.4.
9
+ */
10
+ import type { Migration } from "../migration-runner.js";
11
+ export declare const V8_005_SINGLE_STATUS_SCHEMA: Migration;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * v8-005 Single Status Schema — records Wave 114 status-column cleanup.
3
+ *
4
+ * SQLite cannot safely run `DROP COLUMN IF EXISTS`; the actual idempotent
5
+ * column removal lives in applyStateSchemaMigrations where each statement is
6
+ * isolated. This migration marks the schema version after that defensive pass.
7
+ *
8
+ * Resolves T-SMS.R.4.
9
+ */
10
+ export const V8_005_SINGLE_STATUS_SCHEMA = {
11
+ version: 9,
12
+ label: "v8-single-status-schema",
13
+ sql: `
14
+ SELECT 1;
15
+ `,
16
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * v8-006 — Add proof/trace refs columns to loop_stage_event.
3
+ *
4
+ * The loop_stage_event table was created without proof_refs_json and
5
+ * trace_refs_json columns. This migration adds them as nullable TEXT columns
6
+ * so the v8 provenance tier write path can persist proofRefs and traceRefs.
7
+ */
8
+ import type { Migration } from "../migration-runner.js";
9
+ export declare const V8_006_LOOP_STAGE_EVENT_PROOF_TRACE_COLUMNS: Migration;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * v8-006 — Add proof/trace refs columns to loop_stage_event.
3
+ *
4
+ * The loop_stage_event table was created without proof_refs_json and
5
+ * trace_refs_json columns. This migration adds them as nullable TEXT columns
6
+ * so the v8 provenance tier write path can persist proofRefs and traceRefs.
7
+ */
8
+ export const V8_006_LOOP_STAGE_EVENT_PROOF_TRACE_COLUMNS = {
9
+ version: 6,
10
+ label: "v8_loop_stage_event_proof_trace_columns",
11
+ sql: `
12
+ ALTER TABLE loop_stage_event ADD COLUMN proof_refs_json TEXT;
13
+ ALTER TABLE loop_stage_event ADD COLUMN trace_refs_json TEXT;
14
+ `,
15
+ };