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