@@ -345,10 +345,17 @@ def parse_schema(schema_path: Path) -> dict[str, Any]:
345345 issues : list [dict [str , str ]] = []
346346 raw_capabilities = data .get ("capabilities" )
347347 capabilities = parse_capabilities (raw_capabilities )
348- if raw_capabilities is None :
349- issues .append (schema_issue ("SCHEMA_CAPABILITIES_MISSING" , "blocker" , "schema.yaml must define top-level capabilities" ))
350- elif not isinstance (raw_capabilities , list ) or any (not isinstance (item , str ) or not item .strip () for item in raw_capabilities ):
351- issues .append (schema_issue ("SCHEMA_CAPABILITIES_INVALID" , "blocker" , "schema capabilities must be a non-empty string list" ))
348+ if raw_capabilities is not None and (
349+ not isinstance (raw_capabilities , list )
350+ or any (not isinstance (item , str ) or not item .strip () for item in raw_capabilities )
351+ ):
352+ issues .append (
353+ schema_issue (
354+ "SCHEMA_CAPABILITIES_INVALID" ,
355+ "risk" ,
356+ "schema capabilities should be a non-empty string list when declared" ,
357+ )
358+ )
352359
353360 artifacts : list [ArtifactSpec ] = []
354361 raw_artifacts = data .get ("artifacts" )
@@ -367,7 +374,7 @@ def parse_schema(schema_path: Path) -> dict[str, Any]:
367374 apply_tracks = normalize_track_value (apply .get ("tracks" ))
368375 archive_tracks = parse_tracks (archive .get ("tracks" ))
369376 if apply_tracks is None and "apply_execution" in capabilities :
370- issues .append (schema_issue ("SCHEMA_APPLY_TRACKS_MISSING" , "blocker " , "schema capability apply_execution requires apply.tracks" ))
377+ issues .append (schema_issue ("SCHEMA_APPLY_TRACKS_MISSING" , "risk " , "schema capability apply_execution requires apply.tracks" ))
371378 if "archive_authority" in capabilities and not archive_tracks :
372379 issues .append (schema_issue ("SCHEMA_ARCHIVE_TRACKS_MISSING" , "risk" , "schema capability archive_authority should declare archive.tracks" ))
373380
@@ -434,40 +441,35 @@ def normalize_track_value(value: Any) -> str | None:
434441def validate_artifact_schema (data : dict [str , Any ]) -> list [dict [str , str ]]:
435442 issues : list [dict [str , str ]] = []
436443 artifact_id = str (data .get ("id" ) or "" )
437- requiredness = str (data .get ("requiredness" ) or "" )
444+ raw_requiredness = data .get ("requiredness" )
445+ requiredness = str (raw_requiredness or "always" )
438446 capabilities = data .get ("capabilities" )
439447 if not artifact_id :
440448 issues .append (schema_issue ("SCHEMA_ARTIFACT_ID_MISSING" , "blocker" , "schema artifact is missing id" ))
441- if requiredness not in REQUIREDNESS_VALUES :
449+ if raw_requiredness is not None and requiredness not in REQUIREDNESS_VALUES :
442450 issues .append (
443451 schema_issue (
444452 "SCHEMA_ARTIFACT_REQUIREDNESS_INVALID" ,
445- "blocker " ,
453+ "risk " ,
446454 f"artifact { artifact_id or '<unknown>' } must declare requiredness as one of: always, conditional, never" ,
447455 )
448456 )
449- if capabilities is None :
450- issues .append (
451- schema_issue (
452- "SCHEMA_ARTIFACT_CAPABILITIES_MISSING" ,
453- "blocker" ,
454- f"artifact { artifact_id or '<unknown>' } must declare capabilities" ,
455- )
456- )
457- elif not isinstance (capabilities , list ) or any (not isinstance (item , str ) or not item .strip () for item in capabilities ):
457+ if capabilities is not None and (
458+ not isinstance (capabilities , list ) or any (not isinstance (item , str ) or not item .strip () for item in capabilities )
459+ ):
458460 issues .append (
459461 schema_issue (
460462 "SCHEMA_ARTIFACT_CAPABILITIES_INVALID" ,
461- "blocker " ,
463+ "risk " ,
462464 f"artifact { artifact_id or '<unknown>' } capabilities must be a string list" ,
463465 )
464466 )
465467 na_requires_reason = data .get ("na_requires_reason" )
466- if requiredness == "conditional" and not isinstance (na_requires_reason , bool ):
468+ if raw_requiredness is not None and requiredness == "conditional" and not isinstance (na_requires_reason , bool ):
467469 issues .append (
468470 schema_issue (
469471 "SCHEMA_ARTIFACT_NA_POLICY_MISSING" ,
470- "blocker " ,
472+ "risk " ,
471473 f"artifact { artifact_id or '<unknown>' } must declare na_requires_reason for conditional requiredness" ,
472474 )
473475 )
@@ -496,7 +498,16 @@ def artifact_has_capability(artifact: ArtifactSpec | dict[str, Any], capability:
496498
497499
498500def schema_generates_source_map (schema_info : dict [str , Any ]) -> bool :
499- return schema_has_capability (schema_info , "source_map_routing" )
501+ if schema_has_capability (schema_info , "source_map_routing" ):
502+ return True
503+ return any (
504+ isinstance (spec , ArtifactSpec )
505+ and (
506+ spec .artifact_id == "source-map"
507+ or spec .generates == "source-map.md"
508+ )
509+ for spec in schema_info .get ("artifacts" , [])
510+ )
500511
501512
502513def schema_requires_tasks (schema_info : dict [str , Any ]) -> bool :
0 commit comments