A manifest nobody checks rots within a week: a new waiver lands in a log but not in the table, a rerun refreshes a result but names the old revision, a second map revision appears in one header. The checker runs every night and fails loudly on any of it. This lesson is the checker itself, small enough to read in full, running over the NanoSoC rows. Its one job is completeness and currency, not colour: it proves every result is on the baseline, and the dashboard of the next topic says whether those results are green. Waiver policy, what counts as excused, is the topic after.
The checker enforces four rules. Every discipline the dashboard tracks has a result row: timing, power, physical verification, crossings, verification coverage, connectivity, equivalence and gate-level simulation, eight rows on NanoSoC. Every result names the revisions it needs, each equal to the frozen baseline: timing names constraints, netlist, layout, parasitics, library and tool versions; connectivity names RTL and map; equivalence names RTL and netlist. Every waiver names an owner and an unexpired date, computed from its grant day and class. Every consumer of shared sources, the headers, the decoder, the verification model, carries the current map version. Each rule is a loop over a table, and the script proves each rule can fail by injecting a violation.
# The nightly manifest checker: four rules, each able to fail.
# Revision labels, days and waiver data are illustrative.
BASE = {"rtl": "214", "map": "7", "sdc": "12", "upf": "5",
"netlist": "n88", "layout": "gds-31", "spef": "spef-31",
"lib": "lib-9", "tools": "t4", "fw": "boot-img-33"}
NEEDS = { # the revisions each result must name
"timing": ["sdc", "netlist", "layout", "spef", "lib", "tools"],
"power": ["upf", "netlist", "layout"],
"physical": ["layout", "netlist", "tools"],
"crossings": ["rtl", "sdc"],
"verification": ["rtl", "fw"],
"connectivity": ["rtl", "map"],
"equivalence": ["rtl", "netlist"],
"gate-level-sim": ["netlist", "sdc", "fw"],
}
EXPIRES = {"false": 90, "proven-safe": 180, "bounded-risk": 180}
DAY = 150
results = {d: {k: BASE[k] for k in keys} for d, keys in NEEDS.items()}
waivers = [ # id, owner, class, granted day
("W-009", "timing owner", "false", 120),
("W-014", "cdc owner", "proven-safe", 60),
("W-021", "timing owner", "proven-safe", 140),
("W-027", "verify owner", "bounded-risk", 100),
]
consumers = [("sw-headers", "7"), ("decoder", "7"), ("verify-model", "7")]
def check(results, waivers, consumers, day):
bad = []
for disc, keys in NEEDS.items():
ran = results.get(disc)
if ran is None:
bad.append((disc, "missing"))
continue
for k in keys:
if ran.get(k) != BASE[k]:
bad.append((disc, k, ran.get(k)))
for wid, owner, kind, granted in waivers:
if not owner:
bad.append((wid, "no owner"))
if granted + EXPIRES[kind] <= day:
bad.append((wid, "expired"))
for name, v in consumers:
if v != BASE["map"]:
bad.append((name, "map", v))
return bad
assert len(NEEDS) == 8
assert check(results, waivers, consumers, DAY) == []
# inject one violation per rule and demand exactly that finding
stale = dict(results, timing=dict(results["timing"], netlist="n87"))
assert check(stale, waivers, consumers, DAY) == [("timing", "netlist", "n87")]
gap = {d: v for d, v in results.items() if d != "equivalence"}
assert check(gap, waivers, consumers, DAY) == [("equivalence", "missing")]
assert check(results, waivers, consumers, 215) == [("W-009", "expired")]
ownerless = waivers + [("W-031", "", "false", 140)]
assert check(results, ownerless, consumers, DAY) == [("W-031", "no owner")]
assert check(results, waivers, [("decoder", "6")], DAY) == [("decoder", "map", "6")]
print("PASS: 8 results on baseline, 4 waivers live; each of 5 injected faults caught")The checker output for the frozen baseline is attached to the review, green, dated, and rerun after every ECO.
The waiver table the checker sees is the same table the review sees: one source, no side lists.
A red checker blocks the review agenda from proceeding to go and no-go; there is no discussing results the checker has not tied to the baseline.
When the checker fails, fix the manifest, not the checker: a result mismatch means rerun the check, an expired waiver means re-justify or fix the violation, a stale consumer means regenerate from the map. If the checker itself needs a ninth row, that is a process change the integrator announces; silent edits to the checker are falsifying the record.
# not-run: what the nightly log records, illustrative generic format
night 150: 8 results tied to rtl 214 / netlist n88 / layout gds-31, 4 waivers live, PASS
night 151: ECO-3 applied, netlist now n89, 5 rows stale (timing, power, physical, equivalence, gate-level-sim)
night 152: 8 results tied to netlist n89, waivers re-confirmed, PASSIt is not, if the ECO moved the netlist revision: the timing row would mismatch the baseline. A passing checker with a stale result means someone edited the revision by hand instead of rerunning, which is why results arrive from the flow, never typed in.