Skip to main content

reddb_server/application/
ports.rs

1use std::collections::BTreeMap;
2
3use crate::application::entity::{
4    apply_patch_operations_to_json, apply_patch_operations_to_storage_map,
5    apply_patch_operations_to_vector_fields, json_to_metadata_value, json_to_storage_value,
6    metadata_from_json, metadata_to_json, CreateDocumentInput, CreateEdgeInput, CreateEntityOutput,
7    CreateKvInput, CreateNodeInput, CreateRowInput, CreateRowsBatchInput,
8    CreateTimeSeriesPointInput, CreateVectorInput, DeleteEntityInput, DeleteEntityOutput,
9    PatchEntityInput, PatchEntityOperation, PatchEntityOperationType,
10};
11use crate::application::schema::{
12    CreateTableInput, CreateTimeSeriesInput, DropTableInput, DropTimeSeriesInput,
13};
14use crate::application::tree::{
15    CreateTreeInput, DeleteTreeNodeInput, DropTreeInput, InsertTreeNodeInput, MoveTreeNodeInput,
16    RebalanceTreeInput, ValidateTreeInput,
17};
18use crate::catalog::{
19    CatalogAnalyticsJobStatus, CatalogAttentionSummary, CatalogConsistencyReport,
20    CatalogGraphProjectionStatus, CatalogIndexStatus, CatalogModelSnapshot, CollectionDescriptor,
21};
22use crate::health::HealthProvider;
23use crate::physical::{ExportDescriptor, ManifestEvent, PhysicalMetadataFile, SnapshotDescriptor};
24use crate::runtime::{
25    RedDBRuntime, RuntimeFilter, RuntimeGraphCentralityAlgorithm, RuntimeGraphCentralityResult,
26    RuntimeGraphClusteringResult, RuntimeGraphCommunityResult, RuntimeGraphComponentsMode,
27    RuntimeGraphComponentsResult, RuntimeGraphCyclesResult, RuntimeGraphDirection,
28    RuntimeGraphHitsResult, RuntimeGraphNeighborhoodResult, RuntimeGraphPathAlgorithm,
29    RuntimeGraphPathResult, RuntimeGraphPattern, RuntimeGraphProjection,
30    RuntimeGraphPropertiesResult, RuntimeGraphTopologicalSortResult, RuntimeGraphTraversalResult,
31    RuntimeGraphTraversalStrategy, RuntimeIvfSearchResult, RuntimeQueryExplain, RuntimeQueryResult,
32    RuntimeQueryWeights, RuntimeStats, ScanCursor, ScanPage,
33};
34use crate::storage::engine::PhysicalFileHeader;
35use crate::storage::unified::devx::refs::{NodeRef, TableRef, VectorRef};
36use crate::storage::unified::devx::{
37    NativeVectorArtifactBatchInspection, NativeVectorArtifactInspection, PhysicalAuthorityStatus,
38    SimilarResult,
39};
40use crate::storage::unified::dsl::QueryResult as DslQueryResult;
41use crate::storage::unified::store::{
42    NativeCatalogSummary, NativeManifestSummary, NativeMetadataStateSummary, NativePhysicalState,
43    NativeRecoverySummary, NativeRegistrySummary, NativeVectorArtifactPageSummary,
44};
45use crate::RedDBResult;
46use crate::{PhysicalAnalyticsJob, PhysicalGraphProjection, PhysicalIndexState};
47
48pub trait RuntimeQueryPort {
49    fn execute_query(&self, query: &str) -> RedDBResult<RuntimeQueryResult>;
50    fn explain_query(&self, query: &str) -> RedDBResult<RuntimeQueryExplain>;
51    fn scan_collection(
52        &self,
53        collection: &str,
54        cursor: Option<ScanCursor>,
55        limit: usize,
56    ) -> RedDBResult<ScanPage>;
57    fn search_similar(
58        &self,
59        collection: &str,
60        vector: &[f32],
61        k: usize,
62        min_score: f32,
63    ) -> RedDBResult<Vec<SimilarResult>>;
64    fn search_ivf(
65        &self,
66        collection: &str,
67        vector: &[f32],
68        k: usize,
69        n_lists: usize,
70        n_probes: Option<usize>,
71    ) -> RedDBResult<RuntimeIvfSearchResult>;
72    fn search_hybrid(
73        &self,
74        vector: Option<Vec<f32>>,
75        query: Option<String>,
76        k: Option<usize>,
77        collections: Option<Vec<String>>,
78        entity_types: Option<Vec<String>>,
79        capabilities: Option<Vec<String>>,
80        graph_pattern: Option<RuntimeGraphPattern>,
81        filters: Vec<RuntimeFilter>,
82        weights: Option<RuntimeQueryWeights>,
83        min_score: Option<f32>,
84        limit: Option<usize>,
85    ) -> RedDBResult<DslQueryResult>;
86    fn search_text(
87        &self,
88        query: String,
89        collections: Option<Vec<String>>,
90        entity_types: Option<Vec<String>>,
91        capabilities: Option<Vec<String>>,
92        fields: Option<Vec<String>>,
93        limit: Option<usize>,
94        fuzzy: bool,
95    ) -> RedDBResult<DslQueryResult>;
96    fn search_multimodal(
97        &self,
98        query: String,
99        collections: Option<Vec<String>>,
100        entity_types: Option<Vec<String>>,
101        capabilities: Option<Vec<String>>,
102        limit: Option<usize>,
103    ) -> RedDBResult<DslQueryResult>;
104    fn search_index(
105        &self,
106        index: String,
107        value: String,
108        exact: bool,
109        collections: Option<Vec<String>>,
110        entity_types: Option<Vec<String>>,
111        capabilities: Option<Vec<String>>,
112        limit: Option<usize>,
113    ) -> RedDBResult<DslQueryResult>;
114    fn search_context(
115        &self,
116        input: crate::application::SearchContextInput,
117    ) -> RedDBResult<crate::runtime::ContextSearchResult>;
118    fn resolve_semantic_api_key(&self, provider: &crate::ai::AiProvider) -> RedDBResult<String>;
119}
120
121pub trait RuntimeEntityPort {
122    fn create_row(&self, input: CreateRowInput) -> RedDBResult<CreateEntityOutput>;
123    fn create_rows_batch(
124        &self,
125        input: CreateRowsBatchInput,
126    ) -> RedDBResult<Vec<CreateEntityOutput>>;
127    /// Pre-validated bulk insert — caller has already checked column
128    /// types and uniqueness. Server skips
129    /// `normalize_row_fields_for_contract`, `enforce_row_uniqueness`,
130    /// and `enforce_row_batch_uniqueness`. Returns the row count.
131    /// Used by `MSG_BULK_INSERT_PREVALIDATED`.
132    fn create_rows_batch_prevalidated(&self, input: CreateRowsBatchInput) -> RedDBResult<usize>;
133    /// Columnar pre-validated bulk insert — the wire handler
134    /// decoded straight into `Vec<Vec<Value>>` + a shared column-
135    /// name vector, no per-cell `(String, Value)` tuples allocated.
136    /// Avoids ~N×ncols String clones vs the tuple path. The schema
137    /// is shared across every row as a single `Arc<Vec<String>>`.
138    fn create_rows_batch_prevalidated_columnar(
139        &self,
140        collection: String,
141        column_names: std::sync::Arc<Vec<String>>,
142        rows: Vec<Vec<crate::storage::schema::Value>>,
143    ) -> RedDBResult<usize>;
144    /// Columnar bulk insert with full contract validation — wire
145    /// handler shape (one `Arc<Vec<String>>` schema shared across
146    /// every row, `Vec<Vec<Value>>` row payload). Equivalent to
147    /// `create_rows_batch` semantically but skips the per-row
148    /// `(String, Value)` tuple materialisation in the wire decoder.
149    /// When the collection has no contract (or no declared columns)
150    /// fast-paths to `create_rows_batch_prevalidated_columnar`;
151    /// otherwise falls back to the tuple path so contract
152    /// normalisation can run.
153    fn create_rows_batch_columnar(
154        &self,
155        collection: String,
156        column_names: std::sync::Arc<Vec<String>>,
157        rows: Vec<Vec<crate::storage::schema::Value>>,
158    ) -> RedDBResult<usize>;
159    /// Columnar bulk insert that also returns assigned entity ids.
160    /// Kept separate from [`Self::create_rows_batch_columnar`] so bulk wire
161    /// callers can retain their count-only contract.
162    fn create_rows_batch_columnar_with_outputs(
163        &self,
164        collection: String,
165        column_names: std::sync::Arc<Vec<String>>,
166        rows: Vec<Vec<crate::storage::schema::Value>>,
167    ) -> RedDBResult<Vec<CreateEntityOutput>>;
168    fn create_node(&self, input: CreateNodeInput) -> RedDBResult<CreateEntityOutput>;
169    fn create_edge(&self, input: CreateEdgeInput) -> RedDBResult<CreateEntityOutput>;
170    fn create_vector(&self, input: CreateVectorInput) -> RedDBResult<CreateEntityOutput>;
171    fn create_document(&self, input: CreateDocumentInput) -> RedDBResult<CreateEntityOutput>;
172    fn create_kv(&self, input: CreateKvInput) -> RedDBResult<CreateEntityOutput>;
173    fn create_timeseries_point(
174        &self,
175        input: CreateTimeSeriesPointInput,
176    ) -> RedDBResult<CreateEntityOutput>;
177    fn get_kv(
178        &self,
179        collection: &str,
180        key: &str,
181    ) -> RedDBResult<Option<(crate::storage::schema::Value, crate::storage::EntityId)>>;
182    fn delete_kv(&self, collection: &str, key: &str) -> RedDBResult<bool>;
183    fn patch_entity(&self, input: PatchEntityInput) -> RedDBResult<CreateEntityOutput>;
184    fn delete_entity(&self, input: DeleteEntityInput) -> RedDBResult<DeleteEntityOutput>;
185}
186
187pub trait RuntimeSchemaPort {
188    fn create_table(&self, input: CreateTableInput) -> RedDBResult<RuntimeQueryResult>;
189    fn drop_table(&self, input: DropTableInput) -> RedDBResult<RuntimeQueryResult>;
190    fn create_timeseries(&self, input: CreateTimeSeriesInput) -> RedDBResult<RuntimeQueryResult>;
191    fn drop_timeseries(&self, input: DropTimeSeriesInput) -> RedDBResult<RuntimeQueryResult>;
192}
193
194pub trait RuntimeTreePort {
195    fn create_tree(&self, input: CreateTreeInput) -> RedDBResult<RuntimeQueryResult>;
196    fn drop_tree(&self, input: DropTreeInput) -> RedDBResult<RuntimeQueryResult>;
197    fn insert_tree_node(&self, input: InsertTreeNodeInput) -> RedDBResult<RuntimeQueryResult>;
198    fn move_tree_node(&self, input: MoveTreeNodeInput) -> RedDBResult<RuntimeQueryResult>;
199    fn delete_tree_node(&self, input: DeleteTreeNodeInput) -> RedDBResult<RuntimeQueryResult>;
200    fn validate_tree(&self, input: ValidateTreeInput) -> RedDBResult<RuntimeQueryResult>;
201    fn rebalance_tree(&self, input: RebalanceTreeInput) -> RedDBResult<RuntimeQueryResult>;
202}
203
204pub trait RuntimeAdminPort {
205    fn set_index_enabled(&self, name: &str, enabled: bool) -> RedDBResult<PhysicalIndexState>;
206    fn mark_index_building(&self, name: &str) -> RedDBResult<PhysicalIndexState>;
207    fn fail_index(&self, name: &str) -> RedDBResult<PhysicalIndexState>;
208    fn mark_index_stale(&self, name: &str) -> RedDBResult<PhysicalIndexState>;
209    fn mark_index_ready(&self, name: &str) -> RedDBResult<PhysicalIndexState>;
210    fn warmup_index_with_lifecycle(&self, name: &str) -> RedDBResult<PhysicalIndexState>;
211    fn rebuild_indexes_with_lifecycle(
212        &self,
213        collection: Option<&str>,
214    ) -> RedDBResult<Vec<PhysicalIndexState>>;
215    fn save_graph_projection(
216        &self,
217        name: impl Into<String>,
218        projection: RuntimeGraphProjection,
219        source: Option<String>,
220    ) -> RedDBResult<PhysicalGraphProjection>;
221    fn mark_graph_projection_materializing(
222        &self,
223        name: &str,
224    ) -> RedDBResult<PhysicalGraphProjection>;
225    fn materialize_graph_projection(&self, name: &str) -> RedDBResult<PhysicalGraphProjection>;
226    fn fail_graph_projection(&self, name: &str) -> RedDBResult<PhysicalGraphProjection>;
227    fn mark_graph_projection_stale(&self, name: &str) -> RedDBResult<PhysicalGraphProjection>;
228    fn save_analytics_job(
229        &self,
230        kind: impl Into<String>,
231        projection_name: Option<String>,
232        metadata: BTreeMap<String, String>,
233    ) -> RedDBResult<PhysicalAnalyticsJob>;
234    fn start_analytics_job(
235        &self,
236        kind: impl Into<String>,
237        projection_name: Option<String>,
238        metadata: BTreeMap<String, String>,
239    ) -> RedDBResult<PhysicalAnalyticsJob>;
240    fn queue_analytics_job(
241        &self,
242        kind: impl Into<String>,
243        projection_name: Option<String>,
244        metadata: BTreeMap<String, String>,
245    ) -> RedDBResult<PhysicalAnalyticsJob>;
246    fn fail_analytics_job(
247        &self,
248        kind: impl Into<String>,
249        projection_name: Option<String>,
250        metadata: BTreeMap<String, String>,
251    ) -> RedDBResult<PhysicalAnalyticsJob>;
252    fn mark_analytics_job_stale(
253        &self,
254        kind: impl Into<String>,
255        projection_name: Option<String>,
256        metadata: BTreeMap<String, String>,
257    ) -> RedDBResult<PhysicalAnalyticsJob>;
258    fn complete_analytics_job(
259        &self,
260        kind: impl Into<String>,
261        projection_name: Option<String>,
262        metadata: BTreeMap<String, String>,
263    ) -> RedDBResult<PhysicalAnalyticsJob>;
264}
265
266pub trait RuntimeCatalogPort {
267    fn collections(&self) -> Vec<String>;
268    fn catalog(&self) -> CatalogModelSnapshot;
269    fn catalog_consistency_report(&self) -> CatalogConsistencyReport;
270    fn catalog_attention_summary(&self) -> CatalogAttentionSummary;
271    fn collection_attention(&self) -> Vec<CollectionDescriptor>;
272    fn indexes(&self) -> Vec<PhysicalIndexState>;
273    fn declared_indexes(&self) -> Vec<PhysicalIndexState>;
274    fn indexes_for_collection(&self, collection: &str) -> Vec<PhysicalIndexState>;
275    fn declared_indexes_for_collection(&self, collection: &str) -> Vec<PhysicalIndexState>;
276    fn index_statuses(&self) -> Vec<CatalogIndexStatus>;
277    fn index_attention(&self) -> Vec<CatalogIndexStatus>;
278    fn graph_projections(&self) -> RedDBResult<Vec<PhysicalGraphProjection>>;
279    fn operational_graph_projections(&self) -> Vec<PhysicalGraphProjection>;
280    fn graph_projection_statuses(&self) -> Vec<CatalogGraphProjectionStatus>;
281    fn graph_projection_attention(&self) -> Vec<CatalogGraphProjectionStatus>;
282    fn analytics_jobs(&self) -> RedDBResult<Vec<PhysicalAnalyticsJob>>;
283    fn operational_analytics_jobs(&self) -> Vec<PhysicalAnalyticsJob>;
284    fn analytics_job_statuses(&self) -> Vec<CatalogAnalyticsJobStatus>;
285    fn analytics_job_attention(&self) -> Vec<CatalogAnalyticsJobStatus>;
286    fn stats(&self) -> RuntimeStats;
287}
288
289pub trait RuntimeNativePort {
290    fn health_report(&self) -> crate::health::HealthReport;
291    fn collection_roots(&self) -> RedDBResult<BTreeMap<String, u64>>;
292    fn snapshots(&self) -> RedDBResult<Vec<SnapshotDescriptor>>;
293    fn exports(&self) -> RedDBResult<Vec<ExportDescriptor>>;
294    fn physical_metadata(&self) -> RedDBResult<PhysicalMetadataFile>;
295    fn manifest_events_filtered(
296        &self,
297        collection: Option<&str>,
298        kind: Option<&str>,
299        since_snapshot: Option<u64>,
300    ) -> RedDBResult<Vec<ManifestEvent>>;
301    fn create_snapshot(&self) -> RedDBResult<SnapshotDescriptor>;
302    fn create_export(&self, name: String) -> RedDBResult<ExportDescriptor>;
303    fn checkpoint(&self) -> RedDBResult<()>;
304    fn apply_retention_policy(&self) -> RedDBResult<()>;
305    fn run_maintenance(&self) -> RedDBResult<()>;
306    fn native_header(&self) -> RedDBResult<PhysicalFileHeader>;
307    fn native_collection_roots(&self) -> RedDBResult<BTreeMap<String, u64>>;
308    fn native_manifest_summary(&self) -> RedDBResult<NativeManifestSummary>;
309    fn native_registry_summary(&self) -> RedDBResult<NativeRegistrySummary>;
310    fn native_recovery_summary(&self) -> RedDBResult<NativeRecoverySummary>;
311    fn native_catalog_summary(&self) -> RedDBResult<NativeCatalogSummary>;
312    fn native_physical_state(&self) -> RedDBResult<NativePhysicalState>;
313    fn native_vector_artifact_pages(&self) -> RedDBResult<Vec<NativeVectorArtifactPageSummary>>;
314    fn inspect_native_vector_artifact(
315        &self,
316        collection: &str,
317        artifact_kind: Option<&str>,
318    ) -> RedDBResult<NativeVectorArtifactInspection>;
319    fn warmup_native_vector_artifact(
320        &self,
321        collection: &str,
322        artifact_kind: Option<&str>,
323    ) -> RedDBResult<NativeVectorArtifactInspection>;
324    fn inspect_native_vector_artifacts(&self) -> RedDBResult<NativeVectorArtifactBatchInspection>;
325    fn warmup_native_vector_artifacts(&self) -> RedDBResult<NativeVectorArtifactBatchInspection>;
326    fn native_header_repair_policy(&self) -> RedDBResult<String>;
327    fn repair_native_header_from_metadata(&self) -> RedDBResult<String>;
328    fn rebuild_physical_metadata_from_native_state(&self) -> RedDBResult<bool>;
329    fn repair_native_physical_state_from_metadata(&self) -> RedDBResult<bool>;
330    fn native_metadata_state_summary(&self) -> RedDBResult<NativeMetadataStateSummary>;
331    fn physical_authority_status(&self) -> PhysicalAuthorityStatus;
332    fn readiness_for_query(&self) -> bool;
333    fn readiness_for_query_serverless(&self) -> bool;
334    fn readiness_for_write(&self) -> bool;
335    fn readiness_for_write_serverless(&self) -> bool;
336    fn readiness_for_repair(&self) -> bool;
337    fn readiness_for_repair_serverless(&self) -> bool;
338}
339
340pub trait RuntimeGraphPort {
341    fn resolve_graph_projection(
342        &self,
343        name: Option<&str>,
344        inline: Option<RuntimeGraphProjection>,
345    ) -> RedDBResult<Option<RuntimeGraphProjection>>;
346    fn graph_neighborhood(
347        &self,
348        node: &str,
349        direction: RuntimeGraphDirection,
350        max_depth: usize,
351        edge_labels: Option<Vec<String>>,
352        projection: Option<RuntimeGraphProjection>,
353    ) -> RedDBResult<RuntimeGraphNeighborhoodResult>;
354    fn graph_traverse(
355        &self,
356        source: &str,
357        direction: RuntimeGraphDirection,
358        max_depth: usize,
359        strategy: RuntimeGraphTraversalStrategy,
360        edge_labels: Option<Vec<String>>,
361        projection: Option<RuntimeGraphProjection>,
362    ) -> RedDBResult<RuntimeGraphTraversalResult>;
363    fn graph_shortest_path(
364        &self,
365        source: &str,
366        target: &str,
367        direction: RuntimeGraphDirection,
368        algorithm: RuntimeGraphPathAlgorithm,
369        edge_labels: Option<Vec<String>>,
370        projection: Option<RuntimeGraphProjection>,
371    ) -> RedDBResult<RuntimeGraphPathResult>;
372    fn graph_components(
373        &self,
374        mode: RuntimeGraphComponentsMode,
375        min_size: usize,
376        projection: Option<RuntimeGraphProjection>,
377    ) -> RedDBResult<RuntimeGraphComponentsResult>;
378    fn graph_centrality(
379        &self,
380        algorithm: RuntimeGraphCentralityAlgorithm,
381        top_k: usize,
382        normalize: bool,
383        max_iterations: Option<usize>,
384        epsilon: Option<f64>,
385        alpha: Option<f64>,
386        projection: Option<RuntimeGraphProjection>,
387    ) -> RedDBResult<RuntimeGraphCentralityResult>;
388    fn graph_communities(
389        &self,
390        algorithm: crate::runtime::RuntimeGraphCommunityAlgorithm,
391        min_size: usize,
392        max_iterations: Option<usize>,
393        resolution: Option<f64>,
394        projection: Option<RuntimeGraphProjection>,
395    ) -> RedDBResult<RuntimeGraphCommunityResult>;
396    fn graph_clustering(
397        &self,
398        top_k: usize,
399        include_triangles: bool,
400        projection: Option<RuntimeGraphProjection>,
401    ) -> RedDBResult<RuntimeGraphClusteringResult>;
402    fn graph_personalized_pagerank(
403        &self,
404        seeds: Vec<String>,
405        top_k: usize,
406        alpha: Option<f64>,
407        epsilon: Option<f64>,
408        max_iterations: Option<usize>,
409        projection: Option<RuntimeGraphProjection>,
410    ) -> RedDBResult<RuntimeGraphCentralityResult>;
411    fn graph_hits(
412        &self,
413        top_k: usize,
414        epsilon: Option<f64>,
415        max_iterations: Option<usize>,
416        projection: Option<RuntimeGraphProjection>,
417    ) -> RedDBResult<RuntimeGraphHitsResult>;
418    fn graph_cycles(
419        &self,
420        max_length: usize,
421        max_cycles: usize,
422        projection: Option<RuntimeGraphProjection>,
423    ) -> RedDBResult<RuntimeGraphCyclesResult>;
424    fn graph_topological_sort(
425        &self,
426        projection: Option<RuntimeGraphProjection>,
427    ) -> RedDBResult<RuntimeGraphTopologicalSortResult>;
428    fn graph_properties(
429        &self,
430        projection: Option<RuntimeGraphProjection>,
431    ) -> RedDBResult<RuntimeGraphPropertiesResult>;
432}
433
434pub trait RuntimeVcsPort {
435    fn vcs_commit(
436        &self,
437        input: crate::application::vcs::CreateCommitInput,
438    ) -> RedDBResult<crate::application::vcs::Commit>;
439
440    fn vcs_branch_create(
441        &self,
442        input: crate::application::vcs::CreateBranchInput,
443    ) -> RedDBResult<crate::application::vcs::Ref>;
444
445    fn vcs_branch_delete(&self, name: &str) -> RedDBResult<()>;
446
447    fn vcs_tag_create(
448        &self,
449        input: crate::application::vcs::CreateTagInput,
450    ) -> RedDBResult<crate::application::vcs::Ref>;
451
452    fn vcs_list_refs(&self, prefix: Option<&str>)
453        -> RedDBResult<Vec<crate::application::vcs::Ref>>;
454
455    fn vcs_checkout(
456        &self,
457        input: crate::application::vcs::CheckoutInput,
458    ) -> RedDBResult<crate::application::vcs::Ref>;
459
460    fn vcs_merge(
461        &self,
462        input: crate::application::vcs::MergeInput,
463    ) -> RedDBResult<crate::application::vcs::MergeOutcome>;
464
465    fn vcs_cherry_pick(
466        &self,
467        connection_id: u64,
468        commit: &str,
469        author: crate::application::vcs::Author,
470    ) -> RedDBResult<crate::application::vcs::MergeOutcome>;
471
472    fn vcs_revert(
473        &self,
474        connection_id: u64,
475        commit: &str,
476        author: crate::application::vcs::Author,
477    ) -> RedDBResult<crate::application::vcs::Commit>;
478
479    fn vcs_reset(&self, input: crate::application::vcs::ResetInput) -> RedDBResult<()>;
480
481    fn vcs_log(
482        &self,
483        input: crate::application::vcs::LogInput,
484    ) -> RedDBResult<Vec<crate::application::vcs::Commit>>;
485
486    fn vcs_diff(
487        &self,
488        input: crate::application::vcs::DiffInput,
489    ) -> RedDBResult<crate::application::vcs::Diff>;
490
491    fn vcs_status(
492        &self,
493        input: crate::application::vcs::StatusInput,
494    ) -> RedDBResult<crate::application::vcs::Status>;
495
496    fn vcs_lca(&self, a: &str, b: &str)
497        -> RedDBResult<Option<crate::application::vcs::CommitHash>>;
498
499    fn vcs_conflicts_list(
500        &self,
501        merge_state_id: &str,
502    ) -> RedDBResult<Vec<crate::application::vcs::Conflict>>;
503
504    fn vcs_conflict_resolve(
505        &self,
506        conflict_id: &str,
507        resolved: crate::json::Value,
508    ) -> RedDBResult<()>;
509
510    fn vcs_resolve_as_of(
511        &self,
512        spec: crate::application::vcs::AsOfSpec,
513    ) -> RedDBResult<crate::storage::transaction::snapshot::Xid>;
514
515    fn vcs_resolve_commitish(&self, spec: &str)
516        -> RedDBResult<crate::application::vcs::CommitHash>;
517
518    fn vcs_set_versioned(&self, collection: &str, enabled: bool) -> RedDBResult<()>;
519    fn vcs_list_versioned(&self) -> RedDBResult<Vec<String>>;
520    fn vcs_is_versioned(&self, collection: &str) -> RedDBResult<bool>;
521}
522
523/// Context-aware extension trait that mirrors `RuntimeEntityPort`
524/// with `&OperationContext` threaded through every method.
525///
526/// This is the migration runway for the `OperationContext` deepening
527/// (PLAN cluster 6). Each default implementation forwards to the
528/// existing context-less method, so today the trait is a pure
529/// pass-through — but new callers can already adopt the
530/// context-passing surface, and a future PR will replace the
531/// defaults with real impls that read `ctx.xid` / `ctx.write_consent`.
532///
533/// Hidden behind the `ctx-ports` feature flag during the migration
534/// window so the impl bloat doesn't burden default builds. Once
535/// every port is migrated, the flag goes away and these traits
536/// become the only surface.
537pub trait RuntimeEntityPortCtx: RuntimeEntityPort {
538    fn create_row_ctx(
539        &self,
540        ctx: &crate::application::OperationContext,
541        input: CreateRowInput,
542    ) -> RedDBResult<CreateEntityOutput> {
543        let _ = ctx;
544        self.create_row(input)
545    }
546    fn create_node_ctx(
547        &self,
548        ctx: &crate::application::OperationContext,
549        input: CreateNodeInput,
550    ) -> RedDBResult<CreateEntityOutput> {
551        let _ = ctx;
552        self.create_node(input)
553    }
554    fn create_edge_ctx(
555        &self,
556        ctx: &crate::application::OperationContext,
557        input: CreateEdgeInput,
558    ) -> RedDBResult<CreateEntityOutput> {
559        let _ = ctx;
560        self.create_edge(input)
561    }
562    fn create_vector_ctx(
563        &self,
564        ctx: &crate::application::OperationContext,
565        input: CreateVectorInput,
566    ) -> RedDBResult<CreateEntityOutput> {
567        let _ = ctx;
568        self.create_vector(input)
569    }
570    fn create_document_ctx(
571        &self,
572        ctx: &crate::application::OperationContext,
573        input: CreateDocumentInput,
574    ) -> RedDBResult<CreateEntityOutput> {
575        let _ = ctx;
576        self.create_document(input)
577    }
578    fn create_kv_ctx(
579        &self,
580        ctx: &crate::application::OperationContext,
581        input: CreateKvInput,
582    ) -> RedDBResult<CreateEntityOutput> {
583        let _ = ctx;
584        self.create_kv(input)
585    }
586    fn create_timeseries_point_ctx(
587        &self,
588        ctx: &crate::application::OperationContext,
589        input: CreateTimeSeriesPointInput,
590    ) -> RedDBResult<CreateEntityOutput> {
591        let _ = ctx;
592        self.create_timeseries_point(input)
593    }
594    fn get_kv_ctx(
595        &self,
596        ctx: &crate::application::OperationContext,
597        collection: &str,
598        key: &str,
599    ) -> RedDBResult<Option<(crate::storage::schema::Value, crate::storage::EntityId)>> {
600        let _ = ctx;
601        self.get_kv(collection, key)
602    }
603    fn delete_kv_ctx(
604        &self,
605        ctx: &crate::application::OperationContext,
606        collection: &str,
607        key: &str,
608    ) -> RedDBResult<bool> {
609        let _ = ctx;
610        self.delete_kv(collection, key)
611    }
612    fn patch_entity_ctx(
613        &self,
614        ctx: &crate::application::OperationContext,
615        input: PatchEntityInput,
616    ) -> RedDBResult<CreateEntityOutput> {
617        let _ = ctx;
618        self.patch_entity(input)
619    }
620    fn delete_entity_ctx(
621        &self,
622        ctx: &crate::application::OperationContext,
623        input: DeleteEntityInput,
624    ) -> RedDBResult<DeleteEntityOutput> {
625        let _ = ctx;
626        self.delete_entity(input)
627    }
628}
629
630/// Blanket impl: every concrete `RuntimeEntityPort` automatically
631/// gains the context-aware surface via the default forwards above.
632impl<T: RuntimeEntityPort + ?Sized> RuntimeEntityPortCtx for T {}
633
634// ─── ctx extension traits for the remaining mutating ports ───
635//
636// Same pattern as RuntimeEntityPortCtx: methods take
637// `&OperationContext` first, default-forward to the existing
638// context-less call. Blanket impls give every concrete port
639// the new surface for free. Future PRs replace the forwards
640// with real `ctx.write_consent` / `ctx.xid` handling.
641//
642// Read-only ports (RuntimeCatalogPort, RuntimeGraphPort) and the
643// read-only methods of mutating ports are intentionally absent —
644// `OperationContext` adds no locality there until the snapshot-
645// xid migration also lands.
646
647pub trait RuntimeQueryPortCtx: RuntimeQueryPort {
648    fn execute_query_ctx(
649        &self,
650        ctx: &crate::application::OperationContext,
651        query: &str,
652    ) -> RedDBResult<RuntimeQueryResult> {
653        let _ = ctx;
654        self.execute_query(query)
655    }
656    fn explain_query_ctx(
657        &self,
658        ctx: &crate::application::OperationContext,
659        query: &str,
660    ) -> RedDBResult<RuntimeQueryExplain> {
661        let _ = ctx;
662        self.explain_query(query)
663    }
664    fn scan_collection_ctx(
665        &self,
666        ctx: &crate::application::OperationContext,
667        collection: &str,
668        cursor: Option<ScanCursor>,
669        limit: usize,
670    ) -> RedDBResult<ScanPage> {
671        let _ = ctx;
672        self.scan_collection(collection, cursor, limit)
673    }
674}
675impl<T: RuntimeQueryPort + ?Sized> RuntimeQueryPortCtx for T {}
676
677pub trait RuntimeSchemaPortCtx: RuntimeSchemaPort {
678    fn create_table_ctx(
679        &self,
680        ctx: &crate::application::OperationContext,
681        input: CreateTableInput,
682    ) -> RedDBResult<RuntimeQueryResult> {
683        let _ = ctx;
684        self.create_table(input)
685    }
686    fn drop_table_ctx(
687        &self,
688        ctx: &crate::application::OperationContext,
689        input: DropTableInput,
690    ) -> RedDBResult<RuntimeQueryResult> {
691        let _ = ctx;
692        self.drop_table(input)
693    }
694    fn create_timeseries_ctx(
695        &self,
696        ctx: &crate::application::OperationContext,
697        input: CreateTimeSeriesInput,
698    ) -> RedDBResult<RuntimeQueryResult> {
699        let _ = ctx;
700        self.create_timeseries(input)
701    }
702    fn drop_timeseries_ctx(
703        &self,
704        ctx: &crate::application::OperationContext,
705        input: DropTimeSeriesInput,
706    ) -> RedDBResult<RuntimeQueryResult> {
707        let _ = ctx;
708        self.drop_timeseries(input)
709    }
710}
711impl<T: RuntimeSchemaPort + ?Sized> RuntimeSchemaPortCtx for T {}
712
713pub trait RuntimeTreePortCtx: RuntimeTreePort {
714    fn create_tree_ctx(
715        &self,
716        ctx: &crate::application::OperationContext,
717        input: CreateTreeInput,
718    ) -> RedDBResult<RuntimeQueryResult> {
719        let _ = ctx;
720        self.create_tree(input)
721    }
722    fn drop_tree_ctx(
723        &self,
724        ctx: &crate::application::OperationContext,
725        input: DropTreeInput,
726    ) -> RedDBResult<RuntimeQueryResult> {
727        let _ = ctx;
728        self.drop_tree(input)
729    }
730    fn insert_tree_node_ctx(
731        &self,
732        ctx: &crate::application::OperationContext,
733        input: InsertTreeNodeInput,
734    ) -> RedDBResult<RuntimeQueryResult> {
735        let _ = ctx;
736        self.insert_tree_node(input)
737    }
738    fn move_tree_node_ctx(
739        &self,
740        ctx: &crate::application::OperationContext,
741        input: MoveTreeNodeInput,
742    ) -> RedDBResult<RuntimeQueryResult> {
743        let _ = ctx;
744        self.move_tree_node(input)
745    }
746    fn delete_tree_node_ctx(
747        &self,
748        ctx: &crate::application::OperationContext,
749        input: DeleteTreeNodeInput,
750    ) -> RedDBResult<RuntimeQueryResult> {
751        let _ = ctx;
752        self.delete_tree_node(input)
753    }
754    fn rebalance_tree_ctx(
755        &self,
756        ctx: &crate::application::OperationContext,
757        input: RebalanceTreeInput,
758    ) -> RedDBResult<RuntimeQueryResult> {
759        let _ = ctx;
760        self.rebalance_tree(input)
761    }
762}
763impl<T: RuntimeTreePort + ?Sized> RuntimeTreePortCtx for T {}
764
765pub trait RuntimeNativePortCtx: RuntimeNativePort {
766    fn create_snapshot_ctx(
767        &self,
768        ctx: &crate::application::OperationContext,
769    ) -> RedDBResult<SnapshotDescriptor> {
770        let _ = ctx;
771        self.create_snapshot()
772    }
773    fn create_export_ctx(
774        &self,
775        ctx: &crate::application::OperationContext,
776        name: String,
777    ) -> RedDBResult<ExportDescriptor> {
778        let _ = ctx;
779        self.create_export(name)
780    }
781    fn checkpoint_ctx(&self, ctx: &crate::application::OperationContext) -> RedDBResult<()> {
782        let _ = ctx;
783        self.checkpoint()
784    }
785    fn apply_retention_policy_ctx(
786        &self,
787        ctx: &crate::application::OperationContext,
788    ) -> RedDBResult<()> {
789        let _ = ctx;
790        self.apply_retention_policy()
791    }
792    fn run_maintenance_ctx(&self, ctx: &crate::application::OperationContext) -> RedDBResult<()> {
793        let _ = ctx;
794        self.run_maintenance()
795    }
796    fn repair_native_header_from_metadata_ctx(
797        &self,
798        ctx: &crate::application::OperationContext,
799    ) -> RedDBResult<String> {
800        let _ = ctx;
801        self.repair_native_header_from_metadata()
802    }
803    fn rebuild_physical_metadata_from_native_state_ctx(
804        &self,
805        ctx: &crate::application::OperationContext,
806    ) -> RedDBResult<bool> {
807        let _ = ctx;
808        self.rebuild_physical_metadata_from_native_state()
809    }
810}
811impl<T: RuntimeNativePort + ?Sized> RuntimeNativePortCtx for T {}
812
813pub trait RuntimeVcsPortCtx: RuntimeVcsPort {
814    fn vcs_branch_delete_ctx(
815        &self,
816        ctx: &crate::application::OperationContext,
817        name: &str,
818    ) -> RedDBResult<()> {
819        let _ = ctx;
820        self.vcs_branch_delete(name)
821    }
822    fn vcs_reset_ctx(
823        &self,
824        ctx: &crate::application::OperationContext,
825        input: crate::application::vcs::ResetInput,
826    ) -> RedDBResult<()> {
827        let _ = ctx;
828        self.vcs_reset(input)
829    }
830    fn vcs_set_versioned_ctx(
831        &self,
832        ctx: &crate::application::OperationContext,
833        collection: &str,
834        enabled: bool,
835    ) -> RedDBResult<()> {
836        let _ = ctx;
837        self.vcs_set_versioned(collection, enabled)
838    }
839    fn vcs_conflict_resolve_ctx(
840        &self,
841        ctx: &crate::application::OperationContext,
842        conflict_id: &str,
843        resolved: crate::json::Value,
844    ) -> RedDBResult<()> {
845        let _ = ctx;
846        self.vcs_conflict_resolve(conflict_id, resolved)
847    }
848}
849impl<T: RuntimeVcsPort + ?Sized> RuntimeVcsPortCtx for T {}
850
851/// Port for native migration operations.
852///
853/// Stub methods — full implementations land in subsequent slices.
854pub trait RuntimeMigrationPort {
855    /// Register a new migration definition (status = pending).
856    fn migration_create(&self, input: MigrationCreateInput) -> RedDBResult<RuntimeQueryResult>;
857    /// Apply a named migration (or `*` for all pending).
858    fn migration_apply(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
859    /// Roll back an applied migration.
860    fn migration_rollback(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
861    /// Explain a migration without executing it.
862    fn migration_explain(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
863    /// List migrations, optionally filtered by status.
864    fn migration_list(&self, status: Option<&str>) -> RedDBResult<RuntimeQueryResult>;
865}
866
867/// Minimal input type for `migration_create`. Expanded in later slices.
868#[derive(Debug, Clone)]
869pub struct MigrationCreateInput {
870    pub name: String,
871    pub kind: MigrationKind,
872    pub body: String,
873    pub author: String,
874    pub depends_on: Vec<String>,
875    pub batch_size: Option<u64>,
876    pub no_rollback: bool,
877}
878
879#[derive(Debug, Clone, PartialEq, Eq)]
880pub enum MigrationKind {
881    Ddl,
882    Data,
883}
884
885#[path = "ports_impls.rs"]
886mod ports_impls;
887pub(crate) use ports_impls::build_row_update_contract_plan;
888pub(crate) use ports_impls::entity_row_fields_snapshot;
889pub(crate) use ports_impls::normalize_row_update_assignment_with_plan;
890pub(crate) use ports_impls::normalize_row_update_value_for_rule;