@haaaiawd/second-nature 0.1.27 → 0.1.29

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 (157) hide show
  1. package/SKILL.md +35 -33
  2. package/agent-inner-guide.md +144 -124
  3. package/index.js +76 -1
  4. package/openclaw.plugin.json +2 -2
  5. package/package.json +2 -1
  6. package/runtime/cli/commands/connector-behavior.d.ts +20 -0
  7. package/runtime/cli/commands/connector-behavior.js +160 -0
  8. package/runtime/cli/commands/index.js +8 -0
  9. package/runtime/cli/index.js +9 -2
  10. package/runtime/cli/ops/manual-run-dispatcher.d.ts +79 -0
  11. package/runtime/cli/ops/manual-run-dispatcher.js +110 -0
  12. package/runtime/cli/ops/ops-router.d.ts +45 -4
  13. package/runtime/cli/ops/ops-router.js +543 -2
  14. package/runtime/cli/read-models/index.js +35 -18
  15. package/runtime/cli/read-models/types.d.ts +1 -0
  16. package/runtime/connectors/agent-network/agent-world/adapter.d.ts +1 -0
  17. package/runtime/connectors/agent-network/agent-world/adapter.js +2 -2
  18. package/runtime/connectors/base/contract.d.ts +4 -1
  19. package/runtime/connectors/base/contract.js +5 -1
  20. package/runtime/connectors/base/effect-commit-ledger-sqlite.d.ts +31 -0
  21. package/runtime/connectors/base/effect-commit-ledger-sqlite.js +86 -0
  22. package/runtime/connectors/base/failure-taxonomy.js +5 -0
  23. package/runtime/connectors/base/manifest-v7.d.ts +151 -0
  24. package/runtime/connectors/base/manifest-v7.js +170 -0
  25. package/runtime/connectors/base/manifest.d.ts +67 -77
  26. package/runtime/connectors/base/manifest.js +7 -7
  27. package/runtime/connectors/base/route-planner.js +11 -8
  28. package/runtime/connectors/base/structured-unavailable-reason.d.ts +59 -0
  29. package/runtime/connectors/base/structured-unavailable-reason.js +113 -0
  30. package/runtime/connectors/base/wet-probe-runner.d.ts +40 -0
  31. package/runtime/connectors/base/wet-probe-runner.js +132 -0
  32. package/runtime/connectors/manifest/manifest-schema.d.ts +4 -0
  33. package/runtime/connectors/manifest/manifest-schema.js +2 -0
  34. package/runtime/connectors/services/connector-executor-adapter.d.ts +1 -0
  35. package/runtime/connectors/services/connector-executor-adapter.js +132 -26
  36. package/runtime/core/second-nature/body/behavior-promotion/behavior-promotion-loop.d.ts +45 -0
  37. package/runtime/core/second-nature/body/behavior-promotion/behavior-promotion-loop.js +132 -0
  38. package/runtime/core/second-nature/body/circuit-breaker/circuit-breaker-manager.d.ts +60 -0
  39. package/runtime/core/second-nature/body/circuit-breaker/circuit-breaker-manager.js +174 -0
  40. package/runtime/core/second-nature/body/probe-signal-adapter.d.ts +38 -0
  41. package/runtime/core/second-nature/body/probe-signal-adapter.js +60 -0
  42. package/runtime/core/second-nature/body/tool-affordance/affordance-assembler.d.ts +51 -0
  43. package/runtime/core/second-nature/body/tool-affordance/affordance-assembler.js +129 -0
  44. package/runtime/core/second-nature/body/tool-affordance/affordance-context-scope.d.ts +30 -0
  45. package/runtime/core/second-nature/body/tool-affordance/affordance-context-scope.js +92 -0
  46. package/runtime/core/second-nature/body/tool-experience/experience-writer.d.ts +34 -0
  47. package/runtime/core/second-nature/body/tool-experience/experience-writer.js +67 -0
  48. package/runtime/core/second-nature/body/tool-experience/pain-signal-query.d.ts +37 -0
  49. package/runtime/core/second-nature/body/tool-experience/pain-signal-query.js +62 -0
  50. package/runtime/core/second-nature/heartbeat/decision-trace-emitter.d.ts +29 -0
  51. package/runtime/core/second-nature/heartbeat/decision-trace-emitter.js +28 -0
  52. package/runtime/core/second-nature/heartbeat/embodied-context-assembler.d.ts +54 -0
  53. package/runtime/core/second-nature/heartbeat/embodied-context-assembler.js +164 -0
  54. package/runtime/core/second-nature/heartbeat/goal-lifecycle-policy.d.ts +37 -0
  55. package/runtime/core/second-nature/heartbeat/goal-lifecycle-policy.js +61 -0
  56. package/runtime/core/second-nature/heartbeat/idle-curiosity-policy.d.ts +37 -0
  57. package/runtime/core/second-nature/heartbeat/idle-curiosity-policy.js +60 -0
  58. package/runtime/core/second-nature/heartbeat/index.d.ts +4 -0
  59. package/runtime/core/second-nature/heartbeat/index.js +5 -0
  60. package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle-v7.d.ts +63 -0
  61. package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle-v7.js +118 -0
  62. package/runtime/core/second-nature/orchestrator/downstream-intent-orchestrator.d.ts +41 -0
  63. package/runtime/core/second-nature/orchestrator/downstream-intent-orchestrator.js +43 -0
  64. package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +2 -1
  65. package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +2 -0
  66. package/runtime/core/second-nature/orchestrator/hard-guard-evaluator.d.ts +31 -0
  67. package/runtime/core/second-nature/orchestrator/hard-guard-evaluator.js +102 -0
  68. package/runtime/core/second-nature/orchestrator/index.d.ts +5 -0
  69. package/runtime/core/second-nature/orchestrator/index.js +7 -0
  70. package/runtime/core/second-nature/quiet/claim-synthesizer.d.ts +53 -0
  71. package/runtime/core/second-nature/quiet/claim-synthesizer.js +153 -0
  72. package/runtime/core/second-nature/quiet/daily-diary-writer.d.ts +29 -0
  73. package/runtime/core/second-nature/quiet/daily-diary-writer.js +92 -0
  74. package/runtime/core/second-nature/quiet/index.d.ts +5 -0
  75. package/runtime/core/second-nature/quiet/index.js +5 -0
  76. package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +19 -12
  77. package/runtime/core/second-nature/types.d.ts +2 -0
  78. package/runtime/guidance/channel-feedback-ingestion-service.d.ts +88 -0
  79. package/runtime/guidance/channel-feedback-ingestion-service.js +231 -0
  80. package/runtime/guidance/guidance-draft-service.d.ts +60 -0
  81. package/runtime/guidance/guidance-draft-service.js +80 -0
  82. package/runtime/guidance/index.d.ts +3 -0
  83. package/runtime/guidance/index.js +3 -0
  84. package/runtime/guidance/outreach-draft-schema.d.ts +8 -8
  85. package/runtime/guidance/outreach-strategy-selector.d.ts +77 -0
  86. package/runtime/guidance/outreach-strategy-selector.js +211 -0
  87. package/runtime/observability/audit/append-only-audit-store.d.ts +20 -2
  88. package/runtime/observability/audit/append-only-audit-store.js +32 -6
  89. package/runtime/observability/audit/audit-envelope.d.ts +2 -1
  90. package/runtime/observability/audit/audit-envelope.js +8 -7
  91. package/runtime/observability/audit/audit-family-registry.json +66 -0
  92. package/runtime/observability/audit/family-registry.d.ts +43 -0
  93. package/runtime/observability/audit/family-registry.js +70 -0
  94. package/runtime/observability/index.d.ts +6 -1
  95. package/runtime/observability/index.js +6 -1
  96. package/runtime/observability/redaction/policy.d.ts +24 -3
  97. package/runtime/observability/redaction/policy.js +74 -0
  98. package/runtime/observability/services/heartbeat-digest-assembler.d.ts +152 -0
  99. package/runtime/observability/services/heartbeat-digest-assembler.js +248 -0
  100. package/runtime/observability/services/lived-experience-audit.js +6 -6
  101. package/runtime/observability/services/narrative-timeline-query-service.d.ts +136 -0
  102. package/runtime/observability/services/narrative-timeline-query-service.js +169 -0
  103. package/runtime/observability/services/restore-audit-service.d.ts +74 -0
  104. package/runtime/observability/services/restore-audit-service.js +79 -0
  105. package/runtime/observability/services/runtime-secret-anchor-view.d.ts +77 -0
  106. package/runtime/observability/services/runtime-secret-anchor-view.js +168 -0
  107. package/runtime/observability/services/self-health-snapshot.d.ts +92 -0
  108. package/runtime/observability/services/self-health-snapshot.js +251 -0
  109. package/runtime/shared/types/goal.d.ts +62 -0
  110. package/runtime/shared/types/goal.js +20 -0
  111. package/runtime/shared/types/index.d.ts +3 -0
  112. package/runtime/shared/types/index.js +3 -0
  113. package/runtime/shared/types/source-ref.d.ts +14 -0
  114. package/runtime/shared/types/source-ref.js +1 -0
  115. package/runtime/shared/types/v7-entities.d.ts +206 -0
  116. package/runtime/shared/types/v7-entities.js +27 -0
  117. package/runtime/storage/db/index.js +3 -0
  118. package/runtime/storage/db/migration-runner.d.ts +30 -0
  119. package/runtime/storage/db/migration-runner.js +93 -0
  120. package/runtime/storage/db/migrations/index.d.ts +5 -0
  121. package/runtime/storage/db/migrations/index.js +13 -0
  122. package/runtime/storage/db/migrations/v7-001-foundation.d.ts +13 -0
  123. package/runtime/storage/db/migrations/v7-001-foundation.js +144 -0
  124. package/runtime/storage/db/migrations/v7-002-effect-commit-ledger.d.ts +8 -0
  125. package/runtime/storage/db/migrations/v7-002-effect-commit-ledger.js +27 -0
  126. package/runtime/storage/db/migrations/v7-003-circuit-breaker.d.ts +7 -0
  127. package/runtime/storage/db/migrations/v7-003-circuit-breaker.js +26 -0
  128. package/runtime/storage/db/migrations/v7-004-behavior-promotion.d.ts +7 -0
  129. package/runtime/storage/db/migrations/v7-004-behavior-promotion.js +26 -0
  130. package/runtime/storage/db/schema/agent-goal.d.ts +38 -0
  131. package/runtime/storage/db/schema/agent-goal.js +2 -0
  132. package/runtime/storage/db/transaction-utils.d.ts +14 -0
  133. package/runtime/storage/db/transaction-utils.js +29 -0
  134. package/runtime/storage/db/write-queue.d.ts +38 -0
  135. package/runtime/storage/db/write-queue.js +97 -0
  136. package/runtime/storage/quiet/persist-quiet-artifact.js +2 -1
  137. package/runtime/storage/services/diary-dream-store.d.ts +35 -0
  138. package/runtime/storage/services/diary-dream-store.js +165 -0
  139. package/runtime/storage/services/embodied-context-state-port.d.ts +77 -0
  140. package/runtime/storage/services/embodied-context-state-port.js +115 -0
  141. package/runtime/storage/services/goal-lifecycle-store.d.ts +42 -0
  142. package/runtime/storage/services/goal-lifecycle-store.js +181 -0
  143. package/runtime/storage/services/history-digest-store.d.ts +33 -0
  144. package/runtime/storage/services/history-digest-store.js +140 -0
  145. package/runtime/storage/services/identity-profile-store.d.ts +25 -0
  146. package/runtime/storage/services/identity-profile-store.js +81 -0
  147. package/runtime/storage/services/interaction-snapshot-projector.d.ts +15 -0
  148. package/runtime/storage/services/interaction-snapshot-projector.js +35 -0
  149. package/runtime/storage/services/restore-snapshot-store.d.ts +52 -0
  150. package/runtime/storage/services/restore-snapshot-store.js +193 -0
  151. package/runtime/storage/services/runtime-secret-anchor-store.d.ts +26 -0
  152. package/runtime/storage/services/runtime-secret-anchor-store.js +82 -0
  153. package/runtime/storage/services/tool-experience-store.d.ts +25 -0
  154. package/runtime/storage/services/tool-experience-store.js +116 -0
  155. package/runtime/storage/services/write-validation-gate.d.ts +46 -0
  156. package/runtime/storage/services/write-validation-gate.js +200 -0
  157. package/workspace-ops-bridge.js +16 -1
@@ -0,0 +1,168 @@
1
+ /**
2
+ * RuntimeSecretAnchorView — T-OBS.C.7
3
+ *
4
+ * Core logic:
5
+ * viewSecretAnchor() probes the encryption key anchor and returns a
6
+ * RuntimeSecretAnchorView that describes the current health status.
7
+ *
8
+ * Three detection scenarios (DR-034):
9
+ * 1. Key path missing / env var not set → status "missing"
10
+ * reasonCode: "runtime_secret_anchor_missing"
11
+ * 2. Key path present but sample decrypt fails with wrong-key signal
12
+ * reasonCode: "credential_recovery_required"
13
+ * 3. Key path present but decrypt call throws / unrecoverable error
14
+ * reasonCode: "runtime_secret_unavailable"
15
+ *
16
+ * RecoveryStep[] is always inline in the view (DR-034).
17
+ * Key plaintext is NEVER stored or returned (ADR-007).
18
+ * Only the key path (env var name / file path) is included.
19
+ *
20
+ * Test coverage: tests/unit/observability/runtime-secret-anchor-view.test.ts
21
+ */
22
+ // ─── Recovery step templates ─────────────────────────────────────────────────
23
+ const RECOVERY_STEPS_MISSING = [
24
+ {
25
+ step: 1,
26
+ action: "Locate your encryption key from a secure vault or backup (see AGENTS.md §Bootstrap Recovery).",
27
+ },
28
+ {
29
+ step: 2,
30
+ action: "Set the environment variable specified in keyPath to the correct key value.",
31
+ command: "export SECOND_NATURE_ENCRYPTION_KEY=<your-key>",
32
+ },
33
+ {
34
+ step: 3,
35
+ action: "Restart the agent process or reload the workspace to pick up the new environment variable.",
36
+ },
37
+ {
38
+ step: 4,
39
+ action: "Run `self_health` to confirm the anchor status changes to verified.",
40
+ },
41
+ ];
42
+ const RECOVERY_STEPS_WRONG_KEY = [
43
+ {
44
+ step: 1,
45
+ action: "The environment variable is set but the key does not match stored credentials. Retrieve the correct key from your vault.",
46
+ },
47
+ {
48
+ step: 2,
49
+ action: "Replace the current environment variable value with the correct key.",
50
+ command: "export SECOND_NATURE_ENCRYPTION_KEY=<correct-key>",
51
+ },
52
+ {
53
+ step: 3,
54
+ action: "If the correct key is unavailable, initiate credential re-encryption with the new key (see AGENTS.md §Credential Rotation).",
55
+ },
56
+ {
57
+ step: 4,
58
+ action: "Run `self_health` to verify the anchor resolves to verified.",
59
+ },
60
+ ];
61
+ const RECOVERY_STEPS_UNAVAILABLE = [
62
+ {
63
+ step: 1,
64
+ action: "The key path exists but the encryption subsystem encountered an unexpected error. Check agent logs for details.",
65
+ },
66
+ {
67
+ step: 2,
68
+ action: "Ensure no other process is locking the key file or environment context.",
69
+ },
70
+ {
71
+ step: 3,
72
+ action: "If the error persists, rotate the key following the procedure in AGENTS.md §Credential Rotation.",
73
+ },
74
+ {
75
+ step: 4,
76
+ action: "Run `self_health` after remediation to confirm resolution.",
77
+ },
78
+ ];
79
+ const RECOVERY_STEPS_VERIFIED = [];
80
+ // ─── Public API ──────────────────────────────────────────────────────────────
81
+ /**
82
+ * Probe the encryption key anchor and return a safe view.
83
+ *
84
+ * Guarantees:
85
+ * - keyPath is a path string (env var name or file path), never a value.
86
+ * - No field in the returned object contains the key plaintext.
87
+ * - recoverySteps is always populated when status ≠ "verified".
88
+ */
89
+ export async function viewSecretAnchor(deps) {
90
+ const now = (deps.now ?? (() => new Date().toISOString()))();
91
+ const keyPath = deps.runtimeOpsPort.getEncryptionKeyPath();
92
+ // Step 1: check whether the key path exists
93
+ let keyExists;
94
+ try {
95
+ keyExists = await deps.runtimeOpsPort.checkKeyPathExists(keyPath);
96
+ }
97
+ catch {
98
+ // checkKeyPathExists itself threw — treat as missing
99
+ keyExists = false;
100
+ }
101
+ if (!keyExists) {
102
+ return {
103
+ anchorId: "primary",
104
+ keyPath,
105
+ status: "missing",
106
+ lastCheckedAt: now,
107
+ recoveryDocRef: "AGENTS.md#bootstrap-recovery",
108
+ recoverySteps: RECOVERY_STEPS_MISSING,
109
+ reasonCode: "runtime_secret_anchor_missing",
110
+ };
111
+ }
112
+ // Step 2: try a sample decrypt to validate the key is correct
113
+ let sampleResult;
114
+ try {
115
+ sampleResult = await deps.credentialPort.verifySampleDecrypt();
116
+ }
117
+ catch {
118
+ // verifySampleDecrypt threw — key exists but subsystem is broken
119
+ return {
120
+ anchorId: "primary",
121
+ keyPath,
122
+ status: "decryption_failed",
123
+ lastCheckedAt: now,
124
+ recoveryDocRef: "AGENTS.md#bootstrap-recovery",
125
+ rotationSchedule: "on workspace migration or manual rotation request",
126
+ checkedCredentialIds: [],
127
+ recoverySteps: RECOVERY_STEPS_UNAVAILABLE,
128
+ reasonCode: "runtime_secret_unavailable",
129
+ };
130
+ }
131
+ if (sampleResult.status === "ok") {
132
+ return {
133
+ anchorId: "primary",
134
+ keyPath,
135
+ status: "verified",
136
+ lastCheckedAt: now,
137
+ recoveryDocRef: "AGENTS.md#bootstrap-recovery",
138
+ rotationSchedule: "on workspace migration or manual rotation request",
139
+ checkedCredentialIds: sampleResult.checkedIds,
140
+ recoverySteps: RECOVERY_STEPS_VERIFIED,
141
+ };
142
+ }
143
+ if (sampleResult.status === "wrong_key") {
144
+ return {
145
+ anchorId: "primary",
146
+ keyPath,
147
+ status: "wrong_key",
148
+ lastCheckedAt: now,
149
+ recoveryDocRef: "AGENTS.md#bootstrap-recovery",
150
+ rotationSchedule: "on workspace migration or manual rotation request",
151
+ checkedCredentialIds: sampleResult.checkedIds,
152
+ recoverySteps: RECOVERY_STEPS_WRONG_KEY,
153
+ reasonCode: "credential_recovery_required",
154
+ };
155
+ }
156
+ // sampleResult.status === "error"
157
+ return {
158
+ anchorId: "primary",
159
+ keyPath,
160
+ status: "decryption_failed",
161
+ lastCheckedAt: now,
162
+ recoveryDocRef: "AGENTS.md#bootstrap-recovery",
163
+ rotationSchedule: "on workspace migration or manual rotation request",
164
+ checkedCredentialIds: sampleResult.checkedIds,
165
+ recoverySteps: RECOVERY_STEPS_UNAVAILABLE,
166
+ reasonCode: "runtime_secret_unavailable",
167
+ };
168
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * SelfHealthSnapshot — T-OBS.C.2
3
+ *
4
+ * Core logic: Run independent health probes for each registered dimension,
5
+ * each with per-probe timeout (DR-036). Total cap: 3000ms via Promise.allSettled.
6
+ * Returns SelfHealthSnapshot with overall status and per-dimension results.
7
+ *
8
+ * DR-036 timeouts:
9
+ * env / storage 200ms → unknown + probe_timeout:env
10
+ * cron / bridge 500ms → unknown + probe_timeout:cron
11
+ * secret / credential 1000ms → unknown + probe_timeout:secret
12
+ * delivery / circuit 800ms → unknown + probe_timeout:delivery
13
+ * state_memory 500ms → degraded + state_memory_unavailable
14
+ *
15
+ * DR-032 circular dependency degradation:
16
+ * If state-memory is unavailable, narrative_timeline and digest probes
17
+ * return degraded — other probes are unaffected.
18
+ *
19
+ * Total timeout:
20
+ * All probes run concurrently via Promise.allSettled, capped at 3000ms.
21
+ * If ALL probes time out: overall = "unknown", reason = "all_probes_timed_out".
22
+ *
23
+ * Dynamic dimension registration:
24
+ * Callers can register additional probe functions via registerHealthProbe().
25
+ * Minimum required dimensions are always included.
26
+ *
27
+ * Test coverage: tests/unit/observability/self-health-snapshot.test.ts
28
+ */
29
+ export type HealthStatus = "healthy" | "degraded" | "unknown";
30
+ export interface DimensionHealth {
31
+ status: HealthStatus;
32
+ reason?: string;
33
+ checkedAt: string;
34
+ lastKnownAt?: string;
35
+ }
36
+ export interface SelfHealthSnapshot {
37
+ generatedAt: string;
38
+ overall: HealthStatus;
39
+ /** Populated if overall = "unknown" due to all probes timing out */
40
+ reason?: string;
41
+ /** Timestamp of last successful snapshot (for all-timeout fallback) */
42
+ lastKnownAt?: string;
43
+ dimensions: Record<string, DimensionHealth>;
44
+ diagnosticReasonCodes: string[];
45
+ /** Dimension IDs that are degraded or unknown */
46
+ degradedDimensions: string[];
47
+ }
48
+ /** A probe function: resolves with DimensionHealth or throws on error */
49
+ export type HealthProbeFunction = () => Promise<DimensionHealth>;
50
+ export interface RegisteredProbe {
51
+ dimensionId: string;
52
+ probe: HealthProbeFunction;
53
+ timeoutMs: number;
54
+ /** If true, timeout returns "degraded" instead of "unknown" (DR-032 state-memory path) */
55
+ timeoutAsDegraded?: boolean;
56
+ }
57
+ export declare const MINIMUM_REQUIRED_DIMENSIONS: string[];
58
+ /**
59
+ * Register a health probe for a named dimension.
60
+ * Built-in minimum dimensions are registered by default with no-op probes
61
+ * that return healthy. Callers override with real probe functions.
62
+ */
63
+ export declare function registerHealthProbe(probe: RegisteredProbe): void;
64
+ /**
65
+ * Remove a probe from the registry (useful for testing).
66
+ */
67
+ export declare function unregisterHealthProbe(dimensionId: string): void;
68
+ /**
69
+ * Clear all registered probes (useful for testing).
70
+ */
71
+ export declare function clearHealthProbeRegistry(): void;
72
+ /** Get all currently registered probes. */
73
+ export declare function getRegisteredProbes(): RegisteredProbe[];
74
+ /**
75
+ * Ensure minimum required dimensions are represented in the registry.
76
+ * Existing registrations (real probes) are not overwritten.
77
+ */
78
+ export declare function ensureMinimumProbes(): void;
79
+ export interface HealthProbeScope {
80
+ /** If specified, only run probes for these dimension IDs */
81
+ dimensions?: string[];
82
+ }
83
+ /**
84
+ * Run all registered health probes and assemble SelfHealthSnapshot.
85
+ *
86
+ * Probes run concurrently (Promise.allSettled) with per-probe timeouts (DR-036).
87
+ * Total cap: 3000ms.
88
+ * All-timeout fallback: overall = "unknown", reason = "all_probes_timed_out".
89
+ *
90
+ * DR-032: state_memory probe timeout marks narrative_timeline + digest as degraded too.
91
+ */
92
+ export declare function getSelfHealthSnapshot(scope?: HealthProbeScope, lastKnownAt?: string): Promise<SelfHealthSnapshot>;
@@ -0,0 +1,251 @@
1
+ /**
2
+ * SelfHealthSnapshot — T-OBS.C.2
3
+ *
4
+ * Core logic: Run independent health probes for each registered dimension,
5
+ * each with per-probe timeout (DR-036). Total cap: 3000ms via Promise.allSettled.
6
+ * Returns SelfHealthSnapshot with overall status and per-dimension results.
7
+ *
8
+ * DR-036 timeouts:
9
+ * env / storage 200ms → unknown + probe_timeout:env
10
+ * cron / bridge 500ms → unknown + probe_timeout:cron
11
+ * secret / credential 1000ms → unknown + probe_timeout:secret
12
+ * delivery / circuit 800ms → unknown + probe_timeout:delivery
13
+ * state_memory 500ms → degraded + state_memory_unavailable
14
+ *
15
+ * DR-032 circular dependency degradation:
16
+ * If state-memory is unavailable, narrative_timeline and digest probes
17
+ * return degraded — other probes are unaffected.
18
+ *
19
+ * Total timeout:
20
+ * All probes run concurrently via Promise.allSettled, capped at 3000ms.
21
+ * If ALL probes time out: overall = "unknown", reason = "all_probes_timed_out".
22
+ *
23
+ * Dynamic dimension registration:
24
+ * Callers can register additional probe functions via registerHealthProbe().
25
+ * Minimum required dimensions are always included.
26
+ *
27
+ * Test coverage: tests/unit/observability/self-health-snapshot.test.ts
28
+ */
29
+ // ─── DR-036 Timeout Constants ─────────────────────────────────────────────────
30
+ const PROBE_TIMEOUTS = {
31
+ env: 200,
32
+ storage: 200,
33
+ cron: 500,
34
+ bridge: 500,
35
+ secret: 1000,
36
+ credential: 1000,
37
+ delivery: 800,
38
+ circuit_breaker: 800,
39
+ dream: 800,
40
+ state_memory: 500,
41
+ narrative_timeline: 500,
42
+ digest: 500,
43
+ };
44
+ const STATE_MEMORY_DEGRADED_DIMENSIONS = new Set([
45
+ "state_memory",
46
+ "narrative_timeline",
47
+ "digest",
48
+ ]);
49
+ const TOTAL_TIMEOUT_MS = 3000;
50
+ // ─── Minimum required dimensions ─────────────────────────────────────────────
51
+ export const MINIMUM_REQUIRED_DIMENSIONS = [
52
+ "env",
53
+ "cron",
54
+ "secret",
55
+ "credential",
56
+ "storage",
57
+ "delivery",
58
+ "dream",
59
+ "bridge",
60
+ "circuit_breaker",
61
+ "state_memory",
62
+ ];
63
+ // ─── Registry ─────────────────────────────────────────────────────────────────
64
+ const _probeRegistry = new Map();
65
+ /**
66
+ * Register a health probe for a named dimension.
67
+ * Built-in minimum dimensions are registered by default with no-op probes
68
+ * that return healthy. Callers override with real probe functions.
69
+ */
70
+ export function registerHealthProbe(probe) {
71
+ _probeRegistry.set(probe.dimensionId, probe);
72
+ }
73
+ /**
74
+ * Remove a probe from the registry (useful for testing).
75
+ */
76
+ export function unregisterHealthProbe(dimensionId) {
77
+ _probeRegistry.delete(dimensionId);
78
+ }
79
+ /**
80
+ * Clear all registered probes (useful for testing).
81
+ */
82
+ export function clearHealthProbeRegistry() {
83
+ _probeRegistry.clear();
84
+ }
85
+ /** Get all currently registered probes. */
86
+ export function getRegisteredProbes() {
87
+ return Array.from(_probeRegistry.values());
88
+ }
89
+ // ─── Default probes for minimum dimensions ───────────────────────────────────
90
+ function makeDefaultProbe(dimensionId) {
91
+ const timeoutMs = PROBE_TIMEOUTS[dimensionId] ?? 500;
92
+ const timeoutAsDegraded = STATE_MEMORY_DEGRADED_DIMENSIONS.has(dimensionId);
93
+ return {
94
+ dimensionId,
95
+ timeoutMs,
96
+ timeoutAsDegraded,
97
+ probe: async () => ({
98
+ status: "healthy",
99
+ checkedAt: new Date().toISOString(),
100
+ }),
101
+ };
102
+ }
103
+ /**
104
+ * Ensure minimum required dimensions are represented in the registry.
105
+ * Existing registrations (real probes) are not overwritten.
106
+ */
107
+ export function ensureMinimumProbes() {
108
+ for (const dim of MINIMUM_REQUIRED_DIMENSIONS) {
109
+ if (!_probeRegistry.has(dim)) {
110
+ _probeRegistry.set(dim, makeDefaultProbe(dim));
111
+ }
112
+ }
113
+ }
114
+ // ─── Probe runner ─────────────────────────────────────────────────────────────
115
+ /**
116
+ * Run a single probe with per-probe timeout.
117
+ * On timeout: returns unknown (or degraded for state_memory path, DR-032).
118
+ * On error: returns unknown + error message.
119
+ */
120
+ async function runProbeWithTimeout(rp, now) {
121
+ const timeoutStatus = rp.timeoutAsDegraded ? "degraded" : "unknown";
122
+ const timeoutReason = STATE_MEMORY_DEGRADED_DIMENSIONS.has(rp.dimensionId)
123
+ ? "state_memory_unavailable"
124
+ : `probe_timeout:${rp.dimensionId}`;
125
+ const timeoutPromise = new Promise((resolve) => {
126
+ setTimeout(() => {
127
+ resolve({
128
+ status: timeoutStatus,
129
+ reason: timeoutReason,
130
+ checkedAt: now,
131
+ });
132
+ }, rp.timeoutMs);
133
+ });
134
+ const probePromise = rp.probe().catch((err) => ({
135
+ status: "unknown",
136
+ reason: `probe_error:${rp.dimensionId}:${err instanceof Error ? err.message : String(err)}`,
137
+ checkedAt: now,
138
+ }));
139
+ return [rp.dimensionId, await Promise.race([probePromise, timeoutPromise])];
140
+ }
141
+ /**
142
+ * Run all registered health probes and assemble SelfHealthSnapshot.
143
+ *
144
+ * Probes run concurrently (Promise.allSettled) with per-probe timeouts (DR-036).
145
+ * Total cap: 3000ms.
146
+ * All-timeout fallback: overall = "unknown", reason = "all_probes_timed_out".
147
+ *
148
+ * DR-032: state_memory probe timeout marks narrative_timeline + digest as degraded too.
149
+ */
150
+ export async function getSelfHealthSnapshot(scope, lastKnownAt) {
151
+ // Ensure minimum probes exist
152
+ ensureMinimumProbes();
153
+ const now = new Date().toISOString();
154
+ // Determine which probes to run
155
+ const allProbes = Array.from(_probeRegistry.values());
156
+ const probes = scope?.dimensions
157
+ ? allProbes.filter((p) => scope.dimensions.includes(p.dimensionId))
158
+ : allProbes;
159
+ if (probes.length === 0) {
160
+ return {
161
+ generatedAt: now,
162
+ overall: "unknown",
163
+ reason: "no_probes_registered",
164
+ lastKnownAt,
165
+ dimensions: {},
166
+ diagnosticReasonCodes: ["no_probes_registered"],
167
+ degradedDimensions: [],
168
+ };
169
+ }
170
+ // Run all probes with individual timeouts, wrapped in a 3s global cap
171
+ const globalTimeoutPromise = new Promise((resolve) => {
172
+ setTimeout(() => {
173
+ // Return all probes as unknown on global timeout
174
+ const fallback = probes.map((p) => [
175
+ p.dimensionId,
176
+ {
177
+ status: "unknown",
178
+ reason: `probe_timeout:${p.dimensionId}`,
179
+ checkedAt: now,
180
+ },
181
+ ]);
182
+ resolve(fallback);
183
+ }, TOTAL_TIMEOUT_MS);
184
+ });
185
+ const probeRunnerPromise = Promise.allSettled(probes.map((p) => runProbeWithTimeout(p, now))).then((results) => results
186
+ .filter((r) => r.status === "fulfilled")
187
+ .map((r) => r.value));
188
+ const results = await Promise.race([probeRunnerPromise, globalTimeoutPromise]);
189
+ // Assemble dimensions map
190
+ const dimensions = {};
191
+ for (const [dimId, health] of results) {
192
+ dimensions[dimId] = health;
193
+ }
194
+ // DR-032: if state_memory is degraded/unknown, propagate to narrative_timeline + digest
195
+ const stateMemoryHealth = dimensions["state_memory"];
196
+ if (stateMemoryHealth &&
197
+ (stateMemoryHealth.status === "degraded" || stateMemoryHealth.status === "unknown")) {
198
+ const smReason = "state_memory_unavailable";
199
+ for (const dim of ["narrative_timeline", "digest"]) {
200
+ if (dimensions[dim] && dimensions[dim].status === "healthy") {
201
+ dimensions[dim] = {
202
+ status: "degraded",
203
+ reason: smReason,
204
+ checkedAt: now,
205
+ };
206
+ }
207
+ else if (!dimensions[dim] && _probeRegistry.has(dim)) {
208
+ dimensions[dim] = {
209
+ status: "degraded",
210
+ reason: smReason,
211
+ checkedAt: now,
212
+ };
213
+ }
214
+ }
215
+ }
216
+ // Collect diagnostic reason codes and degraded dimensions
217
+ const diagnosticReasonCodes = [];
218
+ const degradedDimensions = [];
219
+ for (const [dimId, health] of Object.entries(dimensions)) {
220
+ if (health.status !== "healthy") {
221
+ degradedDimensions.push(dimId);
222
+ if (health.reason)
223
+ diagnosticReasonCodes.push(health.reason);
224
+ }
225
+ }
226
+ // Compute overall status
227
+ const allUnknown = Object.values(dimensions).every((d) => d.status === "unknown");
228
+ const anyDegraded = Object.values(dimensions).some((d) => d.status === "degraded");
229
+ const anyUnknown = Object.values(dimensions).some((d) => d.status === "unknown");
230
+ let overall;
231
+ let reason;
232
+ if (allUnknown) {
233
+ overall = "unknown";
234
+ reason = "all_probes_timed_out";
235
+ }
236
+ else if (anyDegraded || anyUnknown) {
237
+ overall = "degraded";
238
+ }
239
+ else {
240
+ overall = "healthy";
241
+ }
242
+ return {
243
+ generatedAt: now,
244
+ overall,
245
+ reason,
246
+ lastKnownAt: allUnknown ? lastKnownAt : undefined,
247
+ dimensions,
248
+ diagnosticReasonCodes,
249
+ degradedDimensions,
250
+ };
251
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * AgentGoal v7 shared types — DR-014 snake_case kind / scope enforcement.
3
+ *
4
+ * Core logic:
5
+ * - `kind` is a closed union of snake_case lowercase strings.
6
+ * - `scope` controls visibility (global vs platform-specific vs session-bound).
7
+ * - `status` supports full v7 lifecycle including paused → expired/replaced.
8
+ *
9
+ * Dependencies:
10
+ * - `SourceRef` from `./source-ref.js` for grounding.
11
+ *
12
+ * Boundary:
13
+ * - Used by state-memory (GoalLifecycleStore), control-plane
14
+ * (GoalLifecyclePolicy), and runtime-ops (goal command surface).
15
+ * - Non-enum values trigger compile errors via exhaustive union checks.
16
+ *
17
+ * Test coverage: tests/unit/shared/v7-entities.test.ts (invalid kind
18
+ * `@ts-expect-error` compile guard).
19
+ */
20
+ import type { SourceRef } from "./source-ref.js";
21
+ export type AgentGoalKind = "short_term" | "long_term" | "habit" | "maintenance" | "passive_sensing" | "outreach" | "exploration";
22
+ export type AgentGoalStatus = "proposal" | "accepted" | "rejected" | "completed" | "paused" | "expired" | "replaced";
23
+ export type AgentGoalOrigin = "owner_set" | "agent_proposed" | "policy_seeded";
24
+ export type AgentGoalScope = "global" | "platform_specific" | "session_bound";
25
+ export interface AgentGoal {
26
+ goalId: string;
27
+ kind: AgentGoalKind;
28
+ scope: AgentGoalScope;
29
+ status: AgentGoalStatus;
30
+ origin: AgentGoalOrigin;
31
+ description: string;
32
+ completionCriteria: string;
33
+ risk: "low" | "medium" | "high";
34
+ priorityHint: number;
35
+ sourceRefs: SourceRef;
36
+ acceptedBy?: "owner" | "policy_allowlist";
37
+ expiresAt?: string;
38
+ createdAt: string;
39
+ updatedAt: string;
40
+ }
41
+ export interface AgentGoalWrite {
42
+ goalId: string;
43
+ kind: AgentGoalKind;
44
+ scope: AgentGoalScope;
45
+ status: AgentGoalStatus;
46
+ origin: AgentGoalOrigin;
47
+ description: string;
48
+ completionCriteria: string;
49
+ risk: "low" | "medium" | "high";
50
+ priorityHint: number;
51
+ sourceRefs: SourceRef;
52
+ acceptedBy?: "owner" | "policy_allowlist";
53
+ expiresAt?: string;
54
+ createdAt: string;
55
+ updatedAt: string;
56
+ }
57
+ export interface AgentGoalStatusTransition {
58
+ goalId: string;
59
+ newStatus: AgentGoalStatus;
60
+ acceptedBy?: "owner" | "policy_allowlist";
61
+ updatedAt: string;
62
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * AgentGoal v7 shared types — DR-014 snake_case kind / scope enforcement.
3
+ *
4
+ * Core logic:
5
+ * - `kind` is a closed union of snake_case lowercase strings.
6
+ * - `scope` controls visibility (global vs platform-specific vs session-bound).
7
+ * - `status` supports full v7 lifecycle including paused → expired/replaced.
8
+ *
9
+ * Dependencies:
10
+ * - `SourceRef` from `./source-ref.js` for grounding.
11
+ *
12
+ * Boundary:
13
+ * - Used by state-memory (GoalLifecycleStore), control-plane
14
+ * (GoalLifecyclePolicy), and runtime-ops (goal command surface).
15
+ * - Non-enum values trigger compile errors via exhaustive union checks.
16
+ *
17
+ * Test coverage: tests/unit/shared/v7-entities.test.ts (invalid kind
18
+ * `@ts-expect-error` compile guard).
19
+ */
20
+ export {};
@@ -1,3 +1,6 @@
1
1
  export * from "./continuity.js";
2
2
  export * from "./credential.js";
3
3
  export * from "./outreach.js";
4
+ export * from "./source-ref.js";
5
+ export * from "./goal.js";
6
+ export * from "./v7-entities.js";
@@ -1,3 +1,6 @@
1
1
  export * from "./continuity.js";
2
2
  export * from "./credential.js";
3
3
  export * from "./outreach.js";
4
+ export * from "./source-ref.js";
5
+ export * from "./goal.js";
6
+ export * from "./v7-entities.js";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * SourceRef — v7 non-empty tuple for source grounding.
3
+ *
4
+ * Core logic: Every fact claim must carry at least one source reference.
5
+ * DR-025 enforces non-empty at compile time. Empty array assignments are
6
+ * rejected by the TypeScript compiler (`strict: true`).
7
+ *
8
+ * Dependencies: none (primitive shared type).
9
+ * Boundary: Used across state-memory, dream-quiet, guidance-voice, and
10
+ * observability systems for source-backed assertions.
11
+ * Test coverage: tests/unit/shared/v7-entities.test.ts (compile-time
12
+ * `@ts-expect-error` guard for empty tuple).
13
+ */
14
+ export type SourceRef = readonly [string, ...string[]];
@@ -0,0 +1 @@
1
+ export {};