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 health_report_from_catalog(
205        &self,
206        _catalog: &crate::catalog::CatalogModelSnapshot,
207    ) -> crate::health::HealthReport {
208        self.health_report()
209    }
210    /// Derive all readiness flags from one caller-owned health observation.
211    /// The default preserves compatibility with ports implementing scalar checks.
212    fn readiness_from_health(
213        &self,
214        _report: &crate::health::HealthReport,
215    ) -> crate::application::native::RuntimeReadiness {
216        crate::application::native::RuntimeReadiness {
217            query: self.readiness_for_query(),
218            query_serverless: self.readiness_for_query_serverless(),
219            write: self.readiness_for_write(),
220            write_serverless: self.readiness_for_write_serverless(),
221            repair: self.readiness_for_repair(),
222            repair_serverless: self.readiness_for_repair_serverless(),
223        }
224    }
225    fn collection_roots(&self) -> RedDBResult<BTreeMap<String, u64>>;
226    fn snapshots(&self) -> RedDBResult<Vec<SnapshotDescriptor>>;
227    fn exports(&self) -> RedDBResult<Vec<ExportDescriptor>>;
228    fn physical_metadata(&self) -> RedDBResult<PhysicalMetadataFile>;
229    fn manifest_events_filtered(
230        &self,
231        collection: Option<&str>,
232        kind: Option<&str>,
233        since_snapshot: Option<u64>,
234    ) -> RedDBResult<Vec<ManifestEvent>>;
235    fn create_snapshot(&self) -> RedDBResult<SnapshotDescriptor>;
236    fn create_export(&self, name: String) -> RedDBResult<ExportDescriptor>;
237    fn checkpoint(&self) -> RedDBResult<()>;
238    fn apply_retention_policy(&self) -> RedDBResult<()>;
239    fn run_maintenance(&self) -> RedDBResult<()>;
240    fn native_header(&self) -> RedDBResult<PhysicalFileHeader>;
241    fn native_collection_roots(&self) -> RedDBResult<BTreeMap<String, u64>>;
242    fn native_manifest_summary(&self) -> RedDBResult<NativeManifestSummary>;
243    fn native_registry_summary(&self) -> RedDBResult<NativeRegistrySummary>;
244    fn native_recovery_summary(&self) -> RedDBResult<NativeRecoverySummary>;
245    fn native_catalog_summary(&self) -> RedDBResult<NativeCatalogSummary>;
246    fn native_physical_state(&self) -> RedDBResult<NativePhysicalState>;
247    fn native_vector_artifact_pages(&self) -> RedDBResult<Vec<NativeVectorArtifactPageSummary>>;
248    fn inspect_native_vector_artifact(
249        &self,
250        collection: &str,
251        artifact_kind: Option<&str>,
252    ) -> RedDBResult<NativeVectorArtifactInspection>;
253    fn warmup_native_vector_artifact(
254        &self,
255        collection: &str,
256        artifact_kind: Option<&str>,
257    ) -> RedDBResult<NativeVectorArtifactInspection>;
258    fn inspect_native_vector_artifacts(&self) -> RedDBResult<NativeVectorArtifactBatchInspection>;
259    fn warmup_native_vector_artifacts(&self) -> RedDBResult<NativeVectorArtifactBatchInspection>;
260    fn native_header_repair_policy(&self) -> RedDBResult<String>;
261    fn repair_native_header_from_metadata(&self) -> RedDBResult<String>;
262    fn rebuild_physical_metadata_from_native_state(&self) -> RedDBResult<bool>;
263    fn repair_native_physical_state_from_metadata(&self) -> RedDBResult<bool>;
264    fn native_metadata_state_summary(&self) -> RedDBResult<NativeMetadataStateSummary>;
265    fn physical_authority_status(&self) -> PhysicalAuthorityStatus;
266    fn validate_current_serverless_generation(&self) -> RedDBResult<()>;
267    fn readiness_for_query(&self) -> bool;
268    fn readiness_for_query_serverless(&self) -> bool;
269    fn readiness_for_write(&self) -> bool;
270    fn readiness_for_write_serverless(&self) -> bool;
271    fn readiness_for_repair(&self) -> bool;
272    fn readiness_for_repair_serverless(&self) -> bool;
273}
274
275pub trait RuntimeGraphPort {
276    fn resolve_graph_projection(
277        &self,
278        name: Option<&str>,
279        inline: Option<RuntimeGraphProjection>,
280    ) -> RedDBResult<Option<RuntimeGraphProjection>>;
281    fn graph_neighborhood(
282        &self,
283        node: &str,
284        direction: RuntimeGraphDirection,
285        max_depth: usize,
286        edge_labels: Option<Vec<String>>,
287        projection: Option<RuntimeGraphProjection>,
288    ) -> RedDBResult<RuntimeGraphNeighborhoodResult>;
289    fn graph_traverse(
290        &self,
291        source: &str,
292        direction: RuntimeGraphDirection,
293        max_depth: usize,
294        strategy: RuntimeGraphTraversalStrategy,
295        edge_labels: Option<Vec<String>>,
296        projection: Option<RuntimeGraphProjection>,
297    ) -> RedDBResult<RuntimeGraphTraversalResult>;
298    fn graph_shortest_path(
299        &self,
300        source: &str,
301        target: &str,
302        direction: RuntimeGraphDirection,
303        algorithm: RuntimeGraphPathAlgorithm,
304        edge_labels: Option<Vec<String>>,
305        projection: Option<RuntimeGraphProjection>,
306    ) -> RedDBResult<RuntimeGraphPathResult>;
307    fn graph_components(
308        &self,
309        mode: RuntimeGraphComponentsMode,
310        min_size: usize,
311        projection: Option<RuntimeGraphProjection>,
312    ) -> RedDBResult<RuntimeGraphComponentsResult>;
313    fn graph_centrality(
314        &self,
315        algorithm: RuntimeGraphCentralityAlgorithm,
316        top_k: usize,
317        normalize: bool,
318        max_iterations: Option<usize>,
319        epsilon: Option<f64>,
320        alpha: Option<f64>,
321        projection: Option<RuntimeGraphProjection>,
322    ) -> RedDBResult<RuntimeGraphCentralityResult>;
323    fn graph_communities(
324        &self,
325        algorithm: crate::runtime::RuntimeGraphCommunityAlgorithm,
326        min_size: usize,
327        max_iterations: Option<usize>,
328        resolution: Option<f64>,
329        projection: Option<RuntimeGraphProjection>,
330    ) -> RedDBResult<RuntimeGraphCommunityResult>;
331    fn graph_clustering(
332        &self,
333        top_k: usize,
334        include_triangles: bool,
335        projection: Option<RuntimeGraphProjection>,
336    ) -> RedDBResult<RuntimeGraphClusteringResult>;
337    fn graph_personalized_pagerank(
338        &self,
339        seeds: Vec<String>,
340        top_k: usize,
341        alpha: Option<f64>,
342        epsilon: Option<f64>,
343        max_iterations: Option<usize>,
344        projection: Option<RuntimeGraphProjection>,
345    ) -> RedDBResult<RuntimeGraphCentralityResult>;
346    fn graph_hits(
347        &self,
348        top_k: usize,
349        epsilon: Option<f64>,
350        max_iterations: Option<usize>,
351        projection: Option<RuntimeGraphProjection>,
352    ) -> RedDBResult<RuntimeGraphHitsResult>;
353    fn graph_cycles(
354        &self,
355        max_length: usize,
356        max_cycles: usize,
357        projection: Option<RuntimeGraphProjection>,
358    ) -> RedDBResult<RuntimeGraphCyclesResult>;
359    fn graph_topological_sort(
360        &self,
361        projection: Option<RuntimeGraphProjection>,
362    ) -> RedDBResult<RuntimeGraphTopologicalSortResult>;
363    fn graph_properties(
364        &self,
365        projection: Option<RuntimeGraphProjection>,
366    ) -> RedDBResult<RuntimeGraphPropertiesResult>;
367}
368
369pub trait RuntimeVcsPort {
370    fn vcs_commit(
371        &self,
372        input: crate::application::vcs::CreateCommitInput,
373    ) -> RedDBResult<crate::application::vcs::Commit>;
374
375    fn vcs_branch_create(
376        &self,
377        input: crate::application::vcs::CreateBranchInput,
378    ) -> RedDBResult<crate::application::vcs::Ref>;
379
380    fn vcs_branch_delete(&self, name: &str) -> RedDBResult<()>;
381
382    fn vcs_tag_create(
383        &self,
384        input: crate::application::vcs::CreateTagInput,
385    ) -> RedDBResult<crate::application::vcs::Ref>;
386
387    fn vcs_tag_delete(&self, name: &str) -> RedDBResult<()>;
388
389    fn vcs_list_refs(&self, prefix: Option<&str>)
390        -> RedDBResult<Vec<crate::application::vcs::Ref>>;
391
392    fn vcs_checkout(
393        &self,
394        input: crate::application::vcs::CheckoutInput,
395    ) -> RedDBResult<crate::application::vcs::Ref>;
396
397    fn vcs_merge(
398        &self,
399        input: crate::application::vcs::MergeInput,
400    ) -> RedDBResult<crate::application::vcs::MergeOutcome>;
401
402    fn vcs_cherry_pick(
403        &self,
404        connection_id: u64,
405        commit: &str,
406        author: crate::application::vcs::Author,
407    ) -> RedDBResult<crate::application::vcs::MergeOutcome>;
408
409    fn vcs_revert(
410        &self,
411        connection_id: u64,
412        commit: &str,
413        author: crate::application::vcs::Author,
414    ) -> RedDBResult<crate::application::vcs::Commit>;
415
416    fn vcs_reset(&self, input: crate::application::vcs::ResetInput) -> RedDBResult<()>;
417
418    fn vcs_log(
419        &self,
420        input: crate::application::vcs::LogInput,
421    ) -> RedDBResult<Vec<crate::application::vcs::Commit>>;
422
423    fn vcs_diff(
424        &self,
425        input: crate::application::vcs::DiffInput,
426    ) -> RedDBResult<crate::application::vcs::Diff>;
427
428    fn vcs_status(
429        &self,
430        input: crate::application::vcs::StatusInput,
431    ) -> RedDBResult<crate::application::vcs::Status>;
432
433    fn vcs_lca(&self, a: &str, b: &str)
434        -> RedDBResult<Option<crate::application::vcs::CommitHash>>;
435
436    fn vcs_conflicts_list(
437        &self,
438        merge_state_id: &str,
439    ) -> RedDBResult<Vec<crate::application::vcs::Conflict>>;
440
441    fn vcs_conflict_resolve(
442        &self,
443        conflict_id: &str,
444        resolved: crate::json::Value,
445    ) -> RedDBResult<()>;
446
447    fn vcs_resolve_as_of(
448        &self,
449        spec: crate::application::vcs::AsOfSpec,
450    ) -> RedDBResult<crate::storage::transaction::snapshot::Xid>;
451
452    fn vcs_resolve_commitish(&self, spec: &str)
453        -> RedDBResult<crate::application::vcs::CommitHash>;
454
455    fn vcs_set_versioned(&self, collection: &str, enabled: bool) -> RedDBResult<()>;
456    fn vcs_list_versioned(&self) -> RedDBResult<Vec<String>>;
457    fn vcs_is_versioned(&self, collection: &str) -> RedDBResult<bool>;
458}
459
460/// Context-aware extension trait that mirrors `RuntimeEntityPort`
461/// with `&OperationContext` threaded through every method.
462///
463/// This is the migration runway for the `OperationContext` deepening
464/// (PLAN cluster 6). Each default implementation forwards to the
465/// existing context-less method, so today the trait is a pure
466/// pass-through — but new callers can already adopt the
467/// context-passing surface, and a future PR will replace the
468/// defaults with real impls that read `ctx.xid` / `ctx.write_consent`.
469///
470/// Hidden behind the `ctx-ports` feature flag during the migration
471/// window so the impl bloat doesn't burden default builds. Once
472/// every port is migrated, the flag goes away and these traits
473/// become the only surface.
474pub trait RuntimeEntityPortCtx: RuntimeEntityPort {
475    fn create_row_ctx(
476        &self,
477        ctx: &crate::application::OperationContext,
478        input: CreateRowInput,
479    ) -> RedDBResult<CreateEntityOutput> {
480        let _ = ctx;
481        self.create_row(input)
482    }
483    fn create_node_ctx(
484        &self,
485        ctx: &crate::application::OperationContext,
486        input: CreateNodeInput,
487    ) -> RedDBResult<CreateEntityOutput> {
488        let _ = ctx;
489        self.create_node(input)
490    }
491    fn create_edge_ctx(
492        &self,
493        ctx: &crate::application::OperationContext,
494        input: CreateEdgeInput,
495    ) -> RedDBResult<CreateEntityOutput> {
496        let _ = ctx;
497        self.create_edge(input)
498    }
499    fn create_vector_ctx(
500        &self,
501        ctx: &crate::application::OperationContext,
502        input: CreateVectorInput,
503    ) -> RedDBResult<CreateEntityOutput> {
504        let _ = ctx;
505        self.create_vector(input)
506    }
507    fn create_document_ctx(
508        &self,
509        ctx: &crate::application::OperationContext,
510        input: CreateDocumentInput,
511    ) -> RedDBResult<CreateEntityOutput> {
512        let _ = ctx;
513        self.create_document(input)
514    }
515    fn create_kv_ctx(
516        &self,
517        ctx: &crate::application::OperationContext,
518        input: CreateKvInput,
519    ) -> RedDBResult<CreateEntityOutput> {
520        let _ = ctx;
521        self.create_kv(input)
522    }
523    fn create_timeseries_point_ctx(
524        &self,
525        ctx: &crate::application::OperationContext,
526        input: CreateTimeSeriesPointInput,
527    ) -> RedDBResult<CreateEntityOutput> {
528        let _ = ctx;
529        self.create_timeseries_point(input)
530    }
531    fn get_kv_ctx(
532        &self,
533        ctx: &crate::application::OperationContext,
534        collection: &str,
535        key: &str,
536    ) -> RedDBResult<Option<(reddb_types::Value, crate::storage::EntityId)>> {
537        let _ = ctx;
538        self.get_kv(collection, key)
539    }
540    fn delete_kv_ctx(
541        &self,
542        ctx: &crate::application::OperationContext,
543        collection: &str,
544        key: &str,
545    ) -> RedDBResult<bool> {
546        let _ = ctx;
547        self.delete_kv(collection, key)
548    }
549    fn patch_entity_ctx(
550        &self,
551        ctx: &crate::application::OperationContext,
552        input: PatchEntityInput,
553    ) -> RedDBResult<CreateEntityOutput> {
554        let _ = ctx;
555        self.patch_entity(input)
556    }
557    fn delete_entity_ctx(
558        &self,
559        ctx: &crate::application::OperationContext,
560        input: DeleteEntityInput,
561    ) -> RedDBResult<DeleteEntityOutput> {
562        let _ = ctx;
563        self.delete_entity(input)
564    }
565}
566
567/// Blanket impl: every concrete `RuntimeEntityPort` automatically
568/// gains the context-aware surface via the default forwards above.
569impl<T: RuntimeEntityPort + ?Sized> RuntimeEntityPortCtx for T {}
570
571// ─── ctx extension traits for the remaining mutating ports ───
572//
573// Same pattern as RuntimeEntityPortCtx: methods take
574// `&OperationContext` first, default-forward to the existing
575// context-less call. Blanket impls give every concrete port
576// the new surface for free. Future PRs replace the forwards
577// with real `ctx.write_consent` / `ctx.xid` handling.
578//
579// Read-only ports (RuntimeGraphPort) and the
580// read-only methods of mutating ports are intentionally absent —
581// `OperationContext` adds no locality there until the snapshot-
582// xid migration also lands.
583
584pub trait RuntimeSchemaPortCtx: RuntimeSchemaPort {
585    fn create_table_ctx(
586        &self,
587        ctx: &crate::application::OperationContext,
588        input: CreateTableInput,
589    ) -> RedDBResult<RuntimeQueryResult> {
590        let _ = ctx;
591        self.create_table(input)
592    }
593    fn drop_table_ctx(
594        &self,
595        ctx: &crate::application::OperationContext,
596        input: DropTableInput,
597    ) -> RedDBResult<RuntimeQueryResult> {
598        let _ = ctx;
599        self.drop_table(input)
600    }
601    fn create_timeseries_ctx(
602        &self,
603        ctx: &crate::application::OperationContext,
604        input: CreateTimeSeriesInput,
605    ) -> RedDBResult<RuntimeQueryResult> {
606        let _ = ctx;
607        self.create_timeseries(input)
608    }
609    fn drop_timeseries_ctx(
610        &self,
611        ctx: &crate::application::OperationContext,
612        input: DropTimeSeriesInput,
613    ) -> RedDBResult<RuntimeQueryResult> {
614        let _ = ctx;
615        self.drop_timeseries(input)
616    }
617}
618impl<T: RuntimeSchemaPort + ?Sized> RuntimeSchemaPortCtx for T {}
619
620pub trait RuntimeTreePortCtx: RuntimeTreePort {
621    fn create_tree_ctx(
622        &self,
623        ctx: &crate::application::OperationContext,
624        input: CreateTreeInput,
625    ) -> RedDBResult<RuntimeQueryResult> {
626        let _ = ctx;
627        self.create_tree(input)
628    }
629    fn drop_tree_ctx(
630        &self,
631        ctx: &crate::application::OperationContext,
632        input: DropTreeInput,
633    ) -> RedDBResult<RuntimeQueryResult> {
634        let _ = ctx;
635        self.drop_tree(input)
636    }
637    fn insert_tree_node_ctx(
638        &self,
639        ctx: &crate::application::OperationContext,
640        input: InsertTreeNodeInput,
641    ) -> RedDBResult<RuntimeQueryResult> {
642        let _ = ctx;
643        self.insert_tree_node(input)
644    }
645    fn move_tree_node_ctx(
646        &self,
647        ctx: &crate::application::OperationContext,
648        input: MoveTreeNodeInput,
649    ) -> RedDBResult<RuntimeQueryResult> {
650        let _ = ctx;
651        self.move_tree_node(input)
652    }
653    fn delete_tree_node_ctx(
654        &self,
655        ctx: &crate::application::OperationContext,
656        input: DeleteTreeNodeInput,
657    ) -> RedDBResult<RuntimeQueryResult> {
658        let _ = ctx;
659        self.delete_tree_node(input)
660    }
661    fn rebalance_tree_ctx(
662        &self,
663        ctx: &crate::application::OperationContext,
664        input: RebalanceTreeInput,
665    ) -> RedDBResult<RuntimeQueryResult> {
666        let _ = ctx;
667        self.rebalance_tree(input)
668    }
669}
670impl<T: RuntimeTreePort + ?Sized> RuntimeTreePortCtx for T {}
671
672pub trait RuntimeNativePortCtx: RuntimeNativePort {
673    fn create_snapshot_ctx(
674        &self,
675        ctx: &crate::application::OperationContext,
676    ) -> RedDBResult<SnapshotDescriptor> {
677        let _ = ctx;
678        self.create_snapshot()
679    }
680    fn create_export_ctx(
681        &self,
682        ctx: &crate::application::OperationContext,
683        name: String,
684    ) -> RedDBResult<ExportDescriptor> {
685        let _ = ctx;
686        self.create_export(name)
687    }
688    fn checkpoint_ctx(&self, ctx: &crate::application::OperationContext) -> RedDBResult<()> {
689        let _ = ctx;
690        self.checkpoint()
691    }
692    fn apply_retention_policy_ctx(
693        &self,
694        ctx: &crate::application::OperationContext,
695    ) -> RedDBResult<()> {
696        let _ = ctx;
697        self.apply_retention_policy()
698    }
699    fn run_maintenance_ctx(&self, ctx: &crate::application::OperationContext) -> RedDBResult<()> {
700        let _ = ctx;
701        self.run_maintenance()
702    }
703    fn repair_native_header_from_metadata_ctx(
704        &self,
705        ctx: &crate::application::OperationContext,
706    ) -> RedDBResult<String> {
707        let _ = ctx;
708        self.repair_native_header_from_metadata()
709    }
710    fn rebuild_physical_metadata_from_native_state_ctx(
711        &self,
712        ctx: &crate::application::OperationContext,
713    ) -> RedDBResult<bool> {
714        let _ = ctx;
715        self.rebuild_physical_metadata_from_native_state()
716    }
717}
718impl<T: RuntimeNativePort + ?Sized> RuntimeNativePortCtx for T {}
719
720pub trait RuntimeVcsPortCtx: RuntimeVcsPort {
721    fn vcs_branch_delete_ctx(
722        &self,
723        ctx: &crate::application::OperationContext,
724        name: &str,
725    ) -> RedDBResult<()> {
726        let _ = ctx;
727        self.vcs_branch_delete(name)
728    }
729    fn vcs_reset_ctx(
730        &self,
731        ctx: &crate::application::OperationContext,
732        input: crate::application::vcs::ResetInput,
733    ) -> RedDBResult<()> {
734        let _ = ctx;
735        self.vcs_reset(input)
736    }
737    fn vcs_set_versioned_ctx(
738        &self,
739        ctx: &crate::application::OperationContext,
740        collection: &str,
741        enabled: bool,
742    ) -> RedDBResult<()> {
743        let _ = ctx;
744        self.vcs_set_versioned(collection, enabled)
745    }
746    fn vcs_conflict_resolve_ctx(
747        &self,
748        ctx: &crate::application::OperationContext,
749        conflict_id: &str,
750        resolved: crate::json::Value,
751    ) -> RedDBResult<()> {
752        let _ = ctx;
753        self.vcs_conflict_resolve(conflict_id, resolved)
754    }
755}
756impl<T: RuntimeVcsPort + ?Sized> RuntimeVcsPortCtx for T {}
757
758/// Port for native migration operations.
759///
760/// Stub methods — full implementations land in subsequent slices.
761pub trait RuntimeMigrationPort {
762    /// Register a new migration definition (status = pending).
763    fn migration_create(&self, input: MigrationCreateInput) -> RedDBResult<RuntimeQueryResult>;
764    /// Apply a named migration (or `*` for all pending).
765    fn migration_apply(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
766    /// Roll back an applied migration.
767    fn migration_rollback(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
768    /// Explain a migration without executing it.
769    fn migration_explain(&self, name: &str) -> RedDBResult<RuntimeQueryResult>;
770    /// List migrations, optionally filtered by status.
771    fn migration_list(&self, status: Option<&str>) -> RedDBResult<RuntimeQueryResult>;
772}
773
774/// Minimal input type for `migration_create`. Expanded in later slices.
775#[derive(Debug, Clone)]
776pub struct MigrationCreateInput {
777    pub name: String,
778    pub kind: MigrationKind,
779    pub body: String,
780    pub author: String,
781    pub depends_on: Vec<String>,
782    pub batch_size: Option<u64>,
783    pub no_rollback: bool,
784}
785
786#[derive(Debug, Clone, PartialEq, Eq)]
787pub enum MigrationKind {
788    Ddl,
789    Data,
790}
791
792#[path = "ports_impls.rs"]
793mod ports_impls;
794pub(crate) use ports_impls::build_row_update_contract_plan;
795pub(crate) use ports_impls::entity_row_fields_snapshot;
796pub(crate) use ports_impls::normalize_row_update_assignment_with_plan;
797pub(crate) use ports_impls::normalize_row_update_value_for_rule;