superlocalmemory 3.8.14 → 4.0.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 (211) hide show
  1. package/ATTRIBUTION.md +4 -4
  2. package/CHANGELOG.md +113 -137
  3. package/README.md +65 -63
  4. package/docs/pi-dev-integration.md +1 -1
  5. package/package.json +6 -1
  6. package/plugin/.claude-plugin/plugin.json +1 -1
  7. package/plugin/CLAUDE.md +3 -3
  8. package/plugin/agents/slm-governance-advisor.md +1 -1
  9. package/plugin/agents/slm-loop-runner.md +1 -1
  10. package/plugin/agents/slm-memory-advisor.md +1 -1
  11. package/plugin/agents/slm-optimize-advisor.md +1 -1
  12. package/plugin/requirements.txt +1 -1
  13. package/plugin/skills/slm-cache/SKILL.md +1 -1
  14. package/plugin/skills/slm-compress/SKILL.md +1 -1
  15. package/plugin/skills/slm-governance/SKILL.md +1 -1
  16. package/plugin/skills/slm-graph/SKILL.md +1 -1
  17. package/plugin/skills/slm-loop/SKILL.md +1 -1
  18. package/plugin/skills/slm-mesh/SKILL.md +1 -1
  19. package/plugin/skills/slm-profile/SKILL.md +1 -1
  20. package/plugin/skills/slm-recall/SKILL.md +1 -1
  21. package/plugin/skills/slm-remember/SKILL.md +1 -1
  22. package/plugin/skills/slm-scope/SKILL.md +1 -1
  23. package/plugin/skills/slm-session/SKILL.md +1 -1
  24. package/plugin/skills/slm-status/SKILL.md +1 -1
  25. package/plugin-src/rules/AGENTS.md +1 -1
  26. package/plugin-src/skills/slm-cache/SKILL.md +1 -1
  27. package/plugin-src/skills/slm-compress/SKILL.md +1 -1
  28. package/plugin-src/skills/slm-governance/SKILL.md +248 -0
  29. package/plugin-src/skills/slm-graph/SKILL.md +1 -1
  30. package/plugin-src/skills/slm-loop/SKILL.md +99 -0
  31. package/plugin-src/skills/slm-mesh/SKILL.md +282 -0
  32. package/plugin-src/skills/slm-profile/SKILL.md +148 -0
  33. package/plugin-src/skills/slm-recall/SKILL.md +1 -1
  34. package/plugin-src/skills/slm-remember/SKILL.md +1 -1
  35. package/plugin-src/skills/slm-scope/SKILL.md +176 -0
  36. package/plugin-src/skills/slm-session/SKILL.md +1 -1
  37. package/plugin-src/skills/slm-status/SKILL.md +1 -1
  38. package/pyproject.toml +11 -4
  39. package/src/superlocalmemory/__init__.py +1 -1
  40. package/src/superlocalmemory/cli/commands.py +125 -11
  41. package/src/superlocalmemory/cli/daemon.py +5 -1
  42. package/src/superlocalmemory/cli/main.py +35 -2
  43. package/src/superlocalmemory/cli/ops_cmd.py +281 -0
  44. package/src/superlocalmemory/cli/setup_wizard.py +1 -1
  45. package/src/superlocalmemory/compliance/audit.py +65 -0
  46. package/src/superlocalmemory/compliance/eu_ai_act.py +27 -57
  47. package/src/superlocalmemory/compliance/gdpr.py +416 -20
  48. package/src/superlocalmemory/compliance/retention.py +74 -22
  49. package/src/superlocalmemory/compliance/scheduler.py +78 -9
  50. package/src/superlocalmemory/core/actor_context.py +166 -0
  51. package/src/superlocalmemory/core/admission.py +549 -0
  52. package/src/superlocalmemory/core/backend_orchestrator.py +23 -10
  53. package/src/superlocalmemory/core/config.py +202 -24
  54. package/src/superlocalmemory/core/consolidation_engine.py +13 -13
  55. package/src/superlocalmemory/core/context_cache.py +28 -0
  56. package/src/superlocalmemory/core/embeddings.py +64 -2
  57. package/src/superlocalmemory/core/engine.py +7 -2
  58. package/src/superlocalmemory/core/engine_ingestion.py +65 -3
  59. package/src/superlocalmemory/core/engine_wiring.py +32 -5
  60. package/src/superlocalmemory/core/ingest_policy.py +38 -0
  61. package/src/superlocalmemory/core/maintenance.py +255 -0
  62. package/src/superlocalmemory/core/modes.py +40 -13
  63. package/src/superlocalmemory/core/mutations.py +437 -44
  64. package/src/superlocalmemory/core/operation_policy.py +92 -0
  65. package/src/superlocalmemory/core/operation_policy_registry.py +542 -0
  66. package/src/superlocalmemory/core/operation_request.py +127 -0
  67. package/src/superlocalmemory/core/ops_remediation.py +542 -0
  68. package/src/superlocalmemory/core/recall_pipeline.py +7 -0
  69. package/src/superlocalmemory/core/remember_runtime.py +202 -4
  70. package/src/superlocalmemory/core/remote_mode.py +20 -5
  71. package/src/superlocalmemory/core/store_pipeline.py +150 -0
  72. package/src/superlocalmemory/core/topic_signature.py +19 -4
  73. package/src/superlocalmemory/core/transactions/__init__.py +78 -0
  74. package/src/superlocalmemory/core/transactions/concrete_owners.py +597 -0
  75. package/src/superlocalmemory/core/transactions/erasure.py +825 -0
  76. package/src/superlocalmemory/core/transactions/manifest.py +255 -0
  77. package/src/superlocalmemory/core/transactions/manifest_key.py +155 -0
  78. package/src/superlocalmemory/core/transactions/obligations.py +272 -0
  79. package/src/superlocalmemory/core/transactions/owners.py +114 -0
  80. package/src/superlocalmemory/core/transactions/reconciler.py +285 -0
  81. package/src/superlocalmemory/core/transactions/service.py +330 -0
  82. package/src/superlocalmemory/core/worker_pool.py +33 -5
  83. package/src/superlocalmemory/encoding/cognitive_consolidator.py +70 -28
  84. package/src/superlocalmemory/encoding/emotional.py +75 -14
  85. package/src/superlocalmemory/encoding/temporal_parser.py +4 -0
  86. package/src/superlocalmemory/evolution/blind_verifier.py +11 -4
  87. package/src/superlocalmemory/evolution/evolution_store.py +244 -4
  88. package/src/superlocalmemory/evolution/llm_dispatch.py +40 -0
  89. package/src/superlocalmemory/evolution/model_selection.py +18 -3
  90. package/src/superlocalmemory/evolution/mutation_generator.py +3 -0
  91. package/src/superlocalmemory/evolution/skill_activator.py +270 -0
  92. package/src/superlocalmemory/evolution/skill_evolver.py +281 -59
  93. package/src/superlocalmemory/evolution/types.py +30 -8
  94. package/src/superlocalmemory/graph/cozo_backend.py +17 -9
  95. package/src/superlocalmemory/hooks/auto_invoker.py +2 -1
  96. package/src/superlocalmemory/hooks/auto_recall.py +64 -30
  97. package/src/superlocalmemory/hooks/codex_assets.py +14 -1
  98. package/src/superlocalmemory/infra/backup.py +434 -7
  99. package/src/superlocalmemory/infra/process_reaper.py +18 -0
  100. package/src/superlocalmemory/infra/self_heal.py +401 -0
  101. package/src/superlocalmemory/learning/feedback.py +52 -9
  102. package/src/superlocalmemory/loops/engine.py +10 -0
  103. package/src/superlocalmemory/mcp/_daemon_proxy.py +3 -0
  104. package/src/superlocalmemory/mcp/http_transport.py +30 -331
  105. package/src/superlocalmemory/mcp/profiles.py +5 -0
  106. package/src/superlocalmemory/mcp/resources.py +8 -0
  107. package/src/superlocalmemory/mcp/server.py +51 -4
  108. package/src/superlocalmemory/mcp/shared.py +19 -0
  109. package/src/superlocalmemory/mcp/tools_active.py +25 -4
  110. package/src/superlocalmemory/mcp/tools_code_graph.py +26 -18
  111. package/src/superlocalmemory/mcp/tools_context.py +50 -8
  112. package/src/superlocalmemory/mcp/tools_core.py +69 -21
  113. package/src/superlocalmemory/mcp/tools_evolution.py +9 -2
  114. package/src/superlocalmemory/mcp/tools_learning.py +21 -10
  115. package/src/superlocalmemory/mcp/tools_loops.py +29 -18
  116. package/src/superlocalmemory/mcp/tools_mesh.py +8 -0
  117. package/src/superlocalmemory/mcp/tools_ops.py +115 -0
  118. package/src/superlocalmemory/mcp/tools_optimize.py +4 -0
  119. package/src/superlocalmemory/mcp/tools_v28.py +10 -3
  120. package/src/superlocalmemory/mcp/tools_v3.py +34 -14
  121. package/src/superlocalmemory/mcp/tools_v33.py +18 -33
  122. package/src/superlocalmemory/mesh/broker.py +124 -46
  123. package/src/superlocalmemory/mesh/broker_security.py +470 -0
  124. package/src/superlocalmemory/mesh/discovery.py +365 -0
  125. package/src/superlocalmemory/mesh/lock_protocol.py +313 -0
  126. package/src/superlocalmemory/mesh/node_identity.py +97 -0
  127. package/src/superlocalmemory/mesh/outbox_remote.py +429 -0
  128. package/src/superlocalmemory/mesh/remote_sync.py +511 -28
  129. package/src/superlocalmemory/mesh/state_sync.py +286 -0
  130. package/src/superlocalmemory/optimize/config/store.py +45 -0
  131. package/src/superlocalmemory/parameterization/cross_project.py +12 -0
  132. package/src/superlocalmemory/parameterization/prompt_injector.py +13 -11
  133. package/src/superlocalmemory/parameterization/prompt_lifecycle.py +8 -2
  134. package/src/superlocalmemory/parameterization/workflow_miner.py +17 -0
  135. package/src/superlocalmemory/retrieval/ann_index.py +5 -0
  136. package/src/superlocalmemory/retrieval/bm25_channel.py +49 -2
  137. package/src/superlocalmemory/retrieval/engine.py +19 -4
  138. package/src/superlocalmemory/retrieval/fusion.py +4 -1
  139. package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -3
  140. package/src/superlocalmemory/retrieval/remote_reranker.py +47 -22
  141. package/src/superlocalmemory/retrieval/reranker.py +32 -1
  142. package/src/superlocalmemory/retrieval/temporal_channel.py +16 -3
  143. package/src/superlocalmemory/retrieval/temporal_utils.py +107 -0
  144. package/src/superlocalmemory/retrieval/temporal_validity_filter.py +155 -42
  145. package/src/superlocalmemory/retrieval/vector_store.py +214 -8
  146. package/src/superlocalmemory/server/api.py +5 -5
  147. package/src/superlocalmemory/server/egress_policy.py +258 -0
  148. package/src/superlocalmemory/server/rbac_enforce.py +32 -0
  149. package/src/superlocalmemory/server/route_mutations.py +20 -0
  150. package/src/superlocalmemory/server/routes/compliance.py +153 -7
  151. package/src/superlocalmemory/server/routes/data_io.py +43 -2
  152. package/src/superlocalmemory/server/routes/events.py +15 -0
  153. package/src/superlocalmemory/server/routes/memories.py +56 -3
  154. package/src/superlocalmemory/server/routes/mesh.py +82 -1
  155. package/src/superlocalmemory/server/routes/mesh_lock.py +54 -0
  156. package/src/superlocalmemory/server/routes/mesh_state.py +63 -0
  157. package/src/superlocalmemory/server/routes/v3_api.py +50 -27
  158. package/src/superlocalmemory/server/routes/ws.py +86 -0
  159. package/src/superlocalmemory/server/ui.py +6 -6
  160. package/src/superlocalmemory/server/unified_daemon.py +942 -119
  161. package/src/superlocalmemory/storage/_migration_internals.py +568 -0
  162. package/src/superlocalmemory/storage/_schema_version.py +110 -0
  163. package/src/superlocalmemory/storage/database.py +329 -24
  164. package/src/superlocalmemory/storage/embedding_migrator.py +246 -51
  165. package/src/superlocalmemory/storage/erasure_fence.py +45 -0
  166. package/src/superlocalmemory/storage/generation_fence.py +63 -0
  167. package/src/superlocalmemory/storage/migration_runner.py +140 -424
  168. package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +40 -0
  169. package/src/superlocalmemory/storage/migrations/M033_projection_transactions.py +148 -0
  170. package/src/superlocalmemory/storage/migrations/M034_obligation_integrity.py +58 -0
  171. package/src/superlocalmemory/storage/migrations/M035_erasure_receipts.py +113 -0
  172. package/src/superlocalmemory/storage/migrations/M036_vector_row_map.py +107 -0
  173. package/src/superlocalmemory/storage/migrations/M037_manifest_hmac_version.py +162 -0
  174. package/src/superlocalmemory/storage/migrations/{M033_learning_feedback_channel.py → M038_learning_feedback_channel.py} +3 -3
  175. package/src/superlocalmemory/storage/migrations/{M034_scene_fact_members.py → M039_scene_fact_members.py} +15 -5
  176. package/src/superlocalmemory/storage/migrations/__init__.py +4 -4
  177. package/src/superlocalmemory/storage/schema.py +10 -2
  178. package/src/superlocalmemory/storage/write_coordinator.py +125 -0
  179. package/src/superlocalmemory/trust/scorer.py +28 -4
  180. package/src/superlocalmemory/ui/index.html +14 -3
  181. package/src/superlocalmemory/ui/js/auto-settings.js +12 -1
  182. package/src/superlocalmemory/ui/js/brain.js +6 -4
  183. package/src/superlocalmemory/ui/js/compliance.js +66 -12
  184. package/src/superlocalmemory/ui/js/dashboard.js +13 -3
  185. package/src/superlocalmemory/ui/js/feedback.js +8 -2
  186. package/src/superlocalmemory/ui/js/lifecycle.js +7 -1
  187. package/src/superlocalmemory/ui/js/modal.js +272 -5
  188. package/src/superlocalmemory/ui/js/od-backup.js +9 -2
  189. package/src/superlocalmemory/ui/js/od-compliance-ext.js +301 -0
  190. package/src/superlocalmemory/ui/js/od-operations.js +154 -23
  191. package/src/superlocalmemory/ui/js/od-ops-health.js +417 -0
  192. package/src/superlocalmemory/ui/js/od-optimize.js +35 -21
  193. package/src/superlocalmemory/ui/js/od-team.js +9 -2
  194. package/src/superlocalmemory/ui/js/optimize.js +13 -16
  195. package/src/superlocalmemory/ui/js/profiles.js +7 -3
  196. package/src/superlocalmemory/ui/js/settings.js +7 -1
  197. package/src/superlocalmemory/vector/lancedb_backend.py +19 -9
  198. package/src/superlocalmemory/attribution/mathematical_dna.py +0 -235
  199. package/src/superlocalmemory/cli/post_install.py +0 -114
  200. package/src/superlocalmemory/core/clock_monitor.py +0 -45
  201. package/src/superlocalmemory/core/db_pool.py +0 -80
  202. package/src/superlocalmemory/core/error_catalog.py +0 -113
  203. package/src/superlocalmemory/core/loop_watchdog.py +0 -56
  204. package/src/superlocalmemory/core/priority_queue.py +0 -61
  205. package/src/superlocalmemory/core/pruning_engine.py +0 -216
  206. package/src/superlocalmemory/core/queue_dispatcher.py +0 -73
  207. package/src/superlocalmemory/core/slmignore.py +0 -125
  208. package/src/superlocalmemory/infra/heartbeat_monitor.py +0 -140
  209. package/src/superlocalmemory/infra/webhook_dispatcher.py +0 -247
  210. package/src/superlocalmemory/learning/quantization_scheduler.py +0 -320
  211. package/src/superlocalmemory/storage/access_control.py +0 -182
@@ -403,11 +403,24 @@
403
403
  '</div>' +
404
404
  '</div>' +
405
405
 
406
- // Audit trail with All/Denied segment filter
406
+ // Audit trail with All/Denied segment filter + event-type API filter
407
407
  '<div class="card" style="margin-top:16px">' +
408
408
  '<div class="card-head">' +
409
409
  '<h3>Audit trail</h3>' +
410
+ // Task C: chain-integrity badge
411
+ '<span id="od-audit-chain-status"></span>' +
410
412
  '<div class="spacer"></div>' +
413
+ // Task C: event-type filter select (calls API)
414
+ '<select id="od-audit-evt-filter" style="padding:4px 8px;border-radius:6px;' +
415
+ 'border:1px solid var(--border);background:var(--card);color:var(--fg);font-size:12px">' +
416
+ '<option value="">All types</option>' +
417
+ '<option value="recall">recall</option>' +
418
+ '<option value="remember">remember</option>' +
419
+ '<option value="delete">delete</option>' +
420
+ '<option value="lifecycle_transition">lifecycle</option>' +
421
+ '<option value="access_denied">access_denied</option>' +
422
+ '<option value="retention_enforced">retention</option>' +
423
+ '</select>' +
411
424
  '<div class="seg" id="od-audit-filter">' +
412
425
  '<button class="active" data-filter="all">All</button>' +
413
426
  '<button data-filter="denied">Denied</button>' +
@@ -675,8 +688,14 @@
675
688
 
676
689
  if (applyBtn) {
677
690
  applyBtn.addEventListener('click', function () {
678
- if (!window.confirm('This will transition memories to lower lifecycle states. Continue?')) return;
679
- applyBtn.disabled = true;
691
+ window.confirmDestructive({
692
+ title: 'Apply compaction',
693
+ target: 'All eligible memories',
694
+ consequence: 'Transitions memories to lower lifecycle states.',
695
+ confirmLabel: 'Apply',
696
+ }).then(function(confirmed) {
697
+ if (!confirmed) return;
698
+ applyBtn.disabled = true;
680
699
  applyBtn.textContent = 'Running…';
681
700
 
682
701
  fetch('/api/lifecycle/compact', {
@@ -708,6 +727,7 @@
708
727
  applyBtn.disabled = false;
709
728
  applyBtn.textContent = 'Apply compaction';
710
729
  });
730
+ });
711
731
  });
712
732
  }
713
733
  }
@@ -722,10 +742,14 @@
722
742
  var summary = document.getElementById('od-restart-summary');
723
743
  if (!btn) return;
724
744
  btn.addEventListener('click', function () {
725
- if (!window.confirm(
726
- 'Restart the memory daemon now? It will be unavailable for a few ' +
727
- 'seconds. Your memories are not affected.')) return;
728
- btn.disabled = true;
745
+ window.confirmDestructive({
746
+ title: 'Restart memory daemon',
747
+ target: 'Memory daemon',
748
+ consequence: 'Will be unavailable for a few seconds. Your memories are not affected.',
749
+ confirmLabel: 'Restart',
750
+ }).then(function(confirmed) {
751
+ if (!confirmed) return;
752
+ btn.disabled = true;
729
753
  btn.textContent = 'Restarting…';
730
754
  if (summary) summary.textContent = 'Restart requested — waiting for the daemon to come back…';
731
755
 
@@ -782,6 +806,7 @@
782
806
  if (tries > 30) { clearInterval(poll); btn.disabled = false; btn.textContent = 'Restart daemon'; }
783
807
  }, 1000);
784
808
  });
809
+ });
785
810
  });
786
811
  }
787
812
 
@@ -903,40 +928,81 @@
903
928
 
904
929
  var ACTION_CLS = { archive: 'neutral', tombstone: 'danger', notify: 'warn' };
905
930
 
931
+ // Build rows then wire delete buttons post-inject (avoids inline onclick — CSP safe)
906
932
  retTbody.innerHTML = policies.map(function (p) {
907
933
  var ac = ACTION_CLS[p.action] || 'neutral';
908
- // CRIT(c): name, category, action through esc()
909
934
  return (
910
935
  '<tr>' +
911
936
  '<td><b>' + esc(p.name || '') + '</b></td>' +
912
937
  '<td class="num">' + esc(String(p.retention_days || '—')) + '</td>' +
913
938
  '<td><span class="badge neutral">' + esc(p.category || 'all') + '</span></td>' +
914
939
  '<td><span class="badge ' + ac + '">' + esc(p.action || '') + '</span></td>' +
940
+ // Task E: per-row delete — data-pol-name used by wireRetentionDeleteBtns()
915
941
  '<td style="text-align:right">' +
916
- '<button class="btn sm ghost" disabled>Edit</button>' +
917
- // TODO: wire edit button to /api/compliance/retention-policy PATCH when available
942
+ '<button class="btn sm danger" data-pol-name="' + esc(p.name || '') + '">' +
943
+ 'Delete' +
944
+ '</button>' +
918
945
  '</td>' +
919
946
  '</tr>'
920
947
  );
921
948
  }).join('');
949
+
950
+ // Task E: wire delete buttons (CSP-safe addEventListener after innerHTML set)
951
+ wireRetentionDeleteBtns(retTbody);
922
952
  }
923
953
 
924
954
  // Cache of all audit rows (for client-side All/Denied filter)
925
955
  var _allAuditRows = [];
926
956
  /**
927
- * Populate the audit trail table.
957
+ * Task C: Populate the audit trail table.
958
+ * auditFull: response from /api/compliance/audit (preferred, up to 100 events).
959
+ * comp: response from /api/compliance/status (fallback, recent_audit_events).
928
960
  * CRIT(c): actor, action, target, result all through esc().
929
961
  */
930
- function populateAuditTrail(comp) {
962
+ function populateAuditTrail(comp, auditFull) {
931
963
  var auditTbody = document.getElementById('od-audit-body');
932
964
  if (!auditTbody) return;
933
965
 
934
- var events = (comp && comp.recent_audit_events) || [];
966
+ // Prefer full audit endpoint data; fall back to status data
967
+ var events = (auditFull && auditFull.events) || (comp && comp.recent_audit_events) || [];
935
968
  _allAuditRows = events;
936
969
 
937
970
  renderAuditRows(auditTbody, events);
938
971
  }
939
972
 
973
+ /**
974
+ * Task C: Render the chain-integrity badge inside the audit trail card header.
975
+ * Appended to #od-audit-chain-status if it exists.
976
+ */
977
+ function showAuditChainStatus(auditFull) {
978
+ var el = document.getElementById('od-audit-chain-status');
979
+ if (!el || !auditFull) return;
980
+ var ok = auditFull.chain_verified !== false;
981
+ el.innerHTML = ok
982
+ ? '<span class="badge ok" style="margin-left:8px">Chain verified</span>'
983
+ : '<span class="badge danger" style="margin-left:8px">Chain integrity issue</span>';
984
+ }
985
+
986
+ /** Task C: re-fetch audit trail from API with a specific event_type filter. */
987
+ function fetchAndRenderAudit(eventType) {
988
+ var auditTbody = document.getElementById('od-audit-body');
989
+ if (!auditTbody) return;
990
+ auditTbody.innerHTML = '<tr><td colspan="6" class="dim" style="text-align:center;padding:16px">Loading…</td></tr>';
991
+ var url = '/api/compliance/audit?limit=100';
992
+ if (eventType && eventType !== 'all') url += '&event_type=' + encodeURIComponent(eventType);
993
+ fetch(url)
994
+ .then(function (r) { return r.ok ? r.json() : null; })
995
+ .then(function (d) {
996
+ if (!d) return;
997
+ _allAuditRows = d.events || [];
998
+ renderAuditRows(auditTbody, _allAuditRows);
999
+ showAuditChainStatus(d);
1000
+ })
1001
+ .catch(function () {
1002
+ if (auditTbody) auditTbody.innerHTML = '<tr><td colspan="6" class="dim" style="text-align:center;padding:16px">Failed to load audit trail.</td></tr>';
1003
+ });
1004
+ }
1005
+
940
1006
  /** Render audit table rows into tbody, filtering by mode ('all' or 'denied'). */
941
1007
  function renderAuditRows(tbody, events) {
942
1008
  if (events.length === 0) {
@@ -974,14 +1040,16 @@
974
1040
  }).join('');
975
1041
  }
976
1042
  /**
977
- * Wire the All/Denied segment filter in the audit trail header.
978
- * Client-side filter over already-fetched data — no extra network call.
1043
+ * Task C: Wire audit filters.
1044
+ * - All/Denied segment: client-side filter (fast).
1045
+ * - Event-type select (#od-audit-evt-filter): calls API to get filtered results.
979
1046
  */
980
- function wireAuditFilter() {
1047
+ function wireAuditFilter(auditFull) {
981
1048
  var filterEl = document.getElementById('od-audit-filter');
982
1049
  var tbody = document.getElementById('od-audit-body');
983
1050
  if (!filterEl || !tbody) return;
984
1051
 
1052
+ // All / Denied segment buttons — client-side
985
1053
  filterEl.querySelectorAll('button').forEach(function (btn) {
986
1054
  btn.addEventListener('click', function () {
987
1055
  var mode = btn.getAttribute('data-filter');
@@ -1000,6 +1068,54 @@
1000
1068
  renderAuditRows(tbody, rows);
1001
1069
  });
1002
1070
  });
1071
+
1072
+ // Task C: Event-type select — re-fetches from API
1073
+ var evtSelect = document.getElementById('od-audit-evt-filter');
1074
+ if (evtSelect) {
1075
+ evtSelect.addEventListener('change', function () {
1076
+ fetchAndRenderAudit(evtSelect.value);
1077
+ });
1078
+ }
1079
+ }
1080
+
1081
+ /**
1082
+ * Task E: Wire delete buttons injected by populateRetentionPolicies.
1083
+ * Data attribute data-pol-name carries the policy name (already esc'd in innerHTML).
1084
+ * Uses confirmDestructive before calling DELETE /api/compliance/retention-policy?name=.
1085
+ */
1086
+ function wireRetentionDeleteBtns(tbody) {
1087
+ tbody.querySelectorAll('[data-pol-name]').forEach(function (btn) {
1088
+ btn.addEventListener('click', function () {
1089
+ var policyName = btn.getAttribute('data-pol-name');
1090
+ window.confirmDestructive({
1091
+ title: 'Delete retention policy',
1092
+ target: policyName,
1093
+ consequence: 'This policy will no longer be enforced on any memory.',
1094
+ confirmLabel: 'Delete',
1095
+ }).then(function (confirmed) {
1096
+ if (!confirmed) return;
1097
+ btn.disabled = true;
1098
+ fetch('/api/compliance/retention-policy?name=' + encodeURIComponent(policyName), {
1099
+ method: 'DELETE',
1100
+ })
1101
+ .then(function (r) { return r.json(); })
1102
+ .then(function (d) {
1103
+ if (d && d.success !== false) {
1104
+ var pane = document.getElementById('operations-pane');
1105
+ if (pane && typeof window.odRenderOperations === 'function') {
1106
+ window.odRenderOperations(pane);
1107
+ }
1108
+ } else {
1109
+ btn.disabled = false;
1110
+ if (typeof console !== 'undefined') {
1111
+ console.error('[od-ops] retention delete failed:', d && d.error);
1112
+ }
1113
+ }
1114
+ })
1115
+ .catch(function () { btn.disabled = false; });
1116
+ });
1117
+ });
1118
+ });
1003
1119
  }
1004
1120
 
1005
1121
  /**
@@ -1043,11 +1159,18 @@
1043
1159
  })
1044
1160
  .then(function (r) { return r.json(); })
1045
1161
  .then(function (d) {
1046
- if (summary) {
1047
- summary.textContent = d && d.success
1048
- ? ('Retention applied — archived ' + (d.archived || 0) +
1049
- ', tombstoned ' + (d.tombstoned || 0) + ', flagged ' + (d.notified || 0) + '.')
1050
- : ('Retention failed: ' + ((d && d.error) || 'unknown'));
1162
+ if (!summary) return;
1163
+ // Task E: surface all returned counts from the enforce response
1164
+ if (d && d.success) {
1165
+ var parts = [];
1166
+ if (d.archived != null) parts.push('archived ' + fmtNum(d.archived));
1167
+ if (d.tombstoned != null) parts.push('tombstoned ' + fmtNum(d.tombstoned));
1168
+ if (d.notified != null) parts.push('flagged ' + fmtNum(d.notified));
1169
+ if (d.evaluated != null) parts.push('evaluated ' + fmtNum(d.evaluated));
1170
+ if (d.policies_run != null) parts.push('policies run: ' + fmtNum(d.policies_run));
1171
+ summary.textContent = 'Retention applied — ' + (parts.join(', ') || 'no changes needed') + '.';
1172
+ } else {
1173
+ summary.textContent = 'Retention failed: ' + ((d && d.error) || 'unknown');
1051
1174
  }
1052
1175
  })
1053
1176
  .catch(function () { if (summary) summary.textContent = 'Retention run failed. Check console.'; })
@@ -1216,10 +1339,13 @@
1216
1339
  fetch('/api/lifecycle/status').then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; }),
1217
1340
  fetch('/api/trust/stats').then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; }),
1218
1341
  fetch('/api/compliance/status').then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; }),
1342
+ // Task C: wire the full audit trail endpoint (up to 100 events, chain_verified)
1343
+ fetch('/api/compliance/audit?limit=100').then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; }),
1219
1344
  ]).then(function (results) {
1220
1345
  var lc = results[0];
1221
1346
  var trustStats = results[1];
1222
1347
  var comp = results[2];
1348
+ var auditFull = results[3]; // {available, events, chain_verified, ...}
1223
1349
 
1224
1350
  // Inject .ctl class styles (used by Trust section control rows)
1225
1351
  injectCtlStyle();
@@ -1243,10 +1369,15 @@
1243
1369
  // Populate compliance
1244
1370
  populateComplianceKpi(comp);
1245
1371
  populateRetentionPolicies(comp);
1246
- populateAuditTrail(comp);
1372
+ // Task C: prefer the full audit trail from the dedicated endpoint;
1373
+ // fall back to the status endpoint's recent_audit_events on failure.
1374
+ populateAuditTrail(comp, auditFull);
1375
+
1376
+ // Task C: show chain-integrity indicator
1377
+ showAuditChainStatus(auditFull);
1247
1378
 
1248
1379
  // Wire audit filter and new-policy button (listeners on injected DOM)
1249
- wireAuditFilter();
1380
+ wireAuditFilter(auditFull);
1250
1381
  wireNewPolicyBtn();
1251
1382
  wireGdprBtns();
1252
1383