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 validate_current_serverless_generation(&self) -> RedDBResult<()>;
337    fn readiness_for_query(&self) -> bool;
338    fn readiness_for_query_serverless(&self) -> bool;
339    fn readiness_for_write(&self) -> bool;
340    fn readiness_for_write_serverless(&self) -> bool;
341    fn readiness_for_repair(&self) -> bool;
342    fn readiness_for_repair_serverless(&self) -> bool;
343}
344
345pub trait RuntimeGraphPort {
346    fn resolve_graph_projection(
347        &self,
348        name: Option<&str>,
349        inline: Option<RuntimeGraphProjection>,
350    ) -> RedDBResult<Option<RuntimeGraphProjection>>;
351    fn graph_neighborhood(
352        &self,
353        node: &str,
354        direction: RuntimeGraphDirection,
355        max_depth: usize,
356        edge_labels: Option<Vec<String>>,
357        projection: Option<RuntimeGraphProjection>,
358    ) -> RedDBResult<RuntimeGraphNeighborhoodResult>;
359    fn graph_traverse(
360        &self,
361        source: &str,
362        direction: RuntimeGraphDirection,
363        max_depth: usize,
364        strategy: RuntimeGraphTraversalStrategy,
365        edge_labels: Option<Vec<String>>,
366        projection: Option<RuntimeGraphProjection>,
367    ) -> RedDBResult<RuntimeGraphTraversalResult>;
368    fn graph_shortest_path(
369        &self,
370        source: &str,
371        target: &str,
372        direction: RuntimeGraphDirection,
373        algorithm: RuntimeGraphPathAlgorithm,
374        edge_labels: Option<Vec<String>>,
375        projection: Option<RuntimeGraphProjection>,
376    ) -> RedDBResult<RuntimeGraphPathResult>;
377    fn graph_components(
378        &self,
379        mode: RuntimeGraphComponentsMode,
380        min_size: usize,
381        projection: Option<RuntimeGraphProjection>,
382    ) -> RedDBResult<RuntimeGraphComponentsResult>;
383    fn graph_centrality(
384        &self,
385        algorithm: RuntimeGraphCentralityAlgorithm,
386        top_k: usize,
387        normalize: bool,
388        max_iterations: Option<usize>,
389        epsilon: Option<f64>,
390        alpha: Option<f64>,
391        projection: Option<RuntimeGraphProjection>,
392    ) -> RedDBResult<RuntimeGraphCentralityResult>;
393    fn graph_communities(
394        &self,
395        algorithm: crate::runtime::RuntimeGraphCommunityAlgorithm,
396        min_size: usize,
397        max_iterations: Option<usize>,
398        resolution: Option<f64>,
399        projection: Option<RuntimeGraphProjection>,
400    ) -> RedDBResult<RuntimeGraphCommunityResult>;
401    fn graph_clustering(
402        &self,
403        top_k: usize,
404        include_triangles: bool,
405        projection: Option<RuntimeGraphProjection>,
406    ) -> RedDBResult<RuntimeGraphClusteringResult>;
407    fn graph_personalized_pagerank(
408        &self,
409        seeds: Vec<String>,
410        top_k: usize,
411        alpha: Option<f64>,
412        epsilon: Option<f64>,
413        max_iterations: Option<usize>,
414        projection: Option<RuntimeGraphProjection>,
415    ) -> RedDBResult<RuntimeGraphCentralityResult>;
416    fn graph_hits(
417        &self,
418        top_k: usize,
419        epsilon: Option<f64>,
420        max_iterations: Option<usize>,
421        projection: Option<RuntimeGraphProjection>,
422    ) -> RedDBResult<RuntimeGraphHitsResult>;
423    fn graph_cycles(
424        &self,
425        max_length: usize,
426        max_cycles: usize,
427        projection: Option<RuntimeGraphProjection>,
428    ) -> RedDBResult<RuntimeGraphCyclesResult>;
429    fn graph_topological_sort(
430        &self,
431        projection: Option<RuntimeGraphProjection>,
432    ) -> RedDBResult<RuntimeGraphTopologicalSortResult>;
433    fn graph_properties(
434        &self,
435        projection: Option<RuntimeGraphProjection>,
436    ) -> RedDBResult<RuntimeGraphPropertiesResult>;
437}
438
439pub trait RuntimeVcsPort {
440    fn vcs_commit(
441        &self,
442        input: crate::application::vcs::CreateCommitInput,
443    ) -> RedDBResult<crate::application::vcs::Commit>;
444
445    fn vcs_branch_create(
446        &self,
447        input: crate::application::vcs::CreateBranchInput,
448    ) -> RedDBResult<crate::application::vcs::Ref>;
449
450    fn vcs_branch_delete(&self, name: &str) -> RedDBResult<()>;
451
452    fn vcs_tag_create(
453        &self,
454        input: crate::application::vcs::CreateTagInput,
455    ) -> RedDBResult<crate::application::vcs::Ref>;
456
457    fn vcs_list_refs(&self, prefix: Option<&str>)
458        -> RedDBResult<Vec<crate::application::vcs::Ref>>;
459
460    fn vcs_checkout(
461        &self,
462        input: crate::application::vcs::CheckoutInput,
463    ) -> RedDBResult<crate::application::vcs::Ref>;
464
465    fn vcs_merge(
466        &self,
467        input: crate::application::vcs::MergeInput,
468    ) -> RedDBResult<crate::application::vcs::MergeOutcome>;
469
470    fn vcs_cherry_pick(
471        &self,
472        connection_id: u64,
473        commit: &str,
474        author: crate::application::vcs::Author,
475    ) -> RedDBResult<crate::application::vcs::MergeOutcome>;
476
477    fn vcs_revert(
478        &self,
479        connection_id: u64,
480        commit: &str,
481        author: crate::application::vcs::Author,
482    ) -> RedDBResult<crate::application::vcs::Commit>;
483
484    fn vcs_reset(&self, input: crate::application::vcs::ResetInput) -> RedDBResult<()>;
485
486    fn vcs_log(
487        &self,
488        input: crate::application::vcs::LogInput,
489    ) -> RedDBResult<Vec<crate::application::vcs::Commit>>;
490
491    fn vcs_diff(
492        &self,
493        input: crate::application::vcs::DiffInput,
494    ) -> RedDBResult<crate::application::vcs::Diff>;
495
496    fn vcs_status(
497        &self,
498        input: crate::application::vcs::StatusInput,
499    ) -> RedDBResult<crate::application::vcs::Status>;
500
501    fn vcs_lca(&self, a: &str, b: &str)
502        -> RedDBResult<Option<crate::application::vcs::CommitHash>>;
503
504    fn vcs_conflicts_list(
505        &self,
506        merge_state_id: &str,
507    ) -> RedDBResult<Vec<crate::application::vcs::Conflict>>;
508
509    fn vcs_conflict_resolve(
510        &self,
511        conflict_id: &str,
512        resolved: crate::json::Value,
513    ) -> RedDBResult<()>;
514
515    fn vcs_resolve_as_of(
516        &self,
517        spec: crate::application::vcs::AsOfSpec,
518    ) -> RedDBResult<crate::storage::transaction::snapshot::Xid>;
519
520    fn vcs_resolve_commitish(&self, spec: &str)
521        -> RedDBResult<crate::application::vcs::CommitHash>;
522
523    fn vcs_set_versioned(&self, collection: &str, enabled: bool) -> RedDBResult<()>;
524    fn vcs_list_versioned(&self) -> RedDBResult<Vec<String>>;
525    fn vcs_is_versioned(&self, collection: &str) -> RedDBResult<bool>;
526}
527
528/// Context-aware extension trait that mirrors `RuntimeEntityPort`
529/// with `&OperationContext` threaded through every method.
530///
531/// This is the migration runway for the `OperationContext` deepening
532/// (PLAN cluster 6). Each default implementation forwards to the
533/// existing context-less method, so today the trait is a pure
534/// pass-through — but new callers can already adopt the
535/// context-passing surface, and a future PR will replace the
536/// defaults with real impls that read `ctx.xid` / `ctx.write_consent`.
537///
538/// Hidden behind the `ctx-ports` feature flag during the migration
539/// window so the impl bloat doesn't burden default builds. Once
540/// every port is migrated, the flag goes away and these traits
541/// become the only surface.
542pub trait RuntimeEntityPortCtx: RuntimeEntityPort {
543    fn create_row_ctx(
544        &self,
545        ctx: &crate::application::OperationContext,
546        input: CreateRowInput,
547    ) -> RedDBResult<CreateEntityOutput> {
548        let _ = ctx;
549        self.create_row(input)
550    }
551    fn create_node_ctx(
552        &self,
553        ctx: &crate::application::OperationContext,
554        input: CreateNodeInput,
555    ) -> RedDBResult<CreateEntityOutput> {
556        let _ = ctx;
557        self.create_node(input)
558    }
559    fn create_edge_ctx(
560        &self,
561        ctx: &crate::application::OperationContext,
562        input: CreateEdgeInput,
563    ) -> RedDBResult<CreateEntityOutput> {
564        let _ = ctx;
565        self.create_edge(input)
566    }
567    fn create_vector_ctx(
568        &self,
569        ctx: &crate::application::OperationContext,
570        input: CreateVectorInput,
571    ) -> RedDBResult<CreateEntityOutput> {
572        let _ = ctx;
573        self.create_vector(input)
574    }
575    fn create_document_ctx(
576        &self,
577        ctx: &crate::application::OperationContext,
578        input: CreateDocumentInput,
579    ) -> RedDBResult<CreateEntityOutput> {
580        let _ = ctx;
581        self.create_document(input)
582    }
583    fn create_kv_ctx(
584        &self,
585        ctx: &crate::application::OperationContext,
586        input: CreateKvInput,
587    ) -> RedDBResult<CreateEntityOutput> {
588        let _ = ctx;
589        self.create_kv(input)
590    }
591    fn create_timeseries_point_ctx(
592        &self,
593        ctx: &crate::application::OperationContext,
594        input: CreateTimeSeriesPointInput,
595    ) -> RedDBResult<CreateEntityOutput> {
596        let _ = ctx;
597        self.create_timeseries_point(input)
598    }
599    fn get_kv_ctx(
600        &self,
601        ctx: &crate::application::OperationContext,
602        collection: &str,
603        key: &str,
604    ) -> RedDBResult<Option<(crate::storage::schema::Value, crate::storage::EntityId)>> {
605        let _ = ctx;
606        self.get_kv(collection, key)
607    }
608    fn delete_kv_ctx(
609        &self,
610        ctx: &crate::application::OperationContext,
611        collection: &str,
612        key: &str,
613    ) -> RedDBResult<bool> {
614        let _ = ctx;
615        self.delete_kv(collection, key)
616    }
617    fn patch_entity_ctx(
618        &self,
619        ctx: &crate::application::OperationContext,
620        input: PatchEntityInput,
621    ) -> RedDBResult<CreateEntityOutput> {
622        let _ = ctx;
623        self.patch_entity(input)
624    }
625    fn delete_entity_ctx(
626        &self,
627        ctx: &crate::application::OperationContext,
628        input: DeleteEntityInput,
629    ) -> RedDBResult<DeleteEntityOutput> {
630        let _ = ctx;
631        self.delete_entity(input)
632    }
633}
634
635/// Blanket impl: every concrete `RuntimeEntityPort` automatically
636/// gains the context-aware surface via the default forwards above.
637impl<T: RuntimeEntityPort + ?Sized> RuntimeEntityPortCtx for T {}
638
639// ─── ctx extension traits for the remaining mutating ports ───
640//
641// Same pattern as RuntimeEntityPortCtx: methods take
642// `&OperationContext` first, default-forward to the existing
643// context-less call. Blanket impls give every concrete port
644// the new surface for free. Future PRs replace the forwards
645// with real `ctx.write_consent` / `ctx.xid` handling.
646//
647// Read-only ports (RuntimeCatalogPort, RuntimeGraphPort) and the
648// read-only methods of mutating ports are intentionally absent —
649// `OperationContext` adds no locality there until the snapshot-
650// xid migration also lands.
651
652pub trait RuntimeQueryPortCtx: RuntimeQueryPort {
653    fn execute_query_ctx(
654        &self,
655        ctx: &crate::application::OperationContext,
656        query: &str,
657    ) -> RedDBResult<RuntimeQueryResult> {
658        let _ = ctx;
659        self.execute_query(query)
660    }
661    fn explain_query_ctx(
662        &self,
663        ctx: &crate::application::OperationContext,
664        query: &str,
665    ) -> RedDBResult<RuntimeQueryExplain> {
666        let _ = ctx;
667        self.explain_query(query)
668    }
669    fn scan_collection_ctx(
670        &self,
671        ctx: &crate::application::OperationContext,
672        collection: &str,
673        cursor: Option<ScanCursor>,
674        limit: usize,
675    ) -> RedDBResult<ScanPage> {
676        let _ = ctx;
677        self.scan_collection(collection, cursor, limit)
678    }
679}
680impl<T: RuntimeQueryPort + ?Sized> RuntimeQueryPortCtx for T {}
681
682pub trait RuntimeSchemaPortCtx: RuntimeSchemaPort {
683    fn create_table_ctx(
684        &self,
685        ctx: &crate::application::OperationContext,
686        input: CreateTableInput,
687    ) -> RedDBResult<RuntimeQueryResult> {
688        let _ = ctx;
689        self.create_table(input)
690    }
691    fn drop_table_ctx(
692        &self,
693        ctx: &crate::application::OperationContext,
694        input: DropTableInput,
695    ) -> RedDBResult<RuntimeQueryResult> {
696        let _ = ctx;
697        self.drop_table(input)
698    }
699    fn create_timeseries_ctx(
700        &self,
701        ctx: &crate::application::OperationContext,
702        input: CreateTimeSeriesInput,
703    ) -> RedDBResult<RuntimeQueryResult> {
704        let _ = ctx;
705        self.create_timeseries(input)
706    }
707    fn drop_timeseries_ctx(
708        &self,
709        ctx: &crate::application::OperationContext,
710        input: DropTimeSeriesInput,
711    ) -> RedDBResult<RuntimeQueryResult> {
712        let _ = ctx;
713        self.drop_timeseries(input)
714    }
715}
716impl<T: RuntimeSchemaPort + ?Sized> RuntimeSchemaPortCtx for T {}
717
718pub trait RuntimeTreePortCtx: RuntimeTreePort {
719    fn create_tree_ctx(
720        &self,
721        ctx: &crate::application::OperationContext,
722        input: CreateTreeInput,
723    ) -> RedDBResult<RuntimeQueryResult> {
724        let _ = ctx;
725        self.create_tree(input)
726    }
727    fn drop_tree_ctx(
728        &self,
729        ctx: &crate::application::OperationContext,
730        input: DropTreeInput,
731    ) -> RedDBResult<RuntimeQueryResult> {
732        let _ = ctx;
733        self.drop_tree(input)
734    }
735    fn insert_tree_node_ctx(
736        &self,
737        ctx: &crate::application::OperationContext,
738        input: InsertTreeNodeInput,
739    ) -> RedDBResult<RuntimeQueryResult> {
740        let _ = ctx;
741        self.insert_tree_node(input)
742    }
743    fn move_tree_node_ctx(
744        &self,
745        ctx: &crate::application::OperationContext,
746        input: MoveTreeNodeInput,
747    ) -> RedDBResult<RuntimeQueryResult> {
748        let _ = ctx;
749        self.move_tree_node(input)
750    }
751    fn delete_tree_node_ctx(
752        &self,
753        ctx: &crate::application::OperationContext,
754        input: DeleteTreeNodeInput,
755    ) -> RedDBResult<RuntimeQueryResult> {
756        let _ = ctx;
757        self.delete_tree_node(input)
758    }
759    fn rebalance_tree_ctx(
760        &self,
761        ctx: &crate::application::OperationContext,
762        input: RebalanceTreeInput,
763    ) -> RedDBResult<RuntimeQueryResult> {
764        let _ = ctx;
765        self.rebalance_tree(input)
766    }
767}
768impl<T: RuntimeTreePort + ?Sized> RuntimeTreePortCtx for T {}
769
770pub trait RuntimeNativePortCtx: RuntimeNativePort {
771    fn create_snapshot_ctx(
772        &self,
773        ctx: &crate::application::OperationContext,
774    ) -> RedDBResult<SnapshotDescriptor> {
775        let _ = ctx;
776        self.create_snapshot()
777    }
778    fn create_export_ctx(
779        &self,
780        ctx: &crate::application::OperationContext,
781        name: String,
782    ) -> RedDBResult<ExportDescriptor> {
783        let _ = ctx;
784        self.create_export(name)
785    }
786    fn checkpoint_ctx(&self, ctx: &crate::application::OperationContext) -> RedDBResult<()> {
787        let _ = ctx;
788        self.checkpoint()
789    }
790    fn apply_retention_policy_ctx(
791        &self,
792        ctx: &crate::application::OperationContext,
793    ) -> RedDBResult<()> {
794        let _ = ctx;
795        self.apply_retention_policy()
796    }
797    fn run_maintenance_ctx(&self, ctx: &crate::application::OperationContext) -> RedDBResult<()> {
798        let _ = ctx;
799        self.run_maintenance()
800    }
801    fn repair_native_header_from_metadata_ctx(
802        &self,
803        ctx: &crate::application::OperationContext,
804    ) -> RedDBResult<String> {
805        let _ = ctx;
806        self.repair_native_header_from_metadata()
807    }
808    fn rebuild_physical_metadata_from_native_state_ctx(
809        &self,
810        ctx: &crate::application::OperationContext,
811    ) -> RedDBResult<bool> {
812        let _ = ctx;
813        self.rebuild_physical_metadata_from_native_state()
814    }
815}
816impl<T: RuntimeNativePort + ?Sized> RuntimeNativePortCtx for T {}
817
818pub trait RuntimeVcsPortCtx: RuntimeVcsPort {
819    fn vcs_branch_delete_ctx(
820        &self,
821        ctx: &crate::application::OperationContext,
822        name: &str,
823    ) -> RedDBResult<()> {
824        let _ = ctx;
825        self.vcs_branch_delete(name)
826    }
827    fn vcs_reset_ctx(
828        &self,
829        ctx: &crate::application::OperationContext,
830        input: crate::application::vcs::ResetInput,
831    ) -> RedDBResult<()> {
832        let _ = ctx;
833        self.vcs_reset(input)
834    }
835    fn vcs_set_versioned_ctx(
836        &self,
837        ctx: &crate::application::OperationContext,
838        collection: &str,
839        enabled: bool,
840    ) -> RedDBResult<()> {
841        let _ = ctx;
842        self.vcs_set_versioned(collection, enabled)
843    }
844    fn vcs_conflict_resolve_ctx(
845        &self,
846        ctx: &crate::application::OperationContext,
847        conflict_id: &str,
848        resolved: crate::json::Value,
849    ) -> RedDBResult<()> {
850        let _ = ctx;
851        self.vcs_conflict_resolve(conflict_id, resolved)
852    }
853}
854impl<T: RuntimeVcsPort + ?Sized> RuntimeVcsPortCtx for T {}
855
856/// Port for native migration operations.
857///
858/// Stub methods — full implementations land in subsequent slices.
859pub trait RuntimeMigrationPort {
860    /// Register a new migration definition (status = pending).
861    fn migration_create(&self, input: MigrationCreateInput) -> RedDBResult<RuntimeQueryResult>;
862    /// Apply a named migration (or `*` for all pending).
863    fn migration_apply(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
864    /// Roll back an applied migration.
865    fn migration_rollback(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
866    /// Explain a migration without executing it.
867    fn migration_explain(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
868    /// List migrations, optionally filtered by status.
869    fn migration_list(&self, status: Option<&str>) -> RedDBResult<RuntimeQueryResult>;
870}
871
872/// Minimal input type for `migration_create`. Expanded in later slices.
873#[derive(Debug, Clone)]
874pub struct MigrationCreateInput {
875    pub name: String,
876    pub kind: MigrationKind,
877    pub body: String,
878    pub author: String,
879    pub depends_on: Vec<String>,
880    pub batch_size: Option<u64>,
881    pub no_rollback: bool,
882}
883
884#[derive(Debug, Clone, PartialEq, Eq)]
885pub enum MigrationKind {
886    Ddl,
887    Data,
888}
889
890#[path = "ports_impls.rs"]
891mod ports_impls;
892pub(crate) use ports_impls::build_row_update_contract_plan;
893pub(crate) use ports_impls::entity_row_fields_snapshot;
894pub(crate) use ports_impls::normalize_row_update_assignment_with_plan;
895pub(crate) use ports_impls::normalize_row_update_value_for_rule;