@@ -124,6 +124,31 @@ defmodule StackLab.StructuralGateScanner do
124124 ]
125125 @ provider_binding_refs [ "linear_primary" , "github_primary" , "codex_primary" ]
126126
127+ @ product_lower_owner_module_prefixes [
128+ "AITrace" ,
129+ "Anthropic" ,
130+ "Citadel" ,
131+ "Codex" ,
132+ "ExecutionPlane" ,
133+ "GEPA" ,
134+ "GEPAFramework" ,
135+ "Gepa" ,
136+ "GepaFramework" ,
137+ "GitHubEx" ,
138+ "GroundPlane" ,
139+ "Inference" ,
140+ "Jido" ,
141+ "Jido.Integration" ,
142+ "JidoIntegration" ,
143+ "Linear" ,
144+ "Mezzanine" ,
145+ "OpenAI" ,
146+ "OuterBrain" ,
147+ "ReqLLM" ,
148+ "Trinity" ,
149+ "TrinityFramework"
150+ ]
151+
127152 @ ground_plane_higher_layer_tokens [
128153 "AI" ,
129154 "ai" ,
@@ -551,11 +576,19 @@ defmodule StackLab.StructuralGateScanner do
551576 end
552577
553578 defp ast_node_findings ( checked_path , _content , { :alias , meta , [ alias_ast ] } , _remote? ) do
554- { provider_remote_reference_findings ( checked_path , meta , alias_ast , :alias ) , [ ] }
579+ findings =
580+ provider_remote_reference_findings ( checked_path , meta , alias_ast , :alias ) ++
581+ product_lower_owner_reference_findings ( checked_path , meta , alias_ast , :alias )
582+
583+ { findings , [ ] }
555584 end
556585
557586 defp ast_node_findings ( checked_path , _content , { :import , meta , [ alias_ast | _ ] } , _remote? ) do
558- { provider_remote_reference_findings ( checked_path , meta , alias_ast , :import ) , [ ] }
587+ findings =
588+ provider_remote_reference_findings ( checked_path , meta , alias_ast , :import ) ++
589+ product_lower_owner_reference_findings ( checked_path , meta , alias_ast , :import )
590+
591+ { findings , [ ] }
559592 end
560593
561594 defp ast_node_findings (
@@ -565,7 +598,11 @@ defmodule StackLab.StructuralGateScanner do
565598 _remote?
566599 )
567600 when is_atom ( function_name ) do
568- { provider_remote_reference_findings ( checked_path , meta , alias_ast , :remote_call ) , [ ] }
601+ findings =
602+ provider_remote_reference_findings ( checked_path , meta , alias_ast , :remote_call ) ++
603+ product_lower_owner_reference_findings ( checked_path , meta , alias_ast , :remote_call )
604+
605+ { findings , [ ] }
569606 end
570607
571608 defp ast_node_findings ( checked_path , _content , { :%{} , meta , fields } , _remote? ) do
@@ -777,6 +814,52 @@ defmodule StackLab.StructuralGateScanner do
777814
778815 defp provider_remote_reference_findings ( _checked_path , _meta , _alias_ast , _role ) , do: [ ]
779816
817+ defp product_lower_owner_reference_findings (
818+ % CheckedPath { repo: "extravaganza" , zone: :product } = checked_path ,
819+ meta ,
820+ alias_ast ,
821+ ast_role
822+ ) do
823+ alias_text = alias_to_string ( alias_ast )
824+
825+ cond do
826+ alias_text == "" ->
827+ [ ]
828+
829+ allowed_product_lower_owner_reference? ( alias_text ) ->
830+ [ ]
831+
832+ product_lower_owner_reference? ( alias_text ) ->
833+ [
834+ finding ( checked_path , % {
835+ rule: :direct_lower_owner_import_in_product ,
836+ reason: :product_direct_lower_owner_reference ,
837+ line: meta_line ( meta ) ,
838+ token: alias_text ,
839+ ast_role: ast_role ,
840+ owner_phase: "Phase 1" ,
841+ remediation:
842+ "Product code must enter governed behavior through AppKit surfaces; pure Mezzanine.Pack authoring is the only lower exception."
843+ } )
844+ ]
845+
846+ true ->
847+ [ ]
848+ end
849+ end
850+
851+ defp product_lower_owner_reference_findings ( _checked_path , _meta , _alias_ast , _role ) , do: [ ]
852+
853+ defp product_lower_owner_reference? ( alias_text ) do
854+ Enum . any? ( @ product_lower_owner_module_prefixes , fn prefix ->
855+ alias_text == prefix or String . starts_with? ( alias_text , prefix <> "." )
856+ end )
857+ end
858+
859+ defp allowed_product_lower_owner_reference? ( alias_text ) do
860+ alias_text == "Mezzanine.Pack" or String . starts_with? ( alias_text , "Mezzanine.Pack." )
861+ end
862+
780863 defp closed_provider_dispatch_map_findings ( checked_path , meta , fields ) do
781864 if Zones . closed_provider_dispatch_scan_path? ( checked_path ) do
782865 provider_keys =
0 commit comments