Skip to main content

hirn_engine/db/
services.rs

1//! Typed domain view types for HirnDB.
2//!
3//! Each view provides a focused API surface for a single domain,
4//! improving discoverability and making it clear which operations
5//! belong together. Views hold an immutable reference to the underlying
6//! [`HirnDB`] and delegate all calls.
7//!
8//! ```rust,ignore
9//! let db: HirnDB = /* ... */;
10//!
11//! // Domain-scoped API (the public interface):
12//! db.episodic().remember(record).await?;
13//! db.semantic().store(record).await?;
14//! db.graph_view().connect(a, b).await?;
15//! db.recall_view().query(embedding).limit(10).execute().await?;
16//! db.ql().execute("RECALL episodic ABOUT 'test'").await?;
17//! db.admin().stats().await?;
18//! ```
19
20use super::*;
21use crate::graph::EdgeId;
22use crate::policy::Action;
23use hirn_core::types::{AgentId, Namespace};
24use std::collections::HashMap;
25
26// ---------------------------------------------------------------------------
27// View types
28// ---------------------------------------------------------------------------
29
30/// Episodic memory operations: remember, recall and manage event-based memories.
31pub struct EpisodicView<'a>(pub(super) &'a HirnDB);
32
33/// Semantic memory operations: store, query and manage concept-based knowledge.
34pub struct SemanticView<'a>(pub(super) &'a HirnDB);
35
36/// Procedural memory operations: store, execute and track skill/procedure records.
37pub struct ProceduralView<'a>(pub(super) &'a HirnDB);
38
39/// Working memory operations: manage the short-term focus set.
40pub struct WorkingView<'a>(pub(super) &'a HirnDB);
41
42/// Graph operations: create edges and inspect the property graph.
43pub struct GraphView<'a>(pub(super) &'a HirnDB);
44
45/// Recall operations: vector search, think and trace queries.
46pub struct RecallView<'a>(pub(super) &'a HirnDB);
47
48/// Namespace operations: create, list and manage agent namespaces.
49pub struct NamespaceView<'a>(pub(super) &'a HirnDB);
50
51/// Policy operations: Cedar authorization enforcement and evaluation.
52pub struct PolicyView<'a>(pub(super) &'a HirnDB);
53
54/// Admin operations: statistics, compaction, maintenance, and agent management.
55pub struct AdminView<'a>(pub(super) &'a HirnDB);
56
57/// Query operations: HirnQL execution, explain, and prepared statements.
58pub struct QueryView<'a>(pub(super) &'a HirnDB);
59
60/// Causal operations: contradiction detection, quarantine, and ABA resolution.
61pub struct CausalView<'a>(pub(super) &'a HirnDB);
62
63// ---------------------------------------------------------------------------
64// EpisodicView
65// ---------------------------------------------------------------------------
66
67impl<'a> EpisodicView<'a> {
68    #[inline]
69    pub async fn remember(&self, record: EpisodicRecord) -> HirnResult<MemoryId> {
70        self.0.remember(record).await
71    }
72
73    #[inline]
74    pub async fn remember_with_explanation(
75        &self,
76        record: EpisodicRecord,
77    ) -> Result<(MemoryId, crate::RememberExplanation), crate::RememberFailure> {
78        self.0.remember_with_explanation(record).await
79    }
80
81    #[inline]
82    pub async fn batch_remember(&self, records: Vec<EpisodicRecord>) -> Vec<HirnResult<MemoryId>> {
83        self.0.batch_remember(records).await
84    }
85
86    #[inline]
87    pub async fn get(&self, id: MemoryId) -> HirnResult<EpisodicRecord> {
88        self.0.get_episode(id).await
89    }
90
91    #[inline]
92    pub async fn list(&self, filter: &EpisodicFilter) -> HirnResult<Vec<EpisodicRecord>> {
93        self.0.list_episodes(filter).await
94    }
95
96    #[inline]
97    pub async fn delete(&self, id: MemoryId) -> HirnResult<()> {
98        self.0.delete_episode(id).await
99    }
100
101    #[inline]
102    pub async fn archive(&self, id: MemoryId) -> HirnResult<()> {
103        self.0.archive_episode(id).await
104    }
105
106    #[inline]
107    pub async fn decay(&self) -> HirnResult<usize> {
108        self.0.decay_memories().await
109    }
110
111    #[inline]
112    pub async fn purge_expired(&self) -> HirnResult<usize> {
113        self.0.purge_expired().await
114    }
115
116    #[inline]
117    pub async fn in_range(
118        &self,
119        after: Timestamp,
120        before: Timestamp,
121    ) -> HirnResult<Vec<EpisodicRecord>> {
122        self.0.episodes_in_range(after, before).await
123    }
124
125    #[inline]
126    pub async fn after(&self, after: Timestamp) -> HirnResult<Vec<EpisodicRecord>> {
127        self.0.episodes_after(after).await
128    }
129
130    #[inline]
131    pub async fn before(&self, before: Timestamp) -> HirnResult<Vec<EpisodicRecord>> {
132        self.0.episodes_before(before).await
133    }
134
135    #[inline]
136    pub async fn reverse(&self) -> HirnResult<Vec<EpisodicRecord>> {
137        self.0.episodes_reverse().await
138    }
139}
140
141// ---------------------------------------------------------------------------
142// SemanticView
143// ---------------------------------------------------------------------------
144
145impl<'a> SemanticView<'a> {
146    #[inline]
147    pub async fn store(&self, record: SemanticRecord) -> HirnResult<MemoryId> {
148        self.0.store_semantic(record).await
149    }
150
151    #[inline]
152    pub async fn get(&self, id: MemoryId) -> HirnResult<SemanticRecord> {
153        self.0.get_semantic(id).await
154    }
155
156    #[inline]
157    pub async fn get_by_concept(&self, name: &str) -> HirnResult<SemanticRecord> {
158        self.0.get_semantic_by_concept(name).await
159    }
160
161    #[inline]
162    pub async fn list(&self, filter: &SemanticFilter) -> HirnResult<Vec<SemanticRecord>> {
163        self.0.list_semantics(filter).await
164    }
165
166    #[inline]
167    pub async fn correct(
168        &self,
169        id: MemoryId,
170        update: SemanticUpdate,
171    ) -> HirnResult<SemanticRecord> {
172        self.0.correct_semantic(id, update).await
173    }
174
175    #[inline]
176    pub async fn supersede(
177        &self,
178        id: MemoryId,
179        supersession: SemanticSupersession,
180    ) -> HirnResult<SemanticRecord> {
181        self.0.supersede_semantic(id, supersession).await
182    }
183
184    #[inline]
185    pub async fn override_head(
186        &self,
187        id: MemoryId,
188        override_request: SemanticOverride,
189    ) -> HirnResult<SemanticRecord> {
190        self.0.override_semantic(id, override_request).await
191    }
192
193    #[inline]
194    pub async fn merge(
195        &self,
196        target: MemoryId,
197        merge: SemanticMerge,
198    ) -> HirnResult<SemanticMergeOutcome> {
199        self.0.merge_semantic(target, merge).await
200    }
201
202    #[inline]
203    pub async fn retract(
204        &self,
205        id: MemoryId,
206        retraction: SemanticRetraction,
207    ) -> HirnResult<SemanticRecord> {
208        self.0.retract_semantic(id, retraction).await
209    }
210
211    #[inline]
212    pub async fn purge(&self, id: MemoryId) -> HirnResult<()> {
213        self.0.purge_semantic(id).await
214    }
215
216    #[inline]
217    pub async fn history(&self, id: MemoryId) -> HirnResult<Vec<SemanticRecord>> {
218        self.0.semantic_history(id).await
219    }
220
221    #[inline]
222    pub async fn batch_store(&self, records: Vec<SemanticRecord>) -> Vec<HirnResult<MemoryId>> {
223        self.0.batch_store_semantic(records).await
224    }
225
226    #[inline]
227    pub async fn flush_access(&self) -> HirnResult<()> {
228        self.0.flush_semantic_access().await
229    }
230
231    #[inline]
232    pub async fn get_by_concept_ns(
233        &self,
234        name: &str,
235        namespace: &Namespace,
236    ) -> HirnResult<SemanticRecord> {
237        self.0.get_semantic_by_concept_ns(name, namespace).await
238    }
239}
240
241// ---------------------------------------------------------------------------
242// ProceduralView
243// ---------------------------------------------------------------------------
244
245impl<'a> ProceduralView<'a> {
246    #[inline]
247    pub async fn store(&self, record: ProceduralRecord) -> HirnResult<MemoryId> {
248        self.0.store_procedural(record).await
249    }
250
251    #[inline]
252    pub async fn get(&self, id: MemoryId) -> HirnResult<ProceduralRecord> {
253        self.0.get_procedural(id).await
254    }
255
256    #[inline]
257    pub async fn execute(
258        &self,
259        id: MemoryId,
260        executor: &impl hirn_core::procedural::ToolExecutor,
261    ) -> HirnResult<hirn_core::procedural::ProcedureResult> {
262        self.0.execute_procedure(id, executor).await
263    }
264
265    #[inline]
266    pub async fn record_success(&self, id: MemoryId) -> HirnResult<()> {
267        self.0.record_procedural_success(id).await
268    }
269
270    #[inline]
271    pub async fn record_failure(&self, id: MemoryId) -> HirnResult<()> {
272        self.0.record_procedural_failure(id).await
273    }
274
275    /// Record the outcome of a single execution and update the EMA success rate.
276    ///
277    /// Delegates to [`record_success`](Self::record_success) or
278    /// [`record_failure`](Self::record_failure) based on `success`. The
279    /// `actor_id` parameter is accepted for API symmetry and audit context but
280    /// is currently unused internally (the provenance is already tracked on the
281    /// underlying `ProceduralRecord`).
282    #[inline]
283    pub async fn record_execution(
284        &self,
285        id: MemoryId,
286        success: bool,
287        _actor_id: AgentId,
288    ) -> HirnResult<()> {
289        if success {
290            self.0.record_procedural_success(id).await
291        } else {
292            self.0.record_procedural_failure(id).await
293        }
294    }
295
296    #[inline]
297    pub async fn delete(&self, id: MemoryId) -> HirnResult<()> {
298        self.0.delete_procedural(id).await
299    }
300
301    #[inline]
302    pub async fn list(&self, namespace: Option<&Namespace>) -> HirnResult<Vec<ProceduralRecord>> {
303        self.0.list_procedural(namespace).await
304    }
305}
306
307// ---------------------------------------------------------------------------
308// WorkingView
309// ---------------------------------------------------------------------------
310
311impl<'a> WorkingView<'a> {
312    #[inline]
313    pub async fn focus(&self, entry: WorkingMemoryEntry) -> HirnResult<MemoryId> {
314        self.0.focus(entry).await
315    }
316
317    #[inline]
318    pub async fn entries(&self) -> HirnResult<Vec<WorkingMemoryEntry>> {
319        self.0.working_memory().await
320    }
321
322    #[inline]
323    pub async fn entries_for_thread(&self, thread_id: &str) -> HirnResult<Vec<WorkingMemoryEntry>> {
324        self.0.working_memory_for_thread(thread_id).await
325    }
326
327    #[inline]
328    pub async fn defocus(&self, id: MemoryId) -> HirnResult<()> {
329        self.0.defocus(id).await
330    }
331}
332
333// ---------------------------------------------------------------------------
334// GraphView
335// ---------------------------------------------------------------------------
336
337impl<'a> GraphView<'a> {
338    #[inline]
339    pub async fn connect(&self, source: MemoryId, target: MemoryId) -> HirnResult<EdgeId> {
340        self.0.connect(source, target).await
341    }
342
343    #[inline]
344    pub async fn connect_with(
345        &self,
346        source: MemoryId,
347        target: MemoryId,
348        relation: EdgeRelation,
349        weight: f32,
350        metadata: Metadata,
351    ) -> HirnResult<EdgeId> {
352        self.0
353            .connect_with(source, target, relation, weight, metadata)
354            .await
355    }
356
357    #[inline]
358    pub fn persistent_graph(&self) -> &crate::persistent_graph::PersistentGraph {
359        self.0.persistent_graph()
360    }
361
362    #[inline]
363    pub async fn flush_hebbian(&self) -> HirnResult<()> {
364        self.0.flush_hebbian().await
365    }
366}
367
368// ---------------------------------------------------------------------------
369// RecallView
370// ---------------------------------------------------------------------------
371
372impl<'a> RecallView<'a> {
373    #[inline]
374    pub fn query(&self, query_embedding: Vec<f32>) -> RecallBuilder<'a> {
375        self.0.recall(query_embedding)
376    }
377
378    #[inline]
379    pub async fn fetch_resource(
380        &self,
381        actor_id: &AgentId,
382        resource_id: hirn_core::ResourceId,
383        hydration_mode: hirn_core::HydrationMode,
384    ) -> HirnResult<Option<hirn_storage::HydratedResource>> {
385        self.0
386            .fetch_resource(actor_id, resource_id, hydration_mode)
387            .await
388    }
389
390    #[inline]
391    pub async fn batch<'b>(
392        &self,
393        builders: Vec<RecallBuilder<'b>>,
394    ) -> Vec<HirnResult<Vec<RecallResult>>>
395    where
396        'a: 'b,
397    {
398        self.0.batch_recall(builders).await
399    }
400
401    #[inline]
402    pub fn think(&self, query_embedding: Vec<f32>) -> crate::think::ThinkBuilder<'a> {
403        self.0.think(query_embedding)
404    }
405
406    #[inline]
407    pub fn inspect(&self, id: MemoryId) -> crate::inspect::InspectBuilder<'a> {
408        self.0.inspect(id)
409    }
410
411    #[inline]
412    pub fn trace(&self, id: MemoryId) -> crate::trace::TraceBuilder<'a> {
413        self.0.trace(id)
414    }
415}
416
417// ---------------------------------------------------------------------------
418// NamespaceView
419// ---------------------------------------------------------------------------
420
421impl<'a> NamespaceView<'a> {
422    #[inline]
423    pub async fn create(
424        &self,
425        name: &str,
426        kind: hirn_core::types::NamespaceKind,
427        members: Vec<AgentId>,
428    ) -> HirnResult<()> {
429        self.0.create_namespace(name, kind, members).await
430    }
431
432    #[inline]
433    pub async fn list(&self) -> HirnResult<Vec<hirn_core::namespace::NamespaceRecord>> {
434        self.0.list_namespaces().await
435    }
436
437    #[inline]
438    pub async fn get(&self, name: &str) -> HirnResult<hirn_core::namespace::NamespaceRecord> {
439        self.0.get_namespace(name).await
440    }
441
442    #[inline]
443    pub async fn delete(&self, name: &str) -> HirnResult<()> {
444        self.0.delete_namespace(name).await
445    }
446}
447
448// ---------------------------------------------------------------------------
449// PolicyView
450// ---------------------------------------------------------------------------
451
452impl<'a> PolicyView<'a> {
453    /// Evaluate Cedar policy: returns `Ok(())` if allowed, error if denied.
454    #[inline]
455    pub async fn enforce(
456        &self,
457        agent_id: &str,
458        action: Action,
459        realm: &str,
460        namespace: &str,
461    ) -> HirnResult<()> {
462        self.0.enforce(agent_id, action, realm, namespace).await
463    }
464
465    /// Non-async policy check: returns `true` if action is allowed.
466    #[inline]
467    pub fn is_action_allowed(
468        &self,
469        agent_id: &str,
470        action: Action,
471        realm: &str,
472        namespace: &str,
473    ) -> bool {
474        self.0.is_action_allowed(agent_id, action, realm, namespace)
475    }
476}
477
478// ---------------------------------------------------------------------------
479// AdminView
480// ---------------------------------------------------------------------------
481
482impl<'a> AdminView<'a> {
483    /// Return the product-level write guarantee table used by diagnostics and docs.
484    #[inline]
485    pub fn mutation_write_contracts(&self) -> &'static [MutationWriteContract] {
486        self.0.mutation_write_contracts()
487    }
488
489    /// Get aggregate database statistics.
490    #[inline]
491    pub async fn stats(&self) -> HirnResult<DbStats> {
492        self.0.stats().await
493    }
494
495    /// Get per-layer record counts.
496    #[inline]
497    pub async fn count(&self) -> HirnResult<LayerCounts> {
498        self.0.count().await
499    }
500
501    /// Start building a consolidation operation.
502    #[inline]
503    pub fn consolidate(&self) -> crate::consolidation::ConsolidateBuilder<'a> {
504        self.0.consolidate()
505    }
506
507    /// Start building a lifecycle compaction operation.
508    #[inline]
509    pub fn lifecycle_compact(&self) -> crate::consolidation::LifecycleCompactBuilder<'a> {
510        self.0.lifecycle_compact()
511    }
512
513    /// Apply a specific resource retention policy to active resource heads.
514    #[inline]
515    pub async fn apply_resource_retention_policy(
516        &self,
517        policy: &hirn_core::ResourceRetentionPolicy,
518    ) -> HirnResult<hirn_storage::ResourceRetentionApplyResult> {
519        self.0.apply_resource_retention_policy(policy).await
520    }
521
522    /// Apply the configured resource retention policy from [`HirnConfig`].
523    #[inline]
524    pub async fn apply_configured_resource_retention(
525        &self,
526    ) -> HirnResult<hirn_storage::ResourceRetentionApplyResult> {
527        self.0.apply_configured_resource_retention().await
528    }
529
530    /// Query the audit log.
531    #[inline]
532    pub async fn audit_log(
533        &self,
534        after: Option<&Timestamp>,
535        before: Option<&Timestamp>,
536    ) -> HirnResult<Vec<hirn_core::audit::AuditEntry>> {
537        self.0.audit_log(after, before).await
538    }
539
540    /// Consolidate semantic records across agents in a namespace.
541    #[inline]
542    pub async fn cross_agent_consolidate(
543        &self,
544        target_namespace: &Namespace,
545        auto_merge_threshold: f32,
546    ) -> HirnResult<CrossAgentConsolidationResult> {
547        self.0
548            .cross_agent_consolidate(target_namespace, auto_merge_threshold)
549            .await
550    }
551
552    /// Purge all data associated with an agent (GDPR Right to Erasure).
553    #[inline]
554    pub async fn purge_agent(&self, agent_id: &AgentId) -> HirnResult<PurgeReport> {
555        self.0.purge_agent(agent_id).await
556    }
557
558    /// Queue a budgeted offline cognition job.
559    #[inline]
560    pub async fn schedule_offline_job(
561        &self,
562        job: hirn_core::CognitiveJob,
563    ) -> HirnResult<hirn_core::OfflineJobId> {
564        self.0.offline_scheduler_runtime().submit_job(job).await
565    }
566
567    /// Inspect the latest in-memory status for an offline cognition job.
568    #[inline]
569    pub fn offline_job_status(
570        &self,
571        job_id: hirn_core::OfflineJobId,
572    ) -> Option<hirn_core::OfflineJobStatus> {
573        self.0.offline_scheduler_runtime().job_status(job_id)
574    }
575
576    /// Inspect durable audit history and latest state for an offline cognition job.
577    #[inline]
578    pub async fn inspect_offline_job(
579        &self,
580        job_id: hirn_core::OfflineJobId,
581    ) -> HirnResult<Option<hirn_core::OfflineJobInspection>> {
582        self.0.offline_scheduler_runtime().inspect_job(job_id).await
583    }
584
585    /// Retry a failed offline cognition job using the configured retry backoff policy.
586    #[inline]
587    pub async fn retry_offline_job(
588        &self,
589        job_id: hirn_core::OfflineJobId,
590    ) -> HirnResult<hirn_core::OfflineJobId> {
591        self.0.offline_scheduler_runtime().retry_job(job_id).await
592    }
593
594    /// Replay a terminal offline cognition job as a new attempt immediately.
595    #[inline]
596    pub async fn replay_offline_job(
597        &self,
598        job_id: hirn_core::OfflineJobId,
599    ) -> HirnResult<hirn_core::OfflineJobId> {
600        self.0.offline_scheduler_runtime().replay_job(job_id).await
601    }
602
603    /// Inspect the scheduler counters for queued offline cognition jobs.
604    #[inline]
605    pub fn offline_scheduler_metrics(&self) -> hirn_core::OfflineSchedulerMetrics {
606        self.0.offline_scheduler_runtime().metrics_snapshot()
607    }
608
609    /// Close the database, flushing pending writes.
610    #[inline]
611    pub async fn close(&self) -> HirnResult<()> {
612        self.0.close().await
613    }
614
615    /// Retrieve a memory record from any layer by ID.
616    #[inline]
617    pub async fn get_memory(&self, id: MemoryId) -> HirnResult<MemoryRecord> {
618        self.0.get_memory(id).await
619    }
620
621    /// Batch-retrieve memory records from any layer by IDs.
622    #[inline]
623    pub async fn get_memories_batch(
624        &self,
625        ids: &[MemoryId],
626    ) -> HirnResult<HashMap<MemoryId, MemoryRecord>> {
627        self.0.get_memories_batch(ids).await
628    }
629
630    /// Validate semantic revision chains and the runtime semantic head cache.
631    #[inline]
632    pub async fn validate_semantic_revisions(
633        &self,
634    ) -> HirnResult<crate::integrity::SemanticRevisionIntegrityReport> {
635        crate::integrity::check_semantic_revision_integrity(self.0).await
636    }
637
638    /// Rebuild the runtime semantic head cache from authoritative semantic storage state.
639    #[inline]
640    pub async fn repair_semantic_revisions(
641        &self,
642    ) -> HirnResult<crate::integrity::SemanticRevisionRepairReport> {
643        crate::integrity::repair_semantic_revision_integrity(self.0).await
644    }
645}
646
647// ---------------------------------------------------------------------------
648// QueryView
649// ---------------------------------------------------------------------------
650
651impl<'a> QueryView<'a> {
652    /// Execute a HirnQL query through the 7-stage pipeline.
653    #[inline]
654    pub async fn execute(&self, query: &str) -> HirnResult<crate::ql::results::QueryResult> {
655        self.0.execute_ql(query).await
656    }
657
658    /// Execute a HirnQL query and return optional engine diagnostics when the
659    /// authoritative execution path exposes them.
660    #[inline]
661    pub async fn execute_with_diagnostics(
662        &self,
663        query: &str,
664    ) -> HirnResult<(
665        crate::ql::results::QueryResult,
666        Option<crate::diagnostics::QueryDiagnostics>,
667    )> {
668        self.0.execute_ql_with_diagnostics(query).await
669    }
670
671    /// Execute a HirnQL query with namespace access control.
672    #[inline]
673    pub async fn execute_scoped(
674        &self,
675        query: &str,
676        allowed_namespaces: &[Namespace],
677    ) -> HirnResult<crate::ql::results::QueryResult> {
678        self.0.execute_ql_scoped(query, allowed_namespaces).await
679    }
680
681    /// Return the EXPLAIN output for a query.
682    #[inline]
683    pub fn explain(&self, query: &str) -> HirnResult<String> {
684        self.0.explain_plan(query)
685    }
686
687    /// Prepare a parameterized HirnQL query for later execution.
688    #[inline]
689    pub fn prepare(&self, query: &str) -> HirnResult<crate::ql::PreparedStatement> {
690        self.0.prepare(query)
691    }
692
693    /// Execute a prepared statement with bound parameter values.
694    #[inline]
695    pub async fn execute_prepared(
696        &self,
697        prepared: &crate::ql::PreparedStatement,
698        params: &std::collections::HashMap<String, String>,
699    ) -> HirnResult<crate::ql::results::QueryResult> {
700        self.0.execute_prepared(prepared, params).await
701    }
702
703    /// Start building a HirnQL query via the programmatic API.
704    #[inline]
705    pub fn builder(&self) -> crate::ql::builder::QueryBuilder<'a> {
706        self.0.query()
707    }
708
709    /// Invalidate the plan cache (call after schema changes).
710    #[inline]
711    pub fn invalidate_cache(&self) {
712        self.0.invalidate_plan_cache();
713    }
714}
715
716// ---------------------------------------------------------------------------
717// CausalView
718// ---------------------------------------------------------------------------
719
720impl<'a> CausalView<'a> {
721    /// Mark two memories as contradicting each other.
722    #[inline]
723    pub async fn mark_contradiction(&self, id: MemoryId, contradicts: MemoryId) -> HirnResult<()> {
724        self.0.mark_contradiction(id, contradicts).await
725    }
726
727    /// Apply ABA resolution: winner keeps/boosts confidence, loser's is reduced.
728    #[inline]
729    pub async fn apply_aba_resolution(
730        &self,
731        winner: MemoryId,
732        loser: MemoryId,
733        loser_revised_confidence: f32,
734        reason: &str,
735    ) -> HirnResult<()> {
736        self.0
737            .apply_aba_resolution(winner, loser, loser_revised_confidence, reason)
738            .await
739    }
740
741    /// List all quarantined records pending review.
742    #[inline]
743    pub async fn review_quarantine(&self) -> HirnResult<Vec<crate::security::QuarantineEntry>> {
744        self.0.review_quarantine().await
745    }
746
747    /// Approve a quarantined record, promoting or applying it with the reviewer identity.
748    #[inline]
749    pub async fn approve_quarantine(
750        &self,
751        id: MemoryId,
752        approved_by: AgentId,
753    ) -> HirnResult<crate::security::QuarantineApprovalOutcome> {
754        self.0.approve_quarantine(id, approved_by).await
755    }
756
757    /// Reject a quarantined record, permanently removing it.
758    #[inline]
759    pub async fn reject_quarantine(&self, id: MemoryId) -> HirnResult<()> {
760        self.0.reject_quarantine(id).await
761    }
762
763    /// Roll back a previously approved generated output using its durable receipt.
764    #[inline]
765    pub async fn rollback_quarantine_approval(
766        &self,
767        id: MemoryId,
768        rolled_back_by: AgentId,
769        reason: String,
770    ) -> HirnResult<crate::security::QuarantineRollbackOutcome> {
771        self.0
772            .rollback_quarantine_approval(id, rolled_back_by, reason)
773            .await
774    }
775}
776
777// ---------------------------------------------------------------------------
778// Accessor methods on HirnDB
779// ---------------------------------------------------------------------------
780
781impl HirnDB {
782    /// Access episodic memory operations.
783    #[inline]
784    pub fn episodic(&self) -> EpisodicView<'_> {
785        EpisodicView(self)
786    }
787
788    /// Access semantic memory operations.
789    #[inline]
790    pub fn semantic(&self) -> SemanticView<'_> {
791        SemanticView(self)
792    }
793
794    /// Access procedural memory operations.
795    #[inline]
796    pub fn procedural(&self) -> ProceduralView<'_> {
797        ProceduralView(self)
798    }
799
800    /// Access working memory operations.
801    #[inline]
802    pub fn working(&self) -> WorkingView<'_> {
803        WorkingView(self)
804    }
805
806    /// Access graph operations.
807    #[inline]
808    pub fn graph_view(&self) -> GraphView<'_> {
809        GraphView(self)
810    }
811
812    /// Access recall, think and trace operations.
813    #[inline]
814    pub fn recall_view(&self) -> RecallView<'_> {
815        RecallView(self)
816    }
817
818    /// Access namespace management operations.
819    #[inline]
820    pub fn namespaces(&self) -> NamespaceView<'_> {
821        NamespaceView(self)
822    }
823
824    /// Access Cedar policy operations.
825    #[inline]
826    pub fn policy(&self) -> PolicyView<'_> {
827        PolicyView(self)
828    }
829
830    /// Access administrative operations (stats, compaction, maintenance).
831    #[inline]
832    pub fn admin(&self) -> AdminView<'_> {
833        AdminView(self)
834    }
835
836    /// Access HirnQL query execution operations.
837    #[inline]
838    pub fn ql(&self) -> QueryView<'_> {
839        QueryView(self)
840    }
841
842    /// Access causal reasoning operations (contradictions, quarantine, ABA).
843    #[inline]
844    pub fn causal(&self) -> CausalView<'_> {
845        CausalView(self)
846    }
847}