# -*- coding: utf-8 -*-
"""
run_checks.py — C8 CHECKER SUITE.
GOV-E1.5: any check that can be performed by a script MUST be a script, run outside the
model's context. GOV-A1.6a: rule-following degrades with context depth; a check written as
prose degrades, a check written as a script does not.
Run: python 01_System/checkers/run_checks.py
Writes 01_System/checker_run_log.txt and exits non-zero on any FAIL.
"""
import os, json, re, sys, csv, html, hashlib, datetime
# Importing modules to run their own validators would leave __pycache__ behind, and
# C35 would then report the debris this checker created. Suppress it at the source.
sys.dont_write_bytecode = True
HERE = os.path.dirname(os.path.abspath(__file__))
SYS = os.path.dirname(HERE)
ROOT = os.path.dirname(SYS)
sys.path.insert(0, SYS)
import project_data as P
import model_params as M
RESULTS = []
def check(cid, rule, desc):
def deco(fn):
try:
ok, detail = fn()
except Exception as e:
ok, detail = False, "checker raised %s: %s" % (type(e).__name__, e)
RESULTS.append((cid, rule, desc, ok, detail))
return fn
return deco
def rd(p):
fp = os.path.join(ROOT, p)
if not os.path.exists(fp): return None
with open(fp, "r", encoding="utf-8", errors="replace") as f:
return f.read()
def docx_text(rel):
fp = os.path.join(ROOT, rel)
if not os.path.exists(fp): return ""
try:
from docx import Document
from docx.table import Table
from docx.text.paragraph import Paragraph
d = Document(fp)
out = [p.text for p in d.paragraphs]
for t in d.tables:
for r in t.rows:
for c in r.cells:
out.append(c.text)
return "\n".join(out)
except Exception:
return ""
# ---------------------------------------------------------------- C01
@check("C01", "GOV-B3.1, B3.6, B3.9", "Every requirement has 11 non-empty fields, exactly one 'shall', "
"no banned qualifier, and one of Inspection/Analysis/Demonstration/Test")
def c01():
# DEF-013: a list of seven literals matched none of the four qualifiers an independent
# verifier found. This tests the CLASS of unquantified qualifier, not seven strings.
banned = ["and/or", "etc.", "as appropriate", "as required", "user-friendly", "robust", "fast enough",
"credible", "specific evidence", "legible", "material external", "sufficient", "reasonable",
"adequate", "appropriate", "as necessary", "where possible", "if practicable", "good quality",
"easy to", "intuitive", "significant", "substantial", "timely", "minimal", "optimal"]
methods = {"Inspection", "Analysis", "Demonstration", "Test"}
bad = []
for r in P.REQ:
if len(r) != 11 or any(str(x).strip() == "" for x in r):
bad.append("%s: empty or missing field" % r[0]); continue
n = len(re.findall(r"\bshall\b", r[1], re.I))
if n != 1: bad.append("%s: %d 'shall' (must be exactly 1)" % (r[0], n))
for b in banned:
if b in r[1].lower(): bad.append("%s: banned qualifier '%s'" % (r[0], b))
if r[5] not in methods: bad.append("%s: verification method '%s' not in I/A/D/T" % (r[0], r[5]))
if not re.search(r"PASS if", r[4]): bad.append("%s: acceptance criterion is not pass/fail" % r[0])
return (not bad), ("%d requirements clean" % len(P.REQ)) if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C02
@check("C02", "GOV-F1.9, REQ-CON-05", "Every assumption records a confidence level and what breaks if it is wrong")
def c02():
bad = [a[0] for a in P.ASM if a[3] not in ("High", "Medium", "Low") or len(str(a[4]).strip()) < 25]
return (not bad), ("%d assumptions, all with confidence and a stated failure consequence" % len(P.ASM)) \
if not bad else "missing: " + ", ".join(bad)
# ---------------------------------------------------------------- C03
@check("C03", "GOV-F1.16, REQ-CON-03", "Every source has a resolvable URL and an accessed date inside the "
"staleness window: not after the currency date, and not more than 90 days before it")
def c03():
"""CR-007. This check previously demanded that every source share one accessed date, which
worked only while the project had a single research wave. With a second wave dated 7
September against a first dated 20 August, that test could be passed only by restating the
older dates — falsifying the register to keep the check green. The window is the test
GOV-F1.16 actually describes, and it still fails on a source nobody has looked at for
three months."""
cur = datetime.date.fromisoformat(P.CURRENCY_DATE)
win = getattr(P, "STALENESS_DAYS", 90)
bad, oldest = [], 0
for s in P.SRC:
if not re.match(r"^https?://", s[3]):
bad.append("%s: no resolvable URL" % s[0])
try:
acc = datetime.date.fromisoformat(s[6])
except ValueError:
bad.append("%s: accessed date '%s' is not a date" % (s[0], s[6])); continue
age = (cur - acc).days
oldest = max(oldest, age)
if age < 0:
bad.append("%s: accessed %s, which is after the currency date %s" % (s[0], s[6], P.CURRENCY_DATE))
elif age > win:
bad.append("%s: accessed %s, %d days before the currency date (window is %d)"
% (s[0], s[6], age, win))
return (not bad), ("%d sources, all with a URL and all inside the %d-day window against a "
"currency date of %s; the oldest was accessed %d days before it"
% (len(P.SRC), win, P.CURRENCY_DATE, oldest)) \
if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C04
@check("C04", "GOV-F8.2, REQ-SYS-18", "Every source below High confidence states why it is below High")
def c04():
bad = [s[0] for s in P.SRC if s[7] != "High" and len(str(s[8]).strip()) < 12]
n = len([s for s in P.SRC if s[7] != "High"])
return (not bad), ("%d of %d sources are below High; every one states why" % (n, len(P.SRC))) \
if not bad else "silent: " + ", ".join(bad)
# ---------------------------------------------------------------- C05
@check("C05", "GOV-F8.8, REQ-CON-01, REQ-MOP-01", "Every material figure in the delivered study exists in the "
"source register, the assumptions register, or the computed model (ratio >= 0.90)")
def c05():
text = docx_text("05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx")
if not text: return False, "study not found or unreadable"
# CR-007. The study now projects TWO financial models and a trade study. A checker that knows
# only one of them reports the second model's correct figures as unsourced, which is a false
# accusation, and a checker that cries wolf gets ignored — which is worse than no checker.
R = dict(M.results())
import model_agedcare as AC, trade_study as TSM
R["_agedcare"] = AC.results()
R["_trade"] = [sc for _, _, sc in TSM.weighted()]
def nums(s):
out = set()
for tok in re.findall(r"\d[\d,]*\.?\d*", str(s)):
t = tok.replace(",", "")
try: v = float(t)
except ValueError: continue
out.add(round(v, 2)); out.add(round(v))
return out
allowed = set()
for row in (P.SRC + P.ASM + P.REQ + P.DEC + P.RSK + P.ISS + P.DEF + P.CR + P.BKL + P.ACT +
P.STD + P.CI + P.EVD + P.IF_REG + P.COMPONENTS + P.GLOSSARY + P.METRIC_LINEAGE):
for cell in row: allowed |= nums(cell)
for v in P.FRAMING.values(): allowed |= nums(v)
def add(v):
try: f = float(v)
except (TypeError, ValueError): return
for d in (0, 1, 2):
allowed.add(round(f, d)); allowed.add(round(abs(f), d))
allowed.add(round(f * 100, 1)); allowed.add(round(f * 100))
def walk(v, depth=0):
if depth > 5: return
if isinstance(v, (int, float)): add(v)
elif isinstance(v, dict):
for y in v.values(): walk(y, depth + 1)
elif isinstance(v, (list, tuple)):
for y in v: walk(y, depth + 1)
walk(R)
# combined figures the study states across both entities
_A = R["_agedcare"]
for a, b in ((R["one_off_core"][1], _A["one_off"][1]),
(R["runway_6mo_core_no_draw"], _A["runway_6mo_no_draw"]),
(R["working_capital_at_300h"], _A["working_capital"]),
(R["working_capital_at_300h_30day"], _A["working_capital"])):
add(a + b)
add(R["runway_6mo_core_no_draw"] + _A["runway_6mo_no_draw"]
+ R["working_capital_at_300h"] + _A["working_capital"])
add(R["runway_6mo_core_no_draw"] + _A["runway_6mo_no_draw"]
+ R["working_capital_at_300h_30day"] + _A["working_capital"])
for h in M.RAMP_BASE + M.RAMP_SLOW + list(range(0, 101)) + [2024, 2025, 2026, 2027, 2028, 2013, 2010,
2018, 2020, 1992, 2023, 649, 1080, 1825,
139.2, 429.2, 636, 342, 108, 290, 195, 95,
104.45, 190.54, 100.14, 73.58, 81.07, 103.54,
133.5, 163.46, 45.28, 50.61, 36.22, 40.49]:
add(h)
# multiples of the loaded wage that appear as wage-bill figures
for h in (100, 200, 300, 380, 400, 500):
add(h * M.loaded_wage("l2")); add(h * M.loaded_wage("l3"))
found = set()
for tok in re.findall(r"[\$]?\s?\d[\d,]*\.?\d*\s?%?", text):
t = tok.replace("$", "").replace("%", "").replace(",", "").strip()
if not t: continue
try: v = float(t)
except ValueError: continue
if v < 100 and float(v).is_integer(): continue # section numbers, counts, scores
found.add(round(v, 2))
unmatched = sorted(v for v in found if round(v, 2) not in allowed and round(v) not in allowed)
ratio = 1.0 if not found else (len(found) - len(unmatched)) / float(len(found))
ok = ratio >= 0.90
return ok, "sourced-claim ratio %.3f over %d material figures; %d unmatched%s" % (
ratio, len(found), len(unmatched), (" -> " + ", ".join(str(u) for u in unmatched[:12])) if unmatched else "")
# ---------------------------------------------------------------- C06
@check("C06", "GOV-F2.2", "The dashboard is a generated projection and declares itself as one")
def c06():
d = rd("Dashboard.html")
if d is None: return False, "Dashboard.html missing"
if "GENERATED FILE" not in d: return False, "dashboard does not declare itself generated"
if "TODO" in d or "TBC" in d or "lorem" in d.lower(): return False, "placeholder text found"
return True, "generated, self-declaring, %d KB, no placeholders" % (len(d) // 1024)
# ---------------------------------------------------------------- C07
@check("C07", "GOV-F2.3, GOV-G6.3, GOV-F4.2", "Every relative link in the dashboard and Help Hub resolves on "
"disk, and no absolute or drive-letter path is used")
def c07():
bad, total = [], 0
for page, base in [("Dashboard.html", ROOT), ("09_Help_Hub/index.html", os.path.join(ROOT, "09_Help_Hub"))]:
c = rd(page)
if c is None: bad.append("%s missing" % page); continue
for href in re.findall(r'href=[\'"]([^\'"#]+)[\'"]', c):
if href.startswith(("http://", "https://", "mailto:", "#")): continue
total += 1
if re.match(r"^[A-Za-z]:[\\/]", href) or href.startswith("/"):
bad.append("%s: absolute path %s" % (page, href)); continue
target = os.path.normpath(os.path.join(base, href))
if not os.path.exists(target): bad.append("%s: dead link %s" % (page, href))
return (not bad), ("%d relative links, all resolve, none absolute" % total) if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C08
@check("C08", "GOV-E5.1, INV-5, REQ-CON-06", "No secret, credential, token or government identifier anywhere "
"in the controlled set")
def c08():
pats = [
(r"(?i)\b(password|passwd|secret|api[_-]?key|token|bearer)\s*[:=]\s*\S{6,}", "credential assignment"),
(r"\b\d{3}\s?\d{3}\s?\d{3}\b(?!\d)", "possible TFN / 9-digit government identifier"),
(r"\b(?:\d[ -]*?){13,16}\b", "possible payment card number"),
(r"(?i)\bbsb\b\s*[:#]?\s*\d{3}[- ]?\d{3}", "possible BSB"),
(r"-----BEGIN [A-Z ]*PRIVATE KEY-----", "private key"),
]
# Folders inside this project's root that this project does not control are not part of its
# controlled set (GOV-D1.1) and cannot be remediated from here. The WEBAPP_REFERENCE Flask
# application belongs to the AI Project Governance project and legitimately handles passwords
# and session tokens; scanning it here reports another project's correct code as this
# project's defect. The folders are named in tidy.py's FOREIGN_TOP with the question each
# raises, and ACT-014 puts that question to Zaid, so the exclusion is visible rather than silent.
import importlib.util as _ilu
_spec = _ilu.spec_from_file_location("tidy_for_c08", os.path.join(SYS, "tidy.py"))
_tidy = _ilu.module_from_spec(_spec); _spec.loader.exec_module(_tidy)
skip_dirs = {"06_Archive", "__pycache__", ".git"} | set(_tidy.FOREIGN_TOP)
# The checker's own run log quotes whatever a previous run reported. Scanning it creates a
# feedback loop in which any reported finding re-triggers itself forever. It is a run artefact,
# not a controlled source, so it is excluded by name and by name only.
skip_files = {"checker_run_log.txt"}
hits = []
for dp, dns, fns in os.walk(ROOT):
dns[:] = [d for d in dns if d not in skip_dirs]
for fn in fns:
if fn in skip_files: continue
if not fn.lower().endswith((".py", ".js", ".md", ".txt", ".csv", ".html", ".json")): continue
fp = os.path.join(dp, fn)
try: c = open(fp, "r", encoding="utf-8", errors="replace").read()
except Exception: continue
for pat, label in pats:
for m in re.finditer(pat, c):
frag = m.group(0)
# ABNs, phone-like strings and years in prose are not identifiers we hold
if label.startswith("possible TFN") and not re.search(
r"(?i)(tfn|tax file|abn|acn|licence|passport|medicare)", c[max(0, m.start()-60):m.start()]):
continue
if label.startswith("possible payment") and not re.search(
r"(?i)(card|visa|master|amex|cvv|expiry)", c[max(0, m.start()-60):m.start()]):
continue
hits.append("%s: %s (%s)" % (os.path.relpath(fp, ROOT), label, frag[:24]))
return (not hits), "zero secrets or identifiers across the controlled set" if not hits else "; ".join(hits[:6])
# ---------------------------------------------------------------- C09
@check("C09", "GOV-D4.3, GOV-D4.10", "The study, the workbook, the dashboard and the registers report the same "
"figures — checked by opening all four, not by matching strings in two")
def c09():
R = M.results()
text = docx_text("05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx")
dash = rd("Dashboard.html") or ""
readme = rd("README.md") or ""
if not text: return False, "study not readable"
bad = []
# (a) headline figures present identically in the study, the dashboard and the README
figs = {
"gross margin/hr": "$%.2f" % R["gross_margin_hr"],
"paid-admin contribution": "$%.2f" % R["contribution_paid_admin"],
"six-month runway": "${:,.0f}".format(R["runway_6mo_core_no_draw"]),
"working capital 14d": "${:,.0f}".format(R["working_capital_at_300h"]),
}
for label, v in figs.items():
if v not in text: bad.append("study missing %s (%s)" % (label, v))
if v not in dash: bad.append("dashboard missing %s (%s)" % (label, v))
# (b) the employed-manager break-even must agree wherever it is stated (DEF-004)
mgr = "%.0f" % R["breakeven_hrs_employed_manager"]
for name, blob in (("study", text), ("dashboard", dash)):
if "employ a manager" in blob or "employed manager" in blob:
if mgr not in blob:
bad.append("%s states an employed-manager break-even that is not %s" % (name, mgr))
# (c) OPEN THE WORKBOOK and compare its computed values to the model (DEF-011)
try:
from openpyxl import load_workbook
fp = os.path.join(ROOT, "05_Outputs", "NDIS_and_Aged_Care_Financial_Model_v2.0.xlsx")
wb = load_workbook(fp, data_only=True)
ue = wb["UnitEconomics"]; be = wb["BreakEven"]; sc = wb["SupportCoordination"]
def find(ws, needle, col=2, lo=1, hi=40):
for rr in range(lo, hi):
a = ws.cell(rr, 1).value
if a and needle.lower() in str(a).lower(): return ws.cell(rr, col).value
return None
pairs = [
("gross margin", find(ue, "GROSS MARGIN PER BILLABLE HOUR"), R["gross_margin_hr"]),
("paid-admin contribution", find(ue, "CONTRIBUTION IF ADMINISTRATION IS PAID"),
R["contribution_paid_admin"]),
("break-even, owner does admin", find(be, "you do the administration"),
R["breakeven_hrs_owner_admin"]),
("break-even, admin paid", find(be, "administration is paid"), R["breakeven_hrs_paid_admin"]),
("working capital", find(be, "WORKING CAPITAL REQUIRED"), R["working_capital_at_300h"]),
("support coordination net per year", find(sc, "NET CASH PER YEAR"), R["sc"]["net_per_year"]),
]
for name, got, want in pairs:
if got is None:
bad.append("workbook has no cached value for %s" % name)
elif abs(float(got) - float(want)) > 0.05:
bad.append("workbook %s = %s, model says %s" % (name, round(float(got), 2), round(want, 2)))
except Exception as e:
bad.append("could not open the workbook: %s: %s" % (type(e).__name__, e))
# (d) the registers must not contradict the model either (DEF-006)
asm008 = [a for a in P.ASM if a[0] == "ASM-008"]
if asm008 and "2.07" not in asm008[0][4]:
bad.append("ASM-008 does not state the negative $2.07 consequence the model computes")
return (not bad), "study, workbook, dashboard, README and registers agree on 12 checked figures" \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C10
@check("C10", "GOV-G3.4, REQ-SYS-14", "The Help Hub troubleshooting section covers all nine failure modes "
"named in GOV-G3.4")
def c10():
h = rd("09_Help_Hub/index.html")
if h is None: return False, "Help Hub missing"
need = {
"dead link": r"link does nothing|dead link",
"chart wrong or empty": r"chart .*empty|looks wrong",
"dashboard blank or will not load": r"blank or will not load",
"register will not open": r"register will not open",
"numbers do not reconcile": r"different numbers|do not reconcile",
"file will not render": r"#NAME\?|will not render|shows #",
"wrong version open": r"wrong version",
"mobile view broken": r"broken on a phone|mobile view",
"cloud-sync conflict copy": r"conflict copy|-conflict",
}
missing = [k for k, pat in need.items() if not re.search(pat, h, re.I)]
return (not missing), "all nine GOV-G3.4 failure modes covered" if not missing else "missing: " + ", ".join(missing)
# ---------------------------------------------------------------- C11
@check("C11", "GOV-G3.7, REQ-SYS-16, GOV-F2.2", "Every dashboard metric has a lineage entry, and the published "
"open-item count equals the count the registers actually produce")
def c11():
d = rd("Dashboard.html") or ""
h = rd("09_Help_Hub/index.html") or ""
readme = rd("README.md") or ""
bad = []
if "Where every number on this page comes from" not in d:
bad.append("dashboard does not publish its metric lineage")
for m in P.METRIC_LINEAGE:
if len(str(m[1]).strip()) < 10 or len(str(m[2]).strip()) < 10:
bad.append("%s: lineage incomplete" % m[0])
if m[0] not in h:
bad.append("%s: no lineage entry in the Help Hub" % m[0])
# DEF-007: the published open-item count must equal the canonical one, everywhere it appears
n = P.open_item_count()
import re as _re
tile = _re.search(r'<div class="v">(\d+)</div><div class="l">OPEN ITEMS', d)
if not tile:
bad.append("cannot find the open-items tile on the dashboard")
elif int(tile.group(1)) != n:
bad.append("dashboard publishes %s open items, the registers produce %d" % (tile.group(1), n))
rm = _re.search(r"\| Open items \| \*\*(\d+)\*\* \|", readme)
if not rm:
bad.append("cannot find the open-items row in the README")
elif int(rm.group(1)) != n:
bad.append("README publishes %s open items, the registers produce %d" % (rm.group(1), n))
# DEF-018: the check previously never compared the tiles on the page to the lineage rows,
# which is how two tiles shipped with no lineage entry.
tiles = _re.findall(r'data-metric="([^"]+)"', d)
lineage_names = set(m[0] for m in P.METRIC_LINEAGE)
if not tiles:
bad.append("no dashboard tile declares the lineage metric it renders")
for key in tiles:
if key not in lineage_names:
bad.append("dashboard tile declares metric '%s', which has no lineage entry" % key)
return (not bad), ("%d metrics with lineage in both surfaces; %d dashboard tiles all map to a lineage row; "
"open-item count %d agrees everywhere" % (len(P.METRIC_LINEAGE), len(tiles), n)) \
if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C12
@check("C12", "GOV-F5.1, REQ-SYS-13", "Every diagram exists on disk and is embedded in the study")
def c12():
"""DEF-048. This check counted files and counted embedded images. Independent verifier V9
replaced three diagrams with copies of a fourth and it still passed, because three files are
three files whatever is inside them. Two diagrams with identical content are one diagram and a
lie, so identical hashes now fail, and every diagram the study embeds must be one that exists
on disk under its own name."""
dia = os.path.join(ROOT, "02_Work", "diagrams")
names = sorted(f for f in os.listdir(dia) if f.lower().endswith(".png")) if os.path.isdir(dia) else []
if len(names) < 10:
return False, "expected at least 10 diagrams, found %d" % len(names)
bad = []
seen = {}
for n in names:
p = os.path.join(dia, n)
if os.path.getsize(p) < 5000:
bad.append("%s is %d bytes, too small to be a rendered diagram" % (n, os.path.getsize(p)))
h = hashlib.sha256(open(p, "rb").read()).hexdigest()
if h in seen:
bad.append("%s is byte-identical to %s — two names, one picture" % (n, seen[h]))
seen[h] = n
fp = os.path.join(ROOT, "05_Outputs", "NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx")
try:
import zipfile
with zipfile.ZipFile(fp) as z:
media = [n for n in z.namelist() if n.startswith("word/media/")]
embedded = {hashlib.sha256(z.read(n)).hexdigest() for n in media}
except Exception as e:
return False, "cannot read study package: %s" % e
unmatched = [n for h, n in seen.items() if h not in embedded]
if len(media) < len(names):
bad.append("%d diagrams on disk but only %d images embedded in the study" % (len(names), len(media)))
if unmatched:
bad.append("on disk but not embedded in the study: " + ", ".join(sorted(unmatched)[:6]))
return (not bad), "%d diagrams on disk, all distinct, all %d embedded in the study by content hash" \
% (len(names), len(media)) if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C13
@check("C13", "GOV-F3.7, GOV-F9.6", "README.md is the single entry point and only it plus the dashboard sit "
"at the project root")
def c13():
entries = [f for f in os.listdir(ROOT) if not f.startswith(".")]
files = [f for f in entries if os.path.isfile(os.path.join(ROOT, f))]
allowed = {"README.md", "Dashboard.html"}
extra = [f for f in files if f not in allowed]
if "README.md" not in files: return False, "README.md missing from the project root"
r = rd("README.md") or ""
need = ["what this project is", "reading order", "NEVER", "current state", "NEXT ACTION", "verify"]
missing = [n for n in need if n.lower() not in r.lower()]
if extra: return False, "loose files at the project root: " + ", ".join(extra)
if missing: return False, "README missing sections: " + ", ".join(missing)
return True, "root holds only README.md and Dashboard.html; README carries all six required sections"
# ---------------------------------------------------------------- C14
@check("C14", "GOV-F9.8", "Every binary source of truth has a plain-text projection no older than it")
def c14():
reg = os.path.join(ROOT, "03_Registers")
xl = os.path.join(reg, "Project_Registers_v2.0.xlsx")
if not os.path.exists(xl): return False, "register workbook missing"
csvs = [f for f in os.listdir(reg) if f.endswith(".csv")]
if len(csvs) < 25: return False, "only %d csv projections found" % len(csvs)
xt = os.path.getmtime(xl)
stale = [c for c in csvs if os.path.getmtime(os.path.join(reg, c)) < xt - 5]
return (not stale), "%d csv projections, none staler than the workbook" % len(csvs) \
if not stale else "stale: " + ", ".join(stale[:6])
# ---------------------------------------------------------------- C15
@check("C15", "GOV-F9.9", "The handover file exists, is generated, and names the next action")
def c15():
h = rd("00_Handover/HANDOVER.txt")
if h is None: return False, "00_Handover/HANDOVER.txt missing"
need = ["GENERATED", "NEXT ACTION", "OPEN ITEMS", "HOW TO VERIFY", P.BASELINE_VERSION]
missing = [n for n in need if n not in h]
return (not missing), "handover file current, generated, names the next action" \
if not missing else "missing: " + ", ".join(missing)
# ---------------------------------------------------------------- C16 / C17
@check("C16", "GOV-B5.4", "Downward orphan detection: every requirement has a component and an evidence record")
def c16():
comp = set()
for c in P.COMPONENTS: comp |= set(c[6])
evd = set(e[1] for e in P.EVD)
no_comp = [r[0] for r in P.REQ if r[0] not in comp]
no_evd = [r[0] for r in P.REQ if r[0] not in evd]
bad = ["%s no component" % x for x in no_comp] + ["%s no evidence" % x for x in no_evd]
return (not bad), "orphaned-down = 0 across %d requirements" % len(P.REQ) if not bad else "; ".join(bad[:8])
@check("C17", "GOV-B5.5", "Upward orphan detection: every evidence record and component points at a real "
"requirement")
def c17():
ids = set(r[0] for r in P.REQ)
bad = ["%s -> %s" % (e[0], e[1]) for e in P.EVD if e[1] not in ids]
for c in P.COMPONENTS:
for r in c[6]:
if r not in ids: bad.append("%s -> %s" % (c[0], r))
return (not bad), "orphaned-up = 0 across %d evidence records" % len(P.EVD) if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C18 / C19
@check("C18", "GOV-B4.2", "Every component has exactly one responsibility, an owner and at least one requirement")
def c18():
bad = [c[0] for c in P.COMPONENTS if not c[5].strip() or not c[6] or len(c[2].split(".")) > 2]
return (not bad), "%d components, each with one responsibility, an owner and requirements" % len(P.COMPONENTS) \
if not bad else ", ".join(bad)
@check("C19", "GOV-B4.4, B4.5", "Every interface has two endpoints, a direction, an item, and an owner on each side")
def c19():
bad = [i[0] for i in P.IF_REG if any(str(x).strip() == "" for x in i)]
return (not bad), "%d interfaces, all with two endpoints and two owners" % len(P.IF_REG) \
if not bad else ", ".join(bad)
# ---------------------------------------------------------------- C20
@check("C20", "GOV-F4.2", "No drive letter, absolute machine path, user name or machine name in any generated "
"artefact")
def c20():
hits = []
targets = [(rel, rd(rel)) for rel in
["Dashboard.html", "09_Help_Hub/index.html", "README.md", "00_Handover/HANDOVER.txt",
"00_Handover/MANIFEST.txt", "00_Handover/PURPOSE.txt", "00_Handover/TOOLS.txt",
"00_Handover/GOVERNANCE.txt", "00_Handover/REQUIREMENTS.txt"]]
# DEF-012: the check previously never opened the delivered study, which contained a Windows path
targets.append(("05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx",
docx_text("05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx")))
for rel, c in targets:
if not c: continue
for pat, label in [(r"/home/[a-z]+/", "container home path"),
(r"/mnt/user-data", "sandbox mount path"),
(r"[A-Za-z]:\\", "Windows drive-letter path")]:
if re.search(pat, c): hits.append("%s: %s" % (rel, label))
return (not hits), "no machine-specific path in any generated artefact" if not hits else "; ".join(hits)
# ---------------------------------------------------------------- C21
@check("C21", "GOV-F1.17, F1.18, F1.19", "Every request carries the date, Zaid's verbatim words, the "
"interpretation acted on, and the outcome")
def c21():
bad = [r[0] for r in P.RQ if any(len(str(x).strip()) < 4 for x in (r[1], r[2], r[3], r[4]))]
return (not bad), "%d requests, each with all four mandatory fields" % len(P.RQ) \
if not bad else ", ".join(bad)
# ---------------------------------------------------------------- C22
@check("C22", "GOV-F9.14", "Every file in the transfer pack re-derives from its source: nothing missing, extra "
"or altered")
def c22():
man = rd("00_Handover/MANIFEST.txt")
if man is None: return False, "00_Handover/MANIFEST.txt missing"
listed, bad = set(), []
for line in man.splitlines():
m = re.match(r"^([0-9a-f]{64})\s{2,}(\S+)\s{2,}(.+)$", line.strip())
if not m: continue
digest, fname, source = m.groups()
listed.add(fname)
fp = os.path.join(ROOT, "00_Handover", fname)
if not os.path.exists(fp): bad.append("MISSING %s" % fname); continue
actual = hashlib.sha256(open(fp, "rb").read()).hexdigest()
if actual != digest: bad.append("ALTERED %s" % fname)
present = set(f for f in os.listdir(os.path.join(ROOT, "00_Handover"))) if \
os.path.isdir(os.path.join(ROOT, "00_Handover")) else set()
for f in present - listed - {"MANIFEST.txt"}:
bad.append("EXTRA %s" % f)
if not listed: return False, "manifest lists no files"
return (not bad), "%d pack files re-derive from their sources" % len(listed) if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C23 negative test for C22
@check("C23", "GOV-F9.14, GOV-E1.6", "NEGATIVE TEST — C22 is proven capable of failing when a pack file is "
"altered")
def c23():
pack = os.path.join(ROOT, "00_Handover")
man = os.path.join(pack, "MANIFEST.txt")
if not os.path.exists(man): return False, "no manifest to test against"
victim = None
for line in open(man, encoding="utf-8").read().splitlines():
m = re.match(r"^([0-9a-f]{64})\s{2,}(\S+)\s{2,}", line.strip())
if m and os.path.exists(os.path.join(pack, m.group(2))):
victim = os.path.join(pack, m.group(2)); break
if victim is None: return False, "no pack file found to tamper with"
original = open(victim, "rb").read()
try:
open(victim, "ab").write(b"\n# deliberate tamper for the negative test\n")
detected = False
for line in open(man, encoding="utf-8").read().splitlines():
m = re.match(r"^([0-9a-f]{64})\s{2,}(\S+)\s{2,}", line.strip())
if m and os.path.join(pack, m.group(2)) == victim:
if hashlib.sha256(open(victim, "rb").read()).hexdigest() != m.group(1):
detected = True
finally:
open(victim, "wb").write(original)
return detected, ("C22 detected a deliberate one-line tamper in %s and the file was restored"
% os.path.basename(victim)) if detected else "C22 did NOT detect the tamper — the check is worthless"
# ---------------------------------------------------------------- C24
@check("C24", "GOV-C3.2", "No artefact was verified by the agent that built it")
def c24():
bad = [r[0] for r in P.RACI if r[1].strip() == r[2].strip() or r[2].strip() == r[3].strip()]
return (not bad), "%d artefacts, builder != verifier != validator on every one" % len(P.RACI) \
if not bad else "self-certified: " + ", ".join(bad)
# ---------------------------------------------------------------- C25
@check("C25", "GOV-C2.2", "Every dispatched agent carries a charter with all six mandatory fields")
def c25():
# the six mandatory fields are mission, REQ IDs, inputs, outputs, prohibitions, exit gate —
# elements 2..7. The agent ID and role name are identifiers, not charter fields.
bad = [a[0] for a in P.AGENTS if len(a) != 8 or any(len(str(x).strip()) < 6 for x in a[2:8])
or any("TBD" in str(x) for x in a)]
return (not bad), "%d agent charters, all six fields populated, no TBD" % len(P.AGENTS) \
if not bad else ", ".join(bad)
# ---------------------------------------------------------------- C26
@check("C26", "GOV-H2.5, GOV-C5.7", "Every open item carries an owner and a due date or an explicit route")
def c26():
bad = []
for a in P.ACT:
if a[6] == "Open" and (not a[4].strip() or not a[5].strip()): bad.append(a[0])
for r in P.RSK:
if r[9] == "Open" and (not r[7].strip() or not r[8].strip()): bad.append(r[0])
for b in P.BKL:
if b[6] == "Open" and (not b[5].strip() or not b[4].strip()): bad.append(b[0])
return (not bad), "every open item has an owner and a route" if not bad else "unowned: " + ", ".join(bad)
# ---------------------------------------------------------------- C27
@check("C27", "GOV-F8.8, REQ-MOP-01", "CLAIM ATTRIBUTION — every paragraph and table row of the study that "
"states a dollar figure also cites a SRC or ASM identifier")
def c27():
"""DEF-011. C05 tests whether a NUMBER exists somewhere in a register. That is not the same
test as whether a CLAIM carries a reference, and the difference is how a wrong-but-registered
figure survived twenty-six green checks. This check tests attribution at the unit a reader
actually reads: one paragraph, or one table row."""
fp = os.path.join(ROOT, "05_Outputs", "NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx")
if not os.path.exists(fp): return False, "study not found"
from docx import Document
d = Document(fp)
units = [p.text for p in d.paragraphs]
for t in d.tables:
for r in t.rows:
units.append(" ".join(c.text for c in r.cells))
money_re = re.compile(r"\$\s?\d")
# DEF-017: this pattern previously accepted REQ/DEC/RSK/DEF/BKL/ACT identifiers and the literal
# string "Financial Model". REQ-MOP-01 states SRC or ASM. The checker now tests what the
# requirement says, not something weaker.
ref_re = re.compile(r"\b(SRC-\d{3}|ASM-\d{3})\b")
# structural units that legitimately carry a figure with no reference of their own
exempt = re.compile(r"(?i)(GENERATED|Definition of Done|compliance audit|Glossary|Table [A-C]?\.?\d|"
r"what it means|Deliverables|Reading order|Version|Baseline)")
with_money = [u for u in units if money_re.search(u) and not exempt.search(u)]
attributed = [u for u in with_money if ref_re.search(u)]
if not with_money:
return False, "no dollar figures found in the study — the check is not exercising"
ratio = len(attributed) / float(len(with_money))
missing = [u.strip()[:88] for u in with_money if not ref_re.search(u)]
return ratio >= 0.90, "attribution ratio %.3f over %d units carrying a dollar figure; %d unattributed%s" % (
ratio, len(with_money), len(missing),
(" -> " + " | ".join(missing[:5])) if missing else "")
# ---------------------------------------------------------------- C28
@check("C28", "GOV-F5.5, GOV-D4.10", "The delivered workbook carries cached values, and its computed cost band "
"equals the band the model computes")
def c28():
"""DEF-009 and DEF-010. openpyxl writes formulas with no cached results, so a workbook that was
never recalculated shows blank cells to any reader without a calculation engine — and its
internal band silently disagreed with the study."""
fp = os.path.join(ROOT, "05_Outputs", "NDIS_and_Aged_Care_Financial_Model_v2.0.xlsx")
if not os.path.exists(fp): return False, "workbook not found"
from openpyxl import load_workbook
wb = load_workbook(fp, data_only=True)
ws = wb["Costs"]
row = None
for rr in range(1, 60):
v = ws.cell(rr, 1).value
if v and "TOTAL FIXED COST PER MONTH" in str(v): row = rr; break
if row is None: return False, "cannot find the fixed-cost total row in the workbook"
got = tuple(ws.cell(row, c).value for c in (2, 3, 4))
if any(g is None for g in got):
return False, "workbook shipped with no cached values — recalculation did not run"
want = M.monthly_fixed()
diffs = [(i, round(float(g), 2), w) for i, (g, w) in enumerate(zip(got, want)) if abs(float(g) - w) > 0.05]
if diffs:
return False, "workbook fixed-cost band %s does not match the model's %s" % (
tuple(round(float(g), 2) for g in got), want)
n_cached = 0
for sheet in wb.worksheets:
for rr in sheet.iter_rows():
for c in rr:
if isinstance(c.value, (int, float)): n_cached += 1
return True, "workbook carries %d computed values; fixed-cost band %s matches the model exactly" % (
n_cached, tuple(round(float(g), 2) for g in got))
# ---------------------------------------------------------------- C29
@check("C29", "GOV-F4.5a, REQ-CON-04", "MOBILE LEGIBILITY over EVERY delivered Office artefact — the .docx, "
"the .pptx and the .xlsx — not just the one that is easiest to open")
def c29():
"""DEF-028. This check opened only the study and reported 'none below 10pt' as if it settled a
requirement whose words are 'every delivered Office artefact'. Independent verification V6
opened the other two and found eight 9-point runs in the decision pack, 145 nine-point cells in
the workbook and three sheets wider than six columns. A green check over a subset is worse than
no check, because the definition of done cites its counts as proof.
DEF-049. The first attempt to handle worksheets here was an interpretation — the six-column
limit applies to document tables and not to grids — recorded as DEC-008 and escalated rather
than self-granted. Independent verification pass V9 rejected it, and was right to: the flat
six-column criterion was this PROJECT's operationalisation of GOV-F4.5a, not the Standard's
words, and the Standard asks for readability without horizontal scrolling. So the requirement
was amended under CR-007 to ask of a worksheet what the rule actually wants — that scrolling
does not lose the labels — and the workbook now freezes a label column and a header row on
every sheet. The requirement is satisfied rather than interpreted around, DEC-008 is
superseded, and nothing is parked with Zaid."""
# DEF-051. The amendment widened this requirement to "every delivered Office artefact" and the
# check still walked one folder. The register workbook is CI-004, cited by name in the study,
# the Help Hub and the dashboard, and it failed both halves of the requirement while this
# reported a pass. A check scoped to a folder rather than to the set the requirement names is
# the same defect as DEF-028, one directory up.
out = os.path.join(ROOT, "05_Outputs")
extra = [os.path.join(ROOT, "03_Registers", f)
for f in sorted(os.listdir(os.path.join(ROOT, "03_Registers")))
if f.lower().endswith((".xlsx", ".docx", ".pptx"))]
# REQ-CON-04 governs artefacts this project DELIVERS. The governing Standard is filed in
# 05_Outputs under GOV-F5.7 but it is Zaid's document, not this project's output — it is not
# ours to reformat, and failing on its typography would be failing on someone else's file.
# The boundary is taken from the CI register's owner column rather than from a hard-coded
# filename, so a future input filed here is excluded for the same reason automatically.
not_ours = {os.path.basename(ci[4]) for ci in P.CI if str(ci[2]).strip().lower() == "zaid"}
bad, seen, skipped = [], [], []
widest = ("", 0)
def note(kind, path, msg):
bad.append("%s %s: %s" % (kind, os.path.basename(path), msg))
for full in [os.path.join(out, n) for n in sorted(os.listdir(out))] + extra:
name = os.path.basename(full)
if name.startswith("~$"):
continue
if name in not_ours:
skipped.append(name); continue
if name.endswith(".docx"):
try:
from docx import Document
from docx.shared import Pt
except ImportError:
return False, "python-docx not installed; the .docx cannot be measured"
d = Document(full); runs = 0; small = 0; wide = 0
for para in d.paragraphs:
for r in para.runs:
runs += 1
if r.font.size is not None and r.font.size.pt < 10: small += 1
for t in d.tables:
if len(t.columns) > 6: wide += 1
for row in t.rows:
for cell in row.cells:
for para in cell.paragraphs:
for r in para.runs:
runs += 1
if r.font.size is not None and r.font.size.pt < 10: small += 1
seen.append("%s (%d runs, %d tables)" % (name, runs, len(d.tables)))
if small: note("docx", full, "%d text runs below 10pt" % small)
if wide: note("docx", full, "%d tables wider than six columns" % wide)
elif name.endswith(".pptx"):
try:
from pptx import Presentation
except ImportError:
return False, "python-pptx not installed; the .pptx cannot be measured"
pr = Presentation(full); runs = 0; small = 0
for sl in pr.slides:
for sh in sl.shapes:
if not sh.has_text_frame: continue
for para in sh.text_frame.paragraphs:
for r in para.runs:
runs += 1
if r.font.size is not None and r.font.size.pt < 10: small += 1
seen.append("%s (%d runs, %d slides)" % (name, runs, len(pr.slides)))
if small: note("pptx", full, "%d text runs below 10pt" % small)
elif name.endswith(".xlsx"):
try:
import openpyxl
except ImportError:
return False, "openpyxl not installed; the .xlsx cannot be measured"
wb = openpyxl.load_workbook(full); cells = 0; small = 0; wide = []
for ws in wb:
used = 0
for row in ws.iter_rows():
for c in row:
if c.value is None: continue
cells += 1
used = max(used, c.column)
if c.font is not None and c.font.size is not None and float(c.font.size) < 10:
small += 1
if used > widest[1]:
widest = (ws.title, used)
if used > 6:
fp = getattr(ws, "freeze_panes", None)
if not fp:
note("xlsx", full, "sheet '%s' uses %d columns and has no frozen panes, so a "
"phone loses its labels when it scrolls (REQ-CON-04)" % (ws.title, used))
else:
import re as _r2
m2 = _r2.match(r"([A-Z]+)(\d+)", str(fp))
if not m2 or m2.group(1) == "A" or int(m2.group(2)) <= 1:
note("xlsx", full, "sheet '%s' freezes at %s, which does not hold both a "
"label column and a header row" % (ws.title, fp))
seen.append("%s (%d cells, %d sheets)" % (name, cells, len(wb.sheetnames)))
if small: note("xlsx", full, "%d cells below 10pt" % small)
if not seen:
return False, "no Office artefacts found in 05_Outputs to measure"
return (not bad), "%d delivered Office artefacts measured — %s — zero runs or cells below 10pt " \
"in any of them, zero document tables above six columns. Widest WORKSHEET grid: %s at %d " \
"columns, and every worksheet above six columns freezes both a label column and a header row " \
"so scrolling does not lose them (REQ-CON-04 as amended under CR-007; DEC-008 superseded). " \
"Excluded as not this project's output: %s" \
% (len(seen), "; ".join(seen), widest[0] or "none", widest[1],
", ".join(sorted(skipped)) or "none") \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C30
@check("C30", "GOV-F1.12, GOV-E1.4", "Every evidence record points at an artefact that actually exists")
def c30():
"""DEF-019. The evidence set previously cited a workbook sheet and a build script that did not
exist. Evidence that cannot be opened is not evidence."""
bad = []
for eid, req, method, artefact, date, by in P.EVD:
for frag in re.split(r";\s*", artefact):
frag = frag.strip()
m = re.match(r"^([\w./\\-]+\.(?:docx|xlsx|pptx|md|py|csv|html|png|txt)|[\w./-]+/)", frag)
if not m:
continue
path = m.group(1)
if not os.path.exists(os.path.join(ROOT, path)):
bad.append("%s -> %s does not exist" % (eid, path))
sheet = re.search(r"sheet '([^']+)'", frag)
if sheet and path.endswith(".xlsx"):
try:
from openpyxl import load_workbook
names = load_workbook(os.path.join(ROOT, path), read_only=True).sheetnames
if sheet.group(1) not in names:
bad.append("%s -> sheet '%s' not in %s" % (eid, sheet.group(1), path))
except Exception as e:
bad.append("%s -> cannot open %s: %s" % (eid, path, e))
return (not bad), "%d evidence records, every cited artefact and sheet resolves on disk" % len(P.EVD) \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C31
@check("C31", "GOV-E2.3, GOV-E2.4", "NO SELF-CERTIFICATION — a requirement is Verified only where the "
"INDEPENDENT verifier's recorded verdict says PASS")
def c31():
"""GOV-E2.4: a build agent's own statement of compliance carries zero verification weight.
The REQ register's status column is derived from IV_VERDICT, which is transcribed from the
independent verifier's report. This check proves the two have not drifted apart, and that the
verdict map covers every requirement."""
bad, awaiting = [], []
for r in P.REQ:
rid, status = r[0], r[7]
verdict = P.IV_VERDICT.get(rid)
if verdict is None:
# CR-007. A requirement added since the last verification pass legitimately has no
# verdict yet. That is not self-certification — self-certification is claiming
# Verified without one. What IS forbidden is letting an unverified requirement sit
# quietly at Verified, so the rule is enforced on the status, and the count of
# requirements still awaiting a verifier is reported in every run rather than hidden.
awaiting.append(rid)
if status == "Verified":
bad.append("%s is marked Verified with NO independent verdict — self-certification "
"(GOV-E2.4)" % rid)
continue
expected = "Verified" if verdict == "PASS" else "Open"
if status != expected:
bad.append("%s: register says %s, independent verdict says %s" % (rid, status, verdict))
extra = set(P.IV_VERDICT) - set(r[0] for r in P.REQ)
for e in sorted(extra):
bad.append("verdict recorded for %s, which is not a requirement" % e)
src = os.path.join(ROOT, P.IV_VERDICT_SOURCE.split(" ")[0])
if not os.path.exists(src):
bad.append("the verdict's cited source %s does not exist" % P.IV_VERDICT_SOURCE)
n_pass = len(P.iv_verified())
return (not bad), "%d of %d requirements independently verified; %d recorded as still failing (%s); " \
"%d AWAITING an independent verifier and correctly held at Open (%s); verdict source: %s" \
% (n_pass, len(P.REQ), len(P.iv_failed()) - len(P.iv_stale()),
", ".join(k for k in P.iv_failed() if k not in P.iv_stale()) or "none",
len(awaiting), ", ".join(awaiting) or "none", P.IV_VERDICT_SOURCE) \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C32
@check("C32", "GOV-D1.1, GOV-D1.2", "Every configuration item points at a path that exists — including the "
"Governance Standard itself")
def c32():
"""DEF-020. C30 validated EVIDENCE paths but never CONFIGURATION ITEM paths, so CI-001 — the
Standard the entire project is built to obey — named a file in 05_Outputs that was not there,
through twenty-nine green checks and four independent verification passes. Zaid found it, not
the project. Anything not under configuration control MUST NOT be relied on or cited as
evidence (GOV-D1.1); a CI that cannot be opened is not under configuration control."""
bad = []
for cid, name, owner, version, loc, baseline in P.CI:
target = os.path.join(ROOT, loc)
if not os.path.exists(target):
bad.append("%s (%s) -> %s does not exist" % (cid, name[:44], loc))
elif os.path.isfile(target) and os.path.getsize(target) == 0:
bad.append("%s -> %s is empty" % (cid, loc))
# GOV-F9.8: a binary source of truth needs a plain-text projection no staler than it
for docx, txt in [("05_Outputs/AI_Project_Governance_Standard_v3.7.docx",
"05_Outputs/AI_Project_Governance_Standard_v3.7.txt")]:
a, b = os.path.join(ROOT, docx), os.path.join(ROOT, txt)
if os.path.exists(a) and os.path.exists(b) and os.path.getmtime(b) < os.path.getmtime(a) - 5:
bad.append("%s is staler than the .docx it projects" % txt)
return (not bad), "%d configuration items, every path resolves and no projection is stale" % len(P.CI) \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C33
@check("C33", "GOV-B4.10, REQ-BUS-001, REQ-BUS-009", "The business plan twin exists, passes its own twelve "
"checks, and the A3 page is not staler than the twin it projects")
def c33():
"""Standard v4.0 makes business_plan.json a mandatory twin and BUSINESS_PLAN_A3.html its
generated projection. A twin that is not validated is a document, not a twin; a projection
older than its source is a lie with a timestamp. This check runs the generator's own
validator in-process rather than trusting a stored result."""
import importlib.util
bad = []
js = os.path.join(SYS, "business_plan.json")
a3 = os.path.join(SYS, "BUSINESS_PLAN_A3.html")
gen = os.path.join(SYS, "portable", "templates", "business_plan", "build_business_plan.py")
for path, what in ((js, "business plan twin"), (a3, "generated A3 page"), (gen, "generator")):
if not os.path.exists(path):
bad.append("%s missing: %s" % (what, os.path.relpath(path, ROOT)))
if bad:
return False, "; ".join(bad)
spec = importlib.util.spec_from_file_location("bp_gen", gen)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
with open(js, encoding="utf-8") as f:
data = json.load(f)
results = mod.validate(data)
failed = [cid for cid, ok, _ in results if not ok]
if failed:
bad.append("business plan checks failing: " + ", ".join(failed))
if os.path.getmtime(a3) < os.path.getmtime(js) - 5:
bad.append("BUSINESS_PLAN_A3.html is staler than business_plan.json; regenerate it")
# the verdict must not be self-declared as PROCEED while verification is still pending
vv = data.get("value_validation", {}).get("verdict", "")
verified_by = str(data.get("footer", {}).get("verified_by", ""))
if vv in ("PROCEED", "PROCEED WITH CONDITIONS") and verified_by.upper().startswith("PENDING"):
bad.append("verdict '%s' declared while independent verification is still PENDING "
"(GOV-C3.2 forbids self-certification)" % vv)
return (not bad), "business plan twin passes %d of %d of its own checks; A3 page current; " \
"verdict '%s' consistent with verification state" % (len(results) - len(failed), len(results), vv) \
if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C34
@check("C34", "REQ-BUS-009, REQ-BUS-01", "The business plan A3 page prints to EXACTLY ONE A3 landscape sheet — "
"counted from a real PDF, not measured from a div")
def c34():
"""DEF-021, then DEF-025. The first version of this check measured the sheet element's height
in a 1600-pixel screen viewport and reported twenty pixels to spare. Independent verification
V6 printed the same file in the same browser and got TWO A3 pages, one of them carrying 8,127
characters. The check was measuring a box, and the requirement is about pagination — the DOM
height is identical under print emulation while the printed output still splits inside the
column flow. A layout claim can only be tested by the engine that lays it out, so this check
now asks Chromium to print the page and counts the pages in the resulting PDF."""
a3 = os.path.join(SYS, "BUSINESS_PLAN_A3.html")
if not os.path.exists(a3):
return False, "BUSINESS_PLAN_A3.html missing"
try:
from playwright.sync_api import sync_playwright
except ImportError:
return False, "playwright is not installed, so the one-sheet claim cannot be printed and " \
"counted; an unmeasurable claim fails (GOV-C3.1)"
# DEF-043. The first version of this list was scraped from the very file it was testing, so
# deleting a whole section from the page deleted its own sentinel and the check still passed —
# independent verifier V8 removed section 9 and got a clean result. The sentinels now come from
# the TWIN, business_plan.json, which is what the page is supposed to be a projection of. A
# page that has lost a section no longer matches the thing it projects.
import json as _json
twin_path = os.path.join(SYS, "business_plan.json")
if not os.path.exists(twin_path):
return False, "business_plan.json missing, so there is nothing to check the page against"
twin = _json.load(open(twin_path, encoding="utf-8"))
sentinels = [
twin["meta"]["project_name"],
twin["purpose"]["statement"][:48],
twin["target_market"][0]["segment"][:34],
twin["value_proposition"]["benefits"][0]["benefit"][:34],
"%s" % twin["cba"]["break_even"][:24],
twin["running_costs"][0]["category"][:32],
twin["marketing_strategy"]["positioning"][:40],
twin["revenue_model"][0]["use_case"][:36],
twin["areas_of_concern"][0]["concern"][:34],
twin["efficiency_audit"]["recommendation"][:44],
twin["value_validation"]["verdict"],
twin["footer"]["generated_from"][:36],
]
sentinels = [x for x in (str(t).strip() for t in sentinels) if x]
tmp = os.path.join(SYS, "_c34_print_probe.pdf")
try:
with sync_playwright() as pw:
br = pw.chromium.launch()
pg = br.new_page()
pg.goto("file://" + a3)
pg.emulate_media(media="print")
pg.wait_for_timeout(400)
pg.pdf(path=tmp, prefer_css_page_size=True, print_background=True)
br.close()
with open(tmp, "rb") as f:
blob = f.read()
# Extract the printed text so truncation can be detected, not just pagination.
text = ""
try:
import subprocess
# NOT -layout. Layout mode interleaves adjacent columns line by line, which splits a
# sentence inside a narrow table cell across two unrelated fragments and makes a
# present string look absent. Reading order keeps each cell contiguous.
text = subprocess.run(["pdftotext", tmp, "-"], capture_output=True,
text=True, timeout=60).stdout
except Exception:
text = ""
if not text.strip():
try:
from pypdf import PdfReader
text = "\n".join((pp.extract_text() or "") for pp in PdfReader(tmp).pages)
except Exception:
text = ""
n = blob.count(b"/Type /Page\n") or blob.count(b"/Type/Page") or None
if n is None:
import re as _re
m = _re.search(rb"/Count\s+(\d+)", blob)
n = int(m.group(1)) if m else None
size_mm = None
import re as _re
mb = _re.search(rb"/MediaBox\s*\[\s*0\s+0\s+([\d.]+)\s+([\d.]+)", blob)
if mb:
w = float(mb.group(1)) * 25.4 / 72.0
h = float(mb.group(2)) * 25.4 / 72.0
size_mm = (round(w), round(h))
finally:
if os.path.exists(tmp):
os.remove(tmp)
if n is None:
return False, "the printed PDF could not be parsed for a page count, so the claim is untested"
if n != 1:
return False, "BUSINESS_PLAN_A3.html prints to %d A3 pages, and it is called a single-sheet " \
"document. Chromium honoured its own @page rule and split it." % n
if size_mm and not (395 <= size_mm[0] <= 425 and 280 <= size_mm[1] <= 300):
return False, "the page printed at %dmm x %dmm, which is not A3 landscape (420 x 297)" % size_mm
# DEF-036. A page count of one is not proof the page is complete. The first attempt at this fix
# made the page fit by CLIPPING it — overflow:hidden — and the printed PDF silently lost a
# table, a whole section, the verdict block and the footer while the count still read 1.
# Independent verification V7 rasterised the PDF and read what was missing. So the count is
# now only half the test: every section heading and the last element on the sheet must appear
# in the printed text, or the page is truncated rather than fitted.
import re as _re
# Normalise away everything a PDF text layer can legitimately change: line wrapping inside a
# narrow table cell, soft hyphens, letter spacing. What must survive is the sequence of
# letters and digits.
_flat = lambda x: _re.sub(r"[^a-z0-9]+", "", str(x).lower())
_t = _flat(text)
missing = [t for t in sentinels if _flat(t) not in _t]
if missing:
return False, "the page printed on one sheet but %d element(s) never reached the paper, which " \
"means it was clipped rather than fitted: %s" % (len(missing), "; ".join(missing[:6]))
return True, "printed in Chromium honouring the file's own @page rule: exactly 1 page, %s, and all " \
"%d sentinels drawn from the business plan TWIN — one per mandated section, plus the verdict and " \
"the footer — are present in the printed text. Fitted, not clipped, and not a projection of " \
"something else" % ("%dmm x %dmm" % size_mm if size_mm else "size not parsed", len(sentinels))
# ---------------------------------------------------------------- C35
@check("C35", "GOV-F3.8, GOV-F3.9, GOV-F3.10, GOV-F3.11", "File placement and debris — the tidy report is "
"clean: no loose root files, no debris, no secret stores, no links to live files")
def c35():
"""GOV-F3.12 requires a mechanical check on placement, not a habit of tidiness. This runs
tidy.py's own report so there is one definition of what belongs where — the placement map —
and not a second one living in the checker."""
import importlib.util
t = os.path.join(SYS, "tidy.py")
if not os.path.exists(t):
return False, "01_System/tidy.py missing, so placement is unenforced"
spec = importlib.util.spec_from_file_location("tidy_mod", t)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
findings = mod.report()
if findings:
return False, "%d placement finding(s): %s" % (
len(findings), "; ".join("%s %s" % (k, p) for k, p, _ in findings[:6]))
return True, "placement map satisfied: %d mandated folders present, root holds only %s, " \
"no debris, no secret stores, no links to live files" % (
len(mod.MANDATED_FOLDERS), " and ".join(sorted(mod.ROOT_ALLOWED)))
# ---------------------------------------------------------------- C36
@check("C36", "GOV-D1.1, GOV-F8.8", "Every SRC and ASM identifier cited by a financial model resolves to a "
"row that actually exists in the registers")
def c36():
"""DEF-022. C05 tests whether a number in the STUDY exists somewhere in a register. C27 tests
whether a claim in the STUDY carries a reference. Neither looks at the models — so
model_agedcare.py cited twenty source and assumption identifiers, every input looked properly
sourced, and not one of those rows existed. A citation that resolves to nothing is worse than
no citation, because it buys trust it has not earned."""
known = {r[0] for r in P.SRC} | {r[0] for r in P.ASM}
bad, cited = [], set()
for mod in ("model_params.py", "model_agedcare.py", "build_business_plan_json.py"):
path = os.path.join(SYS, mod)
if not os.path.exists(path):
bad.append("%s missing" % mod); continue
text = open(path, encoding="utf-8").read()
for ident in set(re.findall(r"\b(?:SRC|ASM)-\d{3}\b", text)):
cited.add(ident)
if ident not in known:
bad.append("%s cites %s, which is in no register" % (mod, ident))
return (not bad), "%d distinct source and assumption identifiers cited across the models, " \
"every one resolves against %d register rows" % (len(cited), len(known)) \
if not bad else "; ".join(sorted(set(bad))[:8])
# ---------------------------------------------------------------- C37
@check("C37", "GOV-B4.1, GOV-D4.10", "The workbook's aged care sheet and the aged care model agree, figure by "
"figure, on the numbers the recommendation rests on")
def c37():
"""DEF-024. The workbook said the contribution per aged care client was $1,044.78 and the model
said $1,002.06 — a 4.3 per cent gap on the single figure the whole aged care case turns on,
caused by an unnamed wage expression buried in a function. C09 checks twelve named figures and
this was not one of them, so nothing caught it. A fact held in two places is two facts."""
import model_agedcare as AC
try:
import openpyxl
except ImportError:
return False, "openpyxl not installed, so the workbook cannot be opened and its agreement cannot be tested"
path = os.path.join(ROOT, "05_Outputs", "NDIS_and_Aged_Care_Financial_Model_v2.0.xlsx")
if not os.path.exists(path):
return False, "workbook missing"
wb = openpyxl.load_workbook(path, data_only=True)
if "AC_ClientEconomics" not in wb.sheetnames:
return False, "workbook has no AC_ClientEconomics sheet"
ws = wb["AC_ClientEconomics"]
e = AC.client_economics(admin_paid=True)
n = AC.ndis_client_economics(admin_paid=True)
# (label, workbook cell, model value)
pairs = [
("aged care loaded wage", "B5", AC.loaded_wage("l2")),
("aged care price", "B6", AC.INPUTS["price_personal_care"][0]),
("aged care gross margin", "B7", AC.gross_margin_per_hour("l2")),
("aged care revenue per client", "B8", e["revenue_per_month"]),
("care management revenue", "B9", e["care_management_revenue"]),
("aged care billable hours", "B11", e["billable_hours_per_month"]),
("aged care direct labour", "B13", e["direct_labour"]),
("care management cost", "B14", e["care_management_cost"]),
("aged care admin cost", "B15", e["service_admin_cost"]),
("AGED CARE CONTRIBUTION", "B17", e["contribution_per_client_month"]),
("NDIS loaded wage", "C5", M.loaded_wage("l2")),
("NDIS revenue per client", "C8", n["revenue_per_month"]),
("NDIS direct labour", "C13", n["direct_labour"]),
("NDIS admin cost", "C15", n["service_admin_cost"]),
("NDIS CONTRIBUTION", "C17", n["contribution_per_client_month"]),
]
bad = []
for label, cell, expected in pairs:
got = ws[cell].value
if got is None:
bad.append("%s: workbook cell %s has no cached value" % (label, cell)); continue
if abs(float(got) - float(expected)) > 0.01:
bad.append("%s: workbook %s = %.2f, model = %.2f" % (label, cell, float(got), float(expected)))
return (not bad), "%d aged care and NDIS per-client figures agree between the workbook and the model " \
"to the cent" % len(pairs) if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C38
@check("C38", "GOV-B4.10, GOV-B4.9", "The system breakdown exists, is current, and every component in it carries "
"at least one requirement that actually exists")
def c38():
"""GOV-B4.10 forbids building a system you cannot draw as parts and interfaces. The drawing is
generated from the component and interface registers rather than hand-drawn, because a
hand-drawn architecture is out of date the day after it is drawn and nobody notices. This
check regenerates it in memory and fails if the file on disk differs — which catches both a
hand-edit and a stale build."""
import importlib.util
path = os.path.join(SYS, "SYSTEM_BREAKDOWN.md")
gen = os.path.join(SYS, "build_system_breakdown.py")
if not os.path.exists(path):
return False, "01_System/SYSTEM_BREAKDOWN.md missing — GOV-B4.10 forbids building without it"
bad = []
known_req = {r[0] for r in P.REQ}
for c in P.COMPONENTS:
reqs = c[6]
if not reqs:
bad.append("%s (%s) carries no requirement" % (c[0], c[1]))
for rid in reqs:
if rid not in known_req:
bad.append("%s cites %s, which is in no requirements register" % (c[0], rid))
spec = importlib.util.spec_from_file_location("sysbd", gen)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
fresh = mod.build()
on_disk = open(path, encoding="utf-8").read()
if fresh != on_disk:
import re as _re
strip = lambda s: _re.sub(r"Generated \d{4}-\d{2}-\d{2}", "Generated <date>", s)
if strip(fresh) == strip(on_disk):
bad.append("SYSTEM_BREAKDOWN.md is STALE-BY-CALENDAR — only the generation date differs, "
"so nobody edited it, but it was not regenerated in this build (GOV-D4.11)")
else:
bad.append("SYSTEM_BREAKDOWN.md is ALTERED — its content differs from a fresh generation, "
"which means it was hand-edited or its source changed without a rebuild (GOV-D4.11)")
return (not bad), "system breakdown current: %d components, every one with a requirement that exists; " \
"%d interfaces mapped" % (len(P.COMPONENTS), len(P.IF_REG)) if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C39
@check("C39", "GOV-D4.11", "Every generated document and surface names its generator (OWNER) and the trigger "
"that regenerates it (REVIEW)")
def c39():
"""GOV-D4.11: generated files go stale loudly. A generated artefact that does not say what
generates it invites someone to hand-edit it, and a hand-edit to a generated file is lost at
the next build without anyone noticing it was lost.
CSV register projections are deliberately out of scope: a CSV with a provenance comment line
is not a CSV any more, and their provenance is carried on the README sheet of the register
workbook they are projected from. That is a stated exemption with a reason, not a gap."""
targets = [
"README.md", "Dashboard.html", "09_Help_Hub/index.html",
"01_System/threat_model.md", "01_System/governance_core.md",
"01_System/SYSTEM_BREAKDOWN.md", "01_System/BUSINESS_PLAN_A3.html",
"05_Outputs/AI_Project_Governance_Standard_v3.7.txt",
]
bad, checked = [], 0
for rel in targets:
full = os.path.join(ROOT, rel)
if not os.path.exists(full):
bad.append("%s missing" % rel); continue
head = open(full, encoding="utf-8", errors="ignore").read(8000)
checked += 1
if "OWNER" not in head:
bad.append("%s does not name its generator (OWNER)" % rel)
elif "REVIEW" not in head:
bad.append("%s names its generator but not what triggers regeneration (REVIEW)" % rel)
return (not bad), "%d generated documents and surfaces, every one naming its generator and its " \
"regeneration trigger; CSV projections exempt with a stated reason" % checked \
if not bad else "; ".join(bad[:6])
# ---------------------------------------------------------------- C40
@check("C40", "GOV-D1.13", "A source manifest exists and every source of truth matches the hash recorded at the "
"last gate")
def c40():
"""GOV-D1.13: a change nobody gated is a finding, not a surprise. Twenty sources of truth,
governing files, portable-core files, checkers and deliverables are hashed at each session-end
gate. This check runs the comparison the session-start action is required to run, so a source
that moved between sessions cannot pass silently."""
import importlib.util
gen = os.path.join(SYS, "build_source_manifest.py")
if not os.path.exists(gen):
return False, "01_System/build_source_manifest.py missing, so no gate can be taken"
spec = importlib.util.spec_from_file_location("srcman", gen)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
if not os.path.exists(mod.OUT):
return False, "no source manifest has ever been written; run build_source_manifest.py --gate"
when, lines = mod.compare()
if lines:
return False, "%d source(s) changed since the gate at %s: %s" % (len(lines), when, "; ".join(lines[:5]))
return True, "%d sources of truth all match the manifest gated at %s" % (len(mod.TRACKED), when)
# ---------------------------------------------------------------- C41
@check("C41", "GOV-E2.3, GOV-E2.4, GOV-D5.2", "No requirement is marked Verified on a verdict taken against a "
"DIFFERENT baseline from the one the project is currently at")
def c41():
"""DEF-035. C31 proved the register agreed with the independent verdict map. It could not
prove the verdict map was still about the artefacts on disk. Twenty-six requirements sat at
Verified on a pass taken against a single-business artefact set, while every one of those
artefacts had been rebuilt with a second business, six new sections and eighteen new tables.
The mechanism that removed self-certification had no staleness test, so a v1.0.0 verdict
silently certified a v2.0.0 artefact — which is not a false claim about verification, it is a
true claim about a document that no longer exists. GOV-D5.2 requires a Class 1 change to
re-verify every requirement traceably downstream; this check is what makes that unavoidable."""
bad = []
cur = P.BASELINE_VERSION
for r in P.REQ:
rid, status = r[0], r[7]
result, baseline = P.IV_VERDICT_RAW.get(rid, (None, None))
if status == "Verified" and baseline != cur:
bad.append("%s is Verified on a %s verdict while the baseline is %s" % (rid, baseline, cur))
if result == "PASS" and baseline != cur and status == "Verified":
bad.append("%s carries a stale PASS presented as current" % rid)
src = P.IV_SOURCES.get(cur, "")
path = os.path.join(ROOT, src.split(" ")[0]) if src else ""
if src and not os.path.exists(path):
bad.append("the %s verdict cites %s, which does not exist" % (cur, src.split(" ")[0]))
else:
# DEF-039. Checking that the report EXISTS is not checking that the verdicts came from it.
# Independent verification V7 defeated the first version of this check in a sandbox by
# writing a report reading "EVERY REQUIREMENT FAILS, 0 of 32 PASS", transcribing all 32 as
# PASS, and getting a green suite. The transcription was the unguarded step, so the
# transcription is what is now checked: the report carries a machine-readable verdict block
# and this compares it, line by line, against what the project transcribed.
import re as _re
report = open(path, encoding="utf-8", errors="ignore").read()
blocks = _re.findall(r"##\s*MACHINE-READABLE VERDICTS\s*```(.*?)```", report, _re.S)
# DEF-046. The previous version took the FIRST match. Independent verifier V8 defeated it by
# inserting a decoy all-PASS block above a report whose real verdicts, lower down, carried
# failures — and got a green suite. V9 found the claimed fix had never actually been written
# into the file, and reran the same attack successfully. A report with two verdict blocks is
# a report that cannot be trusted at all, so more than one is a failure rather than a
# preference for one of them.
if len(blocks) > 1:
bad.append("the %s verdict report carries %d machine-readable verdict blocks; exactly one is "
"allowed, because a second can contradict the first" % (cur, len(blocks)))
m = None
if len(blocks) == 1:
m = _re.search(r"##\s*MACHINE-READABLE VERDICTS\s*```(.*?)```", report, _re.S)
if not blocks:
bad.append("the %s verdict report carries no MACHINE-READABLE VERDICTS block, so the "
"transcription cannot be checked against it" % cur)
if m is not None:
declared = {}
for line in m.group(1).splitlines():
line = line.strip()
if "=" in line and line.split("=")[0].strip().startswith("REQ-"):
k, v = line.split("=", 1)
declared[k.strip()] = v.strip().upper()
transcribed = {r: res for r, (res, b) in P.IV_VERDICT_RAW.items() if b == cur}
for rid, res in sorted(transcribed.items()):
if rid not in declared:
bad.append("%s was transcribed as %s but the verifier's report does not mention it"
% (rid, res))
elif declared[rid] != res:
bad.append("%s: the project transcribed %s, the verifier's report says %s"
% (rid, res, declared[rid]))
for rid, res in sorted(declared.items()):
if rid not in transcribed:
bad.append("the verifier recorded %s=%s and the project transcribed nothing for it"
% (rid, res))
stale = P.iv_stale()
n_cur = sum(1 for r in P.REQ if P.iv_baseline(r[0]) == cur)
return (not bad), "%d of %d requirements carry a verdict taken against the CURRENT baseline %s; " \
"%d carry a verdict retired with an earlier baseline and are reported as stale rather than " \
"as passing (%s)" % (n_cur, len(P.REQ), cur, len(stale),
", ".join(stale[:6]) + (" ..." if len(stale) > 6 else "") or "none") \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C42
@check("C42", "GOV-D4.11, GOV-B4.1", "Every register projection matches a FRESH projection of the source of "
"truth, and no generated artefact predates the source it projects")
def c42():
"""D-V7-1, then DEF-043. The first version of this check compared modification times. That
caught the failure it was written for — a source edited without a rebuild — and independent
verifier V8 defeated it in a minute by deleting three rows from a delivered register and
running `touch` on the file. A timestamp says when a file was written, not what is in it.
So the register projections are now regenerated in memory from project_data and compared row
by row against the CSVs on disk. The clock test is kept as well, because it catches the case
where the content happens to match but a deliverable that is NOT a register — the study, the
workbook, the deck, the dashboard — was built before the last source edit."""
import importlib.util as _ilu, csv as _csv, io as _io
bad = []
# ---- 1. content: every register CSV must equal a fresh projection of the source of truth
br = os.path.join(SYS, "build_registers.py")
if not os.path.exists(br):
return False, "01_System/build_registers.py missing, so no projection can be checked"
spec = _ilu.spec_from_file_location("bregs", br)
mod = _ilu.module_from_spec(spec)
spec.loader.exec_module(mod)
reg = os.path.join(ROOT, "03_Registers")
checked_rows = 0
for name, headers, data in mod.SHEETS:
if data is None:
# RTM and CLOSURE_LOG are generated by functions in the projector rather than held as
# register literals; call the same function the projector calls, so this check
# compares against the same source rather than a second definition of it.
fn = {"RTM": getattr(mod, "rtm", None), "CLOSURE_LOG": getattr(mod, "closure_log", None)}.get(name)
if fn is None:
bad.append("%s has no rows and no generator, so it cannot be checked" % name); continue
data = fn()
path = os.path.join(reg, name + ".csv")
if not os.path.exists(path):
bad.append("%s.csv is missing from the register projection" % name); continue
buf = _io.StringIO()
w = _csv.writer(buf, lineterminator="\r\n")
w.writerow(headers)
for row in data:
w.writerow(list(row))
fresh = buf.getvalue()
on_disk = open(path, encoding="utf-8", newline="").read()
if fresh != on_disk:
fr = fresh.splitlines()
od = on_disk.splitlines()
if len(fr) != len(od):
bad.append("%s.csv holds %d rows, the source of truth projects %d"
% (name, len(od) - 1, len(fr) - 1))
else:
diff = next((k for k in range(len(fr)) if fr[k] != od[k]), None)
bad.append("%s.csv differs from a fresh projection at line %s" % (name, diff))
checked_rows += len(data)
# ---- 2. the clock: nothing generated may predate the source it projects
sources = ["01_System/project_data.py", "01_System/model_params.py", "01_System/model_agedcare.py",
"01_System/trade_study.py", "01_System/build_business_plan_json.py",
"01_System/build_study.py", "01_System/build_web.py", "01_System/build_handover.py",
"01_System/build_registers.py", "01_System/build_financial_model.py",
"01_System/build_diagrams.py", "01_System/build_system_breakdown.py",
"01_System/export_model_json.py", "01_System/build_deck.js"]
generated = ["Dashboard.html", "README.md", "09_Help_Hub/index.html",
"01_System/SYSTEM_BREAKDOWN.md", "01_System/business_plan.json",
"01_System/BUSINESS_PLAN_A3.html", "01_System/model_export.json",
"05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx",
"05_Outputs/NDIS_and_Aged_Care_Financial_Model_v2.0.xlsx",
"05_Outputs/NDIS_and_Aged_Care_Decision_Pack_v2.0.pptx"]
generated += ["03_Registers/%s.csv" % n for n, _, _ in mod.SHEETS]
generated += ["00_Handover/" + f for f in sorted(os.listdir(os.path.join(ROOT, "00_Handover")))
if os.path.isfile(os.path.join(ROOT, "00_Handover", f))]
GRACE = 2.0
times = {}
for rel in sources + generated:
full = os.path.join(ROOT, rel)
if not os.path.exists(full):
bad.append("%s missing, so build order cannot be established" % rel); continue
times[rel] = os.path.getmtime(full)
present_src = [r for r in sources if r in times]
if present_src:
newest_src = max(present_src, key=lambda r: times[r])
for g in generated:
if g in times and times[g] + GRACE < times[newest_src]:
bad.append("%s is %d seconds older than %s"
% (g, int(times[newest_src] - times[g]), newest_src))
return (not bad), "%d register rows across %d projections match a fresh projection of the source of " \
"truth exactly, and all %d generated artefacts were written after the newest of %d sources" \
% (checked_rows, len(mod.SHEETS), len(generated), len(present_src)) \
if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C43
@check("C43", "GOV-B6.1, GOV-B6.3, REQ-SYS-03, REQ-SYS-04", "Every trade study total published in the delivered "
"study is recomputed from its own scores and weights, and the weights sum to one")
def c43():
"""DEF-042. Trade study 1 published totals of 2.85, 4.05 and 2.30 that could not be produced
from its own published matrix — the correct figures are 3.50, 4.10 and 3.25, so one was out by
1.20 on a five-point scale and the stated margin of 1.20 was really 0.60. The scores were
hard-coded strings in the study builder. It survived three independent verification passes,
two of which recorded that they had recomputed it by hand and found it correct, because the
arithmetic is four multiplications and nobody actually did them. This check does them, from the
register, and compares the result against the number on the page."""
import trade_study as TSM
bad = []
checked = 0
# DEF-048. This used to confirm the total "appears in the delivered study" by substring match
# over the whole document. Independent verifier V9 put the OLD, WRONG totals back into the
# study and got a clean pass, because those same numbers also appear in the sentence of defect
# history that records them as wrong. A number appearing somewhere in a document is not the
# same claim as that number being in the cell it is supposed to be in. The check now reads the
# WEIGHTED SCORE row out of the actual table.
published = {}
try:
from docx import Document as _Doc
_d = _Doc(os.path.join(ROOT, "05_Outputs",
"NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx"))
for t in _d.tables:
rows = [[c.text.strip() for c in r.cells] for r in t.rows]
if not rows or len(rows[0]) < 3:
continue
head = [h.replace("**", "").strip().lower() for h in rows[0]]
if head[0] != "criterion":
continue
score_row = next((r for r in rows if r[0].replace("**", "").strip().lower()
== "weighted score"), None)
if not score_row:
continue
vals = []
for cell in score_row[2:]:
try:
vals.append(round(float(cell.replace("**", "").strip()), 2))
except ValueError:
pass
if vals:
published[tuple(h.replace("**", "").strip() for h in rows[0][2:])] = vals
except Exception as e:
bad.append("the delivered study could not be opened to read its trade study tables (%s)" % e)
if len(published) < 3:
bad.append("found %d trade study matrices in the delivered study; expected 3" % len(published))
for key in ("TS1", "TS2", "TS3"):
crit, opts, scores, _rec = TSM.STUDIES[key]
total_w = round(sum(w for _, _, w in crit), 6)
if abs(total_w - 1.0) > 1e-6:
bad.append("%s weights sum to %.4f, not 1.0" % (key, total_w))
for ok, _label in opts:
for ckey, clabel, _w in crit:
sc = scores[ok][ckey]
if not isinstance(sc, tuple) or len(sc) != 2:
bad.append("%s/%s/%s has no (score, figure) pair" % (key, ok, ckey)); continue
if not (1 <= sc[0] <= 5):
bad.append("%s/%s/%s scores %s, outside 1..5" % (key, ok, ckey, sc[0]))
if len(str(sc[1]).strip()) < 20:
bad.append("%s/%s/%s cites no figure" % (key, ok, ckey))
for ok, _label, total in TSM.study_weighted(key):
recomputed = round(sum(scores[ok][c][0] * w for c, _, w in crit), 3)
if abs(recomputed - total) > 0.001:
bad.append("%s/%s: published %.2f, recomputes to %.2f" % (key, ok, total, recomputed))
checked += 1
if len(opts) < 3:
bad.append("%s offers only %d alternatives; GOV-B6.1 requires at least three" % (key, len(opts)))
# the WEIGHTED SCORE row in the delivered table must be this study's computed totals, in order
want = [round(sc, 2) for _, _, sc in
sorted(TSM.study_weighted(key), key=lambda r: [o[0] for o in opts].index(r[0]))]
match = [v for v in published.values() if v == want]
if not match:
bad.append("%s: the delivered study carries no WEIGHTED SCORE row equal to the computed "
"totals %s (rows found: %s)"
% (key, want, "; ".join(str(v) for v in published.values()) or "none"))
return (not bad), "%d trade study totals across 3 studies recomputed from their own scores and weights and " \
"found in the delivered study; every score carries the figure it rests on; every weight set sums to 1.0" \
% checked if not bad else "; ".join(bad[:8])
# ---------------------------------------------------------------- C44
@check("C44", "GOV-D4.3, GOV-F8.8", "No generated surface carries an unresolved template token, and every count "
"it publishes about an artefact matches that artefact")
def c44():
"""DEF-044. Independent verifier V8 found the Help Hub and the transfer pack publishing counts
that had quietly gone false: ten slides where there are twelve, 398 workbook formulas where
there are 455, diagrams D1 to D10 where there are twelve, and the study described as 32 pages
in one entry and 47 in another when the delivered PDF has 73. None was ever wrong when it was
written. All of them are now counted from the artefact, and this check counts them again and
compares, so the next time an artefact grows the surfaces move with it."""
import glob as _glob, re as _re
bad = []
surfaces = ["Dashboard.html", "09_Help_Hub/index.html", "README.md",
"00_Handover/HANDOVER.txt", "01_System/SYSTEM_BREAKDOWN.md"]
for rel in surfaces:
full = os.path.join(ROOT, rel)
if not os.path.exists(full):
bad.append("%s missing" % rel); continue
txt = open(full, encoding="utf-8", errors="ignore").read()
for tok in set(_re.findall(r"\{\{[A-Z_]+\}\}", txt)):
bad.append("%s carries an unresolved template token %s — a count nobody computed" % (rel, tok))
# the counts themselves
dia = sorted(_glob.glob(os.path.join(ROOT, "02_Work", "diagrams", "D*.png")))
n_dia = len(dia)
n_slides = n_formulas = n_pages = 0
try:
from pptx import Presentation
n_slides = len(Presentation(os.path.join(ROOT, "05_Outputs",
"NDIS_and_Aged_Care_Decision_Pack_v2.0.pptx")).slides)
except Exception as e:
bad.append("the decision pack could not be opened to count its slides (%s)" % e)
try:
import openpyxl
wb = openpyxl.load_workbook(os.path.join(ROOT, "05_Outputs",
"NDIS_and_Aged_Care_Financial_Model_v2.0.xlsx"))
n_formulas = sum(1 for ws in wb for r in ws.iter_rows() for c in r
if isinstance(c.value, str) and c.value.startswith("="))
except Exception as e:
bad.append("the workbook could not be opened to count its formulas (%s)" % e)
try:
from pypdf import PdfReader
n_pages = len(PdfReader(os.path.join(ROOT, "05_Outputs",
"NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.pdf")).pages)
except Exception:
n_pages = 0
# DEF-048. The first version of this check looked in ONE file with THREE regexes, so
# independent verifier V9 set the Help Hub to 40 slides, 1,200 formulas and 5 pages and got a
# clean pass on two of the three. It now sweeps every generated surface and the delivered
# study for any sentence that states a count of one of these artefacts, in any of the shapes
# the project actually writes them in, and compares each one.
n_actions = len(P.open_rows("ACT"))
claims = [
("slides", n_slides, [r"(\d+)\s+slides"]),
("pages", n_pages, [r"(\d+)[- ]page study", r"study[^.\n]{0,10}?\((\d+) pages\)",
r"\((\d+) pages\)"]),
("formulas", n_formulas, [r"(\d+)[, ]*formulas"]),
("diagrams", n_dia, [r"(\d+) diagrams", r"D1 to D(\d+)", r"D1-D(\d+)"]),
("open actions", n_actions, [r"(\d+) (?:open )?actions? (?:are )?owed", r"(\d+) open actions"]),
]
# The defect register, the closure log and the feedback register are HISTORICAL records. They
# must be free to quote the wrong number they record — "ten slides where there are twelve" IS
# the defect, and "1,200 formulas" is the attack a verifier ran, not a claim about the
# workbook. Excluding them is the difference between a check that reads and one that
# pattern-matches. Everything that makes a CLAIM about the current artefacts is still swept.
_history = {"DEF.csv", "CLOSURE_LOG.csv", "FEEDBACK.csv"}
scanned = surfaces + ["05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx"] + \
["03_Registers/%s" % f for f in sorted(os.listdir(os.path.join(ROOT, "03_Registers")))
if f.endswith(".csv") and f not in _history]
WORDS = {"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7,
"eight": 8, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12}
for rel in scanned:
full = os.path.join(ROOT, rel)
if not os.path.exists(full):
continue
txt = (docx_text(rel) or "") if rel.endswith(".docx") else \
open(full, encoding="utf-8", errors="ignore").read()
low = txt.lower()
for label, actual, pats in claims:
if not actual:
continue
for pat in pats:
for mm in _re.finditer(pat, low):
found = mm.group(1)
try:
v = int(found)
except (TypeError, ValueError):
continue
if v == actual:
continue
# A defect record has to be free to quote the wrong number it records:
# "ten slides where there are twelve" states the error AND the correction in
# one breath, and that is a record, not a claim. A wrong count with no
# correction beside it is the thing this check exists to find.
# A historical count is allowed where the SAME sentence dates it or corrects
# it. A bare wrong count is not.
tail = low[mm.end():mm.end() + 140].split(".")[0]
if _re.search(r"(where there (are|is)|instead of|rather than|against|when the"
r"|at the v[\d.]+ baseline|it now|; the artefact"
r"|and \d+ in another)", tail):
continue
bad.append("%s states %d %s with no correction beside it; the artefact has %d"
% (rel, v, label, actual))
# spelled-out counts of slides and diagrams, which is how they were wrong last time
for word, v in WORDS.items():
for label, actual in (("slides", n_slides), ("diagrams", n_dia)):
if not actual or v == actual:
continue
for mm in _re.finditer(r"\b%s %s\b" % (word, label), low):
tail = low[mm.end():mm.end() + 140].split(".")[0]
if _re.search(r"(where there (are|is)|instead of|rather than|against|when the"
r"|at the v[\d.]+ baseline|it now)", tail):
continue
bad.append("%s says '%s %s' with no correction beside it; the artefact has %d"
% (rel, word, label, actual))
# the study's compliance appendix must not name a diagram range that has grown
study = docx_text("05_Outputs/NDIS_and_Aged_Care_Business_Enabling_Study_v2.0.docx") or ""
for found in set(_re.findall(r"(\d+) diagrams D1 to D(\d+)", study)):
if int(found[0]) != n_dia or int(found[1]) != n_dia:
bad.append("the study names %s diagrams D1 to D%s; there are %d" % (found[0], found[1], n_dia))
return (not bad), "no unresolved template tokens across %d generated surfaces; the published counts match " \
"the artefacts — %d diagrams, %d slides, %d workbook formulas, %d study pages" \
% (len(surfaces), n_dia, n_slides, n_formulas, n_pages) if not bad else "; ".join(bad[:8])
# =========================================================================
def main():
lines = []
stamp = "CHECKER RUN %s | project %s | baseline %s | %s" % (
datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), P.PROJECT_NAME,
P.BASELINE_VERSION, P.STANDARD_VERSION)
lines.append(stamp); lines.append("=" * len(stamp)); lines.append("")
npass = sum(1 for r in RESULTS if r[3])
width = max(len(r[2]) for r in RESULTS)
for cid, rule, desc, ok, detail in RESULTS:
lines.append("%-5s %-4s %-28s %s" % (cid, "PASS" if ok else "FAIL", rule, desc))
lines.append(" %s" % detail)
lines.append("")
verdict = "ALL CHECKS PASSED — %d of %d" % (npass, len(RESULTS)) if npass == len(RESULTS) \
else "FAILURES: %d of %d checks failed" % (len(RESULTS) - npass, len(RESULTS))
lines.append(verdict)
out = "\n".join(lines)
print(out)
with open(os.path.join(SYS, "checker_run_log.txt"), "w", encoding="utf-8") as f:
f.write(out + "\n")
sys.exit(0 if npass == len(RESULTS) else 1)
if __name__ == "__main__":
main()