108 lines
3.9 KiB
Python
108 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""CHECK: re-derive the catalog from the raw JSON source and diff against the
|
|
produced artifact (catalog.json + catalog.md). Exit 0 only if they agree.
|
|
|
|
This is a real regression test, not a tautology: it re-reads the source file and
|
|
re-derives the rows, then compares against the committed artifact bytes.
|
|
"""
|
|
import json
|
|
import re
|
|
import sys
|
|
|
|
SRC = '/root/stackchain_catalog_raw.json'
|
|
ACTUAL_JSON = '/root/.hermes/wizard-outputs/ledger/catalog.json'
|
|
ACTUAL_MD = '/root/.hermes/wizard-outputs/ledger/catalog.md'
|
|
|
|
TYPE_RE = re.compile(r'"type"\s*:\s*"(.*?)"')
|
|
TEXT_RE = re.compile(r'"text"\s*:\s*"(.*?)"', re.DOTALL)
|
|
DOUBLE_N = '\\\\n'
|
|
SINGLE_N = '\\n'
|
|
|
|
|
|
def reextract():
|
|
raw = json.load(open(SRC, encoding='utf-8'))
|
|
rows = []
|
|
for idx, (fname, v) in enumerate(raw.items(), 1):
|
|
m_type = TYPE_RE.search(v)
|
|
ftype = m_type.group(1) if m_type else None
|
|
m_text = TEXT_RE.search(v)
|
|
text = m_text.group(1) if m_text else None
|
|
if text is not None:
|
|
text = text.replace(DOUBLE_N, '\n').replace(SINGLE_N, '\n')
|
|
rows.append({
|
|
'no': idx,
|
|
'entry': fname,
|
|
'type': ftype if ftype is not None else '(not transcribed)',
|
|
'text': text,
|
|
'words': len(text.split()) if text else 0,
|
|
})
|
|
return rows
|
|
|
|
|
|
def load_actual():
|
|
rows = json.load(open(ACTUAL_JSON, encoding='utf-8'))
|
|
md = open(ACTUAL_MD, encoding='utf-8').read()
|
|
return rows, md
|
|
|
|
|
|
def md_table_rows(md):
|
|
rows = []
|
|
for line in md.splitlines():
|
|
if line.startswith('|') and '---' not in line and 'No.' not in line:
|
|
cells = [c.strip() for c in line.strip('|').split('|')]
|
|
if cells:
|
|
rows.append(cells)
|
|
return rows
|
|
|
|
|
|
def main():
|
|
errors = []
|
|
expected = reextract()
|
|
actual, md = load_actual()
|
|
|
|
if len(actual) != len(expected):
|
|
errors.append(f'row count: actual={len(actual)} expected={len(expected)}')
|
|
|
|
for i, (a, e) in enumerate(zip(actual, expected), 1):
|
|
for key in ('no', 'entry', 'type', 'text', 'words'):
|
|
if a.get(key) != e[key]:
|
|
errors.append(f'row {i} field {key}: actual={a.get(key)!r} expected={e[key]!r}')
|
|
|
|
# markdown sanity: every entry must appear, with a type, and word counts must
|
|
# match the numbers in the table.
|
|
seen = set()
|
|
for cells in md_table_rows(md):
|
|
if len(cells) == 5 and cells[1].startswith('`'):
|
|
seen.add(cells[1].strip('`'))
|
|
if cells[3] == '—':
|
|
if actual[int(cells[0]) - 1]['text'] is not None:
|
|
errors.append(f'row {cells[0]} shows — but source text present')
|
|
else:
|
|
text = actual[int(cells[0]) - 1]['text']
|
|
if text is None:
|
|
errors.append(f'row {cells[0]} preview missing but source text absent')
|
|
else:
|
|
single = ' '.join(text.split())
|
|
exp_preview = single[:140].rstrip() + ('…' if len(single) > 140 else '')
|
|
if cells[3] != exp_preview:
|
|
errors.append(f'row {cells[0]} preview mismatch: {cells[3]!r} vs {exp_preview!r}')
|
|
if cells[2] != actual[int(cells[0]) - 1]['type']:
|
|
errors.append(f'row {cells[0]} type: {cells[2]} vs {actual[int(cells[0]) - 1]["type"]}')
|
|
expected_entries = {r['entry'] for r in expected}
|
|
if seen != expected_entries:
|
|
errors.append('md entries missing/extra: ' + ', '.join(sorted(seen ^ expected_entries)))
|
|
|
|
if errors:
|
|
print('CHECK FAILED:')
|
|
for e in errors:
|
|
print(' -', e)
|
|
sys.exit(1)
|
|
print(f'CHECK OK: {len(actual)} rows match the source exactly '
|
|
f'({sum(1 for r in actual if r["text"])} transcribed, '
|
|
f'{sum(1 for r in actual if not r["text"])} empty).')
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|