test(pdf): diagnose S01 metric mismatch without changing fidelity gates
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""Explain each unchanged S01 failure using actual DOM/PDF baseline and font-cell math.
|
||||
|
||||
This report is evidence only. It never replaces the historical oracle or grants approval.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pdfplumber
|
||||
from pypdf import PdfReader
|
||||
|
||||
spec = importlib.util.spec_from_file_location('baseline_math', Path(__file__).with_name('baseline-math.py'))
|
||||
math = importlib.util.module_from_spec(spec); spec.loader.exec_module(math)
|
||||
|
||||
|
||||
def sha(file): return hashlib.sha256(file.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('corpus', type=Path)
|
||||
parser.add_argument('dom', type=Path)
|
||||
parser.add_argument('output', type=Path)
|
||||
args = parser.parse_args()
|
||||
if args.output.exists(): raise ValueError('Keep earlier reports immutable')
|
||||
measured = json.loads(args.dom.read_text(encoding='utf-8'))
|
||||
oracle = json.loads((args.corpus/'fidelity-results.json').read_text(encoding='utf-8'))
|
||||
ink = json.loads((args.corpus/'name-box-metrics.json').read_text(encoding='utf-8'))
|
||||
rows = []
|
||||
for dom in measured['rows']:
|
||||
file = args.corpus/dom['fixture']/'export.pdf'
|
||||
assert sha(file) == dom['pdfSha256'], 'Native PDF changed since DOM measurement binding'
|
||||
original = next(row for row in oracle['fixtures'] if row['fixture'] == dom['fixture'])
|
||||
comparison = next(row for row in original['comparisons'] if row['token'] == 'S01')
|
||||
assert all(failure.startswith('S01: position delta ') for failure in original['failures'])
|
||||
pixels = next(row for row in ink['fixtures'] if row['fixture'] == dom['fixture'])
|
||||
with pdfplumber.open(file) as document:
|
||||
page = document.pages[0]
|
||||
markers = [word for word in page.extract_words() if word['text'] == 'S01']
|
||||
assert len(markers) == 1, 'Missing or duplicate source marker'
|
||||
marker = markers[0]
|
||||
char = next(char for char in page.chars if char['text'] == 'S' and abs(char['x0']-marker['x0'])<0.01 and abs(char['top']-marker['top'])<0.01)
|
||||
assert abs(char['matrix'][1]) < 1e-6 and abs(char['matrix'][2]) < 1e-6, 'Unexpected rotated source'
|
||||
font = next(font.get_object() for font in PdfReader(file).pages[0]['/Resources']['/Font'].values() if str(font.get_object()['/BaseFont']).lstrip('/') == char['fontname'])
|
||||
if '/DescendantFonts' in font: font = font['/DescendantFonts'][0].get_object()
|
||||
descriptor = font['/FontDescriptor'].get_object()
|
||||
descent, ascent = float(descriptor['/Descent']), float(descriptor['/Ascent'])
|
||||
baseline = (page.height-char['matrix'][5])*96/72
|
||||
values = math.compare(dom['rangeTop'],dom['sentinelBaseline'],baseline,char['top']*96/72,char['size']*96/72,descent)
|
||||
assert values['cellFormulaResidualPx'] < 0.01, 'Font-cell formula does not explain native coordinates'
|
||||
assert abs(values['oldCellDeltaMm']-comparison['deltaYmm']) < 0.001, 'Original native oracle mismatch'
|
||||
assert values['baselineDeltaMm'] <= 2 and pixels['visibleInkTopDeltaPx'] <= 3, 'Actual baseline/visible-ink difference needs separate investigation'
|
||||
values.update(fixture=dom['fixture'], originalPass=original['pass'], originalFailures=original['failures'],
|
||||
classification='INCORRECT_TEST_ASSUMPTION' if not original['pass'] else 'PASS_CONTROL_WITH_SAME_METRIC_MISMATCH',
|
||||
secondaryCause='PLATFORM_FONT_DESCRIPTOR_METRICS', pdfSha256=sha(file), font=char['fontname'],
|
||||
descriptorAscent=ascent,descriptorDescent=descent,domRangeTopPx=dom['rangeTop'],
|
||||
domBaselinePx=dom['sentinelBaseline'],pdfBaselinePx=baseline,pdfCellTopPx=char['top']*96/72,
|
||||
fontSizePt=char['size'], visibleInkTopDeltaPx=pixels['visibleInkTopDeltaPx'])
|
||||
rows.append(values)
|
||||
assert len(rows)==36
|
||||
report=dict(status='DIAGNOSTIC_COMPLETE_OWNER_DISPOSITION_REQUIRED', policy='NO_ORIGINAL_GATE_OR_GOLDEN_CHANGE',
|
||||
originalOracleSha256=sha(args.corpus/'fidelity-results.json'),domReportSha256=sha(args.dom),
|
||||
inkReportSha256=sha(args.corpus/'name-box-metrics.json'),
|
||||
total=36,originalPass=sum(row['originalPass'] for row in rows),
|
||||
classifiedFailures=sum(not row['originalPass'] for row in rows),
|
||||
maxBaselineDeltaMm=max(row['baselineDeltaMm'] for row in rows),
|
||||
maxCellFormulaResidualPx=max(row['cellFormulaResidualPx'] for row in rows),
|
||||
maxVisibleInkTopDeltaPx=max(row['visibleInkTopDeltaPx'] for row in rows),rows=rows)
|
||||
args.output.write_bytes((json.dumps(report,ensure_ascii=False,indent=2)+'\n').encode())
|
||||
print(f"Classified {report['classifiedFailures']}/36 original failures; max actual baseline delta {report['maxBaselineDeltaMm']:.4f}mm; original gate unchanged")
|
||||
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
Reference in New Issue
Block a user