@@ -12,7 +12,7 @@ class PlainModuleRenderState:
1212 last_render_module : PlainModule
1313 last_render_frid : str | None
1414 change : PlainModule | None = None
15- change_type : Literal ["spec_change" , "code_change" ] | None = None
15+ change_type : Literal ["spec_change" , "code_change" , "missing_conformance_tests" ] | None = None
1616
1717
1818@dataclass
@@ -56,6 +56,19 @@ def code_change(plain_module: PlainModule) -> PlainModule | None:
5656 return None
5757
5858
59+ def archive_missing_conformance_tests (plain_module : PlainModule , render_conformance_tests : bool ) -> PlainModule | None :
60+ """Return the first module available only as a "<module>.module" archive that has no conformance
61+ tests while conformance testing is enabled. Such an archive cannot be consumed as-is (regression
62+ needs the tests), so the module must be re-rendered."""
63+ if not render_conformance_tests :
64+ return None
65+ all_modules = plain_module .all_required_modules + [plain_module ]
66+ for _module in all_modules :
67+ if _module .is_archived_only () and not _module .archive_has_conformance_tests ():
68+ return _module
69+ return None
70+
71+
5972def module_comes_before_or_equal (
6073 all_required_modules : list [PlainModule ],
6174 module1 : PlainModule ,
@@ -70,15 +83,24 @@ def module_comes_before_or_equal(
7083 raise ValueError (f"Module { module1 .module_name } and { module2 .module_name } not found in { all_required_modules } " )
7184
7285
73- def get_plain_module_render_state (plain_module : PlainModule ) -> PlainModuleRenderState | None :
86+ def get_plain_module_render_state (
87+ plain_module : PlainModule , render_conformance_tests : bool = False
88+ ) -> PlainModuleRenderState | None :
7489 sc = spec_change (plain_module )
7590 cc = code_change (plain_module )
91+ mt = archive_missing_conformance_tests (plain_module , render_conformance_tests )
7692 all_required_modules = plain_module .all_required_modules
7793 last_rendered_module_name , last_rendered_frid = plain_module .get_module_render_status ()
78- if last_rendered_module_name is None and last_rendered_frid is None :
94+ if last_rendered_module_name is None and last_rendered_frid is None and mt is None :
7995 return None
8096
81- if last_rendered_module_name == plain_module .module_name :
97+ if last_rendered_module_name is None :
98+ # Nothing has been rendered yet, but an archived module blocks consumption (no tests).
99+ # Anchor the state on that module so the user is prompted to re-render it.
100+ assert mt is not None # guaranteed by the early return above
101+ module = mt
102+ last_rendered_frid = None
103+ elif last_rendered_module_name == plain_module .module_name :
82104 module = plain_module
83105 else :
84106 found_module : PlainModule | None = None
@@ -99,6 +121,13 @@ def get_plain_module_render_state(plain_module: PlainModule) -> PlainModuleRende
99121 change_type = None ,
100122 )
101123
124+ # An archive that lacks conformance tests (while testing is enabled) is a hard blocker: it cannot
125+ # be consumed as-is, so it takes precedence over spec/code changes.
126+ if mt is not None :
127+ pr .change = mt
128+ pr .change_type = "missing_conformance_tests"
129+ return pr
130+
102131 if sc is None and cc is None :
103132 return pr
104133
@@ -129,6 +158,8 @@ def get_all_affected_modules_from_change(
129158 start_module = plain_module .get_next_module (plain_module_render_state .change .module_name )
130159 else :
131160 start_module = plain_module_render_state .change
161+ elif plain_module_render_state .change_type == "missing_conformance_tests" :
162+ start_module = plain_module_render_state .change
132163 else :
133164 raise ValueError (f"Unknown change type: { plain_module_render_state .change_type } " )
134165
0 commit comments