"""Render the Cortex Bank knowledge base into realistic PDF documents.
Usage: python -m generator.render_pdfs (run from cortex/)
Outputs: pdfs/*.pdf, pdfs/manifest.json
"""
import json
from pathlib import Path
from reportlab.lib import colors
from reportlab.lib.enums import TA_RIGHT
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import mm
from reportlab.platypus import Image, Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
from content import bank as B
ROOT = Path(__file__).resolve().parent.parent
OUT = ROOT / "pdfs"
LOGO = ROOT / "docs" / "brand" / "cortex-logo.png"
NAVY = colors.HexColor("#0B1B3A")
ORANGE = colors.HexColor("#F97316")
GREY = colors.HexColor("#64748B")
LEVEL_LABEL = {0: "L0 PUBLIC / CONTRACTOR", 1: "L1 INTERNAL", 2: "L2 CONFIDENTIAL", 3: "L3 RESTRICTED", 4: "L4 HIGHLY RESTRICTED"}
ss = getSampleStyleSheet()
S = {
"title": ParagraphStyle("t", parent=ss["Title"], textColor=NAVY, fontSize=18, leading=22, alignment=0, spaceAfter=4),
"h": ParagraphStyle("h", parent=ss["Heading2"], textColor=NAVY, fontSize=12, spaceBefore=10, spaceAfter=4),
"p": ParagraphStyle("p", parent=ss["BodyText"], fontSize=9.5, leading=13),
"small": ParagraphStyle("s", parent=ss["BodyText"], fontSize=8, textColor=GREY),
"cls": ParagraphStyle("c", parent=ss["BodyText"], fontSize=8, textColor=ORANGE, alignment=TA_RIGHT),
}
DEPT = {d[0]: d for d in B.DEPARTMENTS}
REG = {r[0]: r for r in B.REGULATIONS}
CTL = {c[0]: c for c in B.CONTROLS}
RISK = {r[0]: r for r in B.RISKS}
SYS = {s[0]: s for s in B.SYSTEMS}
POL = {p[0]: p for p in B.POLICIES}
def reg(rid):
return f"{REG[rid][1]} ({rid})"
def ctl(cid):
return f"{CTL[cid][1]} ({cid})"
def sysn(sid):
return f"{SYS[sid][1]} ({sid})"
def dept(code):
return f"{DEPT[code][1]} ({code})"
def table(rows, widths, header=True):
t = Table(rows, colWidths=widths, repeatRows=1 if header else 0)
style = [("FONTSIZE", (0, 0), (-1, -1), 8), ("GRID", (0, 0), (-1, -1), 0.3, colors.HexColor("#CBD5E1")),
("VALIGN", (0, 0), (-1, -1), "TOP")]
if header:
style += [("BACKGROUND", (0, 0), (-1, 0), NAVY), ("TEXTCOLOR", (0, 0), (-1, 0), colors.white)]
t.setStyle(TableStyle(style))
return t
def P(text, style="p"):
return Paragraph(text, S[style])
def bullets(items):
return [P(f"• {i}") for i in items]
class Doc:
def __init__(self, doc_id, title, doc_type, dept_code, level, version, effective, owner=None):
self.id, self.title, self.type, self.dept, self.level = doc_id, title, doc_type, dept_code, level
self.version, self.effective = version, effective
self.owner = owner or DEPT[dept_code][2]
self.body = []
def meta(self):
return {"id": self.id, "title": self.title, "type": self.type, "dept": self.dept, "level": self.level,
"version": self.version, "effective": self.effective, "file": f"{self.id}.pdf"}
def render(self):
path = OUT / f"{self.id}.pdf"
cls = LEVEL_LABEL[self.level]
def frame(canvas, doc):
canvas.saveState()
if LOGO.exists():
canvas.drawImage(str(LOGO), 18 * mm, 277 * mm, 12 * mm, 12 * mm, mask="auto")
canvas.setFont("Helvetica-Bold", 11)
canvas.setFillColor(NAVY)
canvas.drawString(32 * mm, 284 * mm, "CORTEX BANK")
canvas.setFont("Helvetica", 7)
canvas.setFillColor(GREY)
canvas.drawString(32 * mm, 280 * mm, f"{B.BANK['tagline']} | {B.BANK['hq']}")
canvas.setFillColor(ORANGE)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawRightString(192 * mm, 284 * mm, cls)
canvas.setFillColor(GREY)
canvas.setFont("Helvetica", 7)
canvas.drawRightString(192 * mm, 280 * mm, f"{self.id} v{self.version}")
canvas.line(18 * mm, 276 * mm, 192 * mm, 276 * mm)
canvas.drawString(18 * mm, 10 * mm, f"{cls} - Synthetic document for demonstration. Not a real bank.")
canvas.drawRightString(192 * mm, 10 * mm, f"Page {doc.page}")
canvas.restoreState()
head = [P(self.title, "title"),
table([["Document ID", self.id, "Type", self.type],
["Owner", f"{self.owner}, {DEPT[self.dept][1]}", "Classification", cls],
["Version", self.version, "Effective", self.effective]],
[28 * mm, 62 * mm, 28 * mm, 56 * mm], header=False),
Spacer(1, 6)]
SimpleDocTemplate(str(path), pagesize=A4, topMargin=26 * mm, bottomMargin=18 * mm,
leftMargin=18 * mm, rightMargin=18 * mm, title=self.title,
author="Cortex Bank (synthetic)").build(head + self.body, onFirstPage=frame, onLaterPages=frame)
def approval(d, approver):
return [P("Approval", "h"), table([["Approved by", "Date"], [approver, d.effective]], [120 * mm, 54 * mm])]
def related(ids):
return [P("Related Documents", "h"), P(", ".join(ids))] if ids else []
def build_policy(p):
pid, title, dcode, regs, ctls, stmts, ver, eff, lvl = p
d = Doc(pid, title, "Policy", dcode, lvl, ver, eff)
sops = [s[0] for s in B.SOPS if pid in s[3]]
grds = [g[0] for g in B.GUARDRAILS if pid in g[3]]
risks = sorted({r for c in ctls for r in CTL[c][5]})
d.body += [P("1. Purpose", "h"),
P(f"This policy sets out Cortex Bank's requirements for {title.replace(' Policy', '')}. "
f"It is owned by the {d.owner} in {dept(dcode)} and applies to all staff, contractors and subsidiaries.")]
if regs:
d.body += [P("2. Regulatory Basis", "h"),
P("This policy implements the bank's obligations under " + "; ".join(reg(r) for r in regs) + "."),
*bullets(f"{REG[r][1]}: {REG[r][3]}" for r in regs)]
d.body += [P("3. Policy Statements", "h"), *bullets(stmts)]
if ctls:
d.body += [P("4. Key Controls", "h"),
P("Compliance with this policy is achieved through the following controls:"),
table([["Control", "Name", "Type", "Frequency", "Owner", "Mitigates"]] +
[[c, Paragraph(CTL[c][1], S["p"]), CTL[c][2], CTL[c][3], CTL[c][4], ", ".join(CTL[c][5])] for c in ctls],
[22 * mm, 62 * mm, 20 * mm, 22 * mm, 14 * mm, 34 * mm])]
if risks:
d.body += [P("5. Risks Addressed", "h"), P(", ".join(f"{RISK[r][1]} ({r})" for r in risks) + ".")]
if sops:
d.body += [P("6. Implementing Procedures", "h"), P("This policy is implemented by: " + ", ".join(sops) + ".")]
if grds:
d.body += [P("7. Applicable Standards", "h"), P("The following guardrail standards apply: " + ", ".join(grds) + ".")]
d.body += related(sops + grds + regs) + approval(d, "Board Risk Committee" if lvl >= 2 else DEPT[dcode][2])
return d
def build_sop(s):
sid, title, dcode, pols, systems, steps, ver, eff, lvl = s
d = Doc(sid, title, "Standard Operating Procedure", dcode, lvl, ver, eff)
legacy = [l for l in B.LEGACY_SOPS if l[6] == sid]
grds = [g[0] for g in B.GUARDRAILS if sid in g[3]]
d.body += [P("1. Purpose and Scope", "h"),
P(f"This procedure describes how {DEPT[dcode][1]} performs '{title}'. "
f"It implements " + ", ".join(f"{POL[p][1]} ({p})" for p in pols) + ".")]
if systems:
d.body += [P("2. Systems Used", "h"), *bullets(f"{sysn(x)}: {SYS[x][2]}" for x in systems)]
rows = [["Step", "Activity", "Controls"]]
for i, (text, cs) in enumerate(steps, 1):
rows.append([str(i), Paragraph(text, S["p"]), Paragraph("
".join(ctl(c) for c in cs) or "-", S["p"])])
d.body += [P("3. Procedure", "h"), table(rows, [12 * mm, 100 * mm, 62 * mm])]
if grds:
d.body += [P("4. Guardrails", "h"), P("This procedure is subject to: " + ", ".join(grds) + ".")]
vh = [["Version", "Effective", "Change"]]
for l in legacy:
vh.append([l[3], l[4], f"Original procedure ({l[0]}), retired {l[5]}."])
vh.append([ver, eff, "Current version." + (f" Supersedes {legacy[0][0]}." if legacy else "")])
d.body += [P("5. Version History", "h"), table(vh, [18 * mm, 24 * mm, 132 * mm])]
d.body += related(pols + grds + [l[0] for l in legacy]) + approval(d, DEPT[dcode][2])
return d
def build_legacy(l):
lid, title, dcode, ver, eff, retired, sup, summary, lvl = l
d = Doc(lid, title, "Standard Operating Procedure (Retired)", dcode, lvl, ver, eff)
d.body += [P("STATUS: RETIRED", "h"),
P(f"This procedure was in force from {eff} until {retired}. It is superseded by {sup}. Retained for record-keeping only."),
P("1. Procedure Summary", "h"), P(summary)] + related([sup])
return d
def build_guardrail(g):
gid, title, dcode, applies, rules, lvl = g
d = Doc(gid, title, "Guardrail Standard", dcode, lvl, "1.0", "2025-01-01")
d.body += [P("1. Purpose", "h"), P(f"This standard defines mandatory guardrails. Owner: {dept(dcode)}."),
P("2. Mandatory Rules", "h"), *bullets(rules),
P("3. Applies To", "h"), P(", ".join(applies) + ".")]
if gid == "GRD-004":
rows = [["Role", "Clearance", "Department scope"]] + [[r[1], f"L{r[2]}", ", ".join(r[3])] for r in B.ROLES]
d.body += [P("4. Role Access Matrix", "h"), table(rows, [70 * mm, 30 * mm, 74 * mm])]
return d
def build_kri(k):
kid, title, dcode, lvl, inds = k
d = Doc(kid, title, "KRI / KPI Framework", dcode, lvl, "2026.Q2", "2026-06-30")
rows = [["Indicator", "Name", "Measures", "Target", "Current", "Status"]]
rows += [[i[0], Paragraph(i[1], S["p"]), ", ".join(i[2]), i[3], i[4], i[5]] for i in inds]
breaches = [i for i in inds if i[5] == "Breach"]
d.body += [P("1. Purpose", "h"), P(f"Key indicators monitored by {dept(dcode)} and reported quarterly to the Board Risk Committee."),
P("2. Indicators (as at 30 June 2026)", "h"),
table(rows, [20 * mm, 62 * mm, 26 * mm, 20 * mm, 20 * mm, 26 * mm])]
if breaches:
d.body += [P("3. Breaches Requiring Action", "h"),
*bullets(f"{i[0]} ({i[1]}) is in breach: {i[4]} against a target of {i[3]}. Linked control: {', '.join(ctl(c) for c in i[2])}." for i in breaches)]
return d
def build_audit(a):
aid, title, date, lvl, scope, findings = a
d = Doc(aid, title, "Internal Audit Report", "IAU", lvl, "Final", date)
rating = "Unsatisfactory" if any(f[2] == "High" for f in findings) else "Needs Improvement"
d.body += [P("1. Executive Summary", "h"),
P(f"Internal Audit reviewed {', '.join(dept(s) for s in scope)}. Overall rating: {rating}. "
f"{len(findings)} finding(s) raised, reported to the Board Audit Committee."),
P("2. Findings", "h")]
for f in findings:
d.body += [P(f"{f[0]}: {f[1]}"),
P(f"Severity: {f[2]}. Control: {ctl(f[3])}. Owner: {dept(f[4])}. Remediation due: {f[5]}. Status: {f[6]}."),
Spacer(1, 4)]
return d
def build_regsum(r):
rid, short, full, summary = r
pols = [p for p in B.POLICIES if rid in p[3]]
d = Doc(f"RS-{rid[4:]}", f"Regulatory Obligation Summary: {short}", "Regulatory Summary", "LGL", 1, "2026.1", "2026-01-10")
d.body += [P("1. Regulation", "h"), P(f"{full} ({rid}). {summary}"),
P("2. How Cortex Bank Complies", "h"),
table([["Policy", "Title", "Owner"]] + [[p[0], Paragraph(p[1], S["p"]), p[2]] for p in pols],
[28 * mm, 110 * mm, 36 * mm])]
return d
def build_rcn(c):
cid, title, date, rid, summary, pols, actions = c
d = Doc(cid, title, "Regulatory Change Notice", "LGL", 1, "1.0", date)
d.body += [P("1. Change", "h"), P(f"{summary} Regulation: {reg(rid)}."),
P("2. Impacted Policies", "h"), *bullets(f"{POL[p][1]} ({p})" for p in pols),
P("3. Required Actions", "h"), *bullets(actions)]
return d
def build_history():
d = Doc("HIS-001", "Cortex Bank: A Century of Banking (1926-2026)", "Corporate History", "LGL", 1, "1.0", "2026-01-01")
d.body += [P("Milestones", "h"), table([["Year", "Event"]] + [[str(y), Paragraph(e, S["p"])] for y, e in B.HISTORY], [20 * mm, 154 * mm]),
P("Legacy Systems Still in Use", "h"), *bullets(f"{sysn(s[0])}: {s[2]}" for s in B.SYSTEMS if s[0] in ("SYS-CORE", "SYS-TRD"))]
return d
def build_org():
d = Doc("ORG-001", "Organisation & Department Mandates", "Organisation Chart", "HRS", 1, "2026.1", "2026-01-01")
d.body += [P("Departments", "h"),
table([["Code", "Department", "Head", "Mandate"]] + [[x[0], x[1], x[2], Paragraph(x[3], S["p"])] for x in B.DEPARTMENTS],
[14 * mm, 44 * mm, 40 * mm, 76 * mm])]
return d
def all_docs():
docs = [build_policy(p) for p in B.POLICIES] + [build_sop(s) for s in B.SOPS]
docs += [build_legacy(l) for l in B.LEGACY_SOPS] + [build_guardrail(g) for g in B.GUARDRAILS]
docs += [build_kri(k) for k in B.KRI_FRAMEWORKS] + [build_audit(a) for a in B.AUDIT_REPORTS]
docs += [build_regsum(r) for r in B.REGULATIONS] + [build_rcn(c) for c in B.CHANGE_NOTICES]
docs += [build_history(), build_org()]
return docs
def main():
OUT.mkdir(exist_ok=True)
docs = all_docs()
for d in docs:
d.render()
(OUT / "manifest.json").write_text(json.dumps([d.meta() for d in docs], indent=1))
print(f"Rendered {len(docs)} PDFs to {OUT}")
if __name__ == "__main__":
main()