@@ -279,11 +279,11 @@ mod octad_tests {
279279/// temporal versions, and access policies. It never writes to your target database.
280280#[ derive( Debug , Clone , Serialize , Deserialize ) ]
281281pub struct SidecarConfig {
282- /// Storage backend for the sidecar. `"sqlite"` (default) is the only
283- /// implemented store; `"postgres"`/`"postgresql"` selects the
284- /// PostgreSQL DDL dialect. `"json"` is **not implemented** and is
285- /// rejected at `generate` time — tracked by #112 (V-L2-F2). The
286- /// dialect mapping lives in `codegen::overlay::SqlDialect` .
282+ /// Storage backend for the sidecar. `"sqlite"` (default) is the
283+ /// reference store; `"postgres"`/`"postgresql"` selects the PostgreSQL
284+ /// DDL dialect. Any other value is rejected at `validate` and
285+ /// `generate` time by `codegen::overlay::SqlDialect::from_storage`,
286+ /// the single source of truth for supported stores .
287287 #[ serde( default = "default_sidecar_storage" ) ]
288288 pub storage : String ,
289289
@@ -394,6 +394,41 @@ mod validate_manifest_tests {
394394 assert_eq ! ( failed, vec![ "schema-source-exists" ] ) ;
395395 }
396396
397+ /// An unsupported `[sidecar].storage` (here the dropped `json` store,
398+ /// V-L2-F2 / #112) must fail `sidecar-storage-supported`, and the
399+ /// failure detail must not advertise json as a planned option.
400+ #[ test]
401+ fn unsupported_storage_fails ( ) {
402+ let dir = tempfile:: tempdir ( ) . expect ( "tempdir" ) ;
403+ let path = dir. path ( ) . join ( "verisimiser.toml" ) ;
404+ let sidecar_path = dir. path ( ) . join ( "sidecar.db" ) ;
405+ let body = format ! (
406+ "[project]\n \
407+ name = \" test\" \n \
408+ [database]\n \
409+ backend = \" sqlite\" \n \
410+ [sidecar]\n \
411+ storage = \" json\" \n \
412+ path = \" {}\" \n ",
413+ sidecar_path. display( ) . to_string( ) . replace( '\\' , "/" )
414+ ) ;
415+ std:: fs:: write ( & path, body) . expect ( "write" ) ;
416+
417+ let report = validate_manifest ( path. to_str ( ) . unwrap ( ) ) ;
418+ assert ! ( !report. passed) ;
419+ let storage = report
420+ . checks
421+ . iter ( )
422+ . find ( |c| c. name == "sidecar-storage-supported" )
423+ . expect ( "storage check must run" ) ;
424+ assert ! ( !storage. passed, "json storage must fail the check" ) ;
425+ let detail = storage. detail . as_deref ( ) . unwrap_or_default ( ) ;
426+ assert ! (
427+ detail. contains( "unsupported" ) && !detail. contains( "#112" ) ,
428+ "detail must reject json plainly without a 'coming soon' pointer; got: {detail}"
429+ ) ;
430+ }
431+
397432 /// A malformed manifest must fail `manifest-loads` and stop further
398433 /// checks (because the rest depend on having a parsed manifest).
399434 #[ test]
@@ -621,6 +656,7 @@ enable-constraints = {enable_constraints}
621656enable-simulation = {enable_simulation}
622657
623658[sidecar]
659+ # storage backend: "sqlite" (default) or "postgres"/"postgresql"
624660storage = "{sidecar_storage}"
625661path = "{sidecar_path}"
626662
@@ -734,6 +770,9 @@ impl ValidationReport {
734770/// set, the file at that path is readable.
735771/// 3. **`sidecar-path-writable`** — the parent directory of
736772/// `[sidecar].path` is writable (or createable).
773+ /// 4. **`sidecar-storage-supported`** — `[sidecar].storage` names a
774+ /// backend `codegen` can emit (`sqlite`/`postgres`). Catches typos and
775+ /// the dropped `json` store (V-L2-F2 / #112).
737776///
738777/// Out of scope here: V-L2-E1 backend/target_db conflict (own issue),
739778/// target-DB reachability (needs live connection).
@@ -820,6 +859,28 @@ pub fn validate_manifest(path: &str) -> ValidationReport {
820859 ) ) ,
821860 } ) ;
822861 }
862+
863+ // 4. Sidecar storage backend is supported. Delegates to the one
864+ // validator (`SqlDialect::from_storage`) so `validate`/`doctor`
865+ // and `generate` agree on the accepted set. This is where a typo'd
866+ // or dropped backend (e.g. the never-implemented `json` store,
867+ // V-L2-F2 / #112) is surfaced before it reaches codegen.
868+ let storage_check = ValidationCheck {
869+ name : "sidecar-storage-supported" . to_string ( ) ,
870+ description : "[sidecar].storage names a supported backend" . to_string ( ) ,
871+ passed : true ,
872+ detail : None ,
873+ } ;
874+ checks. push (
875+ match crate :: codegen:: overlay:: SqlDialect :: from_storage ( & m. sidecar . storage ) {
876+ Ok ( _) => storage_check,
877+ Err ( e) => ValidationCheck {
878+ passed : false ,
879+ detail : Some ( e. to_string ( ) ) ,
880+ ..storage_check
881+ } ,
882+ } ,
883+ ) ;
823884 }
824885
825886 let passed = checks. iter ( ) . all ( |c| c. passed ) ;
0 commit comments