Bayan AI commited on
Commit ·
e661f43
1
Parent(s): 4ec5188
Phase 15: Bypass StageLocker for S-V Grammar collision overlap fixes
Browse files- src/app.py +83 -74
src/app.py
CHANGED
|
@@ -2170,9 +2170,89 @@ def analyze_text():
|
|
| 2170 |
corr_text = d.get('correction', '')
|
| 2171 |
logger.info(f'[FILTER-TEL] {_tel_json.dumps({"event":"grammar_diff","original":orig_text[:80],"correction":corr_text[:80],"start":d["start"],"end":d["end"]})}')
|
| 2172 |
_tel_events.append({"event":"grammar_diff","original":orig_text[:80],"correction":corr_text[:80],"start":d["start"],"end":d["end"]})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2173 |
# StageLocker: skip diffs that overlap with locked ranges
|
| 2174 |
# Phase 11: Hierarchy-aware — grammar (3) overrides spelling (2)
|
| 2175 |
-
|
|
|
|
| 2176 |
logger.info(
|
| 2177 |
f"[LOCK] Grammar blocked on [{d['start']}:{d['end']}] "
|
| 2178 |
f"'{d.get('original','')}' — locked by equal/higher priority stage"
|
|
@@ -2244,7 +2324,7 @@ def analyze_text():
|
|
| 2244 |
# Block diffs where the only change is punctuation removal/addition.
|
| 2245 |
if orig_text and corr_text:
|
| 2246 |
import re as _re_pstrip
|
| 2247 |
-
_PUNCT_CHARS = '.,،؛;:!؟?()[]{}«»
|
| 2248 |
_orig_stripped = orig_text.strip(_PUNCT_CHARS)
|
| 2249 |
_corr_stripped = corr_text.strip(_PUNCT_CHARS)
|
| 2250 |
if _orig_stripped == _corr_stripped and orig_text != corr_text:
|
|
@@ -2285,82 +2365,11 @@ def analyze_text():
|
|
| 2285 |
if _orig_normed == _corr_normed and orig_text != corr_text:
|
| 2286 |
logger.info(
|
| 2287 |
f"[GRAMMAR] Blocked punct spacing: "
|
| 2288 |
-
f"'{orig_text}'
|
| 2289 |
)
|
| 2290 |
continue
|
| 2291 |
|
| 2292 |
|
| 2293 |
-
|
| 2294 |
-
|
| 2295 |
-
|
| 2296 |
-
|
| 2297 |
-
# Evaluate grammar patterns early to bypass heuristic blocks.
|
| 2298 |
-
_is_grammar_pattern = False
|
| 2299 |
-
if orig_text and corr_text:
|
| 2300 |
-
_o_cl = orig_text.rstrip('.,،؛;:!؟?()[]{}«»"\'…')
|
| 2301 |
-
_c_cl = corr_text.rstrip('.,،؛;:!؟?()[]{}«»"\'…')
|
| 2302 |
-
|
| 2303 |
-
# Priority 4: Diacritic-Normalized Grammar Validation
|
| 2304 |
-
import re as _re_diac
|
| 2305 |
-
_o_cl = _re_diac.sub(r'[\u064B-\u065F\u0670]', '', _o_cl)
|
| 2306 |
-
_c_cl = _re_diac.sub(r'[\u064B-\u065F\u0670]', '', _c_cl)
|
| 2307 |
-
|
| 2308 |
-
|
| 2309 |
-
# Case: ون/ان → ين (sound masculine plural / dual case change)
|
| 2310 |
-
if (_o_cl.endswith('ون') and _c_cl.endswith('ين') and _o_cl[:-2] == _c_cl[:-2]):
|
| 2311 |
-
_is_grammar_pattern = True
|
| 2312 |
-
elif (_o_cl.endswith('ان') and _c_cl.endswith('ين') and _o_cl[:-2] == _c_cl[:-2] and len(_o_cl) >= 4):
|
| 2313 |
-
_is_grammar_pattern = True
|
| 2314 |
-
# Nasb/Jazm: ون → وا (verb mood)
|
| 2315 |
-
elif (_o_cl.endswith('ون') and _c_cl.endswith('وا') and len(_o_cl) >= 3):
|
| 2316 |
-
_o_stem = _o_cl[:-2]
|
| 2317 |
-
_c_stem = _c_cl[:-2]
|
| 2318 |
-
if _o_stem == _c_stem or (len(_o_stem) > 1 and _o_stem[1:] == _c_stem[1:] and _o_stem[0] in 'يت' and _c_stem[0] in 'يت'):
|
| 2319 |
-
_is_grammar_pattern = True
|
| 2320 |
-
# Five nouns: وك → اك/يك
|
| 2321 |
-
elif (len(_o_cl) >= 3 and len(_c_cl) >= 3 and _o_cl[-2:] in ('وك', 'وه') and _c_cl[-2:] in ('اك', 'يك', 'اه', 'يه')):
|
| 2322 |
-
_is_grammar_pattern = True
|
| 2323 |
-
# Demonstrative: هذان→هاتان, هاتان→هذان
|
| 2324 |
-
elif ({_o_cl, _c_cl} <= {'هذان', 'هاتان'}):
|
| 2325 |
-
_is_grammar_pattern = True
|
| 2326 |
-
# Past tense masc plural: verb→verb+وا
|
| 2327 |
-
elif (_c_cl.endswith('وا') and _c_cl[:-2] == _o_cl and len(_o_cl) >= 3):
|
| 2328 |
-
_is_grammar_pattern = True
|
| 2329 |
-
# Past tense fem plural: verb→verb+ن
|
| 2330 |
-
elif (_c_cl.endswith('ن') and _c_cl[:-1] == _o_cl and len(_o_cl) >= 3):
|
| 2331 |
-
_is_grammar_pattern = True
|
| 2332 |
-
# Present tense fem plural: ون → ن
|
| 2333 |
-
elif (_o_cl.endswith('ون') and _c_cl.endswith('ن') and len(_o_cl) >= 3):
|
| 2334 |
-
_o_stem = _o_cl[:-2]
|
| 2335 |
-
_c_stem = _c_cl[:-1]
|
| 2336 |
-
if _o_stem == _c_stem or (len(_o_stem) > 1 and _o_stem[1:] == _c_stem[1:] and _o_stem[0] in 'يت' and _c_stem[0] in 'يت'):
|
| 2337 |
-
_is_grammar_pattern = True
|
| 2338 |
-
# Masc Plural Addition: +ون
|
| 2339 |
-
elif (_c_cl.endswith('ون') and _c_cl[:-2] == _o_cl and len(_o_cl) >= 3):
|
| 2340 |
-
_is_grammar_pattern = True
|
| 2341 |
-
# Dual Addition: +ان or +ين
|
| 2342 |
-
elif ((_c_cl.endswith('ان') or _c_cl.endswith('ين')) and _c_cl[:-2] == _o_cl and len(_o_cl) >= 3):
|
| 2343 |
-
_is_grammar_pattern = True
|
| 2344 |
-
# Feminine Dual Addition: +تان / +تين
|
| 2345 |
-
elif (_c_cl.endswith('تان') or _c_cl.endswith('تين')):
|
| 2346 |
-
if _o_cl.endswith('ة') and _c_cl[:-3] == _o_cl[:-1] and len(_o_cl) >= 3:
|
| 2347 |
-
_is_grammar_pattern = True
|
| 2348 |
-
elif _c_cl[:-3] == _o_cl and len(_o_cl) >= 3:
|
| 2349 |
-
_is_grammar_pattern = True
|
| 2350 |
-
# Feminine Plural Addition: +ات
|
| 2351 |
-
elif (_c_cl.endswith('ات') and len(_c_cl) >= 4):
|
| 2352 |
-
if _o_cl.endswith('ة') and _c_cl[:-2] == _o_cl[:-1]:
|
| 2353 |
-
_is_grammar_pattern = True
|
| 2354 |
-
elif _c_cl[:-2] == _o_cl:
|
| 2355 |
-
_is_grammar_pattern = True
|
| 2356 |
-
# Gender: +ة (جميل→جميلة)
|
| 2357 |
-
elif (_c_cl.endswith('ة') and _c_cl[:-1] == _o_cl and len(_o_cl) >= 3):
|
| 2358 |
-
_is_grammar_pattern = True
|
| 2359 |
-
# Gender with ي: ذكي→ذكية
|
| 2360 |
-
elif (_c_cl.endswith('ية') and _c_cl[:-1] == _o_cl[:-1] + 'ي' and _o_cl.endswith('ي') and len(_o_cl) >= 3):
|
| 2361 |
-
_is_grammar_pattern = True
|
| 2362 |
-
|
| 2363 |
-
|
| 2364 |
# ── FIX-42d: Grammar trailing letter addition guard ──
|
| 2365 |
# Block grammar changes that add ا/ي to end of IV words.
|
| 2366 |
# Catches: واجب→واجبا, معطف→معطفا
|
|
|
|
| 2170 |
corr_text = d.get('correction', '')
|
| 2171 |
logger.info(f'[FILTER-TEL] {_tel_json.dumps({"event":"grammar_diff","original":orig_text[:80],"correction":corr_text[:80],"start":d["start"],"end":d["end"]})}')
|
| 2172 |
_tel_events.append({"event":"grammar_diff","original":orig_text[:80],"correction":corr_text[:80],"start":d["start"],"end":d["end"]})
|
| 2173 |
+
|
| 2174 |
+
# Evaluate grammar patterns early to bypass heuristic blocks.
|
| 2175 |
+
_is_grammar_pattern = False
|
| 2176 |
+
if orig_text and corr_text:
|
| 2177 |
+
_o_cl = orig_text.rstrip('.,،؛;:!؟?()[]{}«»"\'…')
|
| 2178 |
+
_c_cl = corr_text.rstrip('.,،؛;:!؟?()[]{}«»"\'…')
|
| 2179 |
+
|
| 2180 |
+
# Priority 4: Diacritic-Normalized Grammar Validation
|
| 2181 |
+
import re as _re_diac
|
| 2182 |
+
_o_cl = _re_diac.sub(r'[\u064B-\u065F\u0670]', '', _o_cl)
|
| 2183 |
+
_c_cl = _re_diac.sub(r'[\u064B-\u065F\u0670]', '', _c_cl)
|
| 2184 |
+
|
| 2185 |
+
# Case: ون/ان → ين (sound masculine plural / dual case change)
|
| 2186 |
+
if (_o_cl.endswith('ون') and _c_cl.endswith('ين') and _o_cl[:-2] == _c_cl[:-2]):
|
| 2187 |
+
_is_grammar_pattern = True
|
| 2188 |
+
elif (_o_cl.endswith('ان') and _c_cl.endswith('ين') and _o_cl[:-2] == _c_cl[:-2] and len(_o_cl) >= 4):
|
| 2189 |
+
_is_grammar_pattern = True
|
| 2190 |
+
# Nasb/Jazm: ون → وا (verb mood)
|
| 2191 |
+
elif (_o_cl.endswith('ون') and _c_cl.endswith('وا') and len(_o_cl) >= 3):
|
| 2192 |
+
_o_stem = _o_cl[:-2]
|
| 2193 |
+
_c_stem = _c_cl[:-2]
|
| 2194 |
+
if _o_stem == _c_stem or (len(_o_stem) > 1 and _o_stem[1:] == _c_stem[1:] and _o_stem[0] in 'يت' and _c_stem[0] in 'يت'):
|
| 2195 |
+
_is_grammar_pattern = True
|
| 2196 |
+
# Five nouns: وك → اك/يك
|
| 2197 |
+
elif (len(_o_cl) >= 3 and len(_c_cl) >= 3 and _o_cl[-2:] in ('وك', 'وه', 'يك', 'يه') and _c_cl[-2:] in ('اك', 'اه', 'وك', 'وه', 'يك', 'يه')):
|
| 2198 |
+
if _o_cl[:-2] == _c_cl[:-2]:
|
| 2199 |
+
_is_grammar_pattern = True
|
| 2200 |
+
# Demonstrative: هذان→هاتان, هاتان→هذان
|
| 2201 |
+
elif ({_o_cl, _c_cl} <= {'هذان', 'هاتان'}):
|
| 2202 |
+
_is_grammar_pattern = True
|
| 2203 |
+
# Past tense masc plural: verb→verb+وا
|
| 2204 |
+
elif (_c_cl.endswith('وا') and _c_cl[:-2] == _o_cl and len(_o_cl) >= 3):
|
| 2205 |
+
_is_grammar_pattern = True
|
| 2206 |
+
# Past tense masc plural replacement (Collision Fixes): ت/ن/ى/ة → وا
|
| 2207 |
+
elif (_c_cl.endswith('وا') and _o_cl[-1:] in ('ت', 'ن', 'ى', 'ة', 'و') and _c_cl[:-2] == _o_cl[:-1] and len(_o_cl) >= 3):
|
| 2208 |
+
_is_grammar_pattern = True
|
| 2209 |
+
# Past tense masc plural replacement: ون/ين/ان → وا
|
| 2210 |
+
elif (_c_cl.endswith('وا') and _o_cl[-2:] in ('ون', 'ين', 'ان') and _c_cl[:-2] == _o_cl[:-2] and len(_o_cl) >= 4):
|
| 2211 |
+
_is_grammar_pattern = True
|
| 2212 |
+
# Past tense fem plural: verb→verb+ن
|
| 2213 |
+
elif (_c_cl.endswith('ن') and _c_cl[:-1] == _o_cl and len(_o_cl) >= 3):
|
| 2214 |
+
_is_grammar_pattern = True
|
| 2215 |
+
# Past tense fem plural replacement (Collision Fixes): ت/ى/ة/و → ن
|
| 2216 |
+
elif (_c_cl.endswith('ن') and _o_cl[-1:] in ('ت', 'ى', 'ة', 'و') and _c_cl[:-1] == _o_cl[:-1] and len(_o_cl) >= 3):
|
| 2217 |
+
_is_grammar_pattern = True
|
| 2218 |
+
# Past tense fem plural replacement: وا/ون/ين/ان → ن
|
| 2219 |
+
elif (_c_cl.endswith('ن') and _o_cl[-2:] in ('وا', 'ون', 'ين', 'ان') and _c_cl[:-1] == _o_cl[:-2] and len(_o_cl) >= 4):
|
| 2220 |
+
_is_grammar_pattern = True
|
| 2221 |
+
# Present tense fem plural: ون → ن
|
| 2222 |
+
elif (_o_cl.endswith('ون') and _c_cl.endswith('ن') and len(_o_cl) >= 3):
|
| 2223 |
+
_o_stem = _o_cl[:-2]
|
| 2224 |
+
_c_stem = _c_cl[:-1]
|
| 2225 |
+
if _o_stem == _c_stem or (len(_o_stem) > 1 and _o_stem[1:] == _c_stem[1:] and _o_stem[0] in 'يت' and _c_stem[0] in 'يت'):
|
| 2226 |
+
_is_grammar_pattern = True
|
| 2227 |
+
# Masc Plural Addition: +ون
|
| 2228 |
+
elif (_c_cl.endswith('ون') and _c_cl[:-2] == _o_cl and len(_o_cl) >= 3):
|
| 2229 |
+
_is_grammar_pattern = True
|
| 2230 |
+
# Dual Addition: +ان or +ين
|
| 2231 |
+
elif ((_c_cl.endswith('ان') or _c_cl.endswith('ين')) and _c_cl[:-2] == _o_cl and len(_o_cl) >= 3):
|
| 2232 |
+
_is_grammar_pattern = True
|
| 2233 |
+
# Feminine Dual Addition: +تان / +تين
|
| 2234 |
+
elif (_c_cl.endswith('تان') or _c_cl.endswith('تين')):
|
| 2235 |
+
if _o_cl.endswith('ة') and _c_cl[:-3] == _o_cl[:-1] and len(_o_cl) >= 3:
|
| 2236 |
+
_is_grammar_pattern = True
|
| 2237 |
+
elif _c_cl[:-3] == _o_cl and len(_o_cl) >= 3:
|
| 2238 |
+
_is_grammar_pattern = True
|
| 2239 |
+
# Feminine Plural Addition: +ات
|
| 2240 |
+
elif (_c_cl.endswith('ات') and len(_c_cl) >= 4):
|
| 2241 |
+
if _o_cl.endswith('ة') and _c_cl[:-2] == _o_cl[:-1]:
|
| 2242 |
+
_is_grammar_pattern = True
|
| 2243 |
+
elif _c_cl[:-2] == _o_cl:
|
| 2244 |
+
_is_grammar_pattern = True
|
| 2245 |
+
# Gender: +ة (جميل→جميلة)
|
| 2246 |
+
elif (_c_cl.endswith('ة') and _c_cl[:-1] == _o_cl and len(_o_cl) >= 3):
|
| 2247 |
+
_is_grammar_pattern = True
|
| 2248 |
+
# Gender with ي: ذكي→ذكية
|
| 2249 |
+
elif (_c_cl.endswith('ية') and _c_cl[:-1] == _o_cl[:-1] + 'ي' and _o_cl.endswith('ي') and len(_o_cl) >= 3):
|
| 2250 |
+
_is_grammar_pattern = True
|
| 2251 |
+
|
| 2252 |
# StageLocker: skip diffs that overlap with locked ranges
|
| 2253 |
# Phase 11: Hierarchy-aware — grammar (3) overrides spelling (2)
|
| 2254 |
+
# Phase 15: Bypass StageLocker entirely for valid Grammar S-V patches to fix collisions
|
| 2255 |
+
if not _is_grammar_pattern and ctx.stage_locker.is_locked_for(d['start'], d['end'], 'grammar'):
|
| 2256 |
logger.info(
|
| 2257 |
f"[LOCK] Grammar blocked on [{d['start']}:{d['end']}] "
|
| 2258 |
f"'{d.get('original','')}' — locked by equal/higher priority stage"
|
|
|
|
| 2324 |
# Block diffs where the only change is punctuation removal/addition.
|
| 2325 |
if orig_text and corr_text:
|
| 2326 |
import re as _re_pstrip
|
| 2327 |
+
_PUNCT_CHARS = '.,،؛;:!؟?()[]{}«»"\'…'
|
| 2328 |
_orig_stripped = orig_text.strip(_PUNCT_CHARS)
|
| 2329 |
_corr_stripped = corr_text.strip(_PUNCT_CHARS)
|
| 2330 |
if _orig_stripped == _corr_stripped and orig_text != corr_text:
|
|
|
|
| 2365 |
if _orig_normed == _corr_normed and orig_text != corr_text:
|
| 2366 |
logger.info(
|
| 2367 |
f"[GRAMMAR] Blocked punct spacing: "
|
| 2368 |
+
f"'{orig_text}'→'{corr_text}'"
|
| 2369 |
)
|
| 2370 |
continue
|
| 2371 |
|
| 2372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2373 |
# ── FIX-42d: Grammar trailing letter addition guard ──
|
| 2374 |
# Block grammar changes that add ا/ي to end of IV words.
|
| 2375 |
# Catches: واجب→واجبا, معطف→معطفا
|