Repository navigation
receipt-keys gate red on main since 2026-09-28: header comments read as keyless instantiations #877
Description
What is wrong
TRI-NET portability and receipt keys (.github/workflows/trinet-portability.yml, job receipt-keys) has failed on every scheduled run on main from 2026-09-28 through 2026-10-04: 7 of 7. The last green scheduled run was 2026-09-27 on 9947512ff.
receipt-key check: 2 module default(s), 5 testbench instantiation(s) of 2 keyed module(s)
RULE 2 formal/tern_tc_layer_rtl_tb.v:7: instantiates trinet_node_core without passing RECEIPT_KEY. ...
RULE 2 formal/tern_tc_layer_rtl_tb.v:18: instantiates trinet_node_core without passing RECEIPT_KEY. ...
FAIL: 2 problem(s)
Lines 7 and 18 are comments in the testbench header. Both name the file fpga/portable/trinet_node_core.v. The only real instantiation is line 42, and it passes the key: trinet_node_core #(.BAUD_DIV_P(BAUD_DIV), .RECEIPT_KEY(128'h0)) dut (. So the bench obeys rule 2, and the red is a false positive in conformance/key_default_check.py, which matches module names in raw source, comments included.
The same defect also produces a false negative. The check accepts an instantiation if the text RECEIPT_KEY appears anywhere in its parameter list, so #(.BAUD_DIV_P(BAUD_DIV), /* .RECEIPT_KEY(128'h0) */) counts as passing a key. On today's tree that mutant reports only the two comment lines, nothing at line 42.
How it got onto main unseen
The testbench reached main in d7e9718 (merge of #355, 2026-09-27). The checker reads every formal/**/*_tb.v and every fpga/**/*.v, but the workflow's paths: list names one testbench and three RTL locations. #355 changed 13 files the checker reads and none on the list, so the gate did not run on the PR or on the push, only on the next day's schedule. Measured on main first-parent history since 2026-09-04: 3 commits touched files the checker reads (d7e9718, 0f4512b, 57de4a1), and all 3 were outside the paths list.
This is the same defect class as #875: one list of paths in the workflow and a second one inside the script, maintained by hand.
Plan
- This issue: blank comments and string literals before matching, keeping newlines so line numbers stay right. Add a CI guard step: a key written only in a comment must be rejected, at the line of the real instantiation.
- Follow-up, after ci: run nine workflows once per PR commit, on every path their push run watched #876 merges (it rewrites the same
on:block): make the workflow's paths cover what the checker reads. Widening the whole workflow tofpga/**/*.vwould also run theportabilityjob on every RTL change. That job takes about 2 minutes: 2m00s to 2m02s on four runs on 2026-10-04. (I first wrote "25-minute" here, which is itstimeout-minutes, not its duration.) Movingreceipt-keysinto its own workflow would avoid those 2 minutes per run, but it is no longer clearly the better shape. That is the owner's call.
Done when
python3 conformance/key_default_check.pyexits 0 onmain's tree and reports 3 testbench instantiations (not 5).- Mutants that must fail still fail, each with exactly one RULE line in the right place: the two the workflow already applies, plus the bench dropping its key and the key moved into a comment.
- Mutants that must pass do pass: a commented-out non-null default, and the module name inside a
$displaystring.
Part of #851 (W15: gates that fail or pass for a reason other than their claim).
🤖 Generated with Claude Code
Activity
ci(trinet): watch the bench the comment-key guard mutates
fix(conformance): stop reading header comments as receipt-key instant…
ci(trinet): watch the bench the comment-key guard mutates