@haaaiawd/second-nature 0.1.51 → 0.2.0

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 (71) hide show
  1. package/openclaw.plugin.json +29 -29
  2. package/package.json +55 -55
  3. package/runtime/cli/commands/index.js +326 -325
  4. package/runtime/cli/ops/heartbeat-surface.d.ts +84 -84
  5. package/runtime/cli/ops/heartbeat-surface.js +100 -100
  6. package/runtime/cli/ops/ops-router.js +1555 -1482
  7. package/runtime/cli/ops/workspace-heartbeat-runner.d.ts +85 -85
  8. package/runtime/cli/ops/workspace-heartbeat-runner.js +242 -242
  9. package/runtime/connectors/base/contract.d.ts +111 -111
  10. package/runtime/connectors/base/failure-taxonomy.d.ts +13 -13
  11. package/runtime/connectors/base/failure-taxonomy.js +186 -186
  12. package/runtime/connectors/base/map-life-evidence.js +137 -137
  13. package/runtime/connectors/base/policy-layer.js +202 -202
  14. package/runtime/connectors/evidence-normalizer.d.ts +45 -0
  15. package/runtime/connectors/evidence-normalizer.js +115 -0
  16. package/runtime/connectors/manifest/manifest-schema.d.ts +152 -152
  17. package/runtime/connectors/manifest/manifest-schema.js +54 -54
  18. package/runtime/connectors/services/connector-executor-adapter.d.ts +20 -20
  19. package/runtime/connectors/services/connector-executor-adapter.js +645 -645
  20. package/runtime/core/second-nature/action/action-closure-recorder.d.ts +70 -0
  21. package/runtime/core/second-nature/action/action-closure-recorder.js +184 -0
  22. package/runtime/core/second-nature/action/action-proposal-builder.d.ts +70 -0
  23. package/runtime/core/second-nature/action/action-proposal-builder.js +217 -0
  24. package/runtime/core/second-nature/action/autonomy-policy-evaluator.d.ts +43 -0
  25. package/runtime/core/second-nature/action/autonomy-policy-evaluator.js +213 -0
  26. package/runtime/core/second-nature/action/policy-bound-dispatch.d.ts +69 -0
  27. package/runtime/core/second-nature/action/policy-bound-dispatch.js +112 -0
  28. package/runtime/core/second-nature/body/tool-affordance/affordance-side-effect.d.ts +49 -0
  29. package/runtime/core/second-nature/body/tool-affordance/affordance-side-effect.js +100 -0
  30. package/runtime/core/second-nature/control-plane/accepted-projection-loader.d.ts +45 -0
  31. package/runtime/core/second-nature/control-plane/accepted-projection-loader.js +85 -0
  32. package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.d.ts +38 -0
  33. package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.js +165 -0
  34. package/runtime/core/second-nature/guidance/guidance-proposal-consumer.d.ts +51 -0
  35. package/runtime/core/second-nature/guidance/guidance-proposal-consumer.js +113 -0
  36. package/runtime/core/second-nature/heartbeat/goal-lifecycle-policy.d.ts +24 -24
  37. package/runtime/core/second-nature/heartbeat/goal-lifecycle-policy.js +61 -61
  38. package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +97 -97
  39. package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +397 -397
  40. package/runtime/core/second-nature/orchestrator/platform-capability-router.js +149 -149
  41. package/runtime/core/second-nature/perception/judgment-engine.d.ts +53 -0
  42. package/runtime/core/second-nature/perception/judgment-engine.js +239 -0
  43. package/runtime/core/second-nature/perception/perception-builder.d.ts +62 -0
  44. package/runtime/core/second-nature/perception/perception-builder.js +208 -0
  45. package/runtime/core/second-nature/perception/sensitivity-classifier.d.ts +37 -0
  46. package/runtime/core/second-nature/perception/sensitivity-classifier.js +87 -0
  47. package/runtime/core/second-nature/quiet-dream/dream-consolidation-runner.d.ts +44 -0
  48. package/runtime/core/second-nature/quiet-dream/dream-consolidation-runner.js +180 -0
  49. package/runtime/core/second-nature/quiet-dream/dream-scheduler.d.ts +36 -0
  50. package/runtime/core/second-nature/quiet-dream/dream-scheduler.js +105 -0
  51. package/runtime/core/second-nature/quiet-dream/memory-projection-lifecycle.d.ts +36 -0
  52. package/runtime/core/second-nature/quiet-dream/memory-projection-lifecycle.js +151 -0
  53. package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.d.ts +46 -0
  54. package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.js +123 -0
  55. package/runtime/observability/causal-loop-health.d.ts +44 -0
  56. package/runtime/observability/causal-loop-health.js +118 -0
  57. package/runtime/observability/diagnostic-redaction.d.ts +43 -0
  58. package/runtime/observability/diagnostic-redaction.js +114 -0
  59. package/runtime/observability/loop-stage-event-sink.d.ts +43 -0
  60. package/runtime/observability/loop-stage-event-sink.js +148 -0
  61. package/runtime/observability/loop-status.d.ts +46 -0
  62. package/runtime/observability/loop-status.js +85 -0
  63. package/runtime/shared/types/index.js +3 -0
  64. package/runtime/shared/types/v8-contracts.d.ts +86 -0
  65. package/runtime/shared/types/v8-contracts.js +84 -0
  66. package/runtime/storage/db/schema/index.d.ts +1 -0
  67. package/runtime/storage/db/schema/index.js +1 -0
  68. package/runtime/storage/db/schema/v8-entities.d.ts +1973 -0
  69. package/runtime/storage/db/schema/v8-entities.js +160 -0
  70. package/runtime/storage/v8-state-stores.d.ts +147 -0
  71. package/runtime/storage/v8-state-stores.js +491 -0
@@ -0,0 +1,491 @@
1
+ /**
2
+ * v8 State Stores — Bounded write/read ports for Living Perception Loop entities.
3
+ *
4
+ * Core logic: Persist and retrieve EvidenceItem, PerceptionCard, JudgmentVerdict,
5
+ * ActionClosureRecord, QuietDailyReview, DreamConsolidationRun,
6
+ * LongTermMemoryProjection, HeartbeatCycleTrace, and LoopStageEvent.
7
+ *
8
+ * Design authority:
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/state-memory-system.md`
10
+ * - `.anws/v8/04_SYSTEM_DESIGN/shared-v8-contracts.md`
11
+ *
12
+ * Dependencies:
13
+ * - drizzle-orm (SQLite)
14
+ * - `src/storage/db/schema/v8-entities.js`
15
+ * - `src/shared/types/v8-contracts.js` (SourceRef, DegradedOperationResult)
16
+ *
17
+ * Boundary:
18
+ * - Write validation: rejects missing source refs, checks redaction class.
19
+ * - Read models: bounded by family + status filters; no cross-family joins.
20
+ * - Degraded state: returns DegradedOperationResult on DB failure, never throws.
21
+ *
22
+ * Test coverage: tests/unit/storage/v8-state-stores.test.ts
23
+ */
24
+ import { eq, desc, like } from "drizzle-orm";
25
+ import { evidenceItem, perceptionCard, judgmentVerdict, actionClosureRecord, quietDailyReview, dreamConsolidationRun, longTermMemoryProjection, heartbeatCycleTrace, loopStageEvent, } from "./db/schema/v8-entities.js";
26
+ // ───────────────────────────────────────────────────────────────
27
+ // Shared helpers
28
+ // ───────────────────────────────────────────────────────────────
29
+ function serializeSourceRefs(refs) {
30
+ return JSON.stringify(refs);
31
+ }
32
+ function parseSourceRefs(json) {
33
+ if (!json)
34
+ return [];
35
+ try {
36
+ const parsed = JSON.parse(json);
37
+ if (Array.isArray(parsed))
38
+ return parsed;
39
+ return [];
40
+ }
41
+ catch {
42
+ return [];
43
+ }
44
+ }
45
+ function makeDegraded(reason, ownerStage, operatorNextAction, sourceRefs = []) {
46
+ return {
47
+ status: "degraded",
48
+ reason,
49
+ ownerStage,
50
+ sourceRefs,
51
+ operatorNextAction,
52
+ retryable: true,
53
+ };
54
+ }
55
+ function validateSourceRefs(sourceRefs, ownerStage) {
56
+ if (!sourceRefs || sourceRefs.length === 0) {
57
+ return {
58
+ ok: false,
59
+ degraded: makeDegraded("source_refs_unresolved", ownerStage, "Ensure caller supplies at least one SourceRef"),
60
+ };
61
+ }
62
+ return { ok: true, record: sourceRefs };
63
+ }
64
+ // ───────────────────────────────────────────────────────────────
65
+ // EvidenceItem store
66
+ // ───────────────────────────────────────────────────────────────
67
+ export async function writeEvidenceItem(db, row) {
68
+ const validated = validateSourceRefs(row.sourceRefs, "ingestion");
69
+ if (!validated.ok)
70
+ return validated.degraded;
71
+ try {
72
+ const record = {
73
+ ...row,
74
+ sourceRefsJson: serializeSourceRefs(validated.record),
75
+ };
76
+ await db.db.insert(evidenceItem).values(record);
77
+ return { id: row.id };
78
+ }
79
+ catch {
80
+ return makeDegraded("state_unreadable", "ingestion", "Retry evidence write after DB recovery", validated.record);
81
+ }
82
+ }
83
+ export async function readEvidenceItemsByStatus(db, lifecycleStatus) {
84
+ try {
85
+ const rows = await db.db
86
+ .select()
87
+ .from(evidenceItem)
88
+ .where(eq(evidenceItem.lifecycleStatus, lifecycleStatus))
89
+ .orderBy(desc(evidenceItem.createdAt));
90
+ return { rows };
91
+ }
92
+ catch {
93
+ return {
94
+ rows: [],
95
+ degraded: makeDegraded("state_unreadable", "ingestion", "Check state database connectivity"),
96
+ };
97
+ }
98
+ }
99
+ // ───────────────────────────────────────────────────────────────
100
+ // PerceptionCard store
101
+ // ───────────────────────────────────────────────────────────────
102
+ export async function writePerceptionCard(db, row) {
103
+ const validated = validateSourceRefs(row.sourceRefs, "perception");
104
+ if (!validated.ok)
105
+ return validated.degraded;
106
+ try {
107
+ const record = {
108
+ ...row,
109
+ sourceRefsJson: serializeSourceRefs(validated.record),
110
+ };
111
+ await db.db.insert(perceptionCard).values(record);
112
+ return { id: row.id };
113
+ }
114
+ catch {
115
+ return makeDegraded("state_unreadable", "perception", "Retry perception write after DB recovery", validated.record);
116
+ }
117
+ }
118
+ export async function readPerceptionCardsByCycle(db, cycleId) {
119
+ try {
120
+ const rows = await db.db
121
+ .select()
122
+ .from(perceptionCard)
123
+ .where(eq(perceptionCard.cycleId, cycleId))
124
+ .orderBy(desc(perceptionCard.createdAt));
125
+ return { rows };
126
+ }
127
+ catch {
128
+ return {
129
+ rows: [],
130
+ degraded: makeDegraded("state_unreadable", "perception", "Check state database connectivity"),
131
+ };
132
+ }
133
+ }
134
+ export async function readPerceptionCardById(db, id) {
135
+ try {
136
+ const rows = await db.db
137
+ .select()
138
+ .from(perceptionCard)
139
+ .where(eq(perceptionCard.id, id))
140
+ .limit(1);
141
+ return { row: rows[0] };
142
+ }
143
+ catch {
144
+ return {
145
+ degraded: makeDegraded("state_unreadable", "perception", "Check state database connectivity"),
146
+ };
147
+ }
148
+ }
149
+ // ───────────────────────────────────────────────────────────────
150
+ // JudgmentVerdict store
151
+ // ───────────────────────────────────────────────────────────────
152
+ export async function writeJudgmentVerdict(db, row) {
153
+ const validated = validateSourceRefs(row.sourceRefs, "judgment");
154
+ if (!validated.ok)
155
+ return validated.degraded;
156
+ try {
157
+ const record = {
158
+ ...row,
159
+ sourceRefsJson: serializeSourceRefs(validated.record),
160
+ };
161
+ await db.db.insert(judgmentVerdict).values(record);
162
+ return { id: row.id };
163
+ }
164
+ catch {
165
+ return makeDegraded("state_unreadable", "judgment", "Retry judgment write after DB recovery", validated.record);
166
+ }
167
+ }
168
+ export async function readJudgmentVerdictsByCycle(db, cycleId) {
169
+ try {
170
+ const rows = await db.db
171
+ .select()
172
+ .from(judgmentVerdict)
173
+ .where(eq(judgmentVerdict.cycleId, cycleId))
174
+ .orderBy(desc(judgmentVerdict.createdAt));
175
+ return { rows };
176
+ }
177
+ catch {
178
+ return {
179
+ rows: [],
180
+ degraded: makeDegraded("state_unreadable", "judgment", "Check state database connectivity"),
181
+ };
182
+ }
183
+ }
184
+ export async function readJudgmentVerdictById(db, id) {
185
+ try {
186
+ const rows = await db.db
187
+ .select()
188
+ .from(judgmentVerdict)
189
+ .where(eq(judgmentVerdict.id, id))
190
+ .limit(1);
191
+ return { row: rows[0] };
192
+ }
193
+ catch {
194
+ return {
195
+ degraded: makeDegraded("state_unreadable", "judgment", "Check state database connectivity"),
196
+ };
197
+ }
198
+ }
199
+ // ───────────────────────────────────────────────────────────────
200
+ // ActionClosureRecord store
201
+ // ───────────────────────────────────────────────────────────────
202
+ export async function writeActionClosureRecord(db, row) {
203
+ const validated = validateSourceRefs(row.sourceRefs, "closure");
204
+ if (!validated.ok)
205
+ return validated.degraded;
206
+ try {
207
+ const record = {
208
+ ...row,
209
+ sourceRefsJson: serializeSourceRefs(validated.record),
210
+ };
211
+ await db.db.insert(actionClosureRecord).values(record);
212
+ return { id: row.id };
213
+ }
214
+ catch {
215
+ return makeDegraded("state_unreadable", "closure", "Retry closure write after DB recovery", validated.record);
216
+ }
217
+ }
218
+ export async function readActionClosuresByCycle(db, cycleId) {
219
+ try {
220
+ const rows = await db.db
221
+ .select()
222
+ .from(actionClosureRecord)
223
+ .where(eq(actionClosureRecord.cycleId, cycleId))
224
+ .orderBy(desc(actionClosureRecord.createdAt));
225
+ return { rows };
226
+ }
227
+ catch {
228
+ return {
229
+ rows: [],
230
+ degraded: makeDegraded("state_unreadable", "closure", "Check state database connectivity"),
231
+ };
232
+ }
233
+ }
234
+ export async function readActionClosuresByDay(db, day) {
235
+ try {
236
+ const rows = await db.db
237
+ .select()
238
+ .from(actionClosureRecord)
239
+ .where(like(actionClosureRecord.createdAt, `${day}%`))
240
+ .orderBy(desc(actionClosureRecord.createdAt));
241
+ return { rows };
242
+ }
243
+ catch {
244
+ return {
245
+ rows: [],
246
+ degraded: makeDegraded("state_unreadable", "closure", "Check state database connectivity"),
247
+ };
248
+ }
249
+ }
250
+ // ───────────────────────────────────────────────────────────────
251
+ // QuietDailyReview store
252
+ // ───────────────────────────────────────────────────────────────
253
+ export async function writeQuietDailyReview(db, row) {
254
+ const validated = validateSourceRefs(row.sourceRefs, "quiet");
255
+ if (!validated.ok)
256
+ return validated.degraded;
257
+ try {
258
+ const record = {
259
+ ...row,
260
+ sourceRefsJson: serializeSourceRefs(validated.record),
261
+ };
262
+ await db.db.insert(quietDailyReview).values(record);
263
+ return { id: row.id };
264
+ }
265
+ catch {
266
+ return makeDegraded("state_unreadable", "quiet", "Retry Quiet write after DB recovery", validated.record);
267
+ }
268
+ }
269
+ export async function readQuietDailyReviewById(db, id) {
270
+ try {
271
+ const rows = await db.db
272
+ .select()
273
+ .from(quietDailyReview)
274
+ .where(eq(quietDailyReview.id, id))
275
+ .limit(1);
276
+ return { row: rows[0] };
277
+ }
278
+ catch {
279
+ return {
280
+ degraded: makeDegraded("state_unreadable", "quiet", "Check state database connectivity"),
281
+ };
282
+ }
283
+ }
284
+ export async function readQuietDailyReviewsByDay(db, day) {
285
+ try {
286
+ const rows = await db.db
287
+ .select()
288
+ .from(quietDailyReview)
289
+ .where(eq(quietDailyReview.day, day))
290
+ .orderBy(desc(quietDailyReview.createdAt));
291
+ return { rows };
292
+ }
293
+ catch {
294
+ return {
295
+ rows: [],
296
+ degraded: makeDegraded("state_unreadable", "quiet", "Check state database connectivity"),
297
+ };
298
+ }
299
+ }
300
+ // ───────────────────────────────────────────────────────────────
301
+ // DreamConsolidationRun store
302
+ // ───────────────────────────────────────────────────────────────
303
+ export async function writeDreamConsolidationRun(db, row) {
304
+ const validated = validateSourceRefs(row.sourceRefs, "dream");
305
+ if (!validated.ok)
306
+ return validated.degraded;
307
+ try {
308
+ const record = {
309
+ ...row,
310
+ sourceRefsJson: serializeSourceRefs(validated.record),
311
+ };
312
+ await db.db.insert(dreamConsolidationRun).values(record);
313
+ return { id: row.id };
314
+ }
315
+ catch {
316
+ return makeDegraded("state_unreadable", "dream", "Retry Dream write after DB recovery", validated.record);
317
+ }
318
+ }
319
+ export async function readDreamConsolidationRunById(db, id) {
320
+ try {
321
+ const rows = await db.db
322
+ .select()
323
+ .from(dreamConsolidationRun)
324
+ .where(eq(dreamConsolidationRun.id, id))
325
+ .limit(1);
326
+ return { row: rows[0] };
327
+ }
328
+ catch {
329
+ return {
330
+ degraded: makeDegraded("state_unreadable", "dream", "Check state database connectivity"),
331
+ };
332
+ }
333
+ }
334
+ export async function readDreamConsolidationRunsByQuietId(db, quietReviewId) {
335
+ try {
336
+ const rows = await db.db
337
+ .select()
338
+ .from(dreamConsolidationRun)
339
+ .where(eq(dreamConsolidationRun.quietReviewId, quietReviewId))
340
+ .orderBy(desc(dreamConsolidationRun.createdAt));
341
+ return { rows };
342
+ }
343
+ catch {
344
+ return {
345
+ rows: [],
346
+ degraded: makeDegraded("state_unreadable", "dream", "Check state database connectivity"),
347
+ };
348
+ }
349
+ }
350
+ // ───────────────────────────────────────────────────────────────
351
+ // LongTermMemoryProjection store
352
+ // ───────────────────────────────────────────────────────────────
353
+ export async function writeLongTermMemoryProjection(db, row) {
354
+ const validated = validateSourceRefs(row.sourceRefs, "projection");
355
+ if (!validated.ok)
356
+ return validated.degraded;
357
+ try {
358
+ const record = {
359
+ ...row,
360
+ sourceRefsJson: serializeSourceRefs(validated.record),
361
+ };
362
+ await db.db.insert(longTermMemoryProjection).values(record);
363
+ return { id: row.id };
364
+ }
365
+ catch {
366
+ return makeDegraded("state_unreadable", "projection", "Retry projection write after DB recovery", validated.record);
367
+ }
368
+ }
369
+ export async function readMemoryProjectionsByStatus(db, status) {
370
+ try {
371
+ const rows = await db.db
372
+ .select()
373
+ .from(longTermMemoryProjection)
374
+ .where(eq(longTermMemoryProjection.status, status))
375
+ .orderBy(desc(longTermMemoryProjection.createdAt));
376
+ return { rows };
377
+ }
378
+ catch {
379
+ return {
380
+ rows: [],
381
+ degraded: makeDegraded("state_unreadable", "projection", "Check state database connectivity"),
382
+ };
383
+ }
384
+ }
385
+ export async function readMemoryProjectionsByTopic(db, topicKey) {
386
+ try {
387
+ const rows = await db.db
388
+ .select()
389
+ .from(longTermMemoryProjection)
390
+ .where(eq(longTermMemoryProjection.topicKey, topicKey))
391
+ .orderBy(desc(longTermMemoryProjection.createdAt));
392
+ return { rows };
393
+ }
394
+ catch {
395
+ return {
396
+ rows: [],
397
+ degraded: makeDegraded("state_unreadable", "projection", "Check state database connectivity"),
398
+ };
399
+ }
400
+ }
401
+ // ───────────────────────────────────────────────────────────────
402
+ // HeartbeatCycleTrace store
403
+ // ───────────────────────────────────────────────────────────────
404
+ export async function writeHeartbeatCycleTrace(db, row) {
405
+ try {
406
+ const record = {
407
+ ...row,
408
+ sourceRefsJson: row.sourceRefs ? serializeSourceRefs(row.sourceRefs) : "[]",
409
+ };
410
+ await db.db.insert(heartbeatCycleTrace).values(record);
411
+ return { id: row.id };
412
+ }
413
+ catch {
414
+ return makeDegraded("state_unreadable", "ingestion", "Retry cycle trace write after DB recovery");
415
+ }
416
+ }
417
+ export async function readHeartbeatCycleTraces(db, limit = 100) {
418
+ try {
419
+ const rows = await db.db
420
+ .select()
421
+ .from(heartbeatCycleTrace)
422
+ .orderBy(desc(heartbeatCycleTrace.cycleSequence))
423
+ .limit(limit);
424
+ return { rows };
425
+ }
426
+ catch {
427
+ return {
428
+ rows: [],
429
+ degraded: makeDegraded("state_unreadable", "ingestion", "Check state database connectivity"),
430
+ };
431
+ }
432
+ }
433
+ // ───────────────────────────────────────────────────────────────
434
+ // LoopStageEvent store
435
+ // ───────────────────────────────────────────────────────────────
436
+ export async function writeLoopStageEvent(db, row) {
437
+ const stage = row.stage;
438
+ const validated = validateSourceRefs(row.sourceRefs, stage);
439
+ if (!validated.ok)
440
+ return validated.degraded;
441
+ try {
442
+ const record = {
443
+ ...row,
444
+ sourceRefsJson: serializeSourceRefs(validated.record),
445
+ };
446
+ await db.db.insert(loopStageEvent).values(record);
447
+ return { id: row.id };
448
+ }
449
+ catch {
450
+ return makeDegraded("state_unreadable", stage, "Retry stage event write after DB recovery", validated.record);
451
+ }
452
+ }
453
+ export async function readLoopStageEventsByCycle(db, cycleId) {
454
+ try {
455
+ const rows = await db.db
456
+ .select()
457
+ .from(loopStageEvent)
458
+ .where(eq(loopStageEvent.cycleId, cycleId))
459
+ .orderBy(desc(loopStageEvent.occurredAt));
460
+ return { rows };
461
+ }
462
+ catch {
463
+ return {
464
+ rows: [],
465
+ degraded: makeDegraded("state_unreadable", "closure", "Check state database connectivity"),
466
+ };
467
+ }
468
+ }
469
+ export async function readLoopStageEventsByStage(db, stage, limit = 100) {
470
+ try {
471
+ const rows = await db.db
472
+ .select()
473
+ .from(loopStageEvent)
474
+ .where(eq(loopStageEvent.stage, stage))
475
+ .orderBy(desc(loopStageEvent.occurredAt))
476
+ .limit(limit);
477
+ return { rows };
478
+ }
479
+ catch {
480
+ return {
481
+ rows: [],
482
+ degraded: makeDegraded("state_unreadable", "closure", "Check state database connectivity"),
483
+ };
484
+ }
485
+ }
486
+ // ───────────────────────────────────────────────────────────────
487
+ // SourceRef round-trip helper (for tests and consumers)
488
+ // ───────────────────────────────────────────────────────────────
489
+ export function extractSourceRefs(row) {
490
+ return parseSourceRefs(row.sourceRefsJson);
491
+ }