@haaaiawd/second-nature 0.1.18 → 0.1.19
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 +855 -855
- package/openclaw.plugin.json +29 -29
- package/package.json +52 -52
- package/runtime/cli/commands/index.d.ts +14 -14
- package/runtime/cli/commands/index.js +193 -193
- package/runtime/cli/explain/explain-surface-subject.d.ts +8 -8
- package/runtime/cli/explain/explain-surface-subject.js +9 -9
- package/runtime/cli/explain/format-explanation.d.ts +12 -12
- package/runtime/cli/explain/format-explanation.js +12 -12
- package/runtime/cli/explain/resolve-subject.js +41 -41
- package/runtime/cli/host-capability/classify-delivery.d.ts +14 -14
- package/runtime/cli/host-capability/classify-delivery.js +20 -20
- package/runtime/cli/host-capability/probe-host-capability.d.ts +2 -2
- package/runtime/cli/host-capability/probe-host-capability.js +58 -58
- package/runtime/cli/host-capability/record-host-capability.d.ts +6 -6
- package/runtime/cli/host-capability/record-host-capability.js +14 -14
- package/runtime/cli/host-capability/types.d.ts +71 -71
- package/runtime/cli/host-capability/types.js +6 -6
- package/runtime/cli/host-smoke/run-host-smoke.d.ts +2 -2
- package/runtime/cli/host-smoke/run-host-smoke.js +40 -40
- package/runtime/cli/host-smoke/types.d.ts +35 -35
- package/runtime/cli/host-smoke/types.js +6 -6
- package/runtime/cli/index.js +65 -58
- package/runtime/cli/ops/heartbeat-surface.d.ts +45 -38
- package/runtime/cli/ops/heartbeat-surface.js +79 -73
- package/runtime/cli/ops/ops-router.d.ts +26 -19
- package/runtime/cli/ops/ops-router.js +102 -89
- package/runtime/cli/ops/show-operator-fallback.d.ts +13 -13
- package/runtime/cli/ops/show-operator-fallback.js +22 -22
- package/runtime/cli/ops/workspace-heartbeat-runner.d.ts +40 -19
- package/runtime/cli/ops/workspace-heartbeat-runner.js +93 -39
- package/runtime/cli/read-models/index.d.ts +35 -29
- package/runtime/cli/read-models/index.js +365 -256
- package/runtime/cli/read-models/operator-explain-map.d.ts +6 -6
- package/runtime/cli/read-models/operator-explain-map.js +10 -10
- package/runtime/cli/read-models/types.d.ts +112 -79
- package/runtime/cli/runtime/runtime-artifact-boundary.d.ts +28 -28
- package/runtime/cli/runtime/runtime-artifact-boundary.js +94 -94
- package/runtime/connectors/base/contract.d.ts +87 -87
- package/runtime/connectors/base/execution-policy.d.ts +47 -47
- package/runtime/connectors/base/execution-policy.js +82 -82
- package/runtime/connectors/base/index.d.ts +8 -8
- package/runtime/connectors/base/index.js +8 -8
- package/runtime/connectors/base/manifest.d.ts +64 -64
- package/runtime/connectors/base/manifest.js +86 -86
- package/runtime/connectors/base/map-life-evidence.d.ts +16 -16
- package/runtime/connectors/base/map-life-evidence.js +79 -79
- package/runtime/connectors/base/policy-layer.d.ts +29 -29
- package/runtime/connectors/base/policy-layer.js +198 -198
- package/runtime/connectors/base/route-planner.js +99 -99
- package/runtime/connectors/index.d.ts +5 -5
- package/runtime/connectors/index.js +5 -5
- package/runtime/connectors/near-real/near-real-connector-smoke.d.ts +19 -19
- package/runtime/connectors/near-real/near-real-connector-smoke.js +152 -152
- package/runtime/core/second-nature/heartbeat/heartbeat-executor.js +114 -114
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +63 -63
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +162 -139
- package/runtime/core/second-nature/heartbeat/index.d.ts +8 -8
- package/runtime/core/second-nature/heartbeat/index.js +7 -7
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.d.ts +21 -21
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.js +35 -35
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +28 -28
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.js +35 -35
- package/runtime/core/second-nature/heartbeat/signal.d.ts +42 -42
- package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +51 -51
- package/runtime/core/second-nature/index.d.ts +22 -22
- package/runtime/core/second-nature/index.js +22 -22
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +100 -100
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +144 -144
- package/runtime/core/second-nature/orchestrator/guard-layer.d.ts +8 -8
- package/runtime/core/second-nature/orchestrator/guard-layer.js +110 -110
- package/runtime/core/second-nature/orchestrator/intent-planner.d.ts +13 -13
- package/runtime/core/second-nature/orchestrator/intent-planner.js +199 -199
- package/runtime/core/second-nature/orchestrator/lease-manager.d.ts +14 -14
- package/runtime/core/second-nature/orchestrator/lease-manager.js +58 -58
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.d.ts +6 -6
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +63 -63
- package/runtime/core/second-nature/outreach/delivery-target.d.ts +26 -26
- package/runtime/core/second-nature/outreach/delivery-target.js +70 -70
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +38 -38
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +119 -119
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.d.ts +7 -7
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +45 -45
- package/runtime/core/second-nature/outreach/judge-outreach.d.ts +40 -40
- package/runtime/core/second-nature/outreach/judge-outreach.js +121 -121
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.d.ts +21 -21
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +123 -123
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.d.ts +15 -15
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.js +52 -52
- package/runtime/core/second-nature/rhythm/policy-bridge.d.ts +19 -19
- package/runtime/core/second-nature/rhythm/policy-bridge.js +34 -34
- package/runtime/core/second-nature/runtime/service-entry.js +45 -45
- package/runtime/core/second-nature/types.d.ts +51 -51
- package/runtime/guidance/draft-outreach-message.d.ts +7 -7
- package/runtime/guidance/draft-outreach-message.js +42 -42
- package/runtime/guidance/evidence-guidance.d.ts +40 -40
- package/runtime/guidance/evidence-guidance.js +52 -52
- package/runtime/guidance/index.d.ts +11 -11
- package/runtime/guidance/index.js +11 -11
- package/runtime/guidance/outreach-draft-schema.d.ts +228 -228
- package/runtime/guidance/outreach-draft-schema.js +80 -80
- package/runtime/observability/audit/append-only-audit-store.d.ts +14 -14
- package/runtime/observability/audit/append-only-audit-store.js +21 -21
- package/runtime/observability/audit/audit-envelope.d.ts +51 -51
- package/runtime/observability/audit/audit-envelope.js +130 -130
- package/runtime/observability/audit/verify-audit-hash-chain.d.ts +23 -23
- package/runtime/observability/audit/verify-audit-hash-chain.js +83 -83
- package/runtime/observability/db/index.js +47 -47
- package/runtime/observability/db/schema/host-capability-reports.d.ts +180 -180
- package/runtime/observability/db/schema/host-capability-reports.js +12 -12
- package/runtime/observability/db/schema/index.d.ts +947 -947
- package/runtime/observability/db/schema/index.js +71 -71
- package/runtime/observability/index.d.ts +20 -20
- package/runtime/observability/index.js +19 -19
- package/runtime/observability/query/explain-query.d.ts +48 -48
- package/runtime/observability/query/explain-query.js +114 -114
- package/runtime/observability/query/export-audit-bundle.d.ts +22 -22
- package/runtime/observability/query/export-audit-bundle.js +27 -27
- package/runtime/observability/services/decision-ledger.d.ts +46 -46
- package/runtime/observability/services/decision-ledger.js +161 -161
- package/runtime/observability/services/governance-audit.d.ts +41 -41
- package/runtime/observability/services/governance-audit.js +163 -163
- package/runtime/observability/services/governance-plane-recorder.d.ts +47 -47
- package/runtime/observability/services/governance-plane-recorder.js +55 -55
- package/runtime/observability/services/lived-experience-audit.d.ts +97 -97
- package/runtime/observability/services/lived-experience-audit.js +162 -162
- package/runtime/observability/services/runtime-decision-recorder.d.ts +29 -29
- package/runtime/observability/services/runtime-decision-recorder.js +94 -94
- package/runtime/storage/bootstrap/native-sqlite-probe.d.ts +7 -7
- package/runtime/storage/bootstrap/native-sqlite-probe.js +28 -28
- package/runtime/storage/bootstrap/repair-gate.d.ts +17 -17
- package/runtime/storage/bootstrap/repair-gate.js +71 -71
- package/runtime/storage/bootstrap/storage-mode-smoke.d.ts +38 -38
- package/runtime/storage/bootstrap/storage-mode-smoke.js +85 -85
- package/runtime/storage/db/index.js +61 -61
- package/runtime/storage/db/schema/delivery-attempts.d.ts +199 -199
- package/runtime/storage/db/schema/delivery-attempts.js +13 -13
- package/runtime/storage/db/schema/index.d.ts +9 -9
- package/runtime/storage/db/schema/index.js +9 -9
- package/runtime/storage/db/schema/life-evidence-index.d.ts +161 -161
- package/runtime/storage/db/schema/life-evidence-index.js +11 -11
- package/runtime/storage/db/schema/operator-fallback-artifacts.d.ts +161 -161
- package/runtime/storage/db/schema/operator-fallback-artifacts.js +11 -11
- package/runtime/storage/db/schema/policies.d.ts +98 -98
- package/runtime/storage/db/schema/policies.js +8 -8
- package/runtime/storage/delivery/query-delivery-attempts.d.ts +3 -3
- package/runtime/storage/delivery/query-delivery-attempts.js +32 -32
- package/runtime/storage/delivery/types.d.ts +27 -27
- package/runtime/storage/delivery/types.js +1 -1
- package/runtime/storage/delivery/write-delivery-attempt.d.ts +6 -6
- package/runtime/storage/delivery/write-delivery-attempt.js +36 -36
- package/runtime/storage/fallback/load-operator-fallback.d.ts +14 -14
- package/runtime/storage/fallback/load-operator-fallback.js +47 -47
- package/runtime/storage/fallback/operator-fallback-types.d.ts +9 -9
- package/runtime/storage/fallback/operator-fallback-types.js +1 -1
- package/runtime/storage/fallback/operator-fallback-view.d.ts +11 -11
- package/runtime/storage/fallback/operator-fallback-view.js +1 -1
- package/runtime/storage/fallback/write-operator-fallback.d.ts +6 -6
- package/runtime/storage/fallback/write-operator-fallback.js +21 -21
- package/runtime/storage/index.d.ts +37 -37
- package/runtime/storage/index.js +30 -30
- package/runtime/storage/life-evidence/append-life-evidence.d.ts +7 -7
- package/runtime/storage/life-evidence/append-life-evidence.js +64 -64
- package/runtime/storage/life-evidence/types.d.ts +45 -45
- package/runtime/storage/life-evidence/types.js +6 -6
- package/runtime/storage/quiet/persist-quiet-artifact.d.ts +7 -7
- package/runtime/storage/quiet/persist-quiet-artifact.js +22 -22
- package/runtime/storage/quiet/quiet-artifact-types.d.ts +18 -18
- package/runtime/storage/quiet/quiet-artifact-types.js +1 -1
- package/runtime/storage/quiet/quiet-artifact-writer.d.ts +15 -15
- package/runtime/storage/quiet/quiet-artifact-writer.js +56 -56
- package/runtime/storage/repositories/credential-repository.js +30 -30
- package/runtime/storage/rhythm/rhythm-policy-snapshot.d.ts +10 -10
- package/runtime/storage/rhythm/rhythm-policy-snapshot.js +34 -34
- package/runtime/storage/services/credential-vault.d.ts +13 -13
- package/runtime/storage/services/credential-vault.js +116 -116
- package/runtime/storage/snapshots/continuity-snapshot.d.ts +9 -9
- package/runtime/storage/snapshots/continuity-snapshot.js +41 -41
- package/runtime/storage/snapshots/life-evidence-snapshot.d.ts +6 -6
- package/runtime/storage/snapshots/life-evidence-snapshot.js +114 -114
- package/runtime/storage/snapshots/types.d.ts +58 -58
- package/runtime/storage/snapshots/types.js +1 -1
- package/runtime/storage/state-api.js +104 -104
- package/runtime/storage/user-interest/load-user-interest-snapshot.d.ts +2 -2
- package/runtime/storage/user-interest/load-user-interest-snapshot.js +150 -150
- package/runtime/storage/user-interest/types.d.ts +25 -25
- package/runtime/storage/user-interest/types.js +1 -1
- package/workspace-ops-bridge.js +81 -81
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime Decision Recorder (T1.2.3).
|
|
3
|
-
*
|
|
4
|
-
* Core logic: after a workspace `runHeartbeatCycle` completes, persist two rows that
|
|
5
|
-
* `loadStatus` already filters on, so operator status stops returning `unknown` for
|
|
6
|
-
* `rhythm.mode` / `runtime.serviceStatus` once the runtime has executed at least once.
|
|
7
|
-
* - `decision_ledger` row via `DecisionLedger.recordHeartbeatDecision()` with
|
|
8
|
-
* `traceId` prefix `sn-runtime-` (matches `INTERNAL_RUNTIME_TRACE_PREFIX`).
|
|
9
|
-
* - `execution_attempts` row via `ExecutionTelemetry.startAttempt` +
|
|
10
|
-
* `completeAttempt` with `platformId === "second-nature-runtime"` (matches
|
|
11
|
-
* `INTERNAL_RUNTIME_PLATFORM_ID`).
|
|
12
|
-
*
|
|
13
|
-
* Boundaries:
|
|
14
|
-
* - Recorder failure must NOT break the heartbeat surface response — caller wraps with try/catch.
|
|
15
|
-
* - Carrier-only / probe-only / runtime-unavailable paths do NOT invoke this recorder
|
|
16
|
-
* (their semantics intentionally remain "unknown" until a full-runtime turn happens).
|
|
17
|
-
* - This is a derived observability writer; it is not the canonical decision producer
|
|
18
|
-
* (control-plane keeps that contract). It exists to close the read-side aggregation gap.
|
|
19
|
-
*/
|
|
20
|
-
import { randomUUID } from "node:crypto";
|
|
21
|
-
import { DecisionLedger } from "./decision-ledger.js";
|
|
22
|
-
import { ExecutionTelemetry } from "./execution-telemetry.js";
|
|
23
|
-
export const RUNTIME_DECISION_TRACE_PREFIX = "sn-runtime-";
|
|
24
|
-
export const RUNTIME_INTERNAL_PLATFORM_ID = "second-nature-runtime";
|
|
25
|
-
const RUNTIME_INTERNAL_CAPABILITY = "runtime.heartbeat";
|
|
26
|
-
const RUNTIME_INTERNAL_CHANNEL = "internal";
|
|
27
|
-
export function createRuntimeDecisionRecorder(observabilityDb, overrides = {}) {
|
|
28
|
-
const ledger = overrides.ledger ?? new DecisionLedger(observabilityDb);
|
|
29
|
-
const telemetry = overrides.telemetry ?? new ExecutionTelemetry(observabilityDb);
|
|
30
|
-
return {
|
|
31
|
-
async recordHeartbeatCycle({ cycle, signal, rhythmMode }) {
|
|
32
|
-
const timestamp = typeof signal.payload.timestamp === "string" && signal.payload.timestamp.trim().length > 0
|
|
33
|
-
? signal.payload.timestamp
|
|
34
|
-
: new Date().toISOString();
|
|
35
|
-
const uniqueId = randomUUID();
|
|
36
|
-
const traceId = `${RUNTIME_DECISION_TRACE_PREFIX}${cycle.scope}-${cycle.status}-${uniqueId}`;
|
|
37
|
-
const decisionId = `decision-runtime-${uniqueId}`;
|
|
38
|
-
const tickId = `tick-runtime-${uniqueId}`;
|
|
39
|
-
const event = {
|
|
40
|
-
id: decisionId,
|
|
41
|
-
tickId,
|
|
42
|
-
traceId,
|
|
43
|
-
runtimeScope: cycle.scope,
|
|
44
|
-
triggerSource: signal.trigger,
|
|
45
|
-
decisionStatus: mapCycleStatus(cycle.status),
|
|
46
|
-
reasons: cycle.reasons,
|
|
47
|
-
intentId: cycle.selectedIntentId,
|
|
48
|
-
mode: rhythmMode ?? "active",
|
|
49
|
-
createdAt: timestamp,
|
|
50
|
-
};
|
|
51
|
-
await ledger.recordHeartbeatDecision(event);
|
|
52
|
-
const attemptId = await telemetry.startAttempt({
|
|
53
|
-
traceId,
|
|
54
|
-
decisionId,
|
|
55
|
-
intentId: cycle.selectedIntentId ?? `${RUNTIME_INTERNAL_PLATFORM_ID}-tick`,
|
|
56
|
-
platformId: RUNTIME_INTERNAL_PLATFORM_ID,
|
|
57
|
-
capability: RUNTIME_INTERNAL_CAPABILITY,
|
|
58
|
-
channel: RUNTIME_INTERNAL_CHANNEL,
|
|
59
|
-
startedAt: timestamp,
|
|
60
|
-
});
|
|
61
|
-
const status = isFailureCycle(cycle.status) ? "failed" : "succeeded";
|
|
62
|
-
const failureClass = status === "failed" ? cycleStatusFailureClass(cycle.status) : undefined;
|
|
63
|
-
await telemetry.completeAttempt(traceId, status, undefined, failureClass);
|
|
64
|
-
return { traceId, decisionId, attemptId };
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function mapCycleStatus(status) {
|
|
69
|
-
switch (status) {
|
|
70
|
-
case "intent_selected":
|
|
71
|
-
return "intent_selected";
|
|
72
|
-
case "denied":
|
|
73
|
-
return "denied";
|
|
74
|
-
case "deferred":
|
|
75
|
-
return "deferred";
|
|
76
|
-
case "delivery_unavailable":
|
|
77
|
-
return "delivery_unavailable";
|
|
78
|
-
case "runtime_carrier_only":
|
|
79
|
-
return "runtime_carrier_only";
|
|
80
|
-
case "heartbeat_ok":
|
|
81
|
-
default:
|
|
82
|
-
return "heartbeat_ok";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
function isFailureCycle(status) {
|
|
86
|
-
return status === "delivery_unavailable" || status === "denied";
|
|
87
|
-
}
|
|
88
|
-
function cycleStatusFailureClass(status) {
|
|
89
|
-
if (status === "delivery_unavailable")
|
|
90
|
-
return "delivery_unavailable";
|
|
91
|
-
if (status === "denied")
|
|
92
|
-
return "decision_denied";
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Decision Recorder (T1.2.3).
|
|
3
|
+
*
|
|
4
|
+
* Core logic: after a workspace `runHeartbeatCycle` completes, persist two rows that
|
|
5
|
+
* `loadStatus` already filters on, so operator status stops returning `unknown` for
|
|
6
|
+
* `rhythm.mode` / `runtime.serviceStatus` once the runtime has executed at least once.
|
|
7
|
+
* - `decision_ledger` row via `DecisionLedger.recordHeartbeatDecision()` with
|
|
8
|
+
* `traceId` prefix `sn-runtime-` (matches `INTERNAL_RUNTIME_TRACE_PREFIX`).
|
|
9
|
+
* - `execution_attempts` row via `ExecutionTelemetry.startAttempt` +
|
|
10
|
+
* `completeAttempt` with `platformId === "second-nature-runtime"` (matches
|
|
11
|
+
* `INTERNAL_RUNTIME_PLATFORM_ID`).
|
|
12
|
+
*
|
|
13
|
+
* Boundaries:
|
|
14
|
+
* - Recorder failure must NOT break the heartbeat surface response — caller wraps with try/catch.
|
|
15
|
+
* - Carrier-only / probe-only / runtime-unavailable paths do NOT invoke this recorder
|
|
16
|
+
* (their semantics intentionally remain "unknown" until a full-runtime turn happens).
|
|
17
|
+
* - This is a derived observability writer; it is not the canonical decision producer
|
|
18
|
+
* (control-plane keeps that contract). It exists to close the read-side aggregation gap.
|
|
19
|
+
*/
|
|
20
|
+
import { randomUUID } from "node:crypto";
|
|
21
|
+
import { DecisionLedger } from "./decision-ledger.js";
|
|
22
|
+
import { ExecutionTelemetry } from "./execution-telemetry.js";
|
|
23
|
+
export const RUNTIME_DECISION_TRACE_PREFIX = "sn-runtime-";
|
|
24
|
+
export const RUNTIME_INTERNAL_PLATFORM_ID = "second-nature-runtime";
|
|
25
|
+
const RUNTIME_INTERNAL_CAPABILITY = "runtime.heartbeat";
|
|
26
|
+
const RUNTIME_INTERNAL_CHANNEL = "internal";
|
|
27
|
+
export function createRuntimeDecisionRecorder(observabilityDb, overrides = {}) {
|
|
28
|
+
const ledger = overrides.ledger ?? new DecisionLedger(observabilityDb);
|
|
29
|
+
const telemetry = overrides.telemetry ?? new ExecutionTelemetry(observabilityDb);
|
|
30
|
+
return {
|
|
31
|
+
async recordHeartbeatCycle({ cycle, signal, rhythmMode }) {
|
|
32
|
+
const timestamp = typeof signal.payload.timestamp === "string" && signal.payload.timestamp.trim().length > 0
|
|
33
|
+
? signal.payload.timestamp
|
|
34
|
+
: new Date().toISOString();
|
|
35
|
+
const uniqueId = randomUUID();
|
|
36
|
+
const traceId = `${RUNTIME_DECISION_TRACE_PREFIX}${cycle.scope}-${cycle.status}-${uniqueId}`;
|
|
37
|
+
const decisionId = `decision-runtime-${uniqueId}`;
|
|
38
|
+
const tickId = `tick-runtime-${uniqueId}`;
|
|
39
|
+
const event = {
|
|
40
|
+
id: decisionId,
|
|
41
|
+
tickId,
|
|
42
|
+
traceId,
|
|
43
|
+
runtimeScope: cycle.scope,
|
|
44
|
+
triggerSource: signal.trigger,
|
|
45
|
+
decisionStatus: mapCycleStatus(cycle.status),
|
|
46
|
+
reasons: cycle.reasons,
|
|
47
|
+
intentId: cycle.selectedIntentId,
|
|
48
|
+
mode: rhythmMode ?? "active",
|
|
49
|
+
createdAt: timestamp,
|
|
50
|
+
};
|
|
51
|
+
await ledger.recordHeartbeatDecision(event);
|
|
52
|
+
const attemptId = await telemetry.startAttempt({
|
|
53
|
+
traceId,
|
|
54
|
+
decisionId,
|
|
55
|
+
intentId: cycle.selectedIntentId ?? `${RUNTIME_INTERNAL_PLATFORM_ID}-tick`,
|
|
56
|
+
platformId: RUNTIME_INTERNAL_PLATFORM_ID,
|
|
57
|
+
capability: RUNTIME_INTERNAL_CAPABILITY,
|
|
58
|
+
channel: RUNTIME_INTERNAL_CHANNEL,
|
|
59
|
+
startedAt: timestamp,
|
|
60
|
+
});
|
|
61
|
+
const status = isFailureCycle(cycle.status) ? "failed" : "succeeded";
|
|
62
|
+
const failureClass = status === "failed" ? cycleStatusFailureClass(cycle.status) : undefined;
|
|
63
|
+
await telemetry.completeAttempt(traceId, status, undefined, failureClass);
|
|
64
|
+
return { traceId, decisionId, attemptId };
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function mapCycleStatus(status) {
|
|
69
|
+
switch (status) {
|
|
70
|
+
case "intent_selected":
|
|
71
|
+
return "intent_selected";
|
|
72
|
+
case "denied":
|
|
73
|
+
return "denied";
|
|
74
|
+
case "deferred":
|
|
75
|
+
return "deferred";
|
|
76
|
+
case "delivery_unavailable":
|
|
77
|
+
return "delivery_unavailable";
|
|
78
|
+
case "runtime_carrier_only":
|
|
79
|
+
return "runtime_carrier_only";
|
|
80
|
+
case "heartbeat_ok":
|
|
81
|
+
default:
|
|
82
|
+
return "heartbeat_ok";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isFailureCycle(status) {
|
|
86
|
+
return status === "delivery_unavailable" || status === "denied";
|
|
87
|
+
}
|
|
88
|
+
function cycleStatusFailureClass(status) {
|
|
89
|
+
if (status === "delivery_unavailable")
|
|
90
|
+
return "delivery_unavailable";
|
|
91
|
+
if (status === "denied")
|
|
92
|
+
return "decision_denied";
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export interface NativeSqliteProbeResult {
|
|
2
|
-
moduleLoadOk: boolean;
|
|
3
|
-
/** package version when load succeeds */
|
|
4
|
-
version?: string;
|
|
5
|
-
errorMessage?: string;
|
|
6
|
-
}
|
|
7
|
-
export declare function probeNativeSqliteLoad(): NativeSqliteProbeResult;
|
|
1
|
+
export interface NativeSqliteProbeResult {
|
|
2
|
+
moduleLoadOk: boolean;
|
|
3
|
+
/** package version when load succeeds */
|
|
4
|
+
version?: string;
|
|
5
|
+
errorMessage?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function probeNativeSqliteLoad(): NativeSqliteProbeResult;
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Optional better-sqlite3 load probe (T4.1.4). Second Nature state DB currently uses sql.js only;
|
|
3
|
-
* this probe records whether the native module can load for packaging / host diagnostics.
|
|
4
|
-
*/
|
|
5
|
-
import { createRequire } from "node:module";
|
|
6
|
-
const require = createRequire(import.meta.url);
|
|
7
|
-
export function probeNativeSqliteLoad() {
|
|
8
|
-
try {
|
|
9
|
-
const Database = require("better-sqlite3");
|
|
10
|
-
const db = new Database(":memory:");
|
|
11
|
-
db.close();
|
|
12
|
-
let version;
|
|
13
|
-
try {
|
|
14
|
-
const pkg = require("better-sqlite3/package.json");
|
|
15
|
-
version = pkg.version;
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
version = undefined;
|
|
19
|
-
}
|
|
20
|
-
return { moduleLoadOk: true, version };
|
|
21
|
-
}
|
|
22
|
-
catch (error) {
|
|
23
|
-
return {
|
|
24
|
-
moduleLoadOk: false,
|
|
25
|
-
errorMessage: error instanceof Error ? error.message : String(error),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Optional better-sqlite3 load probe (T4.1.4). Second Nature state DB currently uses sql.js only;
|
|
3
|
+
* this probe records whether the native module can load for packaging / host diagnostics.
|
|
4
|
+
*/
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
export function probeNativeSqliteLoad() {
|
|
8
|
+
try {
|
|
9
|
+
const Database = require("better-sqlite3");
|
|
10
|
+
const db = new Database(":memory:");
|
|
11
|
+
db.close();
|
|
12
|
+
let version;
|
|
13
|
+
try {
|
|
14
|
+
const pkg = require("better-sqlite3/package.json");
|
|
15
|
+
version = pkg.version;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
version = undefined;
|
|
19
|
+
}
|
|
20
|
+
return { moduleLoadOk: true, version };
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return {
|
|
24
|
+
moduleLoadOk: false,
|
|
25
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type { StateDatabase } from "../db/index.js";
|
|
2
|
-
import { createRepairAndBackupService, type RepairAndBackupOptions } from "../services/repair-and-backup.js";
|
|
3
|
-
export interface RepairStateIndexesOptions {
|
|
4
|
-
startupGate?: boolean;
|
|
5
|
-
workspaceRoot: string;
|
|
6
|
-
/** When true, also runs asset registry repair + backup (existing repair service) */
|
|
7
|
-
reconcileAssets?: boolean;
|
|
8
|
-
assetRepairOptions?: RepairAndBackupOptions;
|
|
9
|
-
}
|
|
10
|
-
export type RepairGateStatus = "ok" | "repair_required";
|
|
11
|
-
export interface RepairSummary {
|
|
12
|
-
status: RepairGateStatus;
|
|
13
|
-
repairedEvidenceIndexRows: number;
|
|
14
|
-
repairNotes: string[];
|
|
15
|
-
assetRepair?: Awaited<ReturnType<ReturnType<typeof createRepairAndBackupService>["runStartupRepair"]>>;
|
|
16
|
-
}
|
|
17
|
-
export declare function repairStateIndexes(state: StateDatabase, options: RepairStateIndexesOptions): Promise<RepairSummary>;
|
|
1
|
+
import type { StateDatabase } from "../db/index.js";
|
|
2
|
+
import { createRepairAndBackupService, type RepairAndBackupOptions } from "../services/repair-and-backup.js";
|
|
3
|
+
export interface RepairStateIndexesOptions {
|
|
4
|
+
startupGate?: boolean;
|
|
5
|
+
workspaceRoot: string;
|
|
6
|
+
/** When true, also runs asset registry repair + backup (existing repair service) */
|
|
7
|
+
reconcileAssets?: boolean;
|
|
8
|
+
assetRepairOptions?: RepairAndBackupOptions;
|
|
9
|
+
}
|
|
10
|
+
export type RepairGateStatus = "ok" | "repair_required";
|
|
11
|
+
export interface RepairSummary {
|
|
12
|
+
status: RepairGateStatus;
|
|
13
|
+
repairedEvidenceIndexRows: number;
|
|
14
|
+
repairNotes: string[];
|
|
15
|
+
assetRepair?: Awaited<ReturnType<ReturnType<typeof createRepairAndBackupService>["runStartupRepair"]>>;
|
|
16
|
+
}
|
|
17
|
+
export declare function repairStateIndexes(state: StateDatabase, options: RepairStateIndexesOptions): Promise<RepairSummary>;
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Startup repair gate for state indexes (T4.1.3) — reconciles life evidence filesystem vs SQLite index.
|
|
3
|
-
*
|
|
4
|
-
* Core logic: scan `.second-nature/evidence/*.json`; on startupGate, corrupt JSON fails closed with repair_required;
|
|
5
|
-
* otherwise backfill missing `life_evidence_index` rows from parsed artifacts.
|
|
6
|
-
*
|
|
7
|
-
* Test coverage: tests/unit/storage/repair-gate.test.ts
|
|
8
|
-
*/
|
|
9
|
-
import fs from "node:fs";
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { eq } from "drizzle-orm";
|
|
12
|
-
import { lifeEvidenceIndex } from "../db/schema/life-evidence-index.js";
|
|
13
|
-
import { createRepairAndBackupService, } from "../services/repair-and-backup.js";
|
|
14
|
-
export async function repairStateIndexes(state, options) {
|
|
15
|
-
const notes = [];
|
|
16
|
-
let repaired = 0;
|
|
17
|
-
const evidenceDir = path.join(options.workspaceRoot, ".second-nature", "evidence");
|
|
18
|
-
if (!fs.existsSync(evidenceDir)) {
|
|
19
|
-
notes.push("no_evidence_dir");
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
const entries = fs.readdirSync(evidenceDir);
|
|
23
|
-
for (const name of entries) {
|
|
24
|
-
if (!name.endsWith(".json") || name.startsWith(".")) {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
const abs = path.join(evidenceDir, name);
|
|
28
|
-
let parsed;
|
|
29
|
-
try {
|
|
30
|
-
parsed = JSON.parse(fs.readFileSync(abs, "utf-8"));
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
if (options.startupGate) {
|
|
34
|
-
return {
|
|
35
|
-
status: "repair_required",
|
|
36
|
-
repairedEvidenceIndexRows: repaired,
|
|
37
|
-
repairNotes: [...notes, `corrupt_evidence_json:${name}`],
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
notes.push(`skip_corrupt:${name}`);
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const existing = await state.db.select().from(lifeEvidenceIndex).where(eq(lifeEvidenceIndex.id, parsed.id)).limit(1);
|
|
44
|
-
if (existing.length === 0) {
|
|
45
|
-
await state.db.insert(lifeEvidenceIndex).values({
|
|
46
|
-
id: parsed.id,
|
|
47
|
-
timestamp: parsed.timestamp,
|
|
48
|
-
evidenceType: parsed.evidenceType,
|
|
49
|
-
sensitivity: parsed.sensitivity,
|
|
50
|
-
producer: parsed.producer,
|
|
51
|
-
artifactPath: path.join(".second-nature", "evidence", `${parsed.id}.json`).replace(/\\/g, "/"),
|
|
52
|
-
platformId: parsed.platformId ?? null,
|
|
53
|
-
sourceRefsJson: JSON.stringify(parsed.sourceRefs),
|
|
54
|
-
});
|
|
55
|
-
repaired += 1;
|
|
56
|
-
notes.push(`reindexed:${parsed.id}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
let assetRepair;
|
|
61
|
-
if (options.reconcileAssets) {
|
|
62
|
-
const svc = createRepairAndBackupService(state);
|
|
63
|
-
assetRepair = await svc.runStartupRepair(options.assetRepairOptions ?? {});
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
status: "ok",
|
|
67
|
-
repairedEvidenceIndexRows: repaired,
|
|
68
|
-
repairNotes: notes,
|
|
69
|
-
assetRepair,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Startup repair gate for state indexes (T4.1.3) — reconciles life evidence filesystem vs SQLite index.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: scan `.second-nature/evidence/*.json`; on startupGate, corrupt JSON fails closed with repair_required;
|
|
5
|
+
* otherwise backfill missing `life_evidence_index` rows from parsed artifacts.
|
|
6
|
+
*
|
|
7
|
+
* Test coverage: tests/unit/storage/repair-gate.test.ts
|
|
8
|
+
*/
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { eq } from "drizzle-orm";
|
|
12
|
+
import { lifeEvidenceIndex } from "../db/schema/life-evidence-index.js";
|
|
13
|
+
import { createRepairAndBackupService, } from "../services/repair-and-backup.js";
|
|
14
|
+
export async function repairStateIndexes(state, options) {
|
|
15
|
+
const notes = [];
|
|
16
|
+
let repaired = 0;
|
|
17
|
+
const evidenceDir = path.join(options.workspaceRoot, ".second-nature", "evidence");
|
|
18
|
+
if (!fs.existsSync(evidenceDir)) {
|
|
19
|
+
notes.push("no_evidence_dir");
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const entries = fs.readdirSync(evidenceDir);
|
|
23
|
+
for (const name of entries) {
|
|
24
|
+
if (!name.endsWith(".json") || name.startsWith(".")) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const abs = path.join(evidenceDir, name);
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(fs.readFileSync(abs, "utf-8"));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
if (options.startupGate) {
|
|
34
|
+
return {
|
|
35
|
+
status: "repair_required",
|
|
36
|
+
repairedEvidenceIndexRows: repaired,
|
|
37
|
+
repairNotes: [...notes, `corrupt_evidence_json:${name}`],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
notes.push(`skip_corrupt:${name}`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const existing = await state.db.select().from(lifeEvidenceIndex).where(eq(lifeEvidenceIndex.id, parsed.id)).limit(1);
|
|
44
|
+
if (existing.length === 0) {
|
|
45
|
+
await state.db.insert(lifeEvidenceIndex).values({
|
|
46
|
+
id: parsed.id,
|
|
47
|
+
timestamp: parsed.timestamp,
|
|
48
|
+
evidenceType: parsed.evidenceType,
|
|
49
|
+
sensitivity: parsed.sensitivity,
|
|
50
|
+
producer: parsed.producer,
|
|
51
|
+
artifactPath: path.join(".second-nature", "evidence", `${parsed.id}.json`).replace(/\\/g, "/"),
|
|
52
|
+
platformId: parsed.platformId ?? null,
|
|
53
|
+
sourceRefsJson: JSON.stringify(parsed.sourceRefs),
|
|
54
|
+
});
|
|
55
|
+
repaired += 1;
|
|
56
|
+
notes.push(`reindexed:${parsed.id}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
let assetRepair;
|
|
61
|
+
if (options.reconcileAssets) {
|
|
62
|
+
const svc = createRepairAndBackupService(state);
|
|
63
|
+
assetRepair = await svc.runStartupRepair(options.assetRepairOptions ?? {});
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
status: "ok",
|
|
67
|
+
repairedEvidenceIndexRows: repaired,
|
|
68
|
+
repairNotes: notes,
|
|
69
|
+
assetRepair,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { probeNativeSqliteLoad } from "./native-sqlite-probe.js";
|
|
2
|
-
export interface StorageModeSmokeSemantics {
|
|
3
|
-
sqlJs: {
|
|
4
|
-
walAssumed: false;
|
|
5
|
-
journalConcurrencyNotes: string;
|
|
6
|
-
backupNotes: string;
|
|
7
|
-
repairNotes: string;
|
|
8
|
-
};
|
|
9
|
-
nativeSqliteWhenAvailable: {
|
|
10
|
-
journalConcurrencyNotes: string;
|
|
11
|
-
backupNotes: string;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
export interface StorageModeSmokeRepairFixtureResult {
|
|
15
|
-
ran: boolean;
|
|
16
|
-
workspaceRoot?: string;
|
|
17
|
-
repairStatus?: "ok" | "repair_required";
|
|
18
|
-
repairedEvidenceIndexRows?: number;
|
|
19
|
-
repairNotes?: string[];
|
|
20
|
-
}
|
|
21
|
-
export interface StorageModeSmokeReport {
|
|
22
|
-
generatedAt: string;
|
|
23
|
-
/** Implementation backing `createStateDatabase` today — wasm sql.js, not native WAL */
|
|
24
|
-
runtimeIndexDriver: "sql_js";
|
|
25
|
-
nativeSqliteProbe: ReturnType<typeof probeNativeSqliteLoad> & {
|
|
26
|
-
/** Current code path does not use native driver even when load succeeds */
|
|
27
|
-
runtimeUsesNativeDriver: false;
|
|
28
|
-
};
|
|
29
|
-
semantics: StorageModeSmokeSemantics;
|
|
30
|
-
repairFromArtifactsFixture?: StorageModeSmokeRepairFixtureResult;
|
|
31
|
-
}
|
|
32
|
-
export interface RunStorageModeSmokeOptions {
|
|
33
|
-
/** Required when runRepairFixture is true — temp dir created if omitted */
|
|
34
|
-
workspaceRoot?: string;
|
|
35
|
-
/** Run artifact→index backfill smoke (sql.js path); uses temp workspace when workspaceRoot unset */
|
|
36
|
-
runRepairFixture?: boolean;
|
|
37
|
-
}
|
|
38
|
-
export declare function runStorageModeSmoke(options?: RunStorageModeSmokeOptions): Promise<StorageModeSmokeReport>;
|
|
1
|
+
import { probeNativeSqliteLoad } from "./native-sqlite-probe.js";
|
|
2
|
+
export interface StorageModeSmokeSemantics {
|
|
3
|
+
sqlJs: {
|
|
4
|
+
walAssumed: false;
|
|
5
|
+
journalConcurrencyNotes: string;
|
|
6
|
+
backupNotes: string;
|
|
7
|
+
repairNotes: string;
|
|
8
|
+
};
|
|
9
|
+
nativeSqliteWhenAvailable: {
|
|
10
|
+
journalConcurrencyNotes: string;
|
|
11
|
+
backupNotes: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface StorageModeSmokeRepairFixtureResult {
|
|
15
|
+
ran: boolean;
|
|
16
|
+
workspaceRoot?: string;
|
|
17
|
+
repairStatus?: "ok" | "repair_required";
|
|
18
|
+
repairedEvidenceIndexRows?: number;
|
|
19
|
+
repairNotes?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface StorageModeSmokeReport {
|
|
22
|
+
generatedAt: string;
|
|
23
|
+
/** Implementation backing `createStateDatabase` today — wasm sql.js, not native WAL */
|
|
24
|
+
runtimeIndexDriver: "sql_js";
|
|
25
|
+
nativeSqliteProbe: ReturnType<typeof probeNativeSqliteLoad> & {
|
|
26
|
+
/** Current code path does not use native driver even when load succeeds */
|
|
27
|
+
runtimeUsesNativeDriver: false;
|
|
28
|
+
};
|
|
29
|
+
semantics: StorageModeSmokeSemantics;
|
|
30
|
+
repairFromArtifactsFixture?: StorageModeSmokeRepairFixtureResult;
|
|
31
|
+
}
|
|
32
|
+
export interface RunStorageModeSmokeOptions {
|
|
33
|
+
/** Required when runRepairFixture is true — temp dir created if omitted */
|
|
34
|
+
workspaceRoot?: string;
|
|
35
|
+
/** Run artifact→index backfill smoke (sql.js path); uses temp workspace when workspaceRoot unset */
|
|
36
|
+
runRepairFixture?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare function runStorageModeSmoke(options?: RunStorageModeSmokeOptions): Promise<StorageModeSmokeReport>;
|