1515screening — the docs redundancy filter (D5), evidence inside the group's
1616files, pinned claims, placement, the advisory judge — and are appended to the
1717owner's rule page (never editing an existing rule; a full page spills to a
18- sibling). The pass stops when the rule-bearing PR-weighted coverage reaches
18+ sibling; a briefing doc is never written to). Owners come from the
19+ repository's ``_routes.yaml`` or, when it has none, from the adapter
20+ manifest's ``review_routes`` (``init_coverage.owner_table``): a repository
21+ routed by its manifest is deepened onto the pages the manifest routes to.
22+ The pass stops when the rule-bearing PR-weighted coverage reaches
1923``init.coverage_target``, the budget runs out, or no hot group is left, and it
2024always says which in the record's notes (and so the PR body): a pass never
2125ends below the target without the reason and the hottest files still
3741
3842import yaml
3943
40- from ..knowledge_service .lifecycle import LifecycleError , Page
4144from .init_budget import BudgetExhausted
42- from .init_coverage import Owner , load_owners , make_include , most_specific , pr_weighted_coverage
45+ from .init_coverage import Owner , make_include , most_specific , pr_weighted_coverage
4346from .init_modules import scan_modules
4447from .init_stages import (
4548 ROUTES_NAME , _Candidate , _fence , _numbered , _one_line , _Stage , _title_of , adapter_missing ,
@@ -119,13 +122,10 @@ def _build(self, tree: Path) -> InitRecord:
119122
120123 init = self .lifecycle .init
121124 routes_path = f"{ self .repo_dir } /{ ROUTES_NAME } "
122- text = self .base .get (routes_path )
123- if text is None :
124- return self ._blocked ([f"{ routes_path } does not exist: run (and merge) the earlier stages first" ])
125- try :
126- owners = load_owners (text )
127- except (ValueError , yaml .YAMLError ) as exc :
128- return self ._blocked ([f"{ routes_path } is not a valid route table: { exc } " ])
125+ if self .route_source == "none" :
126+ return self ._blocked ([f"{ routes_path } does not exist and the adapter declares no review_routes: "
127+ "run (and merge) the earlier stages first" ])
128+ owners = self .owners # the routes file, or the adapter manifest's review_routes (same precedence as Direct)
129129 flip , problems = self ._flip ()
130130 if problems :
131131 return self ._blocked (problems )
@@ -183,6 +183,7 @@ def _build(self, tree: Path) -> InitRecord:
183183 "uncovered_hot" : [list (item ) for item in self ._without_rules (prs , owners , include )[:MAX_HOT_LIST ]],
184184 "unrouted_hot" : [list (item ) for item in current .uncovered_hot [:MAX_HOT_LIST ]],
185185 "target" : init .coverage_target ,
186+ "routes_source" : self .route_source ,
186187 }
187188 from ..knowledge_service .pinned_claims import Evidence
188189
@@ -234,15 +235,6 @@ def _without_rules(self, prs, owners: list[Owner], include) -> list[tuple[str, i
234235 return sorted (missed .items (), key = lambda item : (- item [1 ], item [0 ]))
235236
236237 # -- rule pages ------------------------------------------------------------------
237- def _active_rules (self , path : str ) -> int :
238- text = self .head .get (path )
239- if text is None or not path .endswith (".md" ):
240- return 0
241- try :
242- return sum (1 for s in Page .parse (text ).rules () if s .footer .status == "active" )
243- except (LifecycleError , yaml .YAMLError ):
244- return 0
245-
246238 def _rule_pages (self , owners : list [Owner ]) -> set [str ]:
247239 """Owner paths that bear rules: the page itself holds an active rule,
248240 or (an entry or prose page) a page in the SAME directory does — never a
@@ -253,33 +245,17 @@ def _rule_pages(self, owners: list[Owner]) -> set[str]:
253245 if self ._active_rules (owner .path ):
254246 bearing .add (owner .path )
255247 continue
248+ redirected = self ._redirect_of (owner .path )
249+ if redirected != owner .path and self ._active_rules (redirected ):
250+ bearing .add (owner .path ) # a briefing doc's rules live beside it
251+ continue
256252 if owner .path in self .head and self ._is_rule_page (owner .path ):
257253 continue # a rule page owns its rules itself: an empty one bears none
258254 directory = PurePosixPath (owner .path ).parent
259255 if any (PurePosixPath (p ).parent == directory and self ._active_rules (p ) for p in self .head ):
260256 bearing .add (owner .path )
261257 return bearing
262258
263- def _is_rule_page (self , path : str ) -> bool :
264- try :
265- page = Page .parse (self .head [path ])
266- return page .frontmatter_data ().get ("type" ) == "rule" or bool (page .rules ())
267- except (KeyError , LifecycleError , yaml .YAMLError ):
268- return False
269-
270- def _rule_page_for (self , owner : Owner ) -> str :
271- """Where an owner's new rules go: its own page when that is a rule
272- page, else ``rules.md`` beside it (``rules-code.md`` when a prose
273- ``rules.md`` is in the way)."""
274- if owner .path in self .head and self ._is_rule_page (owner .path ):
275- return owner .path
276- directory = str (PurePosixPath (owner .path ).parent )
277- for name in ("rules.md" , "rules-code.md" ):
278- path = f"{ directory } /{ name } "
279- if path not in self .head or self ._is_rule_page (path ):
280- return path
281- raise InitError (f"no rule page can be placed beside { owner .path } " )
282-
283259 # -- one module --------------------------------------------------------------------
284260 def _code_payload (self , tree : Path , files : list [str ]) -> list [dict ]:
285261 out , used = [], 0
0 commit comments