import json
import os
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LEDGER = os.path.join(ROOT, "web", "data", "verification-matrix.json")
SVG_OUT = os.path.join(ROOT, "docs", "assets", "figures", "validation-breakdown.svg")
PNG_OUT = os.path.join(ROOT, "docs", "assets", "figures", "validation-breakdown.png")
ORACLE_SVG_OUT = os.path.join(ROOT, "docs", "assets", "figures", "oracle-kind-stacked.svg")
ORACLE_PNG_OUT = os.path.join(ROOT, "docs", "assets", "figures", "oracle-kind-stacked.png")
WIDTH = 780
HEIGHT = 300
MARGIN_X = 40
BAR_Y = 150
BAR_H = 64
BAR_W = WIDTH - 2 * MARGIN_X
SEGMENTS = [
("validated", "Validated", "#1b7837"), ("modelled", "Modelled", "#b8860b"), ("partner_owned", "Partner", "#4a4a8a"), ]
def load_counts():
with open(LEDGER, encoding="utf-8") as fh:
data = json.load(fh)
s = data["summary"]
counts = {
"validated": int(s["validated"]),
"modelled": int(s["modelled"]),
"partner_owned": int(s["partner_owned"]),
"total": int(s["total"]),
}
seg_sum = counts["validated"] + counts["modelled"] + counts["partner_owned"]
if seg_sum != counts["total"]:
raise SystemExit(
f"ledger summary inconsistent: {seg_sum} segments != {counts['total']} total"
)
return counts
def fmt(x):
return f"{round(x, 2):g}"
def build_svg(counts):
total = counts["total"]
lines = []
a = lines.append
a('<?xml version="1.0" encoding="UTF-8"?>')
a(
f'<svg xmlns="http://www.w3.org/2000/svg" width="{WIDTH}" '
f'height="{HEIGHT}" viewBox="0 0 {WIDTH} {HEIGHT}" '
'font-family="Helvetica, Arial, sans-serif">'
)
a(
' <title>kshana verification status breakdown across all '
f'{total} capabilities</title>'
)
a(' <desc>Generated from src/verification.rs via web/data/verification-matrix.json '
'by tools/gen_validation_figures.py. Do not edit by hand.</desc>')
a(f' <rect x="0" y="0" width="{WIDTH}" height="{HEIGHT}" fill="#ffffff"/>')
a(
f' <text x="{MARGIN_X}" y="56" font-size="26" font-weight="700" '
f'fill="#212121">Verification status</text>'
)
a(
f' <text x="{MARGIN_X}" y="86" font-size="16" fill="#555555">'
f'{total} capabilities · one row per requirement in the matrix</text>'
)
x = float(MARGIN_X)
n = len(SEGMENTS)
for i, (key, _label, colour) in enumerate(SEGMENTS):
count = counts[key]
if i == n - 1:
seg_w = (MARGIN_X + BAR_W) - x
else:
seg_w = BAR_W * count / total if total else 0.0
a(
f' <rect x="{fmt(x)}" y="{BAR_Y}" width="{fmt(seg_w)}" '
f'height="{BAR_H}" fill="{colour}"/>'
)
if seg_w >= 34:
cx = x + seg_w / 2
cy = BAR_Y + BAR_H / 2 + 8
a(
f' <text x="{fmt(cx)}" y="{fmt(cy)}" font-size="24" '
f'font-weight="700" fill="#ffffff" text-anchor="middle">{count}</text>'
)
x += seg_w
a(
f' <rect x="{MARGIN_X}" y="{BAR_Y}" width="{BAR_W}" height="{BAR_H}" '
f'fill="none" stroke="#212121" stroke-width="1"/>'
)
legend_y = BAR_Y + BAR_H + 52
swatch = 18
slot = BAR_W / n
for i, (key, label, colour) in enumerate(SEGMENTS):
count = counts[key]
sx = MARGIN_X + i * slot
a(
f' <rect x="{fmt(sx)}" y="{legend_y - swatch + 3}" width="{swatch}" '
f'height="{swatch}" fill="{colour}"/>'
)
a(
f' <text x="{fmt(sx + swatch + 8)}" y="{legend_y}" font-size="17" '
f'fill="#212121"><tspan font-weight="700">{count}</tspan> {label}</text>'
)
a('</svg>')
return "\n".join(lines) + "\n"
def write_png(svg_text, png_out, width, height):
try:
import cairosvg
except ImportError as exc: raise SystemExit(
"cairosvg is required to render the PNG: pip install cairosvg "
f"(import failed: {exc})"
)
cairosvg.svg2png(
bytestring=svg_text.encode("utf-8"),
write_to=png_out,
output_width=width,
output_height=height,
)
OWIDTH = 820
OHEIGHT = 400
OMARGIN = 40
OBAR_X = 168 OBAR_MAX_W = OWIDTH - OBAR_X - 70 OROW_Y0 = 120
OROW_STEP = 62
OBAR_H = 42
ORACLE_KINDS = [
("ExternalDataset", "#1b7837"),
("ReferenceImpl", "#b8860b"),
("InternalConsistency", "#cd853f"),
("NoneKind", "#4a4a8a"),
]
STATUS_ROWS = [
("VALIDATED", "Validated"),
("MODELLED", "Modelled"),
("PARTNER", "Partner"),
]
def load_breakdown():
with open(LEDGER, encoding="utf-8") as fh:
data = json.load(fh)
rows = data["rows"]
bd = {s: {k: 0 for k, _ in ORACLE_KINDS} for s, _ in STATUS_ROWS}
for r in rows:
status = r["status"]
kind = r["oracle_kind"]
if status in bd and kind in bd[status]:
bd[status][kind] += 1
else:
raise SystemExit(f"unexpected status/oracle_kind: {status!r}/{kind!r}")
return bd, len(rows)
def build_oracle_svg(bd, total):
validated = sum(bd["VALIDATED"].values())
modelled = bd["MODELLED"]
modelled_total = sum(modelled.values())
partner = sum(bd["PARTNER"].values())
row_totals = {s: sum(bd[s].values()) for s, _ in STATUS_ROWS}
max_total = max(row_totals.values()) or 1
scale = OBAR_MAX_W / max_total
lines = []
a = lines.append
a('<?xml version="1.0" encoding="UTF-8"?>')
a(
f'<svg xmlns="http://www.w3.org/2000/svg" width="{OWIDTH}" '
f'height="{OHEIGHT}" viewBox="0 0 {OWIDTH} {OHEIGHT}" '
'font-family="Helvetica, Arial, sans-serif">'
)
a(' <title>kshana verification status by oracle kind</title>')
a(' <desc>Generated from src/verification.rs via web/data/verification-matrix.json '
'by tools/gen_validation_figures.py. Do not edit by hand.</desc>')
a(f' <rect x="0" y="0" width="{OWIDTH}" height="{OHEIGHT}" fill="#ffffff"/>')
a(
f' <text x="{OMARGIN}" y="50" font-size="24" font-weight="700" '
f'fill="#212121">Validated means external oracle — by construction</text>'
)
a(
f' <text x="{OMARGIN}" y="78" font-size="15" fill="#555555">'
f'Status × oracle kind from verification-matrix.json (n={total}). '
f'Validated = {validated}/{validated} ExternalDataset — CI-enforced.</text>'
)
for i, (status, label) in enumerate(STATUS_ROWS):
y = OROW_Y0 + i * OROW_STEP
a(
f' <text x="{OMARGIN}" y="{fmt(y + OBAR_H / 2 + 5)}" font-size="17" '
f'font-weight="700" fill="#212121">{label}</text>'
)
x = float(OBAR_X)
for kind, colour in ORACLE_KINDS:
count = bd[status][kind]
if count == 0:
continue
seg_w = count * scale
a(
f' <rect x="{fmt(x)}" y="{y}" width="{fmt(seg_w)}" '
f'height="{OBAR_H}" fill="{colour}"/>'
)
if seg_w >= 22:
a(
f' <text x="{fmt(x + seg_w / 2)}" y="{fmt(y + OBAR_H / 2 + 6)}" '
f'font-size="18" font-weight="700" fill="#ffffff" '
f'text-anchor="middle">{count}</text>'
)
x += seg_w
a(
f' <text x="{fmt(x + 12)}" y="{fmt(y + OBAR_H / 2 + 6)}" font-size="18" '
f'font-weight="700" fill="#212121">{row_totals[status]}</text>'
)
cap_y = OROW_Y0 + len(STATUS_ROWS) * OROW_STEP + 10
a(
f' <text x="{OMARGIN}" y="{cap_y}" font-size="14" fill="#555555">'
f'Modelled oracle kinds: {modelled["ExternalDataset"]} ExternalDataset, '
f'{modelled["ReferenceImpl"]} ReferenceImpl, '
f'{modelled["InternalConsistency"]} InternalConsistency '
f'(total {modelled_total} Modelled).</text>'
)
legend_y = cap_y + 36
swatch = 16
slot = (OWIDTH - 2 * OMARGIN) / len(ORACLE_KINDS)
for i, (kind, colour) in enumerate(ORACLE_KINDS):
sx = OMARGIN + i * slot
a(
f' <rect x="{fmt(sx)}" y="{legend_y - swatch + 3}" width="{swatch}" '
f'height="{swatch}" fill="{colour}"/>'
)
a(
f' <text x="{fmt(sx + swatch + 6)}" y="{fmt(legend_y)}" font-size="13" '
f'fill="#212121">{kind}</text>'
)
totals_y = legend_y + 34
a(
f' <text x="{OMARGIN}" y="{totals_y}" font-size="15" fill="#212121">'
f'<tspan font-weight="700">{validated}</tspan> Validated · '
f'<tspan font-weight="700">{modelled_total}</tspan> Modelled · '
f'<tspan font-weight="700">{partner}</tspan> Partner · '
f'<tspan font-weight="700">{total}</tspan> total</text>'
)
a('</svg>')
return "\n".join(lines) + "\n"
def main(argv):
counts = load_counts()
svg_text = build_svg(counts)
bd, bd_total = load_breakdown()
oracle_svg_text = build_oracle_svg(bd, bd_total)
if "--check" in argv:
rc = 0
for out, text, name in (
(SVG_OUT, svg_text, "validation-breakdown.svg"),
(ORACLE_SVG_OUT, oracle_svg_text, "oracle-kind-stacked.svg"),
):
with open(out, encoding="utf-8") as fh:
committed = fh.read()
if committed != text:
print(
f"{name} is out of sync with the matrix; "
"run: python3 tools/gen_validation_figures.py",
file=sys.stderr,
)
rc = 1
else:
print(f"{name} is in sync.")
return rc
with open(SVG_OUT, "w", encoding="utf-8") as fh:
fh.write(svg_text)
write_png(svg_text, PNG_OUT, WIDTH, HEIGHT)
print(
f"wrote {os.path.relpath(SVG_OUT, ROOT)} and "
f"{os.path.relpath(PNG_OUT, ROOT)}: "
f"{counts['validated']} Validated / {counts['modelled']} Modelled / "
f"{counts['partner_owned']} Partner of {counts['total']}"
)
with open(ORACLE_SVG_OUT, "w", encoding="utf-8") as fh:
fh.write(oracle_svg_text)
write_png(oracle_svg_text, ORACLE_PNG_OUT, OWIDTH, OHEIGHT)
print(
f"wrote {os.path.relpath(ORACLE_SVG_OUT, ROOT)} and "
f"{os.path.relpath(ORACLE_PNG_OUT, ROOT)}: "
f"{sum(bd['VALIDATED'].values())} Validated / "
f"{sum(bd['MODELLED'].values())} Modelled / "
f"{sum(bd['PARTNER'].values())} Partner of {bd_total}"
)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))