Skip to main content

reddb_server/application/
ports.rs

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