pipelines/fix_critic_findings.py
# Critic fixes on T0_Theme_Registry.NEW.csv (GO-WITH-FIXES, all accepted):
# F1 MAJOR: 8 prose cells still carry the pre-Appendix-S token 'cardinal' in the roster-query
# wording -> 'cardinal_theme' (word-boundary, never touching cardinal_theme or
# cardinal-roster).
# F2 MINOR: JOURNEY_WORLD hard_line_relevance gains the s1.9 anti-over-conservatism
# counterweight sentence before "Care means weight and authenticity".
# F3 MINOR: HOME_AND_LOSS hard_line_relevance citation "(HL_0099)" -> extended-by-relation form.
import csv, io, os, re, sys
SP = os.path.dirname(os.path.abspath(__file__))
P = os.path.join(SP, 'T0_Theme_Registry.NEW.csv')
raw = open(P, 'rb').read()
assert not raw.startswith(b'\xef\xbb\xbf')
assert b'\r\n' in raw
rows = list(csv.reader(io.StringIO(raw.decode('utf-8'))))
hdr = rows[0]
ix = {c: hdr.index(c) for c in ('theme_id', 'notes', 'recent_changes', 'hard_line_relevance')}
by_id = {r[0]: r for r in rows[1:]}
# Only the QUERY FORM is the defect ('row_class = cardinal' / 'row_class cardinal');
# adjective uses ('the cardinal Cassius motif', 'cardinal payoff surface', 'cardinal roster',
# CVD s17.12 'cardinal numerical canon') are correct English prose and stay.
BAD = re.compile(r'row_class(\s*=\s*|\s+)cardinal\b(?!_theme)')
f1_targets = [
('CASSIUS_PHASE_1', 'notes'), ('CASSIUS_PHASE_1', 'recent_changes'),
('CASSIUS_PHASE_2', 'notes'), ('CASSIUS_PHASE_3', 'notes'),
('VIMANA_ACTIVATION', 'notes'), ('VIMANA_ACTIVATION', 'recent_changes'),
('HOME_AND_LOSS', 'notes'), ('JOURNEY_WORLD', 'notes'),
]
fixed = 0
for tid, col in f1_targets:
cell = by_id[tid][ix[col]]
n = len(BAD.findall(cell))
assert n >= 1, f'F1 {tid}.{col}: expected the query-form token, found none'
by_id[tid][ix[col]] = BAD.sub(lambda m: 'row_class' + m.group(1) + 'cardinal_theme', cell)
fixed += n
print(f'F1: {fixed} query-form replacements across 8 cells')
jw = by_id['JOURNEY_WORLD'][ix['hard_line_relevance']]
ANCHOR = 'Care means weight and authenticity'
assert ANCHOR in jw, 'F2 anchor missing'
COUNTER = ('an individual antagonist may be scored fully inside his own culture\'s register with '
'the same craft as that region\'s protagonist cues -- a blanket register ban is the '
'named failure (doctrine s1.9); ')
assert COUNTER not in jw
by_id['JOURNEY_WORLD'][ix['hard_line_relevance']] = jw.replace(ANCHOR, COUNTER + ANCHOR, 1)
print('F2: counterweight sentence inserted')
hl = by_id['HOME_AND_LOSS'][ix['hard_line_relevance']]
OLD = 'never by name (HL_0099)'
NEW = 'never by name (the HL_0099 discipline extended by relation)'
assert OLD in hl, 'F3 anchor missing'
by_id['HOME_AND_LOSS'][ix['hard_line_relevance']] = hl.replace(OLD, NEW, 1)
print('F3: citation corrected')
# Post-conditions: zero bad tokens anywhere; width discipline holds.
out_rows = [hdr] + [by_id[r[0]] for r in rows[1:]]
w = len(hdr)
assert all(len(r) == w for r in out_rows)
whole = '\n'.join(','.join(r) for r in out_rows)
resid = BAD.findall(whole)
assert not resid, f'residual query-form tokens: {resid[:5]}'
buf = io.StringIO()
csv.writer(buf, lineterminator='\r\n').writerows(out_rows)
data = buf.getvalue().encode('utf-8')
tmp = P + '.tmp'
open(tmp, 'wb').write(data)
os.replace(tmp, P)
print('written; post-conditions clean')