@haaaiawd/second-nature 0.2.12 → 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.
- package/index.js +96 -6
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/runtime/cli/commands/index.js +85 -11
- package/runtime/cli/host-capability/host-discovery-port.d.ts +85 -0
- package/runtime/cli/host-capability/host-discovery-port.js +137 -0
- package/runtime/cli/ops/heartbeat-surface.d.ts +3 -3
- package/runtime/cli/ops/heartbeat-surface.js +6 -5
- package/runtime/cli/ops/ops-router.d.ts +6 -2
- package/runtime/cli/ops/ops-router.js +1273 -1145
- package/runtime/connectors/base/normalized-evidence-content.d.ts +4 -0
- package/runtime/connectors/base/normalized-evidence-content.js +21 -2
- package/runtime/connectors/evidence-normalizer.js +32 -1
- package/runtime/core/second-nature/action/action-closure-recorder.d.ts +2 -0
- package/runtime/core/second-nature/action/action-closure-recorder.js +49 -34
- package/runtime/core/second-nature/action/action-proposal-builder.js +3 -2
- package/runtime/core/second-nature/action/policy-bound-dispatch.d.ts +2 -0
- package/runtime/core/second-nature/action/policy-bound-dispatch.js +7 -3
- package/runtime/core/second-nature/control-plane/cycle-finalizer.d.ts +82 -0
- package/runtime/core/second-nature/control-plane/cycle-finalizer.js +187 -0
- package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.js +13 -9
- package/runtime/core/second-nature/control-plane/real-runtime-spine.js +1 -1
- package/runtime/core/second-nature/guidance/guidance-proposal-consumer.d.ts +2 -1
- package/runtime/core/second-nature/guidance/guidance-proposal-consumer.js +4 -2
- package/runtime/core/second-nature/perception/judgment-engine.js +8 -4
- package/runtime/core/second-nature/perception/perception-builder.js +14 -2
- package/runtime/core/second-nature/quiet-dream/daily-rhythm-scheduler.js +30 -3
- package/runtime/core/second-nature/quiet-dream/dream-consolidation-runner.d.ts +5 -1
- package/runtime/core/second-nature/quiet-dream/dream-consolidation-runner.js +68 -29
- package/runtime/core/second-nature/quiet-dream/dream-scheduler.js +2 -1
- package/runtime/core/second-nature/quiet-dream/memory-projection-lifecycle.js +2 -1
- package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.d.ts +1 -0
- package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.js +33 -0
- package/runtime/observability/causal-loop-health.d.ts +2 -1
- package/runtime/observability/causal-loop-health.js +7 -0
- package/runtime/observability/loop-stage-event-sink.js +6 -1
- package/runtime/observability/loop-status.d.ts +2 -0
- package/runtime/observability/loop-status.js +14 -1
- package/runtime/observability/services/heartbeat-digest-assembler.d.ts +3 -0
- package/runtime/observability/services/heartbeat-digest-assembler.js +9 -0
- package/runtime/shared/degraded-status-classifier.d.ts +16 -0
- package/runtime/shared/degraded-status-classifier.js +68 -0
- package/runtime/shared/evidence-level-classifier.d.ts +61 -0
- package/runtime/shared/evidence-level-classifier.js +116 -0
- package/runtime/shared/provenance-tier.d.ts +37 -0
- package/runtime/shared/provenance-tier.js +97 -0
- package/runtime/shared/setup-ack.d.ts +54 -0
- package/runtime/shared/setup-ack.js +108 -0
- package/runtime/shared/source-ref-compat.js +5 -2
- package/runtime/shared/types/v8-contracts.d.ts +13 -2
- package/runtime/storage/db/index.js +71 -28
- package/runtime/storage/db/migrations/v8-005-single-status-schema.js +2 -2
- package/runtime/storage/db/migrations/v8-006-loop-stage-event-proof-trace-columns.d.ts +9 -0
- package/runtime/storage/db/migrations/v8-006-loop-stage-event-proof-trace-columns.js +15 -0
- package/runtime/storage/db/schema/v8-entities.d.ts +76 -0
- package/runtime/storage/db/schema/v8-entities.js +4 -0
- package/runtime/storage/services/write-validation-gate.js +1 -1
- package/runtime/storage/v8-state-stores.d.ts +7 -2
- package/runtime/storage/v8-state-stores.js +37 -19
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup Ack Truth Contract (T-ROS.R.8)
|
|
3
|
+
*
|
|
4
|
+
* Core logic: define the canonical SetupAck schema and a validator that rejects
|
|
5
|
+
* `placedIn: "unspecified"`, missing fields, unknown writers, and hand-written
|
|
6
|
+
* files that do not satisfy the schema.
|
|
7
|
+
*
|
|
8
|
+
* Design authority:
|
|
9
|
+
* - `.anws/v8/04_SYSTEM_DESIGN/runtime-ops-system.md §3.2`
|
|
10
|
+
*
|
|
11
|
+
* Dependencies: none (plain validation to keep plugin load lightweight)
|
|
12
|
+
* Boundary: Pure validation; no I/O.
|
|
13
|
+
* Test coverage: tests/unit/shared/setup-ack-validator.test.ts
|
|
14
|
+
*/
|
|
15
|
+
export const SETUP_ACK_SCHEMA_VERSION = 1;
|
|
16
|
+
const VALID_PLACEMENTS = new Set([
|
|
17
|
+
"workspace_guide",
|
|
18
|
+
"host_skill_registry",
|
|
19
|
+
"agent_profile",
|
|
20
|
+
"manual_operator_instruction",
|
|
21
|
+
]);
|
|
22
|
+
const VALID_WRITERS = new Set([
|
|
23
|
+
"setup_ack_command",
|
|
24
|
+
"host_setup_bridge",
|
|
25
|
+
]);
|
|
26
|
+
export function validateSetupAck(raw) {
|
|
27
|
+
const errors = [];
|
|
28
|
+
if (raw.schemaVersion !== SETUP_ACK_SCHEMA_VERSION) {
|
|
29
|
+
errors.push({
|
|
30
|
+
ok: false,
|
|
31
|
+
field: "schemaVersion",
|
|
32
|
+
reason: `schemaVersion must be ${SETUP_ACK_SCHEMA_VERSION}`,
|
|
33
|
+
repairAction: "Re-run setup_ack with a current client that writes schemaVersion=1.",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const placedIn = typeof raw.placedIn === "string" ? raw.placedIn : undefined;
|
|
37
|
+
if (!placedIn || placedIn === "unspecified") {
|
|
38
|
+
errors.push({
|
|
39
|
+
ok: false,
|
|
40
|
+
field: "placedIn",
|
|
41
|
+
reason: "placedIn is missing or 'unspecified'",
|
|
42
|
+
repairAction: "Provide a concrete placement target such as 'workspace_guide' or 'host_skill_registry'.",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else if (!VALID_PLACEMENTS.has(placedIn)) {
|
|
46
|
+
errors.push({
|
|
47
|
+
ok: false,
|
|
48
|
+
field: "placedIn",
|
|
49
|
+
reason: `placedIn '${placedIn}' is not a recognized placement target`,
|
|
50
|
+
repairAction: `Use one of: ${Array.from(VALID_PLACEMENTS).join(", ")}.`,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const placementProofRef = typeof raw.placementProofRef === "string" ? raw.placementProofRef : undefined;
|
|
54
|
+
if (!placementProofRef || placementProofRef.trim().length === 0) {
|
|
55
|
+
errors.push({
|
|
56
|
+
ok: false,
|
|
57
|
+
field: "placementProofRef",
|
|
58
|
+
reason: "placementProofRef is missing or empty",
|
|
59
|
+
repairAction: "Provide a proof reference such as a host skill registry id, file path, or anchor URI.",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const writer = typeof raw.writer === "string" ? raw.writer : undefined;
|
|
63
|
+
if (!writer || !VALID_WRITERS.has(writer)) {
|
|
64
|
+
errors.push({
|
|
65
|
+
ok: false,
|
|
66
|
+
field: "writer",
|
|
67
|
+
reason: `writer '${writer ?? "missing"}' is not authorized`,
|
|
68
|
+
repairAction: `Writer must be one of: ${Array.from(VALID_WRITERS).join(", ")}.`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const acknowledgedAt = typeof raw.acknowledgedAt === "string" ? raw.acknowledgedAt : undefined;
|
|
72
|
+
if (!acknowledgedAt || Number.isNaN(Date.parse(acknowledgedAt))) {
|
|
73
|
+
errors.push({
|
|
74
|
+
ok: false,
|
|
75
|
+
field: "acknowledgedAt",
|
|
76
|
+
reason: "acknowledgedAt is missing or not a valid ISO timestamp",
|
|
77
|
+
repairAction: "Re-run setup_ack so the client can write a fresh timestamp.",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (errors.length > 0) {
|
|
81
|
+
return { ok: false, errors };
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
ack: {
|
|
86
|
+
schemaVersion: SETUP_ACK_SCHEMA_VERSION,
|
|
87
|
+
acknowledgedAt: acknowledgedAt,
|
|
88
|
+
placedIn: placedIn,
|
|
89
|
+
placementProofRef: placementProofRef,
|
|
90
|
+
writer: writer,
|
|
91
|
+
hostName: typeof raw.hostName === "string" ? raw.hostName : undefined,
|
|
92
|
+
hostVersion: typeof raw.hostVersion === "string" ? raw.hostVersion : undefined,
|
|
93
|
+
acceptedBy: typeof raw.acceptedBy === "string" ? raw.acceptedBy : undefined,
|
|
94
|
+
note: typeof raw.note === "string" ? raw.note : undefined,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check whether a raw marker object can be considered a complete ack.
|
|
100
|
+
* Hand-written files are treated as incomplete until verified.
|
|
101
|
+
*/
|
|
102
|
+
export function isSetupAckComplete(raw) {
|
|
103
|
+
const result = validateSetupAck(raw);
|
|
104
|
+
if (result.ok) {
|
|
105
|
+
return { complete: true, ack: result.ack };
|
|
106
|
+
}
|
|
107
|
+
return { complete: false, errors: result.errors };
|
|
108
|
+
}
|
|
@@ -15,6 +15,11 @@ export function sourceRefFamilyFromLegacyKind(kind) {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
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
|
+
}
|
|
18
23
|
if (ref.uri.startsWith("platform://")) {
|
|
19
24
|
return "platform_item";
|
|
20
25
|
}
|
|
@@ -25,8 +30,6 @@ export function legacyKindFromSourceRef(ref) {
|
|
|
25
30
|
return "user_anchor";
|
|
26
31
|
}
|
|
27
32
|
switch (ref.family) {
|
|
28
|
-
case "connector_result":
|
|
29
|
-
return "connector_result";
|
|
30
33
|
case "judgment":
|
|
31
34
|
return "decision_record";
|
|
32
35
|
case "evidence":
|
|
@@ -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: "
|
|
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_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" | "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>>;
|
|
@@ -232,10 +232,12 @@ const STATE_SCHEMA_SQL = `
|
|
|
232
232
|
status TEXT NOT NULL,
|
|
233
233
|
reason TEXT,
|
|
234
234
|
next_state TEXT,
|
|
235
|
-
source_refs_json TEXT NOT NULL,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
235
|
+
source_refs_json TEXT NOT NULL,
|
|
236
|
+
proof_refs_json TEXT,
|
|
237
|
+
trace_refs_json TEXT,
|
|
238
|
+
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
239
|
+
payload_json TEXT
|
|
240
|
+
);
|
|
239
241
|
CREATE TABLE IF NOT EXISTS quiet_daily_review (
|
|
240
242
|
id TEXT PRIMARY KEY,
|
|
241
243
|
created_at TEXT NOT NULL,
|
|
@@ -254,20 +256,20 @@ const STATE_SCHEMA_SQL = `
|
|
|
254
256
|
quiet_review_id TEXT NOT NULL,
|
|
255
257
|
status TEXT NOT NULL,
|
|
256
258
|
reason TEXT,
|
|
257
|
-
source_refs_json TEXT NOT NULL,
|
|
258
|
-
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
259
|
-
payload_json TEXT
|
|
260
|
-
);
|
|
259
|
+
source_refs_json TEXT NOT NULL,
|
|
260
|
+
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
261
|
+
payload_json TEXT
|
|
262
|
+
);
|
|
261
263
|
CREATE TABLE IF NOT EXISTS long_term_memory_projection (
|
|
262
264
|
id TEXT PRIMARY KEY,
|
|
263
265
|
created_at TEXT NOT NULL,
|
|
264
266
|
candidate_id TEXT NOT NULL,
|
|
265
267
|
topic_key TEXT NOT NULL,
|
|
266
268
|
status TEXT NOT NULL DEFAULT 'candidate',
|
|
267
|
-
source_refs_json TEXT NOT NULL,
|
|
268
|
-
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
269
|
-
payload_json TEXT
|
|
270
|
-
);
|
|
269
|
+
source_refs_json TEXT NOT NULL,
|
|
270
|
+
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
271
|
+
payload_json TEXT
|
|
272
|
+
);
|
|
271
273
|
CREATE TABLE IF NOT EXISTS heartbeat_cycle_trace (
|
|
272
274
|
id TEXT PRIMARY KEY,
|
|
273
275
|
cycle_sequence INTEGER NOT NULL,
|
|
@@ -276,11 +278,11 @@ const STATE_SCHEMA_SQL = `
|
|
|
276
278
|
input_count INTEGER NOT NULL DEFAULT 0,
|
|
277
279
|
output_count INTEGER NOT NULL DEFAULT 0,
|
|
278
280
|
expected_downstream_by_cycle INTEGER,
|
|
279
|
-
status TEXT NOT NULL,
|
|
280
|
-
source_refs_json TEXT,
|
|
281
|
-
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
282
|
-
payload_json TEXT
|
|
283
|
-
);
|
|
281
|
+
status TEXT NOT NULL,
|
|
282
|
+
source_refs_json TEXT,
|
|
283
|
+
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
284
|
+
payload_json TEXT
|
|
285
|
+
);
|
|
284
286
|
CREATE TABLE IF NOT EXISTS loop_stage_event (
|
|
285
287
|
id TEXT PRIMARY KEY,
|
|
286
288
|
cycle_id TEXT NOT NULL,
|
|
@@ -289,11 +291,13 @@ const STATE_SCHEMA_SQL = `
|
|
|
289
291
|
status TEXT NOT NULL,
|
|
290
292
|
reason TEXT,
|
|
291
293
|
source_refs_json TEXT NOT NULL,
|
|
294
|
+
proof_refs_json TEXT,
|
|
295
|
+
trace_refs_json TEXT,
|
|
292
296
|
redaction_class TEXT NOT NULL DEFAULT 'none',
|
|
293
|
-
occurred_at TEXT NOT NULL,
|
|
294
|
-
expected_downstream_by_cycle INTEGER,
|
|
295
|
-
payload_json TEXT
|
|
296
|
-
);
|
|
297
|
+
occurred_at TEXT NOT NULL,
|
|
298
|
+
expected_downstream_by_cycle INTEGER,
|
|
299
|
+
payload_json TEXT
|
|
300
|
+
);
|
|
297
301
|
CREATE TABLE IF NOT EXISTS impulse_context_artifact (
|
|
298
302
|
id TEXT PRIMARY KEY,
|
|
299
303
|
created_at TEXT NOT NULL,
|
|
@@ -365,20 +369,19 @@ function applyStateSchemaMigrations(sqlite) {
|
|
|
365
369
|
// v8-004-schema-closure. Fresh DBs already have these from bootstrap SQL.
|
|
366
370
|
// Each statement is wrapped individually so duplicate-column errors are
|
|
367
371
|
// harmless and do not block startup.
|
|
368
|
-
const
|
|
372
|
+
const addColumnMigrations = [
|
|
369
373
|
"ALTER TABLE policy_records ADD COLUMN outreach_daily_budget INTEGER NOT NULL DEFAULT 2",
|
|
370
374
|
"ALTER TABLE action_closure_record ADD COLUMN platform_id TEXT",
|
|
371
375
|
"ALTER TABLE action_closure_record ADD COLUMN capability_id TEXT",
|
|
372
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
|
-
"ALTER TABLE action_closure_record DROP COLUMN lifecycle_status",
|
|
376
|
-
"ALTER TABLE dream_consolidation_run DROP COLUMN lifecycle_status",
|
|
377
|
-
"ALTER TABLE long_term_memory_projection DROP COLUMN lifecycle_status",
|
|
378
|
-
"ALTER TABLE heartbeat_cycle_trace DROP COLUMN lifecycle_status",
|
|
379
|
-
"ALTER TABLE loop_stage_event DROP COLUMN lifecycle_status",
|
|
380
383
|
];
|
|
381
|
-
for (const sql of
|
|
384
|
+
for (const sql of addColumnMigrations) {
|
|
382
385
|
try {
|
|
383
386
|
sqlite.exec(sql);
|
|
384
387
|
}
|
|
@@ -386,6 +389,46 @@ function applyStateSchemaMigrations(sqlite) {
|
|
|
386
389
|
/* duplicate column / already migrated */
|
|
387
390
|
}
|
|
388
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
|
+
}
|
|
389
432
|
}
|
|
390
433
|
export function createStateDatabase(filename = "state.db") {
|
|
391
434
|
const dbPath = resolveDbPath(filename);
|
|
@@ -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
|
+
};
|
|
@@ -968,6 +968,44 @@ export declare const actionClosureRecord: import("drizzle-orm/sqlite-core").SQLi
|
|
|
968
968
|
}, {}, {
|
|
969
969
|
length: number | undefined;
|
|
970
970
|
}>;
|
|
971
|
+
proofRefsJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
972
|
+
name: "proof_refs_json";
|
|
973
|
+
tableName: "action_closure_record";
|
|
974
|
+
dataType: "string";
|
|
975
|
+
columnType: "SQLiteText";
|
|
976
|
+
data: string;
|
|
977
|
+
driverParam: string;
|
|
978
|
+
notNull: false;
|
|
979
|
+
hasDefault: false;
|
|
980
|
+
isPrimaryKey: false;
|
|
981
|
+
isAutoincrement: false;
|
|
982
|
+
hasRuntimeDefault: false;
|
|
983
|
+
enumValues: [string, ...string[]];
|
|
984
|
+
baseColumn: never;
|
|
985
|
+
identity: undefined;
|
|
986
|
+
generated: undefined;
|
|
987
|
+
}, {}, {
|
|
988
|
+
length: number | undefined;
|
|
989
|
+
}>;
|
|
990
|
+
traceRefsJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
991
|
+
name: "trace_refs_json";
|
|
992
|
+
tableName: "action_closure_record";
|
|
993
|
+
dataType: "string";
|
|
994
|
+
columnType: "SQLiteText";
|
|
995
|
+
data: string;
|
|
996
|
+
driverParam: string;
|
|
997
|
+
notNull: false;
|
|
998
|
+
hasDefault: false;
|
|
999
|
+
isPrimaryKey: false;
|
|
1000
|
+
isAutoincrement: false;
|
|
1001
|
+
hasRuntimeDefault: false;
|
|
1002
|
+
enumValues: [string, ...string[]];
|
|
1003
|
+
baseColumn: never;
|
|
1004
|
+
identity: undefined;
|
|
1005
|
+
generated: undefined;
|
|
1006
|
+
}, {}, {
|
|
1007
|
+
length: number | undefined;
|
|
1008
|
+
}>;
|
|
971
1009
|
redactionClass: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
972
1010
|
name: "redaction_class";
|
|
973
1011
|
tableName: "action_closure_record";
|
|
@@ -1873,6 +1911,44 @@ export declare const loopStageEvent: import("drizzle-orm/sqlite-core").SQLiteTab
|
|
|
1873
1911
|
}, {}, {
|
|
1874
1912
|
length: number | undefined;
|
|
1875
1913
|
}>;
|
|
1914
|
+
proofRefsJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
1915
|
+
name: "proof_refs_json";
|
|
1916
|
+
tableName: "loop_stage_event";
|
|
1917
|
+
dataType: "string";
|
|
1918
|
+
columnType: "SQLiteText";
|
|
1919
|
+
data: string;
|
|
1920
|
+
driverParam: string;
|
|
1921
|
+
notNull: false;
|
|
1922
|
+
hasDefault: false;
|
|
1923
|
+
isPrimaryKey: false;
|
|
1924
|
+
isAutoincrement: false;
|
|
1925
|
+
hasRuntimeDefault: false;
|
|
1926
|
+
enumValues: [string, ...string[]];
|
|
1927
|
+
baseColumn: never;
|
|
1928
|
+
identity: undefined;
|
|
1929
|
+
generated: undefined;
|
|
1930
|
+
}, {}, {
|
|
1931
|
+
length: number | undefined;
|
|
1932
|
+
}>;
|
|
1933
|
+
traceRefsJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
1934
|
+
name: "trace_refs_json";
|
|
1935
|
+
tableName: "loop_stage_event";
|
|
1936
|
+
dataType: "string";
|
|
1937
|
+
columnType: "SQLiteText";
|
|
1938
|
+
data: string;
|
|
1939
|
+
driverParam: string;
|
|
1940
|
+
notNull: false;
|
|
1941
|
+
hasDefault: false;
|
|
1942
|
+
isPrimaryKey: false;
|
|
1943
|
+
isAutoincrement: false;
|
|
1944
|
+
hasRuntimeDefault: false;
|
|
1945
|
+
enumValues: [string, ...string[]];
|
|
1946
|
+
baseColumn: never;
|
|
1947
|
+
identity: undefined;
|
|
1948
|
+
generated: undefined;
|
|
1949
|
+
}, {}, {
|
|
1950
|
+
length: number | undefined;
|
|
1951
|
+
}>;
|
|
1876
1952
|
redactionClass: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
1877
1953
|
name: "redaction_class";
|
|
1878
1954
|
tableName: "loop_stage_event";
|
|
@@ -83,6 +83,8 @@ export const actionClosureRecord = sqliteTable("action_closure_record", {
|
|
|
83
83
|
reason: text("reason"),
|
|
84
84
|
nextState: text("next_state"),
|
|
85
85
|
sourceRefsJson: text("source_refs_json").notNull(),
|
|
86
|
+
proofRefsJson: text("proof_refs_json"),
|
|
87
|
+
traceRefsJson: text("trace_refs_json"),
|
|
86
88
|
redactionClass: text("redaction_class").notNull().default("none"),
|
|
87
89
|
payloadJson: text("payload_json"),
|
|
88
90
|
});
|
|
@@ -154,6 +156,8 @@ export const loopStageEvent = sqliteTable("loop_stage_event", {
|
|
|
154
156
|
status: text("status").notNull(),
|
|
155
157
|
reason: text("reason"),
|
|
156
158
|
sourceRefsJson: text("source_refs_json").notNull(),
|
|
159
|
+
proofRefsJson: text("proof_refs_json"),
|
|
160
|
+
traceRefsJson: text("trace_refs_json"),
|
|
157
161
|
redactionClass: text("redaction_class").notNull().default("none"),
|
|
158
162
|
occurredAt: text("occurred_at").notNull(),
|
|
159
163
|
expectedDownstreamByCycle: integer("expected_downstream_by_cycle"),
|
|
@@ -82,8 +82,11 @@ export declare function readJudgmentVerdictById(db: StateDatabase, id: string):
|
|
|
82
82
|
row?: JudgmentVerdictRecord;
|
|
83
83
|
degraded?: DegradedOperationResult;
|
|
84
84
|
}>;
|
|
85
|
-
export declare function writeActionClosureRecord(db: StateDatabase, row: Omit<ActionClosureRecordInsert, "sourceRefsJson"> & {
|
|
85
|
+
export declare function writeActionClosureRecord(db: StateDatabase, row: Omit<ActionClosureRecordInsert, "sourceRefsJson" | "proofRefsJson" | "traceRefsJson" | "payloadJson"> & {
|
|
86
86
|
sourceRefs: SourceRef[];
|
|
87
|
+
proofRefs?: SourceRef[];
|
|
88
|
+
traceRefs?: SourceRef[];
|
|
89
|
+
payload?: Record<string, unknown>;
|
|
87
90
|
}): Promise<{
|
|
88
91
|
id: string;
|
|
89
92
|
} | DegradedOperationResult>;
|
|
@@ -173,8 +176,10 @@ export declare function readHeartbeatCycleTraces(db: StateDatabase, limit?: numb
|
|
|
173
176
|
rows: HeartbeatCycleTraceRecord[];
|
|
174
177
|
degraded?: DegradedOperationResult;
|
|
175
178
|
}>;
|
|
176
|
-
export declare function writeLoopStageEvent(db: StateDatabase, row: Omit<NewLoopStageEventRecord, "sourceRefsJson"> & {
|
|
179
|
+
export declare function writeLoopStageEvent(db: StateDatabase, row: Omit<NewLoopStageEventRecord, "sourceRefsJson" | "proofRefsJson" | "traceRefsJson"> & {
|
|
177
180
|
sourceRefs: SourceRef[];
|
|
181
|
+
proofRefs?: SourceRef[];
|
|
182
|
+
traceRefs?: SourceRef[];
|
|
178
183
|
}): Promise<{
|
|
179
184
|
id: string;
|
|
180
185
|
} | DegradedOperationResult>;
|