76 lines
4.9 KiB
Python
76 lines
4.9 KiB
Python
"""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()
|