nexo-brain 7.27.3 → 7.28.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 (46) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +5 -1
  3. package/bin/windows-wsl-bridge.js +9 -0
  4. package/package.json +1 -1
  5. package/src/causal_graph.py +763 -0
  6. package/src/classifier_local.py +44 -0
  7. package/src/cognitive/_core.py +3 -0
  8. package/src/cognitive_control_observatory.py +2 -0
  9. package/src/db/__init__.py +8 -0
  10. package/src/db/_commitments.py +344 -0
  11. package/src/db/_entities.py +98 -11
  12. package/src/db/_memory_v2.py +130 -2
  13. package/src/db/_schema.py +565 -0
  14. package/src/desktop_bridge.py +1 -1
  15. package/src/doctor/providers/runtime.py +9 -3
  16. package/src/enforcement_engine.py +128 -2
  17. package/src/entity_live_profile.py +1073 -0
  18. package/src/failure_prevention.py +1052 -0
  19. package/src/hook_guardrails.py +104 -0
  20. package/src/knowledge_graph.py +46 -9
  21. package/src/local_context/api.py +54 -22
  22. package/src/local_context/usage_events.py +273 -8
  23. package/src/memory_executive.py +620 -0
  24. package/src/memory_utility.py +952 -0
  25. package/src/plugin_loader.py +9 -5
  26. package/src/plugins/entities.py +84 -7
  27. package/src/plugins/entity_live_profile.py +101 -0
  28. package/src/plugins/failure_prevention.py +162 -0
  29. package/src/plugins/memory_export.py +55 -18
  30. package/src/plugins/protocol.py +133 -0
  31. package/src/plugins/semantic_layers.py +138 -0
  32. package/src/pre_answer_router.py +622 -28
  33. package/src/pre_answer_runtime.py +463 -18
  34. package/src/r14_correction_learning.py +3 -3
  35. package/src/requirements.txt +5 -1
  36. package/src/runtime_versioning.py +11 -1
  37. package/src/saved_not_used_audit.py +44 -3
  38. package/src/scripts/nexo-followup-runner.py +194 -0
  39. package/src/semantic_layers.py +1153 -0
  40. package/src/semantic_reasoner.py +2 -2
  41. package/src/semantic_router.py +58 -11
  42. package/src/server.py +41 -3
  43. package/src/tools_sessions.py +88 -31
  44. package/src/tools_transcripts.py +38 -22
  45. package/src/user_state_model.py +971 -0
  46. package/tool-enforcement-map.json +230 -0
package/src/db/_schema.py CHANGED
@@ -1139,6 +1139,42 @@ def _m69_provider_runtime_metadata(conn):
1139
1139
  _migrate_add_index(conn, "idx_sessions_provider", "sessions", "session_provider")
1140
1140
 
1141
1141
 
1142
+ def _m70_commitments(conn):
1143
+ """Durable promise/commitment index linked to existing action artifacts."""
1144
+ conn.execute(
1145
+ """
1146
+ CREATE TABLE IF NOT EXISTS commitments (
1147
+ id TEXT PRIMARY KEY,
1148
+ created_at REAL NOT NULL,
1149
+ updated_at REAL NOT NULL,
1150
+ closed_at REAL DEFAULT NULL,
1151
+ source_type TEXT NOT NULL DEFAULT '',
1152
+ source_id TEXT DEFAULT '',
1153
+ memory_event_uid TEXT DEFAULT '',
1154
+ session_id TEXT DEFAULT '',
1155
+ conversation_id TEXT DEFAULT '',
1156
+ project_key TEXT DEFAULT '',
1157
+ statement TEXT NOT NULL,
1158
+ owner TEXT DEFAULT 'agent',
1159
+ deadline TEXT DEFAULT '',
1160
+ status TEXT DEFAULT 'active',
1161
+ confidence REAL DEFAULT 0.5,
1162
+ action_ref_type TEXT DEFAULT '',
1163
+ action_ref_id TEXT DEFAULT '',
1164
+ outcome_id INTEGER DEFAULT NULL,
1165
+ evidence_ref TEXT DEFAULT '',
1166
+ dedupe_key TEXT DEFAULT '',
1167
+ metadata_json TEXT DEFAULT '{}'
1168
+ )
1169
+ """
1170
+ )
1171
+ _migrate_add_index(conn, "idx_commitments_status", "commitments", "status, deadline, updated_at")
1172
+ _migrate_add_index(conn, "idx_commitments_session", "commitments", "session_id, status, updated_at")
1173
+ _migrate_add_index(conn, "idx_commitments_source", "commitments", "source_type, source_id")
1174
+ _migrate_add_index(conn, "idx_commitments_action", "commitments", "action_ref_type, action_ref_id")
1175
+ _migrate_add_index(conn, "idx_commitments_dedupe", "commitments", "dedupe_key")
1176
+
1177
+
1142
1178
  def _m42_v6_0_1_hotfix(conn):
1143
1179
  """v6.0.1 hotfix — last_heartbeat_ts on sessions + hook_inbox_reminders.
1144
1180
 
@@ -2200,6 +2236,528 @@ def _m68_memory_fabric_index(conn):
2200
2236
  )
2201
2237
 
2202
2238
 
2239
+ def _m71_causal_edge_candidates(conn):
2240
+ conn.execute(
2241
+ """
2242
+ CREATE TABLE IF NOT EXISTS causal_edge_candidates (
2243
+ candidate_uid TEXT PRIMARY KEY,
2244
+ created_at REAL NOT NULL,
2245
+ updated_at REAL NOT NULL,
2246
+ source_type TEXT NOT NULL,
2247
+ source_ref TEXT NOT NULL,
2248
+ relation TEXT NOT NULL,
2249
+ target_type TEXT NOT NULL,
2250
+ target_ref TEXT NOT NULL,
2251
+ reason_public TEXT DEFAULT '',
2252
+ evidence_refs_json TEXT DEFAULT '[]',
2253
+ source_event_uid TEXT DEFAULT '',
2254
+ producer TEXT NOT NULL,
2255
+ project_key TEXT DEFAULT '',
2256
+ privacy_level TEXT DEFAULT 'normal',
2257
+ confidence REAL DEFAULT 0.5,
2258
+ status TEXT DEFAULT 'proposed',
2259
+ review_reason TEXT DEFAULT '',
2260
+ promoted_edge_uid TEXT DEFAULT '',
2261
+ metadata_json TEXT DEFAULT '{}'
2262
+ )
2263
+ """
2264
+ )
2265
+ conn.execute(
2266
+ "CREATE INDEX IF NOT EXISTS idx_causal_candidates_status_updated "
2267
+ "ON causal_edge_candidates(status, updated_at)"
2268
+ )
2269
+ conn.execute(
2270
+ "CREATE INDEX IF NOT EXISTS idx_causal_candidates_source "
2271
+ "ON causal_edge_candidates(source_type, source_ref, status)"
2272
+ )
2273
+ conn.execute(
2274
+ "CREATE INDEX IF NOT EXISTS idx_causal_candidates_target "
2275
+ "ON causal_edge_candidates(target_type, target_ref, status)"
2276
+ )
2277
+ conn.execute(
2278
+ "CREATE INDEX IF NOT EXISTS idx_causal_candidates_project "
2279
+ "ON causal_edge_candidates(project_key, status, updated_at)"
2280
+ )
2281
+
2282
+
2283
+ def _m72_memory_utility(conn):
2284
+ """Append-only memory usefulness ledger and idempotent delta applications."""
2285
+ conn.execute(
2286
+ """
2287
+ CREATE TABLE IF NOT EXISTS memory_use_events (
2288
+ event_uid TEXT PRIMARY KEY,
2289
+ created_at REAL NOT NULL,
2290
+ retrieval_trace_id TEXT DEFAULT '',
2291
+ route_event_id TEXT DEFAULT '',
2292
+ session_id TEXT DEFAULT '',
2293
+ conversation_id TEXT DEFAULT '',
2294
+ project_key TEXT DEFAULT '',
2295
+ client TEXT DEFAULT '',
2296
+ consumer_ref TEXT DEFAULT '',
2297
+ memory_ref TEXT NOT NULL,
2298
+ memory_kind TEXT NOT NULL,
2299
+ source_ref TEXT DEFAULT '',
2300
+ query_hash TEXT DEFAULT '',
2301
+ query_preview_redacted TEXT DEFAULT '',
2302
+ context_kind TEXT DEFAULT '',
2303
+ use_stage TEXT NOT NULL DEFAULT 'retrieved',
2304
+ outcome TEXT NOT NULL DEFAULT 'unknown',
2305
+ used_in_answer INTEGER NOT NULL DEFAULT 0,
2306
+ cited_in_answer INTEGER NOT NULL DEFAULT 0,
2307
+ acted_on INTEGER NOT NULL DEFAULT 0,
2308
+ validated_by_ref TEXT DEFAULT '',
2309
+ evidence_refs_json TEXT DEFAULT '[]',
2310
+ reason_code TEXT DEFAULT '',
2311
+ delta_json TEXT DEFAULT '{}',
2312
+ policy_version TEXT DEFAULT 'memory_utility_v1',
2313
+ confidence REAL DEFAULT 0.5,
2314
+ privacy_level TEXT DEFAULT 'normal',
2315
+ redaction_applied INTEGER NOT NULL DEFAULT 0,
2316
+ metadata_json TEXT DEFAULT '{}'
2317
+ )
2318
+ """
2319
+ )
2320
+ _migrate_add_index(conn, "idx_memory_use_events_memory_created", "memory_use_events", "memory_ref, created_at")
2321
+ _migrate_add_index(conn, "idx_memory_use_events_memory_reason", "memory_use_events", "memory_ref, reason_code, created_at")
2322
+ _migrate_add_index(conn, "idx_memory_use_events_trace_stage", "memory_use_events", "retrieval_trace_id, use_stage")
2323
+ _migrate_add_index(conn, "idx_memory_use_events_query_created", "memory_use_events", "query_hash, created_at")
2324
+ _migrate_add_index(conn, "idx_memory_use_events_stage_outcome", "memory_use_events", "use_stage, outcome, created_at")
2325
+ _migrate_add_index(conn, "idx_memory_use_events_policy_created", "memory_use_events", "policy_version, created_at")
2326
+
2327
+ conn.execute(
2328
+ """
2329
+ CREATE TABLE IF NOT EXISTS memory_utility_applications (
2330
+ application_uid TEXT PRIMARY KEY,
2331
+ created_at REAL NOT NULL,
2332
+ memory_ref TEXT NOT NULL,
2333
+ memory_kind TEXT NOT NULL,
2334
+ target_field TEXT NOT NULL,
2335
+ policy_version TEXT NOT NULL,
2336
+ reason_code TEXT NOT NULL,
2337
+ event_uids_hash TEXT NOT NULL,
2338
+ event_uids_json TEXT NOT NULL DEFAULT '[]',
2339
+ old_value REAL,
2340
+ new_value REAL,
2341
+ delta REAL NOT NULL DEFAULT 0,
2342
+ applied INTEGER NOT NULL DEFAULT 0,
2343
+ rolled_back INTEGER NOT NULL DEFAULT 0,
2344
+ rollback_ref TEXT DEFAULT '',
2345
+ metadata_json TEXT DEFAULT '{}'
2346
+ )
2347
+ """
2348
+ )
2349
+ _migrate_add_index(conn, "idx_memory_utility_app_memory", "memory_utility_applications", "memory_ref, created_at")
2350
+ _migrate_add_index(conn, "idx_memory_utility_app_policy", "memory_utility_applications", "policy_version, created_at")
2351
+ _migrate_add_index(conn, "idx_memory_utility_app_rollback", "memory_utility_applications", "rolled_back, created_at")
2352
+
2353
+ conn.execute(
2354
+ """
2355
+ CREATE TABLE IF NOT EXISTS memory_utility_application_events (
2356
+ application_uid TEXT NOT NULL,
2357
+ event_uid TEXT NOT NULL,
2358
+ memory_ref TEXT NOT NULL,
2359
+ target_field TEXT NOT NULL,
2360
+ policy_version TEXT NOT NULL,
2361
+ UNIQUE(event_uid, memory_ref, target_field, policy_version)
2362
+ )
2363
+ """
2364
+ )
2365
+ _migrate_add_index(conn, "idx_memory_utility_app_events_event", "memory_utility_application_events", "event_uid")
2366
+
2367
+
2368
+ def _m73_operational_state_snapshots(conn):
2369
+ """Operational state policy snapshots by area/scope."""
2370
+ conn.execute(
2371
+ """
2372
+ CREATE TABLE IF NOT EXISTS operational_state_snapshots (
2373
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2374
+ policy_uid TEXT NOT NULL UNIQUE,
2375
+ policy_version TEXT NOT NULL,
2376
+ created_at REAL NOT NULL,
2377
+ area_key TEXT NOT NULL,
2378
+ scope_key TEXT NOT NULL,
2379
+ task_type TEXT DEFAULT '',
2380
+ caution_level TEXT NOT NULL,
2381
+ communication_mode TEXT NOT NULL,
2382
+ detail_mode TEXT NOT NULL,
2383
+ verification_requirement TEXT NOT NULL,
2384
+ autonomy_limit TEXT NOT NULL,
2385
+ area_risk TEXT NOT NULL,
2386
+ reason_codes_json TEXT NOT NULL DEFAULT '[]',
2387
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
2388
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2389
+ input_hash TEXT NOT NULL,
2390
+ expires_at REAL NOT NULL,
2391
+ decay_policy_json TEXT NOT NULL DEFAULT '{}'
2392
+ )
2393
+ """
2394
+ )
2395
+ _migrate_add_index(conn, "idx_operational_state_area_created", "operational_state_snapshots", "area_key, created_at")
2396
+ _migrate_add_index(conn, "idx_operational_state_scope", "operational_state_snapshots", "scope_key, created_at")
2397
+ _migrate_add_index(conn, "idx_operational_state_expires", "operational_state_snapshots", "expires_at")
2398
+
2399
+
2400
+ def _m74_entity_live_profiles(conn):
2401
+ """EntityLiveProfile cache plus managed asset/context update bridges.
2402
+
2403
+ The tables below are deliberately non-authoritative. Entity identity,
2404
+ artifacts, local evidence, and history remain owned by their existing
2405
+ stores; this migration only adds cache/bridge/event surfaces.
2406
+ """
2407
+ _m11_artifact_registry(conn)
2408
+ _m59_memory_events(conn)
2409
+
2410
+ conn.execute(
2411
+ """
2412
+ CREATE TABLE IF NOT EXISTS entity_profile_cache (
2413
+ profile_uid TEXT PRIMARY KEY,
2414
+ profile_version TEXT NOT NULL DEFAULT 'entity_live_profile.v1',
2415
+ entity_key TEXT NOT NULL,
2416
+ canonical_kind TEXT DEFAULT '',
2417
+ canonical_name TEXT DEFAULT '',
2418
+ source_refs_hash TEXT NOT NULL,
2419
+ input_hash TEXT NOT NULL,
2420
+ profile_redacted_json TEXT NOT NULL DEFAULT '{}',
2421
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
2422
+ stale_status TEXT NOT NULL DEFAULT 'unknown',
2423
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2424
+ allowed_surfaces_json TEXT NOT NULL DEFAULT '[]',
2425
+ last_verified_at REAL,
2426
+ expires_at REAL,
2427
+ created_at REAL NOT NULL,
2428
+ updated_at REAL NOT NULL,
2429
+ UNIQUE(entity_key, profile_version, source_refs_hash, input_hash)
2430
+ )
2431
+ """
2432
+ )
2433
+ _migrate_add_index(conn, "idx_entity_profile_cache_entity", "entity_profile_cache", "entity_key, profile_version")
2434
+ _migrate_add_index(conn, "idx_entity_profile_cache_expires", "entity_profile_cache", "expires_at")
2435
+ _migrate_add_index(conn, "idx_entity_profile_cache_stale", "entity_profile_cache", "stale_status, expires_at")
2436
+
2437
+ conn.execute(
2438
+ """
2439
+ CREATE TABLE IF NOT EXISTS nexo_managed_assets (
2440
+ asset_uid TEXT PRIMARY KEY,
2441
+ artifact_id INTEGER REFERENCES artifact_registry(id) ON DELETE SET NULL,
2442
+ entity_key TEXT NOT NULL,
2443
+ project_key TEXT DEFAULT '',
2444
+ asset_kind TEXT NOT NULL DEFAULT 'other',
2445
+ provider_ref TEXT DEFAULT '',
2446
+ provider_redacted TEXT DEFAULT '',
2447
+ external_ref_hash TEXT DEFAULT '',
2448
+ status TEXT NOT NULL DEFAULT 'planned',
2449
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
2450
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2451
+ last_verified_at REAL,
2452
+ created_at REAL NOT NULL,
2453
+ updated_at REAL NOT NULL,
2454
+ metadata_json TEXT NOT NULL DEFAULT '{}'
2455
+ )
2456
+ """
2457
+ )
2458
+ conn.execute(
2459
+ """
2460
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_nexo_managed_assets_provider_external
2461
+ ON nexo_managed_assets(provider_ref, external_ref_hash)
2462
+ WHERE provider_ref != '' AND external_ref_hash != ''
2463
+ """
2464
+ )
2465
+ conn.execute(
2466
+ """
2467
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_nexo_managed_assets_artifact
2468
+ ON nexo_managed_assets(artifact_id)
2469
+ WHERE artifact_id IS NOT NULL
2470
+ """
2471
+ )
2472
+ _migrate_add_index(conn, "idx_nexo_managed_assets_entity", "nexo_managed_assets", "entity_key")
2473
+ _migrate_add_index(conn, "idx_nexo_managed_assets_project", "nexo_managed_assets", "project_key")
2474
+ _migrate_add_index(conn, "idx_nexo_managed_assets_status", "nexo_managed_assets", "status")
2475
+
2476
+ conn.execute(
2477
+ """
2478
+ CREATE TABLE IF NOT EXISTS asset_context_updated (
2479
+ event_uid TEXT PRIMARY KEY,
2480
+ entity_key TEXT NOT NULL,
2481
+ asset_uid TEXT NOT NULL,
2482
+ artifact_id INTEGER,
2483
+ project_key TEXT DEFAULT '',
2484
+ change_type TEXT NOT NULL,
2485
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
2486
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2487
+ redaction_applied INTEGER NOT NULL DEFAULT 1,
2488
+ created_at REAL NOT NULL,
2489
+ memory_event_uid TEXT DEFAULT ''
2490
+ )
2491
+ """
2492
+ )
2493
+ _migrate_add_index(conn, "idx_asset_context_updated_entity", "asset_context_updated", "entity_key, created_at")
2494
+ _migrate_add_index(conn, "idx_asset_context_updated_asset", "asset_context_updated", "asset_uid, created_at")
2495
+ _migrate_add_index(conn, "idx_asset_context_updated_artifact", "asset_context_updated", "artifact_id, created_at")
2496
+
2497
+
2498
+ def _m75_failure_prevention_ledger(conn):
2499
+ """FailurePrevention ledger for autopsy candidates and antibody proposals.
2500
+
2501
+ This is deliberately a non-authoritative coordination layer. Canonical
2502
+ rules, outcomes, guard checks, protocol debt, hook runs, corrections, and
2503
+ memory events remain owned by their existing tables.
2504
+ """
2505
+ _m6_error_guard_tables(conn)
2506
+ _m8_adaptive_log_and_somatic(conn)
2507
+ _m22_protocol_discipline_tables(conn)
2508
+ _m32_outcomes(conn)
2509
+ _m39_hook_runs(conn)
2510
+ _m56_session_correction_requirements(conn)
2511
+ _m59_memory_events(conn)
2512
+
2513
+ conn.execute(
2514
+ """
2515
+ CREATE TABLE IF NOT EXISTS failure_prevention_cases (
2516
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2517
+ failure_uid TEXT NOT NULL UNIQUE,
2518
+ policy_version TEXT NOT NULL DEFAULT 'failure_prevention.v1',
2519
+ failure_type TEXT NOT NULL DEFAULT 'other',
2520
+ area TEXT DEFAULT '',
2521
+ entity_refs_json TEXT NOT NULL DEFAULT '[]',
2522
+ primary_source_type TEXT NOT NULL,
2523
+ primary_source_ref TEXT NOT NULL,
2524
+ source_event_refs_json TEXT NOT NULL DEFAULT '[]',
2525
+ evidence_refs_json TEXT NOT NULL DEFAULT '[]',
2526
+ symptom_json TEXT NOT NULL DEFAULT '{}',
2527
+ trigger_json TEXT NOT NULL DEFAULT '{}',
2528
+ missed_signal_json TEXT NOT NULL DEFAULT '{}',
2529
+ wrong_assumption_json TEXT NOT NULL DEFAULT '{}',
2530
+ root_cause_json TEXT NOT NULL DEFAULT '{}',
2531
+ corrective_action_json TEXT NOT NULL DEFAULT '{}',
2532
+ severity TEXT NOT NULL DEFAULT 'p3',
2533
+ frequency_count INTEGER NOT NULL DEFAULT 0,
2534
+ confidence REAL NOT NULL DEFAULT 0.0,
2535
+ status TEXT NOT NULL DEFAULT 'candidate',
2536
+ learning_resolution_json TEXT NOT NULL DEFAULT '{}',
2537
+ antibody_refs_json TEXT NOT NULL DEFAULT '[]',
2538
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2539
+ allowed_surfaces_json TEXT NOT NULL DEFAULT '["debug_local","audit"]',
2540
+ opened_at REAL NOT NULL,
2541
+ updated_at REAL NOT NULL,
2542
+ review_due_at REAL NOT NULL,
2543
+ expires_at REAL NOT NULL,
2544
+ false_positive_count INTEGER NOT NULL DEFAULT 0,
2545
+ last_triggered_at REAL NOT NULL,
2546
+ metadata_json TEXT NOT NULL DEFAULT '{}',
2547
+ CHECK(severity IN ('p0','p1','p2','p3','p4')),
2548
+ CHECK(status IN (
2549
+ 'candidate','analyzing','action_required','antibody_pending',
2550
+ 'verifying','verified','resolved','rejected','false_positive',
2551
+ 'expired','rolled_back','conflict_review'
2552
+ )),
2553
+ CHECK(privacy_level IN ('public','normal','private','sensitive','secret')),
2554
+ CHECK(frequency_count >= 0),
2555
+ CHECK(false_positive_count >= 0),
2556
+ CHECK(confidence >= 0.0 AND confidence <= 1.0)
2557
+ )
2558
+ """
2559
+ )
2560
+ _migrate_add_index(conn, "idx_failure_cases_area_status", "failure_prevention_cases", "area, status")
2561
+ _migrate_add_index(conn, "idx_failure_cases_severity_status", "failure_prevention_cases", "severity, status")
2562
+ _migrate_add_index(conn, "idx_failure_cases_status_review", "failure_prevention_cases", "status, review_due_at")
2563
+ _migrate_add_index(conn, "idx_failure_cases_updated", "failure_prevention_cases", "updated_at")
2564
+
2565
+ conn.execute(
2566
+ """
2567
+ CREATE TABLE IF NOT EXISTS failure_source_events (
2568
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2569
+ source_event_uid TEXT NOT NULL UNIQUE,
2570
+ failure_uid TEXT NOT NULL,
2571
+ policy_version TEXT NOT NULL DEFAULT 'failure_prevention.v1',
2572
+ source_type TEXT NOT NULL,
2573
+ source_ref TEXT NOT NULL,
2574
+ evidence_refs_json TEXT NOT NULL DEFAULT '[]',
2575
+ observed_at REAL NOT NULL,
2576
+ validated INTEGER NOT NULL DEFAULT 0,
2577
+ validator TEXT DEFAULT '',
2578
+ validation_error TEXT DEFAULT '',
2579
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2580
+ created_at REAL NOT NULL,
2581
+ updated_at REAL NOT NULL,
2582
+ metadata_json TEXT NOT NULL DEFAULT '{}',
2583
+ FOREIGN KEY(failure_uid) REFERENCES failure_prevention_cases(failure_uid) ON DELETE CASCADE,
2584
+ CHECK(validated IN (0, 1)),
2585
+ CHECK(privacy_level IN ('public','normal','private','sensitive','secret'))
2586
+ )
2587
+ """
2588
+ )
2589
+ _migrate_add_index(conn, "idx_failure_source_events_failure", "failure_source_events", "failure_uid")
2590
+ _migrate_add_index(conn, "idx_failure_source_events_type", "failure_source_events", "source_type")
2591
+ _migrate_add_index(conn, "idx_failure_source_events_observed", "failure_source_events", "observed_at")
2592
+ _migrate_add_index(conn, "idx_failure_source_events_ref", "failure_source_events", "source_type, source_ref")
2593
+
2594
+ conn.execute(
2595
+ """
2596
+ CREATE TABLE IF NOT EXISTS antibody_actions (
2597
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2598
+ antibody_uid TEXT NOT NULL UNIQUE,
2599
+ failure_uid TEXT NOT NULL,
2600
+ policy_version TEXT NOT NULL DEFAULT 'failure_prevention.v1',
2601
+ action_type TEXT NOT NULL,
2602
+ target_system TEXT NOT NULL,
2603
+ target_ref TEXT NOT NULL,
2604
+ action_payload_ref TEXT DEFAULT '',
2605
+ status TEXT NOT NULL DEFAULT 'proposed',
2606
+ activation_policy TEXT NOT NULL DEFAULT 'candidate_only',
2607
+ required_verification TEXT DEFAULT '',
2608
+ verification_ref TEXT DEFAULT '',
2609
+ verification_status TEXT NOT NULL DEFAULT 'missing',
2610
+ approved_by TEXT DEFAULT '',
2611
+ approved_ref TEXT DEFAULT '',
2612
+ rollback_ref TEXT DEFAULT '',
2613
+ review_due_at REAL NOT NULL,
2614
+ expires_at REAL NOT NULL,
2615
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2616
+ created_at REAL NOT NULL,
2617
+ updated_at REAL NOT NULL,
2618
+ applied_at REAL,
2619
+ verified_at REAL,
2620
+ metadata_json TEXT NOT NULL DEFAULT '{}',
2621
+ FOREIGN KEY(failure_uid) REFERENCES failure_prevention_cases(failure_uid) ON DELETE CASCADE,
2622
+ CHECK(target_ref != ''),
2623
+ CHECK(status IN ('proposed','approved','applied','verifying','verified','rejected','expired','rolled_back','false_positive')),
2624
+ CHECK(activation_policy IN ('candidate_only','shadow','warn','block_after_verification','manual_approval_required')),
2625
+ CHECK(verification_status IN ('missing','pending','passed','failed','not_applicable')),
2626
+ CHECK(privacy_level IN ('public','normal','private','sensitive','secret'))
2627
+ )
2628
+ """
2629
+ )
2630
+ _migrate_add_index(conn, "idx_antibody_actions_failure", "antibody_actions", "failure_uid")
2631
+ _migrate_add_index(conn, "idx_antibody_actions_status", "antibody_actions", "status")
2632
+ _migrate_add_index(conn, "idx_antibody_actions_target", "antibody_actions", "action_type, target_system, target_ref")
2633
+ _migrate_add_index(conn, "idx_antibody_actions_verification", "antibody_actions", "verification_status, review_due_at")
2634
+
2635
+
2636
+ def _m76_semantic_layers(conn):
2637
+ """SemanticLayers cache for compact, source-backed continuity.
2638
+
2639
+ The tables are deliberately non-authoritative. Original facts remain owned
2640
+ by diary, workflow, task, evidence, memory, transcript-index and continuity
2641
+ stores; these rows only cache redacted views with source fingerprints.
2642
+ """
2643
+ conn.execute(
2644
+ """
2645
+ CREATE TABLE IF NOT EXISTS session_diary (
2646
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2647
+ session_id TEXT NOT NULL,
2648
+ created_at TEXT DEFAULT (datetime('now')),
2649
+ decisions TEXT NOT NULL DEFAULT '',
2650
+ discarded TEXT,
2651
+ pending TEXT,
2652
+ context_next TEXT,
2653
+ mental_state TEXT,
2654
+ domain TEXT,
2655
+ user_signals TEXT,
2656
+ summary TEXT NOT NULL DEFAULT ''
2657
+ )
2658
+ """
2659
+ )
2660
+ _m4_session_diary_columns(conn)
2661
+ _m7_diary_source_and_draft(conn)
2662
+ _m22_protocol_discipline_tables(conn)
2663
+ _m24_durable_workflow_runtime(conn)
2664
+ _m25_workflow_goal_stack(conn)
2665
+ _m30_hot_context_memory(conn)
2666
+ _m54_continuity_snapshots(conn)
2667
+ _m59_memory_events(conn)
2668
+ _m60_memory_observations(conn)
2669
+ _m66_transcript_index(conn)
2670
+ _m70_commitments(conn)
2671
+ _m74_entity_live_profiles(conn)
2672
+ _m75_failure_prevention_ledger(conn)
2673
+
2674
+ conn.execute(
2675
+ """
2676
+ CREATE TABLE IF NOT EXISTS semantic_layers (
2677
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2678
+ layer_uid TEXT NOT NULL UNIQUE,
2679
+ scope_type TEXT NOT NULL,
2680
+ scope_id TEXT NOT NULL,
2681
+ layer_kind TEXT NOT NULL,
2682
+ policy_version TEXT NOT NULL DEFAULT 'semantic_layers_v1',
2683
+ status TEXT NOT NULL DEFAULT 'fresh',
2684
+ quality_state TEXT NOT NULL DEFAULT 'complete',
2685
+ value_redacted TEXT NOT NULL DEFAULT '',
2686
+ value_ref TEXT NOT NULL DEFAULT '',
2687
+ token_size INTEGER NOT NULL DEFAULT 0,
2688
+ source_refs_json TEXT NOT NULL DEFAULT '[]',
2689
+ evidence_refs_json TEXT NOT NULL DEFAULT '[]',
2690
+ source_fingerprint TEXT NOT NULL,
2691
+ content_hash TEXT NOT NULL,
2692
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2693
+ allowed_surfaces_json TEXT NOT NULL DEFAULT '[]',
2694
+ confidence REAL NOT NULL DEFAULT 0.0,
2695
+ coverage REAL NOT NULL DEFAULT 0.0,
2696
+ generated_by TEXT NOT NULL DEFAULT '',
2697
+ generator_version TEXT NOT NULL DEFAULT 'continuity_layer_builder_v1',
2698
+ generated_at REAL NOT NULL,
2699
+ updated_at REAL NOT NULL,
2700
+ source_max_updated_at TEXT NOT NULL DEFAULT '',
2701
+ expires_at REAL NOT NULL DEFAULT 0,
2702
+ stale_at REAL NOT NULL DEFAULT 0,
2703
+ stale_reason TEXT NOT NULL DEFAULT '',
2704
+ metadata_json TEXT NOT NULL DEFAULT '{}',
2705
+ CHECK(scope_type IN (
2706
+ 'session','conversation','workflow','workflow_goal',
2707
+ 'protocol_task','release','project_entity'
2708
+ )),
2709
+ CHECK(layer_kind IN (
2710
+ 'headline','brief','timeline','decisions','commitments',
2711
+ 'files','evidence','risks','next_action','semantic_tags',
2712
+ 'source_map'
2713
+ )),
2714
+ CHECK(status IN ('fresh','stale','expired','invalid')),
2715
+ CHECK(quality_state IN (
2716
+ 'complete','partial','degraded','conflicted',
2717
+ 'source_missing','invalid'
2718
+ )),
2719
+ CHECK(privacy_level IN ('public','normal','private','sensitive','secret')),
2720
+ CHECK(confidence >= 0.0 AND confidence <= 1.0),
2721
+ CHECK(coverage >= 0.0 AND coverage <= 1.0),
2722
+ CHECK(token_size >= 0),
2723
+ UNIQUE(scope_type, scope_id, layer_kind, source_fingerprint, policy_version)
2724
+ )
2725
+ """
2726
+ )
2727
+ _migrate_add_index(conn, "idx_semantic_layers_scope_kind_status", "semantic_layers", "scope_type, scope_id, layer_kind, status, updated_at")
2728
+ _migrate_add_index(conn, "idx_semantic_layers_scope_status", "semantic_layers", "scope_type, scope_id, status, updated_at")
2729
+ _migrate_add_index(conn, "idx_semantic_layers_fingerprint", "semantic_layers", "source_fingerprint")
2730
+ _migrate_add_index(conn, "idx_semantic_layers_stale", "semantic_layers", "status, stale_at")
2731
+
2732
+ conn.execute(
2733
+ """
2734
+ CREATE TABLE IF NOT EXISTS semantic_layer_source_refs (
2735
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2736
+ layer_uid TEXT NOT NULL,
2737
+ source_ref TEXT NOT NULL,
2738
+ source_kind TEXT NOT NULL,
2739
+ source_version TEXT NOT NULL,
2740
+ source_updated_at TEXT NOT NULL DEFAULT '',
2741
+ privacy_level TEXT NOT NULL DEFAULT 'normal',
2742
+ required_for_layer INTEGER NOT NULL DEFAULT 1,
2743
+ validation_status TEXT NOT NULL DEFAULT 'ok',
2744
+ validation_error TEXT NOT NULL DEFAULT '',
2745
+ created_at REAL NOT NULL,
2746
+ updated_at REAL NOT NULL,
2747
+ metadata_json TEXT NOT NULL DEFAULT '{}',
2748
+ FOREIGN KEY(layer_uid) REFERENCES semantic_layers(layer_uid) ON DELETE CASCADE,
2749
+ CHECK(required_for_layer IN (0, 1)),
2750
+ CHECK(validation_status IN ('ok','missing','changed','invalid','unsupported')),
2751
+ CHECK(privacy_level IN ('public','normal','private','sensitive','secret')),
2752
+ UNIQUE(layer_uid, source_ref, source_version)
2753
+ )
2754
+ """
2755
+ )
2756
+ _migrate_add_index(conn, "idx_semantic_layer_sources_layer", "semantic_layer_source_refs", "layer_uid")
2757
+ _migrate_add_index(conn, "idx_semantic_layer_sources_ref", "semantic_layer_source_refs", "source_ref")
2758
+ _migrate_add_index(conn, "idx_semantic_layer_sources_kind", "semantic_layer_source_refs", "source_kind, validation_status")
2759
+
2760
+
2203
2761
  MIGRATIONS = [
2204
2762
  (1, "learnings_columns", _m1_learnings_columns),
2205
2763
  (2, "followups_reasoning", _m2_followups_reasoning),
@@ -2270,6 +2828,13 @@ MIGRATIONS = [
2270
2828
  (67, "diary_quality_backfill_repair", _m67_diary_quality_backfill_repair),
2271
2829
  (68, "memory_fabric_index", _m68_memory_fabric_index),
2272
2830
  (69, "provider_runtime_metadata", _m69_provider_runtime_metadata),
2831
+ (70, "commitments", _m70_commitments),
2832
+ (71, "causal_edge_candidates", _m71_causal_edge_candidates),
2833
+ (72, "memory_utility", _m72_memory_utility),
2834
+ (73, "operational_state_snapshots", _m73_operational_state_snapshots),
2835
+ (74, "entity_live_profiles", _m74_entity_live_profiles),
2836
+ (75, "failure_prevention_ledger", _m75_failure_prevention_ledger),
2837
+ (76, "semantic_layers", _m76_semantic_layers),
2273
2838
  ]
2274
2839
 
2275
2840
 
@@ -321,7 +321,7 @@ def _onboard_steps() -> list[dict]:
321
321
  return [
322
322
  {
323
323
  "id": "name",
324
- "prompt": {"es": "¿Cómo te llamamos?", "en": "What should we call you?"},
324
+ "prompt": {"es": "¿Cómo te llamas?", "en": "What's your name?"},
325
325
  "hint": {
326
326
  "es": "Tu nombre corto, el que usarás en el día a día.",
327
327
  "en": "Your short name, the one we'll use day to day.",
@@ -3842,12 +3842,16 @@ def check_local_index_hygiene(fix: bool = False) -> DoctorCheck:
3842
3842
  try:
3843
3843
  from local_context import api as local_context_api
3844
3844
 
3845
- result = local_context_api.local_index_hygiene(fix=fix)
3845
+ try:
3846
+ result = local_context_api.local_index_hygiene(fix=fix, quick=not fix)
3847
+ except TypeError:
3848
+ result = local_context_api.local_index_hygiene(fix=fix)
3846
3849
  residue = result.get("residue") or {}
3847
3850
  cleanup = result.get("cleanup") or {}
3848
3851
  privacy = result.get("privacy") or {}
3849
3852
  privacy_residue = privacy.get("residue") or {}
3850
3853
  privacy_cleanup = privacy.get("cleanup") or {}
3854
+ privacy_truncated = bool(privacy.get("truncated") or privacy_residue.get("truncated"))
3851
3855
  suspect_roots = [str(path) for path in result.get("removed_roots") or []]
3852
3856
  residue_total = sum(int(residue.get(key, 0) or 0) for key in ("assets", "jobs", "errors", "dirs", "checkpoints"))
3853
3857
  cleanup_total = sum(int(cleanup.get(key, 0) or 0) for key in ("assets", "jobs", "errors", "dirs", "checkpoints"))
@@ -3859,9 +3863,11 @@ def check_local_index_hygiene(fix: bool = False) -> DoctorCheck:
3859
3863
  "cleanup=" + json.dumps(cleanup, sort_keys=True),
3860
3864
  "privacy_residue=" + json.dumps(privacy_residue, sort_keys=True),
3861
3865
  "privacy_cleanup=" + json.dumps(privacy_cleanup, sort_keys=True),
3866
+ "quick_scan=" + str(bool(result.get("quick") or privacy.get("quick"))),
3867
+ "privacy_truncated=" + str(privacy_truncated),
3862
3868
  ]
3863
3869
  evidence.extend(f"root={path}" for path in suspect_roots[:5])
3864
- if residue_total == 0 and privacy_residue_total == 0 and not suspect_roots:
3870
+ if residue_total == 0 and privacy_residue_total == 0 and not suspect_roots and not privacy_truncated:
3865
3871
  return DoctorCheck(
3866
3872
  id="runtime.local_index_hygiene",
3867
3873
  tier="runtime",
@@ -3889,7 +3895,7 @@ def check_local_index_hygiene(fix: bool = False) -> DoctorCheck:
3889
3895
  severity="warn",
3890
3896
  summary="Local memory index has stale or private residue",
3891
3897
  evidence=evidence,
3892
- repair_plan=["Run `nexo doctor --tier runtime --fix` to purge stale local memory roots and private local-memory residue"],
3898
+ repair_plan=["Run `nexo doctor --tier runtime --fix` to purge stale local memory roots/private residue, or run a full local_index_hygiene scan outside release readiness"],
3893
3899
  escalation_prompt="Local memory may contain stale or private index payloads that should be purged before indexing continues.",
3894
3900
  )
3895
3901
  except Exception as exc: