Bayan AI commited on
Commit
e661f43
·
1 Parent(s): 4ec5188

Phase 15: Bypass StageLocker for S-V Grammar collision overlap fixes

Browse files
Files changed (1) hide show
  1. 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
- if ctx.stage_locker.is_locked_for(d['start'], d['end'], 'grammar'):
 
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}'\u2192'{corr_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: واجب→واجبا, معطف→معطفا