@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,114 @@
1
+ /**
2
+ * DiagnosticRedaction — Attribute sensitivity blocks and redact diagnostics.
3
+ *
4
+ * Core logic: Given a diagnostic payload, classify its sensitivity,
5
+ * redact credential-shaped values, preserve public technical summaries,
6
+ * and attribute the block to the responsible system.
7
+ *
8
+ * Design authority:
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.detail.md §3.4`
10
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.md §5`
11
+ *
12
+ * Dependencies:
13
+ * - `src/shared/types/v8-contracts.js` (SourceRef, RedactionClass, SensitivityClass)
14
+ *
15
+ * Boundary:
16
+ * - Pure function; no DB access.
17
+ * - Does not modify source data; returns redacted copy.
18
+ * - Public technical vocabulary is preserved.
19
+ *
20
+ * Test coverage: tests/unit/observability/diagnostic-redaction.test.ts
21
+ */
22
+ // ───────────────────────────────────────────────────────────────
23
+ // Helpers
24
+ // ───────────────────────────────────────────────────────────────
25
+ function containsCredentialValue(text) {
26
+ // Match both key=value and Bearer token formats
27
+ return /\b(?:Bearer|token|secret|password|key|credential)\s*[:=\s]\s*[a-zA-Z0-9+/=_-]{8,}\b/i.test(text);
28
+ }
29
+ function containsPrivateMarker(text) {
30
+ return /\b(?:DM|private message|confidential|internal only)\b/i.test(text);
31
+ }
32
+ function redactCredentialValues(text) {
33
+ // Redact both key=value and Bearer token formats
34
+ return text.replace(/\b((?:Bearer|token|secret|password|key|credential)\s*[:=\s]\s*)[a-zA-Z0-9+/=_-]{8,}\b/gi, "$1[REDACTED]");
35
+ }
36
+ /**
37
+ * Classify sensitivity-related diagnostic attribution based on source system
38
+ * and reason code. Maps to deterministic attribution categories per
39
+ * observability-health-system.detail.md §4.2.
40
+ */
41
+ export function classifyDiagnosticAttribution(sourceSystem, reasonCode) {
42
+ // Storage validation blocks
43
+ if (reasonCode === "state_unreadable" || reasonCode === "quiet_validation_failed") {
44
+ return "storage_validation_block";
45
+ }
46
+ // Dream redaction blocks
47
+ if (reasonCode === "dream_blocked_redaction") {
48
+ return "dream_redaction_block";
49
+ }
50
+ // Perception risk blocks
51
+ if (reasonCode === "perception_rules_only" || reasonCode === "evidence_batch_truncated") {
52
+ return "perception_risk_block";
53
+ }
54
+ // Policy denial
55
+ if (reasonCode?.startsWith("policy_denied") || reasonCode === "policy_downgraded_to_draft") {
56
+ return "policy_denial";
57
+ }
58
+ return "no_redaction_needed";
59
+ }
60
+ // ───────────────────────────────────────────────────────────────
61
+ // Public API
62
+ // ───────────────────────────────────────────────────────────────
63
+ export function projectDiagnosticRedaction(payload) {
64
+ const summary = payload.summary;
65
+ const detail = payload.detail;
66
+ // Credential value shape → blocked
67
+ if (containsCredentialValue(summary) || (detail && containsCredentialValue(detail))) {
68
+ return {
69
+ summary: redactCredentialValues(summary),
70
+ detail: detail ? redactCredentialValues(detail) : undefined,
71
+ redactionClass: "blocked",
72
+ attribution: `${payload.sourceSystem}:credential_shape_detected`,
73
+ };
74
+ }
75
+ // Classify attribution from source system + reason code
76
+ const attribution = classifyDiagnosticAttribution(payload.sourceSystem, payload.reasonCode);
77
+ // Private context → redacted
78
+ if (payload.sensitivityHint === "private_context" ||
79
+ containsPrivateMarker(summary) ||
80
+ (detail && containsPrivateMarker(detail))) {
81
+ return {
82
+ summary: "[redacted: private context]",
83
+ detail: undefined,
84
+ redactionClass: "redacted",
85
+ attribution: `${payload.sourceSystem}:${attribution}`,
86
+ };
87
+ }
88
+ // Public technical → preserve with light redaction
89
+ if (payload.sensitivityHint === "public_technical") {
90
+ return {
91
+ summary,
92
+ detail,
93
+ redactionClass: "none",
94
+ attribution: `${payload.sourceSystem}:public_technical_preserved`,
95
+ };
96
+ }
97
+ // Source-system-specific attribution for blocked/redacted cases
98
+ if (attribution !== "no_redaction_needed") {
99
+ const isBlocked = attribution === "policy_denial" || attribution === "dream_redaction_block";
100
+ return {
101
+ summary: isBlocked ? `[blocked: ${attribution.replace(/_/g, " ")}]` : summary,
102
+ detail: isBlocked ? undefined : detail,
103
+ redactionClass: isBlocked ? "blocked" : "redacted",
104
+ attribution: `${payload.sourceSystem}:${attribution}`,
105
+ };
106
+ }
107
+ // Default: preserve
108
+ return {
109
+ summary,
110
+ detail,
111
+ redactionClass: "none",
112
+ attribution: `${payload.sourceSystem}:no_redaction_needed`,
113
+ };
114
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * LoopStageEventSink — v8 observability stage event recorder.
3
+ *
4
+ * Core logic: Validate, redact, and append LoopStageEvent rows.
5
+ * Malformed events produce degraded diagnostics without blocking the
6
+ * heartbeat main loop.
7
+ *
8
+ * Design authority:
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.md §5`
10
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.detail.md §3.1`
11
+ *
12
+ * Dependencies:
13
+ * - `src/storage/v8-state-stores.js` (writeLoopStageEvent)
14
+ * - `src/shared/types/v8-contracts.js` (LoopStageEvent, SourceRef, V8ReasonCode)
15
+ *
16
+ * Boundary:
17
+ * - Does NOT make semantic decisions about stage health.
18
+ * - Does NOT block callers on DB failure; returns degraded result.
19
+ * - Redacts credential-shaped values before persistence.
20
+ *
21
+ * Test coverage: tests/unit/observability/loop-stage-event-sink.test.ts
22
+ */
23
+ import type { StateDatabase } from "../storage/db/index.js";
24
+ import type { LoopStageEvent, DegradedOperationResult } from "../shared/types/v8-contracts.js";
25
+ export interface RecordLoopStageEventOptions {
26
+ now?: string;
27
+ }
28
+ export type RecordLoopStageEventResult = {
29
+ ok: true;
30
+ id: string;
31
+ } | {
32
+ ok: false;
33
+ degraded: DegradedOperationResult;
34
+ };
35
+ export declare function recordLoopStageEvent(db: StateDatabase, event: Partial<LoopStageEvent>, options?: RecordLoopStageEventOptions): Promise<RecordLoopStageEventResult>;
36
+ export interface BatchRecordResult {
37
+ succeeded: string[];
38
+ failed: {
39
+ id?: string;
40
+ degraded: DegradedOperationResult;
41
+ }[];
42
+ }
43
+ export declare function recordLoopStageEvents(db: StateDatabase, events: Partial<LoopStageEvent>[], options?: RecordLoopStageEventOptions): Promise<BatchRecordResult>;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * LoopStageEventSink — v8 observability stage event recorder.
3
+ *
4
+ * Core logic: Validate, redact, and append LoopStageEvent rows.
5
+ * Malformed events produce degraded diagnostics without blocking the
6
+ * heartbeat main loop.
7
+ *
8
+ * Design authority:
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.md §5`
10
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.detail.md §3.1`
11
+ *
12
+ * Dependencies:
13
+ * - `src/storage/v8-state-stores.js` (writeLoopStageEvent)
14
+ * - `src/shared/types/v8-contracts.js` (LoopStageEvent, SourceRef, V8ReasonCode)
15
+ *
16
+ * Boundary:
17
+ * - Does NOT make semantic decisions about stage health.
18
+ * - Does NOT block callers on DB failure; returns degraded result.
19
+ * - Redacts credential-shaped values before persistence.
20
+ *
21
+ * Test coverage: tests/unit/observability/loop-stage-event-sink.test.ts
22
+ */
23
+ import { writeLoopStageEvent } from "../storage/v8-state-stores.js";
24
+ function validateEvent(event) {
25
+ if (!event.cycleId || event.cycleId.trim().length === 0) {
26
+ return { ok: false, reason: "cycle_id_required", field: "cycleId" };
27
+ }
28
+ if (!event.stage || event.stage.trim().length === 0) {
29
+ return { ok: false, reason: "stage_required", field: "stage" };
30
+ }
31
+ if (!event.status || event.status.trim().length === 0) {
32
+ return { ok: false, reason: "status_required", field: "status" };
33
+ }
34
+ if (!event.occurredAt || event.occurredAt.trim().length === 0) {
35
+ return { ok: false, reason: "occurred_at_required", field: "occurredAt" };
36
+ }
37
+ const validStages = [
38
+ "ingestion",
39
+ "perception",
40
+ "judgment",
41
+ "policy",
42
+ "execution",
43
+ "closure",
44
+ "quiet",
45
+ "dream",
46
+ "projection",
47
+ ];
48
+ if (!validStages.includes(event.stage)) {
49
+ return { ok: false, reason: "stage_invalid", field: "stage" };
50
+ }
51
+ const validStatuses = [
52
+ "started",
53
+ "completed",
54
+ "skipped",
55
+ "blocked",
56
+ "failed",
57
+ ];
58
+ if (!validStatuses.includes(event.status)) {
59
+ return { ok: false, reason: "status_invalid", field: "status" };
60
+ }
61
+ return { ok: true };
62
+ }
63
+ // ───────────────────────────────────────────────────────────────
64
+ // Redaction
65
+ // ───────────────────────────────────────────────────────────────
66
+ function redactSourceRefs(refs) {
67
+ let hasRedacted = false;
68
+ let hasBlocked = false;
69
+ const redacted = refs.map((ref) => {
70
+ if (ref.sensitivityClass === "sensitive") {
71
+ hasBlocked = true;
72
+ return {
73
+ ...ref,
74
+ redactionClass: "blocked",
75
+ resolveStatus: "redacted",
76
+ resolveFailureReason: "sensitivity_class_blocked",
77
+ };
78
+ }
79
+ if (ref.sensitivityClass === "private_context") {
80
+ hasRedacted = true;
81
+ return {
82
+ ...ref,
83
+ redactionClass: "redacted",
84
+ resolveStatus: "redacted",
85
+ };
86
+ }
87
+ return ref;
88
+ });
89
+ const redactionClass = hasBlocked
90
+ ? "blocked"
91
+ : hasRedacted
92
+ ? "redacted"
93
+ : "none";
94
+ return { redacted, redactionClass };
95
+ }
96
+ // ───────────────────────────────────────────────────────────────
97
+ // Public API
98
+ // ───────────────────────────────────────────────────────────────
99
+ export async function recordLoopStageEvent(db, event, options) {
100
+ const validation = validateEvent(event);
101
+ if (!validation.ok) {
102
+ const degraded = {
103
+ status: "degraded",
104
+ reason: "stage_event_missing",
105
+ ownerStage: event.stage || "ingestion",
106
+ sourceRefs: event.sourceRefs || [],
107
+ operatorNextAction: `Fix missing ${validation.field} in stage event`,
108
+ retryable: false,
109
+ };
110
+ return { ok: false, degraded };
111
+ }
112
+ const now = options?.now ?? new Date().toISOString();
113
+ const sourceRefs = event.sourceRefs ?? [];
114
+ const { redacted: redactedRefs, redactionClass } = redactSourceRefs(sourceRefs);
115
+ const record = {
116
+ id: event.id ?? `evt_${now.replace(/[:.]/g, "")}_${event.cycleId}_${event.stage}`,
117
+ cycleId: event.cycleId,
118
+ cycleSequence: event.cycleSequence ?? 0,
119
+ stage: event.stage,
120
+ status: event.status,
121
+ reason: event.reason,
122
+ sourceRefs: redactedRefs,
123
+ redactionClass,
124
+ occurredAt: event.occurredAt,
125
+ expectedDownstreamByCycle: event.expectedDownstreamByCycle,
126
+ payloadJson: event.payloadJson ?? null,
127
+ lifecycleStatus: "completed",
128
+ };
129
+ const result = await writeLoopStageEvent(db, record);
130
+ if ("id" in result) {
131
+ return { ok: true, id: result.id };
132
+ }
133
+ return { ok: false, degraded: result };
134
+ }
135
+ export async function recordLoopStageEvents(db, events, options) {
136
+ const succeeded = [];
137
+ const failed = [];
138
+ for (const event of events) {
139
+ const result = await recordLoopStageEvent(db, event, options);
140
+ if (result.ok) {
141
+ succeeded.push(result.id);
142
+ }
143
+ else {
144
+ failed.push({ id: event.id ?? "unknown", degraded: result.degraded });
145
+ }
146
+ }
147
+ return { succeeded, failed };
148
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * LoopStatus — Expose loop health and stalled stage diagnostics.
3
+ *
4
+ * Core logic: Call assembleLoopStatus, format into v8 loop_status shape,
5
+ * and include policy-denied closure counts.
6
+ *
7
+ * Design authority:
8
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.md §5`
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/runtime-ops-system.md`
10
+ *
11
+ * Dependencies:
12
+ * - `src/observability/causal-loop-health.js` (assembleLoopStatus)
13
+ * - `src/storage/v8-state-stores.js` (readLoopStageEventsByStage)
14
+ *
15
+ * Boundary:
16
+ * - Read-only diagnostic query; does not modify state.
17
+ * - Returns degraded envelope when state unreadable.
18
+ *
19
+ * Test coverage: tests/unit/observability/loop-status.test.ts
20
+ */
21
+ import type { StateDatabase } from "../storage/db/index.js";
22
+ import type { DegradedOperationResult } from "../shared/types/v8-contracts.js";
23
+ export interface LoopStatusReadModel {
24
+ ok: true;
25
+ overallStatus: string;
26
+ stalledAt?: string;
27
+ lastCycleSequence: number;
28
+ lastHeartbeatAt?: string;
29
+ stageSummaries: StageSummary[];
30
+ policyDeniedCount: number;
31
+ nextAction: string;
32
+ }
33
+ export interface StageSummary {
34
+ stage: string;
35
+ eventCount: number;
36
+ stalled: boolean;
37
+ lastEventAt?: string;
38
+ }
39
+ export type LoopStatusResult = {
40
+ ok: true;
41
+ status: LoopStatusReadModel;
42
+ } | {
43
+ ok: false;
44
+ degraded: DegradedOperationResult;
45
+ };
46
+ export declare function readLoopStatus(db: StateDatabase): Promise<LoopStatusResult>;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * LoopStatus — Expose loop health and stalled stage diagnostics.
3
+ *
4
+ * Core logic: Call assembleLoopStatus, format into v8 loop_status shape,
5
+ * and include policy-denied closure counts.
6
+ *
7
+ * Design authority:
8
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.md §5`
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/runtime-ops-system.md`
10
+ *
11
+ * Dependencies:
12
+ * - `src/observability/causal-loop-health.js` (assembleLoopStatus)
13
+ * - `src/storage/v8-state-stores.js` (readLoopStageEventsByStage)
14
+ *
15
+ * Boundary:
16
+ * - Read-only diagnostic query; does not modify state.
17
+ * - Returns degraded envelope when state unreadable.
18
+ *
19
+ * Test coverage: tests/unit/observability/loop-status.test.ts
20
+ */
21
+ import { assembleLoopStatus } from "./causal-loop-health.js";
22
+ // ───────────────────────────────────────────────────────────────
23
+ // Helpers
24
+ // ───────────────────────────────────────────────────────────────
25
+ function computeNextAction(overallStatus, stalledAt) {
26
+ if (overallStatus === "healthy") {
27
+ return "No operator action required. Loop is progressing normally.";
28
+ }
29
+ if (overallStatus === "no_data") {
30
+ return "Run a heartbeat cycle or check connector configuration to generate initial evidence.";
31
+ }
32
+ if (overallStatus === "degraded") {
33
+ return "Check state database connectivity and retry. If persistent, review logs for state_unreadable errors.";
34
+ }
35
+ if (overallStatus === "stalled" && stalledAt) {
36
+ const actions = {
37
+ ingestion: "Verify connector credentials and platform availability. Check ingestion_connector_failed events.",
38
+ perception: "Check perception model availability or rules-only fallback. Review evidence_batch_empty vs perception_blocked_redaction.",
39
+ judgment: "Review judgment_low_confidence or judgment_missing_source_refs. Ensure perception cards have valid source refs.",
40
+ policy: "Review policy_denied_high_risk or policy_denied_missing_permission. Check affordance map and breaker status.",
41
+ execution: "Verify connector executor and guidance port availability. Check execution_unavailable or execution_timeout events.",
42
+ closure: "Check closure_missing or closure_failed. Verify state write validation and idempotency key uniqueness.",
43
+ quiet: "Quiet review may be empty or failed. Check quiet_empty_input or quiet_failed events. Daily review triggers after 36h window.",
44
+ dream: "Dream scheduler may be unavailable or redaction blocked. Check dream_scheduler_unavailable or dream_blocked_redaction events.",
45
+ projection: "Projection may be rejected or missing source refs. Check projection_rejected events and candidate validation.",
46
+ };
47
+ return actions[stalledAt] ?? `Review ${stalledAt} stage events for blocked or failed status.`;
48
+ }
49
+ return "Review loop stage events and state database health.";
50
+ }
51
+ // ───────────────────────────────────────────────────────────────
52
+ // Public API
53
+ // ───────────────────────────────────────────────────────────────
54
+ export async function readLoopStatus(db) {
55
+ const health = await assembleLoopStatus(db, { limit: 50 });
56
+ if ("status" in health && health.status === "degraded") {
57
+ return {
58
+ ok: false,
59
+ degraded: health,
60
+ };
61
+ }
62
+ const snapshot = health;
63
+ const stageSummaries = snapshot.stages.map((s) => ({
64
+ stage: s.stage,
65
+ eventCount: s.eventCount,
66
+ stalled: s.stalled,
67
+ lastEventAt: s.lastEventAt,
68
+ }));
69
+ // Policy denied count is a placeholder; real implementation would query action closures
70
+ const policyDeniedCount = 0;
71
+ const nextAction = computeNextAction(snapshot.overallStatus, snapshot.stalledAt);
72
+ return {
73
+ ok: true,
74
+ status: {
75
+ ok: true,
76
+ overallStatus: snapshot.overallStatus,
77
+ stalledAt: snapshot.stalledAt,
78
+ lastCycleSequence: snapshot.lastCycleSequence,
79
+ lastHeartbeatAt: snapshot.lastHeartbeatAt,
80
+ stageSummaries,
81
+ policyDeniedCount,
82
+ nextAction,
83
+ },
84
+ };
85
+ }
@@ -4,3 +4,6 @@ export * from "./outreach.js";
4
4
  export * from "./source-ref.js";
5
5
  export * from "./goal.js";
6
6
  export * from "./v7-entities.js";
7
+ // v8-contracts intentionally NOT re-exported from index to avoid SourceRef
8
+ // name collision with v7 tuple type. v8 consumers import directly from
9
+ // `./v8-contracts.js`.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * v8 Shared Contracts — Cross-system value contracts for Living Perception Loop.
3
+ *
4
+ * Core logic: Single source of truth for types that would otherwise be
5
+ * duplicated across perception-judgment, action-closure-policy,
6
+ * dream-quiet-memory, observability-health, and control-plane systems.
7
+ *
8
+ * Design authority:
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/shared-v8-contracts.md`
10
+ * - `.anws/v8/04_SYSTEM_DESIGN/action-closure-policy-system.detail.md §1`
11
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.detail.md §2`
12
+ *
13
+ * Dependencies: none (primitive shared types).
14
+ * Boundary: Type definitions only; no runtime logic.
15
+ * Test coverage: tests/unit/contracts/v8-shared-contracts.test.ts
16
+ */
17
+ export type PlatformNeutralActionKind = "ignore" | "watch" | "remember" | "notify_owner" | "draft_reply" | "auto_reply" | "draft_publish" | "auto_publish" | "run_connector";
18
+ export type ActionSideEffectClass = "none" | "local_state" | "owner_attention" | "external_write" | "external_read" | "capability_declared";
19
+ export type ActionAttentionClass = "none" | "owner_visible" | "external_visible" | "depends_on_capability";
20
+ export interface ActionKindMetadata {
21
+ kind: PlatformNeutralActionKind;
22
+ sideEffectClass: ActionSideEffectClass;
23
+ attentionClass: ActionAttentionClass;
24
+ requiresPolicyDecision: boolean;
25
+ allowedDowngrades: PlatformNeutralActionKind[];
26
+ }
27
+ export type ConnectorCapabilitySideEffect = "external_read" | "external_write" | "local_state" | "unknown";
28
+ export type SourceRefFamily = "evidence" | "perception" | "judgment" | "action_closure" | "quiet_review" | "dream_run" | "memory_projection" | "tool_experience" | "connector_result" | "audit";
29
+ export type RedactionClass = "none" | "redacted" | "blocked";
30
+ export type SensitivityClass = "public_technical" | "public_general" | "private_context" | "sensitive";
31
+ export type SourceResolveStatus = "resolvable" | "missing" | "redacted" | "permission_denied";
32
+ export interface SourceRef {
33
+ uri: string;
34
+ family: SourceRefFamily;
35
+ id: string;
36
+ redactionClass: RedactionClass;
37
+ sensitivityClass?: SensitivityClass;
38
+ resolveStatus?: SourceResolveStatus;
39
+ resolveFailureReason?: string;
40
+ }
41
+ export type HeartbeatCycleStatus = "started" | "completed" | "failed" | "degraded";
42
+ export interface HeartbeatCycleTrace {
43
+ cycleId: string;
44
+ cycleSequence: number;
45
+ heartbeatStartedAt: string;
46
+ heartbeatCompletedAt?: string;
47
+ inputCount: number;
48
+ outputCount: number;
49
+ expectedDownstreamByCycle?: number;
50
+ status: HeartbeatCycleStatus;
51
+ }
52
+ export type LoopStage = "ingestion" | "perception" | "judgment" | "policy" | "execution" | "closure" | "quiet" | "dream" | "projection";
53
+ export type LoopStageEventStatus = "started" | "completed" | "skipped" | "blocked" | "failed";
54
+ export interface LoopStageEvent {
55
+ id: string;
56
+ cycleId: string;
57
+ cycleSequence: number;
58
+ stage: LoopStage;
59
+ status: LoopStageEventStatus;
60
+ reason?: V8ReasonCode;
61
+ sourceRefs: SourceRef[];
62
+ redactionClass: RedactionClass;
63
+ occurredAt: string;
64
+ expectedDownstreamByCycle?: number;
65
+ payloadJson?: string;
66
+ }
67
+ export type MemoryReviewClosureSubtype = "remember_for_review";
68
+ export interface MemoryReviewCandidateClosure {
69
+ closureSubtype: MemoryReviewClosureSubtype;
70
+ perceptionRef: SourceRef;
71
+ judgmentVerdictRef: SourceRef;
72
+ topicKey: string;
73
+ memoryIntentReason: string;
74
+ reviewPriority: "low" | "medium" | "high";
75
+ sourceRefs: [SourceRef, ...SourceRef[]];
76
+ }
77
+ export interface DegradedOperationResult {
78
+ status: "degraded" | "blocked";
79
+ reason: V8ReasonCode;
80
+ ownerStage: LoopStage;
81
+ sourceRefs: SourceRef[];
82
+ operatorNextAction: string;
83
+ retryable: boolean;
84
+ }
85
+ export type V8ReasonCode = "quiet_completed" | "quiet_empty_input" | "quiet_state_unreadable" | "quiet_validation_failed" | "dream_scheduled" | "dream_scheduler_unavailable" | "dream_started" | "dream_completed" | "dream_failed" | "dream_blocked_redaction" | "projection_candidate_created" | "projection_accepted" | "projection_rejected" | "projection_superseded" | "proposal_created" | "proposal_no_action" | "proposal_missing_source_refs" | "proposal_risk_blocked" | "policy_allowed" | "policy_deferred_owner_confirmation" | "policy_downgraded_to_draft" | "policy_denied_missing_permission" | "policy_denied_high_risk" | "policy_denied_breaker_open" | "guidance_unavailable" | "closure_completed" | "closure_no_action" | "closure_denied" | "closure_deferred" | "closure_downgraded" | "closure_downgraded_without_draft" | "closure_failed" | "perception_rules_only" | "evidence_batch_empty" | "evidence_batch_truncated" | "judgment_low_confidence" | "judgment_missing_source_refs" | "source_refs_unresolved" | "state_unreadable" | "stage_event_missing" | "ingestion_no_data" | "ingestion_empty" | "ingestion_state_unreadable" | "ingestion_connector_failed" | "execution_completed" | "execution_failed" | "execution_timeout" | "execution_unavailable";
86
+ export declare const ACTION_KIND_REGISTRY: Readonly<Record<PlatformNeutralActionKind, ActionKindMetadata>>;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * v8 Shared Contracts — Cross-system value contracts for Living Perception Loop.
3
+ *
4
+ * Core logic: Single source of truth for types that would otherwise be
5
+ * duplicated across perception-judgment, action-closure-policy,
6
+ * dream-quiet-memory, observability-health, and control-plane systems.
7
+ *
8
+ * Design authority:
9
+ * - `.anws/v8/04_SYSTEM_DESIGN/shared-v8-contracts.md`
10
+ * - `.anws/v8/04_SYSTEM_DESIGN/action-closure-policy-system.detail.md §1`
11
+ * - `.anws/v8/04_SYSTEM_DESIGN/observability-health-system.detail.md §2`
12
+ *
13
+ * Dependencies: none (primitive shared types).
14
+ * Boundary: Type definitions only; no runtime logic.
15
+ * Test coverage: tests/unit/contracts/v8-shared-contracts.test.ts
16
+ */
17
+ // ───────────────────────────────────────────────────────────────
18
+ // 7. Action Kind Registry Metadata Table
19
+ // ───────────────────────────────────────────────────────────────
20
+ export const ACTION_KIND_REGISTRY = {
21
+ ignore: {
22
+ kind: "ignore",
23
+ sideEffectClass: "none",
24
+ attentionClass: "none",
25
+ requiresPolicyDecision: false,
26
+ allowedDowngrades: [],
27
+ },
28
+ watch: {
29
+ kind: "watch",
30
+ sideEffectClass: "local_state",
31
+ attentionClass: "none",
32
+ requiresPolicyDecision: false,
33
+ allowedDowngrades: [],
34
+ },
35
+ remember: {
36
+ kind: "remember",
37
+ sideEffectClass: "local_state",
38
+ attentionClass: "none",
39
+ requiresPolicyDecision: true,
40
+ allowedDowngrades: ["watch"],
41
+ },
42
+ notify_owner: {
43
+ kind: "notify_owner",
44
+ sideEffectClass: "owner_attention",
45
+ attentionClass: "owner_visible",
46
+ requiresPolicyDecision: true,
47
+ allowedDowngrades: ["watch"],
48
+ },
49
+ draft_reply: {
50
+ kind: "draft_reply",
51
+ sideEffectClass: "local_state",
52
+ attentionClass: "owner_visible",
53
+ requiresPolicyDecision: true,
54
+ allowedDowngrades: ["notify_owner", "watch"],
55
+ },
56
+ auto_reply: {
57
+ kind: "auto_reply",
58
+ sideEffectClass: "external_write",
59
+ attentionClass: "external_visible",
60
+ requiresPolicyDecision: true,
61
+ allowedDowngrades: ["draft_reply", "notify_owner", "watch"],
62
+ },
63
+ draft_publish: {
64
+ kind: "draft_publish",
65
+ sideEffectClass: "local_state",
66
+ attentionClass: "owner_visible",
67
+ requiresPolicyDecision: true,
68
+ allowedDowngrades: ["notify_owner", "watch"],
69
+ },
70
+ auto_publish: {
71
+ kind: "auto_publish",
72
+ sideEffectClass: "external_write",
73
+ attentionClass: "external_visible",
74
+ requiresPolicyDecision: true,
75
+ allowedDowngrades: ["draft_publish", "notify_owner", "watch"],
76
+ },
77
+ run_connector: {
78
+ kind: "run_connector",
79
+ sideEffectClass: "capability_declared",
80
+ attentionClass: "depends_on_capability",
81
+ requiresPolicyDecision: true,
82
+ allowedDowngrades: ["notify_owner", "watch"],
83
+ },
84
+ };
@@ -12,3 +12,4 @@ export * from "./narrative-state.js";
12
12
  export * from "./relationship-memory.js";
13
13
  export * from "./agent-goal.js";
14
14
  export * from "./memory-store.js";
15
+ export * from "./v8-entities.js";
@@ -12,3 +12,4 @@ export * from "./narrative-state.js";
12
12
  export * from "./relationship-memory.js";
13
13
  export * from "./agent-goal.js";
14
14
  export * from "./memory-store.js";
15
+ export * from "./v8-entities.js";