@@ -33,6 +33,24 @@ fn validates_operational_and_reference_documents() {
3333 let result = validate ( directory. path ( ) . to_string_lossy ( ) . as_ref ( ) ) . unwrap ( ) ;
3434
3535 assert_eq ! ( result[ "valid" ] , true ) ;
36+
37+ let without_reference_link = fs:: read_to_string ( directory. path ( ) . join ( "AGENTS.md" ) )
38+ . unwrap ( )
39+ . replace ( "\n Read `AGENTS.reference.md`." , "" ) ;
40+ fs:: write ( directory. path ( ) . join ( "AGENTS.md" ) , without_reference_link) . unwrap ( ) ;
41+
42+ let unreferenced = validate ( directory. path ( ) . to_string_lossy ( ) . as_ref ( ) ) . unwrap ( ) ;
43+ assert_eq ! ( unreferenced[ "valid" ] , false ) ;
44+ assert ! (
45+ unreferenced[ "findings" ]
46+ . as_array( )
47+ . unwrap( )
48+ . iter( )
49+ . any( |finding| {
50+ finding[ "kind" ] == "unreferenced_reference_document"
51+ && finding[ "document" ] == "AGENTS.md"
52+ } )
53+ ) ;
3654}
3755
3856#[ test]
@@ -489,6 +507,153 @@ fn validates_nested_scopes_and_reports_missing_candidates_advisory() {
489507 ) ;
490508}
491509
510+ #[ test]
511+ fn validates_nested_references_with_inherited_signature_configuration ( ) {
512+ let directory = tempdir ( ) . unwrap ( ) ;
513+ fs:: write (
514+ directory. path ( ) . join ( "agentskill.toml" ) ,
515+ "signature = false\n " ,
516+ )
517+ . unwrap ( ) ;
518+ fs:: write (
519+ directory. path ( ) . join ( "AGENTS.md" ) ,
520+ "# Root Guidance\n \n ## Free Region\n \n Root custom instructions.\n " ,
521+ )
522+ . unwrap ( ) ;
523+ fs:: create_dir_all ( directory. path ( ) . join ( "packages/api/src" ) ) . unwrap ( ) ;
524+ fs:: write (
525+ directory. path ( ) . join ( "packages/api/src/lib.rs" ) ,
526+ "pub fn api() {}\n " ,
527+ )
528+ . unwrap ( ) ;
529+ fs:: write (
530+ directory. path ( ) . join ( "packages/api/AGENTS.md" ) ,
531+ "# API Guidance\n \n ## Scope\n \n - Path: packages/api\n - Parent: .\n - Inheritance: additive; nearest scope wins.\n \n ## Mission\n \n Read `src/lib.rs`.\n \n Read `AGENTS.reference.md` for local API context.\n \n ## Free Region\n \n API custom instructions.\n " ,
532+ )
533+ . unwrap ( ) ;
534+ fs:: write (
535+ directory. path ( ) . join ( "packages/api/AGENTS.reference.md" ) ,
536+ "# API Reference\n \n ## Provenance And Decisions\n \n - Agentskill Version: `2.0.0`.\n - Evidence Schema Version: `4`.\n - Repository Revision: `fixture-revision`.\n - Configuration: inherited signature disabled.\n - Maintainer-Confirmed Decisions: Scope uses local API instructions.\n - Unresolved Uncertainty: None recorded.\n \n Local API reference context.\n " ,
537+ )
538+ . unwrap ( ) ;
539+
540+ let root = fs:: read_to_string ( directory. path ( ) . join ( "AGENTS.md" ) ) . unwrap ( ) ;
541+ let scoped = fs:: read_to_string ( directory. path ( ) . join ( "packages/api/AGENTS.md" ) ) . unwrap ( ) ;
542+ let repo = directory. path ( ) . to_string_lossy ( ) . into_owned ( ) ;
543+
544+ let report = validate_with_mode_and_scopes ( & repo, SignatureMode :: Auto , None ) . unwrap ( ) ;
545+ assert_eq ! ( report[ "valid" ] , true ) ;
546+ assert_eq ! ( report[ "configuration" ] [ "signature" ] , false ) ;
547+ assert ! (
548+ report[ "validated_scopes" ]
549+ . as_array( )
550+ . unwrap( )
551+ . iter( )
552+ . any( |path| path == "packages/api" )
553+ ) ;
554+
555+ let root_free = parse ( & root)
556+ . sections
557+ . into_iter ( )
558+ . find ( |section| section. heading == "Free Region" )
559+ . unwrap ( )
560+ . body ;
561+ let scoped_free = parse ( & scoped)
562+ . sections
563+ . into_iter ( )
564+ . find ( |section| section. heading == "Free Region" )
565+ . unwrap ( )
566+ . body ;
567+ assert_ne ! ( root_free, scoped_free) ;
568+
569+ let without_reference_link =
570+ scoped. replace ( "\n Read `AGENTS.reference.md` for local API context." , "" ) ;
571+ fs:: write (
572+ directory. path ( ) . join ( "packages/api/AGENTS.md" ) ,
573+ without_reference_link,
574+ )
575+ . unwrap ( ) ;
576+
577+ let unreferenced = validate_with_mode_and_scopes ( & repo, SignatureMode :: Auto , None ) . unwrap ( ) ;
578+ assert_eq ! ( unreferenced[ "valid" ] , false ) ;
579+ assert ! (
580+ unreferenced[ "findings" ]
581+ . as_array( )
582+ . unwrap( )
583+ . iter( )
584+ . any( |finding| {
585+ finding[ "kind" ] == "unreferenced_reference_document"
586+ && finding[ "document" ] == "AGENTS.md"
587+ } )
588+ ) ;
589+
590+ fs:: write ( directory. path ( ) . join ( "packages/api/AGENTS.md" ) , & scoped) . unwrap ( ) ;
591+
592+ let overridden = validate_with_mode_and_scopes ( & repo, SignatureMode :: On , None ) . unwrap ( ) ;
593+ assert_eq ! ( overridden[ "valid" ] , false ) ;
594+ assert ! (
595+ overridden[ "findings" ]
596+ . as_array( )
597+ . unwrap( )
598+ . iter( )
599+ . any( |finding| finding[ "kind" ] == "missing_signature" )
600+ ) ;
601+
602+ let disabled = validate_with_mode_and_scopes ( & repo, SignatureMode :: Off , None ) . unwrap ( ) ;
603+ assert_eq ! ( disabled[ "valid" ] , true ) ;
604+ }
605+
606+ #[ test]
607+ fn legacy_scoped_documents_are_advisory_until_explicitly_adopted ( ) {
608+ let directory = tempdir ( ) . unwrap ( ) ;
609+ fs:: write (
610+ directory. path ( ) . join ( "AGENTS.md" ) ,
611+ "# Root Guidance\n \n ## Free Region\n \n Root custom instructions.\n " ,
612+ )
613+ . unwrap ( ) ;
614+ fs:: create_dir_all ( directory. path ( ) . join ( "packages/api" ) ) . unwrap ( ) ;
615+ fs:: write (
616+ directory. path ( ) . join ( "packages/api/AGENTS.md" ) ,
617+ "# Legacy API Guidance\n \n ## Free Region\n \n Legacy custom instructions.\n " ,
618+ )
619+ . unwrap ( ) ;
620+
621+ let path = directory. path ( ) . join ( "packages/api/AGENTS.md" ) ;
622+ let before = fs:: read_to_string ( & path) . unwrap ( ) ;
623+ let repo = directory. path ( ) . to_string_lossy ( ) . into_owned ( ) ;
624+ let scopes = agentskill_analyzers:: run_scopes ( & repo, None ) . unwrap ( ) ;
625+ let legacy = scopes[ "scopes" ]
626+ . as_array ( )
627+ . unwrap ( )
628+ . iter ( )
629+ . find ( |scope| scope[ "path" ] == "packages/api" )
630+ . unwrap ( ) ;
631+
632+ assert_eq ! ( legacy[ "status" ] , "legacy" ) ;
633+
634+ let report = validate_with_mode_and_scopes ( & repo, SignatureMode :: Off , None ) . unwrap ( ) ;
635+ assert_eq ! ( report[ "valid" ] , true ) ;
636+ assert ! (
637+ report[ "findings" ]
638+ . as_array( )
639+ . unwrap( )
640+ . iter( )
641+ . any( |finding| {
642+ finding[ "kind" ] == "legacy_scoped_document"
643+ && finding[ "severity" ] == "warning"
644+ && finding[ "document" ] == "packages/api"
645+ } )
646+ ) ;
647+ assert ! (
648+ !report[ "validated_scopes" ]
649+ . as_array( )
650+ . unwrap( )
651+ . iter( )
652+ . any( |path| path == "packages/api" )
653+ ) ;
654+ assert_eq ! ( fs:: read_to_string( & path) . unwrap( ) , before) ;
655+ }
656+
492657#[ test]
493658fn scoped_validation_rejects_incorrect_parent_metadata ( ) {
494659 let directory = tempdir ( ) . unwrap ( ) ;
0 commit comments