|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""WP-062 HTML renderer — Civilizational AGI/ASI Master Synthesis Blueprint 2026-2030.""" |
| 3 | +import json |
| 4 | +from pathlib import Path |
| 5 | +from html import escape |
| 6 | + |
| 7 | +ROOT = Path(__file__).resolve().parent |
| 8 | +SRC = ROOT / "data" / "civ-agi-master-synthesis-2030.json" |
| 9 | +OUT = ROOT / "public" / "civ-agi-master-synthesis-2030.html" |
| 10 | +OUT.parent.mkdir(parents=True, exist_ok=True) |
| 11 | +DOC = json.loads(SRC.read_text(encoding="utf-8")) |
| 12 | + |
| 13 | + |
| 14 | +def e(x): |
| 15 | + return escape(str(x)) |
| 16 | + |
| 17 | + |
| 18 | +SKIP = ( |
| 19 | + "mid", "sid", "title", "pid", "cid", "rid", "aid", "did", "eid", "uid", "yid", |
| 20 | + "iid", "fid", "rsid", "name", "layer", "component", "system", "area", "category", |
| 21 | + "mechanism", "tier", "control", "phase", "milestone", "regime", "clause", |
| 22 | + "capability", "artifact", "scope", "item", "practice", "invariant", "prover", |
| 23 | + "from", "to", "plane", "abstract", "content", |
| 24 | +) |
| 25 | + |
| 26 | + |
| 27 | +def kv_pairs(d, skip=SKIP): |
| 28 | + parts = [] |
| 29 | + for k, v in d.items(): |
| 30 | + if k in skip: |
| 31 | + continue |
| 32 | + if isinstance(v, list): |
| 33 | + inner = "".join( |
| 34 | + f"<li>{e(x) if not isinstance(x, dict) else e(json.dumps(x))}</li>" |
| 35 | + for x in v |
| 36 | + ) |
| 37 | + parts.append(f"<div class='kv'><b>{e(k)}</b><ul>{inner}</ul></div>") |
| 38 | + elif isinstance(v, dict): |
| 39 | + inner = "".join(f"<li><b>{e(kk)}</b>: {e(vv)}</li>" for kk, vv in v.items()) |
| 40 | + parts.append(f"<div class='kv'><b>{e(k)}</b><ul>{inner}</ul></div>") |
| 41 | + else: |
| 42 | + parts.append(f"<div class='kv'><b>{e(k)}</b>: {e(v)}</div>") |
| 43 | + return "".join(parts) |
| 44 | + |
| 45 | + |
| 46 | +def section_html(s): |
| 47 | + body = kv_pairs(s) |
| 48 | + return f"<div class='sec'><h4>{e(s['sid'])}. {e(s['title'])}</h4>{body}</div>" |
| 49 | + |
| 50 | + |
| 51 | +def module_html(m): |
| 52 | + secs = "".join(section_html(s) for s in m["sections"]) |
| 53 | + purpose = m.get("purpose") or m.get("summary") or "" |
| 54 | + return ( |
| 55 | + f"<section class='module' id='{e(m['mid'])}'>" |
| 56 | + f"<h3>{e(m['mid'])} — {e(m['title'])}</h3>" |
| 57 | + f"<p class='sum'>{e(purpose)}</p>" |
| 58 | + f"{secs}</section>" |
| 59 | + ) |
| 60 | + |
| 61 | + |
| 62 | +def list_array(arr, label_keys, anchor, title): |
| 63 | + rows = [] |
| 64 | + for it in arr: |
| 65 | + head_parts = [e(it.get(label_keys[0], ""))] + [e(it.get(k, "")) for k in label_keys[1:]] |
| 66 | + head = " · ".join(p for p in head_parts if p) |
| 67 | + body = kv_pairs(it) |
| 68 | + rows.append(f"<div class='card'><div class='card-head'>{head}</div>{body}</div>") |
| 69 | + return f"<section id='{anchor}'><h3>{title} ({len(arr)})</h3>{''.join(rows)}</section>" |
| 70 | + |
| 71 | + |
| 72 | +# Distinctive arrays specific to WP-062 |
| 73 | +distinctive = [ |
| 74 | + ("refArchLayers", "ref-arch-layers", "Reference Architecture Layers (M3)", ["rid", "system", "layer"]), |
| 75 | + ("platformLayers", "platform-layers", "Governance Platform Layers (M7/M8)", ["pid", "plane", "component"]), |
| 76 | + ("regulatoryCrosswalks", "regulatory-crosswalks", "Regulatory Crosswalks — 30+ Regimes (M2)", ["cid", "regime", "clause"]), |
| 77 | + ("safetyInvariants", "safety-invariants", "Luminous Engine Codex Safety Invariants (M4)", ["iid", "prover", "invariant"]), |
| 78 | + ("frontierRisks", "frontier-risks", "Frontier-Risk Taxonomy (M4)", ["fid", "category"]), |
| 79 | + ("civMechanisms", "civ-mechanisms", "Civilizational Coordination Mechanisms (M5)", ["mid", "name"]), |
| 80 | + ("reportSections", "report-sections", "Regulator-Ready Report Sections (M8)", ["rsid", "title"]), |
| 81 | + ("roadmap", "roadmap-items", "2026-2030 Roadmap Items (M8)", ["rid", "phase", "milestone"]), |
| 82 | + ("dependencies", "dependencies", "Dependency Graph (DAG edges)", ["did", "from", "to"]), |
| 83 | +] |
| 84 | + |
| 85 | + |
| 86 | +toc_modules = "".join( |
| 87 | + f"<li><a href='#{e(m['mid'])}'>{e(m['mid'])} — {e(m['title'])}</a></li>" |
| 88 | + for m in DOC["modules"] |
| 89 | +) |
| 90 | +toc_distinct = "".join( |
| 91 | + f"<li><a href='#{anchor}'>{e(label)}</a></li>" |
| 92 | + for _, anchor, label, _ in distinctive |
| 93 | +) |
| 94 | + |
| 95 | +modules_html = "".join(module_html(m) for m in DOC["modules"]) |
| 96 | +distinctive_html = "".join( |
| 97 | + list_array(DOC[key], keys, anchor, label) |
| 98 | + for key, anchor, label, keys in distinctive |
| 99 | +) |
| 100 | + |
| 101 | + |
| 102 | +def table_rows(rows, cols): |
| 103 | + head = "".join(f"<th>{e(c)}</th>" for c in cols) |
| 104 | + body_rows = [] |
| 105 | + for r in rows: |
| 106 | + tds = "".join(f"<td>{e(r.get(c, ''))}</td>" for c in cols) |
| 107 | + body_rows.append(f"<tr>{tds}</tr>") |
| 108 | + return f"<table><thead><tr>{head}</tr></thead><tbody>{''.join(body_rows)}</tbody></table>" |
| 109 | + |
| 110 | + |
| 111 | +def table_dict(d, key_label, val_label="value"): |
| 112 | + head = f"<tr><th>{e(key_label)}</th><th>{e(val_label)}</th></tr>" |
| 113 | + rows = [] |
| 114 | + for k, v in d.items(): |
| 115 | + if isinstance(v, dict): |
| 116 | + vstr = "; ".join(f"{kk}={vv}" for kk, vv in v.items()) |
| 117 | + elif isinstance(v, list): |
| 118 | + vstr = "; ".join(str(x) for x in v) |
| 119 | + else: |
| 120 | + vstr = str(v) |
| 121 | + rows.append(f"<tr><td>{e(k)}</td><td>{e(vstr)}</td></tr>") |
| 122 | + return f"<table><thead>{head}</thead><tbody>{''.join(rows)}</tbody></table>" |
| 123 | + |
| 124 | + |
| 125 | +# Report sections rendered with abstract/content (whitepaper style) |
| 126 | +report_full_html = ( |
| 127 | + "<section id='report-sections-full'><h3>Whitepaper Sections — <title> / <abstract> / <content></h3>" |
| 128 | + + "".join( |
| 129 | + f"<div class='card'><div class='card-head'>{e(rs['rsid'])} · {e(rs['title'])}</div>" |
| 130 | + f"<div class='kv'><b>abstract</b>: {e(rs['abstract'])}</div>" |
| 131 | + f"<div class='kv'><b>content</b>: {e(rs['content'])}</div></div>" |
| 132 | + for rs in DOC["reportSections"] |
| 133 | + ) |
| 134 | + + "</section>" |
| 135 | +) |
| 136 | + |
| 137 | +# Tail sections |
| 138 | +schemas_html = f"<section id='schemas'><h3>Schemas ({len(DOC['schemas'])})</h3>{table_dict(DOC['schemas'], 'schema', 'fields')}</section>" |
| 139 | +code_html = ( |
| 140 | + "<section id='code'><h3>Code & Skeleton Artifacts (Rego / TLA+ / Coq / Q# / Terraform / Kafka ACL)</h3>" |
| 141 | + + "".join( |
| 142 | + f"<div class='kv'><b>{e(k)}</b><ul>" + "".join(f"<li><pre>{e(item)}</pre></li>" for item in v) + "</ul></div>" |
| 143 | + for k, v in DOC["code"].items() |
| 144 | + ) |
| 145 | + + "</section>" |
| 146 | +) |
| 147 | +kpis_html = f"<section id='kpis'><h3>KPIs / Indices ({len(DOC['kpis'])})</h3>{table_dict(DOC['kpis'], 'index', 'target/cadence')}</section>" |
| 148 | +rcm_html = f"<section id='rcm'><h3>Risk Control Matrix ({len(DOC['riskControlMatrix'])})</h3>{table_rows(DOC['riskControlMatrix'], ['risk','control','owner','evidence'])}</section>" |
| 149 | +trace_html = f"<section id='trace'><h3>Traceability ({len(DOC['traceability'])})</h3>{table_rows(DOC['traceability'], ['from','to','via'])}</section>" |
| 150 | +flows_html = f"<section id='data-flows'><h3>Data Flows ({len(DOC['dataFlows'])})</h3>{table_rows(DOC['dataFlows'], ['flow'])}</section>" |
| 151 | +regs_html = f"<section id='regulators'><h3>Regulators ({len(DOC['regulators'])})</h3>{table_rows(DOC['regulators'], ['name','scope'])}</section>" |
| 152 | +rollout_html = f"<section id='rollout-90'><h3>90-Day Rollout ({len(DOC['rollout90'])})</h3>{table_rows(DOC['rollout90'], ['day','task'])}</section>" |
| 153 | +evidence_html = ( |
| 154 | + f"<section id='evidence-pack'><h3>Regulator Evidence Pack ({len(DOC['evidencePack'])})</h3>" |
| 155 | + + "<ul>" + "".join(f"<li>{e(x)}</li>" for x in DOC["evidencePack"]) + "</ul></section>" |
| 156 | +) |
| 157 | + |
| 158 | +tail_html = schemas_html + code_html + kpis_html + rcm_html + trace_html + flows_html + regs_html + rollout_html + evidence_html |
| 159 | + |
| 160 | + |
| 161 | +# Executive summary |
| 162 | +exs = DOC["executiveSummary"] |
| 163 | +exec_html = f""" |
| 164 | +<section id='exec'><h3>Executive Summary</h3> |
| 165 | +<p><b>Headline:</b> {e(exs['headline'])}</p> |
| 166 | +<p><b>Scope:</b> {e(exs['scope'])}</p> |
| 167 | +<p><b>Investment:</b> {e(exs['investment'])}</p> |
| 168 | +<p><b>Target Indices:</b> {e(exs['targetIndices'])}</p> |
| 169 | +<div class='kv'><b>Differentiators</b><ul>{''.join(f'<li>{e(x)}</li>' for x in exs['differentiators'])}</ul></div> |
| 170 | +</section> |
| 171 | +""" |
| 172 | + |
| 173 | + |
| 174 | +# Meta / directive / regimes / indices / tiers / severities / investment / audiences |
| 175 | +directive = DOC["directive"] |
| 176 | +indices_rows = "".join( |
| 177 | + f"<li><b>{e(k)}</b>: {e(v) if not isinstance(v, dict) else e(json.dumps(v))}</li>" |
| 178 | + for k, v in DOC["indices"].items() |
| 179 | +) |
| 180 | +tiers_rows = "".join(f"<li><b>{e(k)}</b>: {e(v)}</li>" for k, v in DOC["tiers"].items()) |
| 181 | +sev_rows = "".join(f"<li><b>{e(k)}</b>: {e(v)}</li>" for k, v in DOC["severities"].items()) |
| 182 | +invest = DOC["investment"] |
| 183 | +invest_breakdown = "".join(f"<li><b>{e(k)}</b>: {e(v)}</li>" for k, v in invest["breakdown"].items()) |
| 184 | +regimes_list = "".join(f"<li>{e(r)}</li>" for r in DOC["regimes"]) |
| 185 | +audiences_list = "".join(f"<li>{e(a)}</li>" for a in DOC["audiences"]) |
| 186 | + |
| 187 | +meta_html = f""" |
| 188 | +<section id='directive'><h3>Strategic Directive</h3> |
| 189 | +<p><b>Scope:</b> {e(directive['scope'])}</p> |
| 190 | +<div class='kv'><b>Outcomes</b><ul>{''.join(f'<li>{e(x)}</li>' for x in directive['outcomes'])}</ul></div> |
| 191 | +<div class='kv'><b>Do NOT</b><ul>{''.join(f'<li>{e(x)}</li>' for x in directive['doNot'])}</ul></div> |
| 192 | +</section> |
| 193 | +
|
| 194 | +<section id='audiences'><h3>Intended Audiences ({len(DOC['audiences'])})</h3><ul>{audiences_list}</ul></section> |
| 195 | +
|
| 196 | +<section id='regimes'><h3>Regulatory Regimes ({len(DOC['regimes'])})</h3><ul>{regimes_list}</ul></section> |
| 197 | +
|
| 198 | +<section id='indices'><h3>Performance & Civilizational Indices ({len(DOC['indices'])})</h3><ul>{indices_rows}</ul></section> |
| 199 | +
|
| 200 | +<section id='tiers'><h3>AI Risk / Containment Tiers T0-T4</h3><ul>{tiers_rows}</ul></section> |
| 201 | +
|
| 202 | +<section id='severities'><h3>Incident Severity Levels</h3><ul>{sev_rows}</ul></section> |
| 203 | +
|
| 204 | +<section id='investment'><h3>Investment Envelope</h3> |
| 205 | +<p><b>Total Range:</b> {e(invest['totalRange'])} · <b>Window:</b> {e(invest['programWindow'])} · <b>Currency:</b> {e(invest['currency'])}</p> |
| 206 | +<div class='kv'><b>Breakdown</b><ul>{invest_breakdown}</ul></div> |
| 207 | +</section> |
| 208 | +""" |
| 209 | + |
| 210 | + |
| 211 | +html = f"""<!doctype html> |
| 212 | +<html lang="en"><head><meta charset="utf-8"> |
| 213 | +<meta name="viewport" content="width=device-width, initial-scale=1"> |
| 214 | +<title>{e(DOC['title'])}</title> |
| 215 | +<style> |
| 216 | +:root {{ --bg:#0b0f14; --fg:#e6edf3; --muted:#9aa7b2; --acc:#58a6ff; --card:#11161d; --line:#23303d; }} |
| 217 | +* {{ box-sizing:border-box; }} |
| 218 | +body {{ background:var(--bg); color:var(--fg); font-family:-apple-system,Segoe UI,Roboto,Ubuntu,sans-serif; margin:0; line-height:1.5; }} |
| 219 | +header {{ padding:24px 40px; border-bottom:1px solid var(--line); background:#0d1218; }} |
| 220 | +header h1 {{ margin:0 0 4px 0; font-size:22px; }} |
| 221 | +header .meta {{ color:var(--muted); font-size:13px; }} |
| 222 | +.layout {{ display:grid; grid-template-columns:280px 1fr; gap:0; }} |
| 223 | +nav.toc {{ border-right:1px solid var(--line); padding:20px; position:sticky; top:0; height:100vh; overflow-y:auto; background:#0d1218; }} |
| 224 | +nav.toc h4 {{ color:var(--muted); font-size:12px; text-transform:uppercase; letter-spacing:.05em; margin:14px 0 6px; }} |
| 225 | +nav.toc ul {{ list-style:none; padding:0; margin:0; }} |
| 226 | +nav.toc li a {{ color:var(--fg); text-decoration:none; font-size:13px; display:block; padding:4px 6px; border-radius:4px; }} |
| 227 | +nav.toc li a:hover {{ background:#1a232e; color:var(--acc); }} |
| 228 | +main {{ padding:24px 40px; max-width:1200px; }} |
| 229 | +section.module, section {{ background:var(--card); border:1px solid var(--line); border-radius:8px; padding:18px 22px; margin-bottom:18px; }} |
| 230 | +section h3 {{ margin-top:0; color:var(--acc); border-bottom:1px solid var(--line); padding-bottom:6px; }} |
| 231 | +.sum {{ color:var(--muted); font-style:italic; }} |
| 232 | +.sec {{ border-left:3px solid var(--acc); padding:6px 12px; margin:10px 0; background:#0e141b; border-radius:0 6px 6px 0; }} |
| 233 | +.sec h4 {{ margin:4px 0 8px; color:#a5d6ff; font-size:14px; }} |
| 234 | +.kv {{ font-size:13px; margin:4px 0; color:#d0d7de; }} |
| 235 | +.kv b {{ color:#79c0ff; }} |
| 236 | +.kv ul {{ margin:4px 0 4px 18px; padding:0; }} |
| 237 | +.card {{ background:#0e141b; border:1px solid var(--line); border-radius:6px; padding:10px 12px; margin:8px 0; }} |
| 238 | +.card-head {{ font-weight:600; color:#a5d6ff; margin-bottom:6px; font-size:13px; }} |
| 239 | +table {{ width:100%; border-collapse:collapse; font-size:12px; }} |
| 240 | +th, td {{ border:1px solid var(--line); padding:6px 8px; text-align:left; vertical-align:top; }} |
| 241 | +th {{ background:#0e141b; color:var(--acc); }} |
| 242 | +tr:nth-child(even) td {{ background:#0d131a; }} |
| 243 | +pre {{ background:#0a0f15; border:1px solid var(--line); border-radius:4px; padding:8px; font-size:11px; overflow-x:auto; color:#d0d7de; margin:0; white-space:pre-wrap; }} |
| 244 | +.counts {{ display:flex; flex-wrap:wrap; gap:10px; margin:14px 0; }} |
| 245 | +.counts span {{ background:#0e141b; border:1px solid var(--line); padding:4px 10px; border-radius:14px; font-size:12px; color:var(--muted); }} |
| 246 | +.counts span b {{ color:var(--acc); }} |
| 247 | +code {{ background:#0e141b; padding:1px 4px; border-radius:3px; font-size:12px; }} |
| 248 | +@media (max-width:900px) {{ .layout {{ grid-template-columns:1fr; }} nav.toc {{ position:relative; height:auto; }} main {{ padding:20px; }} }} |
| 249 | +</style> |
| 250 | +</head><body> |
| 251 | +<header> |
| 252 | +<h1>{e(DOC['title'])}</h1> |
| 253 | +<div class="meta">docRef <b>{e(DOC['docRef'])}</b> · v{e(DOC['version'])} · {e(DOC['status'])}</div> |
| 254 | +<div class="meta">{e(DOC['classification'])}</div> |
| 255 | +<div class="meta">Horizon: {e(DOC['horizon'])} · API prefix: <code>{e(DOC['apiPrefix'])}</code> · builds on {' · '.join(e(b) for b in DOC['buildsOn'])}</div> |
| 256 | +<div class="counts"> |
| 257 | +{''.join(f"<span><b>{v}</b> {e(k)}</span>" for k,v in DOC['counts'].items())} |
| 258 | +</div> |
| 259 | +</header> |
| 260 | +<div class="layout"> |
| 261 | +<nav class="toc"> |
| 262 | +<h4>Executive</h4> |
| 263 | +<ul> |
| 264 | +<li><a href='#exec'>Executive Summary</a></li> |
| 265 | +<li><a href='#directive'>Strategic Directive</a></li> |
| 266 | +<li><a href='#audiences'>Audiences</a></li> |
| 267 | +<li><a href='#regimes'>Regulatory Regimes</a></li> |
| 268 | +<li><a href='#indices'>Indices</a></li> |
| 269 | +<li><a href='#tiers'>Risk/Containment Tiers</a></li> |
| 270 | +<li><a href='#severities'>Severities</a></li> |
| 271 | +<li><a href='#investment'>Investment</a></li> |
| 272 | +</ul> |
| 273 | +<h4>Modules (M1-M8)</h4> |
| 274 | +<ul>{toc_modules}</ul> |
| 275 | +<h4>Distinctive Arrays</h4> |
| 276 | +<ul>{toc_distinct}</ul> |
| 277 | +<h4>Whitepaper & Tables</h4> |
| 278 | +<ul> |
| 279 | +<li><a href='#report-sections-full'>Whitepaper Sections</a></li> |
| 280 | +<li><a href='#schemas'>Schemas</a></li> |
| 281 | +<li><a href='#code'>Code Skeletons</a></li> |
| 282 | +<li><a href='#kpis'>KPIs</a></li> |
| 283 | +<li><a href='#rcm'>Risk Control Matrix</a></li> |
| 284 | +<li><a href='#trace'>Traceability</a></li> |
| 285 | +<li><a href='#data-flows'>Data Flows</a></li> |
| 286 | +<li><a href='#regulators'>Regulators</a></li> |
| 287 | +<li><a href='#rollout-90'>90-Day Rollout</a></li> |
| 288 | +<li><a href='#evidence-pack'>Evidence Pack</a></li> |
| 289 | +</ul> |
| 290 | +</nav> |
| 291 | +<main> |
| 292 | +{exec_html} |
| 293 | +{meta_html} |
| 294 | +{modules_html} |
| 295 | +{distinctive_html} |
| 296 | +{report_full_html} |
| 297 | +{tail_html} |
| 298 | +</main> |
| 299 | +</div> |
| 300 | +</body></html> |
| 301 | +""" |
| 302 | + |
| 303 | +OUT.write_text(html, encoding="utf-8") |
| 304 | +print(f"WP-062 HTML written: {OUT} ({OUT.stat().st_size} bytes)") |
0 commit comments