@@ -1055,6 +1055,102 @@ def _audit_py_operator(repo_root: Path) -> list[str]:
10551055 return problems
10561056
10571057
1058+ def _audit_prose_label (line : str , expected_by_label : dict [str , str ]) -> str | None :
1059+ """Return a drift message for an ``Agent Assembly <Lang> SDK`` prose line."""
1060+
1061+ label_match = _PROSE_LABEL_RE .search (line )
1062+ if label_match is None :
1063+ return None
1064+ token_match = _VERSION_TOKEN_RE .search (line )
1065+ if token_match is None :
1066+ return None
1067+ expected = expected_by_label [label_match .group (1 )]
1068+ if token_match .group (0 ) == expected :
1069+ return None
1070+ return f"states { token_match .group (0 )!r} , expected { expected !r} "
1071+
1072+
1073+ def _audit_prose_backtick (
1074+ line : str , backtick_checks : tuple [tuple [re .Pattern [str ], str ], ...]
1075+ ) -> list [str ]:
1076+ """Return drift messages for backtick-``package``-labelled prereq rows."""
1077+
1078+ problems : list [str ] = []
1079+ for row_re , expected in backtick_checks :
1080+ row_match = row_re .search (line )
1081+ if row_match is None :
1082+ continue
1083+ token_match = _VERSION_TOKEN_RE .search (row_match .group ("val" ))
1084+ if token_match is not None and token_match .group (0 ) != expected :
1085+ problems .append (f"states { token_match .group (0 )!r} , expected { expected !r} " )
1086+ return problems
1087+
1088+
1089+ def _audit_prose_install (
1090+ line : str , install_checks : tuple [tuple [re .Pattern [str ], str ], ...]
1091+ ) -> list [str ]:
1092+ """Return drift messages for raw install-hint literals on a prose line."""
1093+
1094+ problems : list [str ] = []
1095+ for hint_re , expected in install_checks :
1096+ hint_match = hint_re .search (line )
1097+ if hint_match and hint_match .group ("ver" ) != expected :
1098+ problems .append (
1099+ f"install hint pins { hint_match .group ('ver' )!r} , "
1100+ f"expected { expected !r} "
1101+ )
1102+ return problems
1103+
1104+
1105+ def _audit_prose_line (
1106+ line : str ,
1107+ in_block : bool ,
1108+ expected_by_label : dict [str , str ],
1109+ backtick_checks : tuple [tuple [re .Pattern [str ], str ], ...],
1110+ install_checks : tuple [tuple [re .Pattern [str ], str ], ...],
1111+ ) -> list [str ]:
1112+ """Return every drift message for one prose line, in stable emit order.
1113+
1114+ Install hints are skipped inside the generated sdk-install block — that
1115+ block is generator-owned and the prose install-hint pass excludes it.
1116+ """
1117+
1118+ problems : list [str ] = []
1119+ label_problem = _audit_prose_label (line , expected_by_label )
1120+ if label_problem is not None :
1121+ problems .append (label_problem )
1122+ problems .extend (_audit_prose_backtick (line , backtick_checks ))
1123+ if not in_block :
1124+ problems .extend (_audit_prose_install (line , install_checks ))
1125+ return problems
1126+
1127+
1128+ def _audit_prose_file (
1129+ path : Path ,
1130+ rel : Path ,
1131+ expected_by_label : dict [str , str ],
1132+ backtick_checks : tuple [tuple [re .Pattern [str ], str ], ...],
1133+ install_checks : tuple [tuple [re .Pattern [str ], str ], ...],
1134+ ) -> list [str ]:
1135+ """Report drift for one README/doc, tracking the generated-block region."""
1136+
1137+ problems : list [str ] = []
1138+ in_block = False
1139+ for lineno , line in _audit_lines (path ):
1140+ if SDK_BLOCK_BEGIN in line :
1141+ in_block = True
1142+ elif SDK_BLOCK_END in line :
1143+ in_block = False
1144+ continue
1145+ if EXEMPT_MARKER in line :
1146+ continue
1147+ for suffix in _audit_prose_line (
1148+ line , in_block , expected_by_label , backtick_checks , install_checks
1149+ ):
1150+ problems .append (f"{ rel } :{ lineno } : { suffix } " )
1151+ return problems
1152+
1153+
10581154def _audit_prose (repo_root : Path , versions : SdkVersions ) -> list [str ]:
10591155 """Report every README/doc prose line whose SDK version drifts from the SoT.
10601156
@@ -1089,47 +1185,11 @@ def _audit_prose(repo_root: Path, versions: SdkVersions) -> list[str]:
10891185 problems : list [str ] = []
10901186 for path in _globbed (repo_root , _README_GLOBS + ("docs/*.md" ,)):
10911187 rel = path .relative_to (repo_root )
1092- in_block = False
1093- for lineno , line in _audit_lines (path ):
1094- if SDK_BLOCK_BEGIN in line :
1095- in_block = True
1096- elif SDK_BLOCK_END in line :
1097- in_block = False
1098- continue
1099- if EXEMPT_MARKER in line :
1100- continue
1101-
1102- label_match = _PROSE_LABEL_RE .search (line )
1103- if label_match :
1104- token_match = _VERSION_TOKEN_RE .search (line )
1105- if token_match is not None :
1106- expected = expected_by_label [label_match .group (1 )]
1107- if token_match .group (0 ) != expected :
1108- problems .append (
1109- f"{ rel } :{ lineno } : states { token_match .group (0 )!r} , "
1110- f"expected { expected !r} "
1111- )
1112-
1113- for row_re , expected in backtick_checks :
1114- row_match = row_re .search (line )
1115- if row_match is None :
1116- continue
1117- token_match = _VERSION_TOKEN_RE .search (row_match .group ("val" ))
1118- if token_match is not None and token_match .group (0 ) != expected :
1119- problems .append (
1120- f"{ rel } :{ lineno } : states { token_match .group (0 )!r} , "
1121- f"expected { expected !r} "
1122- )
1123-
1124- if in_block :
1125- continue
1126- for hint_re , expected in install_checks :
1127- hint_match = hint_re .search (line )
1128- if hint_match and hint_match .group ("ver" ) != expected :
1129- problems .append (
1130- f"{ rel } :{ lineno } : install hint pins "
1131- f"{ hint_match .group ('ver' )!r} , expected { expected !r} "
1132- )
1188+ problems .extend (
1189+ _audit_prose_file (
1190+ path , rel , expected_by_label , backtick_checks , install_checks
1191+ )
1192+ )
11331193 return problems
11341194
11351195
0 commit comments