CVDP RTL Agent
tb_top.cvdp_rtl_agentRESET@ 0 ns
22 to 26 October 2026·milestones M0 to M3d, report in public

CVDP RTL Agent: what passes the hidden testbench

IN ONE SENTENCE

An open LangGraph agent writes and fixes SystemVerilog for the 92 free problems of NVIDIA's CVDP benchmark, checks its own work in simulation, and is scored only by hidden cocotb testbenches: it solves 52 to 56 of the 92; none of six changes to how it checks its work, a frozen memory of lessons, two model-free checks run as fixed steps, or making it test before it submits moved that number by a detectable amount, while a richer harness (Deep Agents) added about +4.7 points on the 86 reachable problems, confirmed by a pre-registered run on this one model.

pass@1, best model
52–56 / 92
Haiku 5.5 on two runners; gpt-6-luna 52–53
cost per solved
$0.0105
gpt-6-luna, x86-64; Haiku $0.0184–0.0214
identical-run flips
10
problems change result between two runs of Haiku
ablations with an effect
0 of 6
every 95% interval includes 0
harness effect, confirmed
+4.7 pts
Deep Agents − LangGraph [+1.0, +8.5], pre-registered, 6 new runs an arm; memory, M3c checks and M3d verify step: none detectable
LLM spend, M1–M3d
≈ $50.76
provider-reported; the Claude Code ladder ran on a plan, not counted
Trace replay · csr_using_apb_interface_0001 · M3 run A1 · gpt-6-lunaevents in trace order, not to time scale

This is a real failure, replayed from the committed run data. The agent's design compiled, linted and synthesised, so it submitted after one turn, at a cost of $0.0024 over 52.6 s. The hidden testbench then reached for a clock called pclk. The design calls it clk. The test failed before it had checked any behaviour.

What CVDP is

CVDP (Comprehensive Verilog Design Problems) is a hardware-design benchmark published by NVIDIA researchers in 2025: 783 problems in 13 categories when it was released. Each problem asks for RTL to be written, changed or fixed. The result is scored by a hidden testbench, usually a cocotb test, that the solver never sees.

What this project is

An open LangGraph agent, run end to end in GitHub Actions on the free, open-tool split of CVDP 1.1.0: 92 problems in four categories (spec to RTL 34, RTL modification 25, spec to RTL with module reuse 22, bug fixing 11). Every cost is provider-reported (via OpenRouter), every score comes from the hidden tests, and no LLM ever scores anything.

agent.stateHOW_IT_WORKS

How it works

IN ONE SENTENCE

A six-node graph plans, edits, runs deterministic checks (compile, lint, synthesis, its own testbench) and decides whether to edit again or submit, under hard caps on turns, dollars and wall time, inside a Docker image that a GitHub Actions sweep runs on all 92 problems.

The graph is read_task → plan → edit → check → reflect → (edit | finalize). The LLM writes the plan, the edits and the decision. Everything else is code: the file tool writes only under rtl/, verif/ and docs/, and the checks are real tools (Icarus iverilog -g2012, verilator --lint-only -Wall, a Yosys read and synth, and a testbench the agent writes itself). The replay below is a long problem from the same run: nine turns, ending in a submit after the agent's own testbench had failed.

Graph replay · DES_0003 · M3 run A1 · 9 turns, 19 LLM calls, 27 tool callsturn 9 from the logged excerpt

Turns 1 to 8 are drawn from the problem's totals (each one ended in edit_again, because another turn followed); their individual events are not in the committed excerpt. Turn 9 and the hidden-test line are quoted from it.

The sweep, as a schematic

sweep.yml · one dispatch = one model, one setting, one runnerGitHub Actions
Both images are built natively for x86-64 and Arm64 and pulled from GHCR. The harness runs 4 problems at a time. A shared ledger stops new problems calling the LLM once the summed cost passes the run budget. The work directory is uploaded only if a scan finds nothing key-shaped in it.

Stop rules, checked in code before every step

  • Turns: 10 edit, check and reflect cycles by default.
  • Dollars: $0.10 per problem, provider-reported cost only. A call whose cost is not reported stops the problem (cost_unreported), because the budget can no longer be enforced.
  • Wall time: 480 s, under the harness's 600 s agent timeout. Each LLM call has a hard deadline 2 s before the cap.
  • On any stop or crash, the last edit that compiled is kept, the summary is written, and the agent exits 0.
WHYWhy sweeps run in GitHub Actions, not locally

The CVDP harness needs a Docker daemon, and Actions has one on every runner, free for a public repository, with jobs of up to 6 hours. GitHub's runners come in x86-64 and Arm64, so every sweep can run natively on both with no emulation. Every run leaves a public run ID and a downloadable artifact (per-test logs, traces, summaries), so anyone can check a number against its run. And the heavy Docker work stays off the development machine.

WHYWhy the LLM never scores

Pass or fail comes only from the hidden tests the harness runs after the agent exits. A judge model can be argued with by the thing it judges, and its mistakes would be correlated with the agent's own, since they are the same kind of model. The failure labels are also made by deterministic rules (see the taxonomy), so no number on this page depends on a model's opinion.

WHYWhy cost is taken only from provider-reported usage

Price lists drift, and the provider that serves a call can charge a different price from the list: DeepSeek's calls went to 15 to 19 different providers per sweep. So the agent records the cost OpenRouter reports for each call, asks the generation endpoint if that is missing, and otherwise records null and stops the problem. Nothing is estimated. Where a cost is missing, every table shows a lower bound marked with ≥.

milestone[3:0]M0..M3D

Milestones, M0 to M3d

IN ONE SENTENCE

Each milestone asked one question and answered it with runs anyone can download: does the harness run (M0), does the agent work (M1), how do models and reasoning settings compare (M2a, M2), do the agent's own checks pay for themselves (M3), does a richer harness or a memory of lessons help (M3b, then a confirming run), do two model-free checks run as fixed steps help (M3c), why do the problems no model solves fail (the unsolved analysis), and does making the agent test before it submits help (M3d).

M022 Oct
ASKEDDoes the harness run in Actions on both architectures, and what does an agent that changes nothing score?
ANSWEREDGolden check 1/1 on both. Null agent 0/92 on x86-64 and Arm64, 0/75 on the heavy split. Every pass after this is the agent's own.
M122–23 Oct
ASKEDDoes the agent work end to end, with every cent accounted for?
ANSWEREDOn 10 problems: Haiku 5.5 6/10, DeepSeek V4.1 Flash 5/10. 8 of DeepSeek's 49 calls came back empty after spending the whole token cap on reasoning. 55 tests, none needing an LLM.
M2a23 Oct
ASKEDAre the empty replies a reasoning limit, and what does reasoning cost?
ANSWEREDYes, max_tokens truncation. DeepSeek at off: 6/10 for $0.0867; at low: 7/10 for $0.3546 with 14 empty replies. Retries and seeds added.
M223 Oct
ASKEDHow do three models compare on all 92, and how noisy is one run?
ANSWEREDHaiku and gpt-6-luna tie at 52–56; Luna costs half as much per solved problem; DeepSeek is about 10 behind. 10 problems flip between identical runs. $8.55.
M323–24 Oct
ASKEDDo self-check, lint, turn caps or budget change the pass rate? Why does it fail?
ANSWEREDNo detectable effect from any of six changes. Of 565 failures, 147 are interface mismatches with the hidden testbench. $8.25.
M3b24–25 Oct
ASKEDAt a fixed model, does a richer harness (Deep Agents) or a frozen lessons memory raise pass@1 on the 86 problems an agent can reach?
ANSWEREDThe memory: no detectable effect (+1.6 [−3.1, +6.6]). The harness: perhaps a few points, clearest on top of the memory (+5.8 [+1.9, +10.1]); none passes a Bonferroni correction, so B − A went to a confirming run (next). $10.87.
M3b confirm25 Oct
ASKEDDoes the harness effect, B − A, hold on 6 new runs an arm, by one test fixed in advance?
ANSWEREDYes: +4.7 [+1.0, +8.5], so by the pre-registered rule it is confirmed, on one model and one benchmark. Sign test p = 0.093. $7.59.
M3c25–26 Oct
ASKEDDo a mutation-score gate on the agent's own testbench and an interface diff by elaboration, as fixed graph steps, beat base A on the same 86 problems?
ANSWEREDNo. M − A +0.8 [−3.9, +5.8], I − A −1.6 [−6.2, +3.1]. The gate changes the kind of failure, not the number. $6.39.
Ladder26 Oct · exploratory
ASKEDHow does Claude Code, with four Claude models, do on the same 86 problems?
ANSWEREDOne run each. Only Opus 5.5 is clearly above our agent (+11.6 [+1.9, +21.3]); harness and model both change. On a subscription plan, so no provider-reported cost.
Unsolved26 Oct · analysis
ASKEDWhy do the 12 problems that no Claude model solved fail: the benchmark, our environment, or the agents?
ANSWERED7 are benchmark-limited, with strong evidence: the hidden test needs a detail the task never gives. None is an environment failure. No sweep and no spend: local reruns and counterfactual reruns only.
M3d26 Oct
ASKEDDoes a step that refuses to submit until a testbench has passed (V), or that plus cases written blind from the specification (S), beat base A on the 86?
ANSWEREDNo. V − A −1.9 [−6.6, +2.3], S − A −4.7 [−11.2, +1.6], 97.5% intervals. The agent now tests, and its failures move to "own testbench passed". $7.90.
M4 / M5planned
ASKSM4: the write-up and logs packed for the LBC-bench leaderboard. M5: an open AMBA verification track scored by seeded-bug kill rate.
STATUSPlanned. No results.
results.m23 MODELS

M2: three models, 92 problems, two runners

IN ONE SENTENCE

Haiku 5.5 and gpt-6-luna solve the same share of the 92 problems, Luna at half the cost per solved problem, DeepSeek V4.1 Flash solves about 10 fewer, and two identical runs of one model differ on about 10 problems, so a gap of a few problems means nothing.

Each model ran all 92 problems once on an x86-64 and once on an Arm64 runner, with the same image and settings, against the null agent's floor of zero.

pass@1 with Wilson 95% intervals · one run per runnerCH1 = x86-64 · CH2 = Arm64
Each mark is one sweep of all 92 problems. The null agent (M0) passes none. Settings: $0.10 per problem, 10 turns, self-check and lint on, 4 problems in parallel.
cost per solved problem · provider-reportedUSD
Luna uses less than half of Haiku's tokens (2.6–2.8 M against 5.4–5.9 M per sweep). It is slower per problem: median 67–76 s against 44–47 s.

The capture: every problem, every full run

Below, each row is one problem and each column one full sweep of all 92, like the channels of a logic analyser. A filled cell is a pass; a bare baseline is a fail. The six M2 sweeps come first, then the 13 new M3 sweeps (M3's run A1 is M2's Luna Arm64 sweep, so it is not repeated). Rows are sorted by how often the problem passed.

92 channels x 19 sweeps · 1 = hidden tests passedred hatch = differs from the same model's other runner (M2 columns)
  • Run-to-run noise is large. Between its x86-64 and Arm64 runs, Haiku changed result on 10 problems, Luna on 9 and DeepSeek on 12. The direction is not consistent, so this reads as the model's sampling, not the runner.
  • Haiku against Luna is a tie. Counting each problem's passes over both runners, Haiku is ahead on 12 problems and Luna on 12. Both beat DeepSeek (24 against 6, and 21 against 6).
  • 29 problems passed in all six M2 sweeps and 28 in none. 24 failed in every one of the 20 full runs of M2 and M3.
  • 3 seeds on a 30-problem subset vary by up to 4 problems for one model (seeds table).
WHYWhy Wilson intervals, and why repeat runs

With 92 trials the normal approximation to a binomial interval is poor near 0% and 100% and can go outside [0, 1]; the Wilson score interval keeps its stated coverage at small n. But a Wilson interval only covers sampling over problems. It says nothing about the same problem coming out differently on a second run, which is why M2 ran every model twice and M3 measured the noise floor directly.

results.m36 ARMS

M3: six changes to the agent, none detectable

IN ONE SENTENCE

Turning the self-check or lint off, capping turns at 5 or 20, or cutting the budget to $0.02 changed the pass rate by less than two identical runs differ, though turning lint off made each solved problem 38 to 59% dearer.

Each arm is an ablation: one setting changed, everything else held. Every arm uses gpt-6-luna (the cheapest per solved problem in M2), all 92 problems, Arm64 and 4 threads, and runs twice. Each arm is compared with the base (A) problem by problem: a problem's rate in an arm is its passes over the arm's two runs, so 0, ½ or 1. The effect is the mean of the differences, with a paired bootstrap interval and an exact sign test.

paired effect on pass rate, points [95%] · against base Aband = noise floor, A2 vs A1

Intervals are from tools/ablate.py as committed in docs/reports/m3/arms_paired.md; the point effects and better / worse counts are recomputed from the CSVs by site/data/derive.py and agree.

F (20 turns) is the only arm worth a second look, ahead in both runs (62.0% and 58.7% against 57.6% and 55.4%). But only 6 of its 184 problem-runs used more than 10 turns, and 1 of those passed. The extra turns account for at most 1 of its 7 extra passes; the rest is noise.

Pareto · pooled pass rate against $ per problembars = 95% problem-bootstrap interval
The Pareto front is B, A and F, and its three points sit inside each other's intervals. The clear result is on cost: C and D are 33–55% dearer per problem. C's cost is a lower bound (one call unreported), so it is hollow and kept off the front.

What the agent did with its own testbench

problems where the agent ran its own testbench, of 92per run
With self-check on, the agent ran a testbench on only 31–32 problems. With lint off it ran one on 67, and the pass rate still did not move. Running its testbench more often does not help.
WHYWhy a paired bootstrap plus a sign test, not an unpaired comparison

Problems differ far more from each other than arms do: in M2, 29 problems passed every time and 28 never. An unpaired comparison of two pass rates puts all that between-problem spread into the error bar, and a 2-point effect disappears inside it. Pairing compares each problem with itself, so only within-problem change counts. The bootstrap resamples problems and keeps each problem's runs together, so it does not pretend the 184 problem-runs are independent. The exact sign test needs no distributional assumption at all: on the problems that changed, it asks whether "better" and "worse" are unbalanced.

WHYWhy the noise floor is measured on the same runner (A2 against A1)

An arm's effect means something only if it is bigger than the noise floor: the difference between two runs with nothing changed. Running the base twice on the same runner removes the runner as a cause. The result, −2.2 points [−8.7, +4.3] (3 better, 5 worse), is as wide as M2's Arm64 against x86 (−1.1 [−7.6, +5.4]), so the runner adds no noise of its own and 2 runs per arm resolve about ±5 points.

results.m3b4 ARMS

M3b: a richer harness, or a memory of lessons?

IN ONE SENTENCE

At a fixed model, a frozen memory of 40 lessons did not detectably change the pass rate; the Deep Agents harness added a few points, first as a hypothesis on 3 runs an arm, then confirmed by a pre-registered test on 6 new runs an arm (B − A +4.7 [+1.0, +8.5]), for this one model on this one benchmark.

M3b holds the model (gpt-6-luna), the Arm64 runner and every M2 default fixed, and changes two things in a 2×2 design: the harness that drives the model (M2's hand-built LangGraph graph, or Deep Agents), and whether the agent is given a frozen lessons memory. Each arm ran 3 times on the 86 problems of the evaluation set: the 92 minus 6 that no agent can reach, by a rule fixed before any scored run. Arm A is a fresh run of M2's agent on the same image, so all four arms share an image and a period.

four arms · pooled pass@1 over 258 problem-runs · $ per solved problemarrows = paired effect [95%]
Under each arm: its passes in each of its three runs, of 86. A solid arrow is a comparison whose interval excludes zero; a dashed one includes it. Pre-registered primary comparisons: B − A (harness) and C − A (memory); secondary: D − B and D − C.

The paired effects, null findings first

paired effect on pass rate, points [95%] · 86 problems, 3 runs an armband = noise floor on the 86, M3's A2 vs A1

Intervals are tools/ablate.py's paired problem bootstrap as committed in docs/reports/m3b/; the point effects, the better / worse / same counts and the exact sign tests are recomputed from the run CSVs by site/data/derive.py and agree.

  • The lessons memory did not help. C − A is +1.6 [−3.1, +6.6]: 10 / 8 / 68 problems better / worse / the same, sign test p = 0.82. C's three runs solved 51, 51, 51 of 86. On Deep Agents, D − B is +3.1 [−0.4, +7.0], p = 0.15: not detectable either.
  • The harness may help a little. B − A is +4.3 [+0.0, +8.5], p = 0.21: the interval's lower end rounds to zero and the sign test is far from significant. On top of the memory the harness is clearer: D − C is +5.8 [+1.9, +10.1], 9 / 1 / 76, p = 0.022, the one comparison whose interval excludes zero.
  • Why that was a hypothesis, not yet a finding. With four pre-registered comparisons, a Bonferroni threshold of 0.0125 on the sign tests passes none of them, and the bootstrap intervals are not adjusted. D − A (+7.4 [+2.3, +12.8]) was not pre-registered, so it is exploratory only. For scale: on these 86 problems the noise floor is −2.3 [−9.3, +3.5], and M3's largest effect (20 turns) is +4.1 [−0.6, +9.9]. So M3b named one hypothesis, the harness gain B − A, and a separate run was fixed to test it.

The confirming run: B − A on fresh data

CONFIRMED · 25 OCTOBER 2026

On 6 new runs an arm, B − A is +4.7 [+1.0, +8.5] points. The interval excludes zero and the effect is positive, so by the rule fixed in advance the harness effect is confirmed, for gpt-6-luna on these 86 problems.

The test was written down and committed before any of its runs was dispatched (pre-registration). It is a single pre-registered comparison, B − A, so there is no multiple-comparison correction. It uses 6 new runs per arm (seeds 4 to 9) with M3b's settings unchanged, and M3b's own runs are not pooled in, so the data that suggested the hypothesis does not also test it. The decision rule: if the paired 95% interval excludes zero and the effect is positive, the effect is confirmed; if it excludes zero and is negative, reversed; otherwise not confirmed, with the size it rules out.

B − A, the harness effect, points [95%] · 86 problemsband = noise floor on the 86
The first row is M3b's estimate, which suggested the hypothesis. The second is the confirming run, on data that did not. The pre-registered rule reads only the second row's interval.
confirming run · 516 problem-runs per armA = LangGraph · B = Deep Agents
Descriptive only, as pre-registered: no test on these counts. They check that the mechanism M3b described repeats.
  • How strong. 16 / 7 / 63 problems better / worse / the same; the exact sign test gives p = 0.093. The sign test was not part of the rule. It is shown so that the evidence reads as moderate, not overwhelming.
  • The size repeats. Pooled pass@1 is A 57.9% (299/516) and B 62.6% (323/516), close to M3b's +4.3.
  • So does the mechanism. Deep Agents leaves fewer failures untested (tests_failed_no_selfcheck: A 121, B 79) and stops on its round cap far more often (A 28, B 101 problem-runs), at about the same cost per solved problem (≥ $0.0126 against ≥ $0.0119; one call in each arm had no reported cost).
  • What it covers. One model (gpt-6-luna), one problem set (the 86 free agentic problems) and one Deep Agents version. The memory arms C and D, and D − C, were not re-run: the memory finding stands as M3b reported it.

Why Deep Agents differs: fewer untested failures, more round-cap stops

258 problem-runs per arm · passed, then failures by labellabels from tools/taxonomy.py
Counts are recomputed from the failure_label column of the committed CSVs and match docs/reports/m3b/taxonomy_by_arm.md.

Deep Agents runs a free tool-call loop: the model calls compile, lint, synthesis and its own testbench as tools, as often as it likes, up to a cap of 22 model calls (the most any M2 problem made in 10 turns). It leaves far fewer failures untested (tests_failed_no_selfcheck: A 58, B 39, D 33), but stops more often on its round cap (failures labelled stopped_by_cap: A 11, B 29, D 33). A cap stop still submits the best edit kept so far, and some pass: B hit the cap 49 times and 20 of those passed. With the lessons, the LangGraph agent has more failures whose own testbench passed (C 21 against A 15); with both, the fewest (D 8).

tokens and cost per arm, relative to arm A258 problem-runs each
Deep Agents resends the whole conversation every round: 45.7 M tokens against A's 8.9 M (about 5×; prompt tokens alone 43.6 M against 6.9 M), for about the same provider-reported cost. Its cost per million prompt tokens is $0.044 against $0.268, which points to provider-side prompt caching. Cached tokens are not recorded per call, so that is inferred, not measured.

What the memory learned

The builder read 87 attempts by arm A on 29 heavy-split problems (none in the evaluation set; 19 of the attempts passed), asked the model for general lessons in batches, and froze 40 of them into snapshot b783931cbf160595 for $0.0031. At run time the agent gets the top 5 by BM25 over its task text, with no model in the retrieval. The lessons are generic process advice, several near-duplicates, and 6 are never retrieved for any of the 86 problems (L07, L08, L17, L28, L30, L38: about compile diagnostics and turn budgets, words the problem statements do not use). The four retrieved most often, quoted as built:

The interface lessons did not move the interface failures: compile_fail_hidden stays at 12–13 and signal_missing_hidden at 2–3 on every arm. A null C − A says that this memory does not help, not that no memory could.

Cost

All four arms cost about the same: $0.0067 to $0.0074 per problem-run, and $0.0124 (A), $0.0119 (B), $0.0113 (C) and $0.0106 (D) per solved problem, with no unreported call in any of the 1,032 problem-runs. The arms differ in pass rate, not in price. The scored sweeps cost $7.27 in all, the learning runs at least $3.41.

WHYWhy the evaluation set leaves out unreachable problems

If the hidden testbench needs a name that appears nowhere in what the agent is given, no change to the agent can make that problem pass. Keeping it adds only noise and shrinks every effect towards zero. So the rule was committed before any scored run: a problem is unreachable when a name its hidden testbench reads is given nowhere to the agent and M3 labelled it an interface failure in at least half of its 14 runs. Both halves are needed: two problems read names the agent is not given but failed on them in only 1 of 14 runs, so they stay. Six problems are excluded, five of them for internal register or instance names and one whose context is empty.

WHYWhy the memory is frozen, and learned only on other problems

A memory that has seen the evaluation problems' outcomes or traces can carry their answers into the test. That is leakage, and it would make any gain meaningless. So the memory learns only from 29 heavy-split problems whose files to change all lie inside the agent's edit roots; the builder refuses, in code and under test, any work directory that holds one of the 92 agentic problems; the snapshot is built once in Actions, committed as built with no hand edits, mounted read-only and checked against its hash on load; and every result row names that hash. The memory does not grow during evaluation, so C − A measures one fixed memory.

results.m3c2 CHECKS

M3c: two model-free checks, as fixed steps

IN ONE SENTENCE

A mutation-score gate on the agent's own testbench and an interface diff by elaboration, each run in code at a fixed point of the graph, left the pass rate where it was (M − A +0.8, I − A −1.6 points, both intervals across zero); the gate changed the kind of failure, not the number.

M3 and M3b found the failures in two places: interface mismatches with the hidden testbench, and weak self-checks (no testbench of its own, or one that passes on code the hidden tests fail). M3c adds one deterministic check for each, with no model in it, to the LangGraph agent, and runs each against a fresh base A, 3 runs an arm on the same 86 problems. M − A and I − A are the two pre-registered comparisons.

  • M, a mutation-score gate before submit. Yosys mutate makes 12 mutated copies of the agent's design, and the agent's last testbench must fail on at least half of those that compile. With no testbench, the gate refuses the submit. After 2 gate failures the agent may submit anyway.
  • I, an interface diff by elaboration after every edit. pyslang elaborates the design, and its modules, ports and parameters are compared with the interface the agent was given. It never reads the hidden testbench. A mismatch turns one submit into one more edit, then lets it through.
paired effect on pass rate, points [95%] · against base A · 86 problems, 3 runs an armband = noise floor on the 86
Both intervals contain zero, and both point effects are smaller than two identical runs of the base differ. Pooled pass@1: A 61.6%, M 62.4%, I 60.1%. M − A is 13 / 10 / 63 better / worse / same (p = 0.68); I − A is 10 / 13 / 63 (p = 0.68).

The gate changes the kind of failure, not the number

258 problem-runs per arm · passed, then failures by labellabels from tools/taxonomy.py
Counts are recomputed from the failure_label column of the committed CSVs and match docs/reports/m3c/taxonomy_by_arm.md.

The gate did what it was built to do: it will not let the agent submit without a testbench, so failures with no testbench of the agent's own fell from 56 on A to 0 on M. But they did not become passes. Failures where the agent's own testbench passed and the hidden tests still failed rose from 14 to 50, and stops on a cap from 4 to 19, as the gate's extra rounds used up turns. Requiring a testbench is not requiring a correct one. The interface check moved neither of its own labels: the two interface labels together are 16 failures on A and 16 on I.

What the checks found

mutants killed, gate
56%
1,051 of 1,872 compiled mutants, by the testbenches the gate forced
gate runs skipped
61 / 390
Yosys could not mutate, or a parameter did not resolve: these fail open and let the submit through
cost per solved, M vs A
1.9×
≥ $0.0190 against ≥ $0.0099; median 135 s a problem against 51 s
interface checks with a mismatch
99 / 672
on 38 problem-runs
of those, passed anyway
21 / 38
so most findings were false, or named something the hidden tests do not read
submits turned into an edit
3
the interface check's soft block, over 258 problem-runs

The gate scores the agent's testbench, not the design. A testbench that checks the wrong behaviour thoroughly kills mutants and passes the gate, and the hidden tests then fail the design. The interface check reads the given interface from prompts and documents by rules, not by a parser of the specification, so a port listed in an unusual format is missed and a document can produce a false finding. Neither check costs tokens itself; M's extra cost is the extra rounds of reflect and edit it causes.

WHYWhy the new checks are fixed steps, not tools

A check the model may skip is a check it often skips. In M3, with self-check available as a tool, the agent ran its own testbench on only 31–32 of 92 problems, and the largest failure label in M3b is still "hidden tests failed, no testbench of its own" (58 of arm A's failures). So M3c's checks run in code at fixed points of the graph; the model sees their results but does not decide whether they run.

WHYWhy a mutation score, and why a threshold of one half

A testbench that passes says nothing about whether it could fail. Mutation testing asks that directly: change the design a little, and see whether the testbench notices. Some mutants change nothing the outputs can show (equivalent mutants), so no testbench can kill all of them; that is why the bar is half of the compiled mutants, not all. The gate's settings (12 mutants, seed 1, threshold 0.5, 60 s, 2 failures) were fixed before any scored run.

results.claude_code4 MODELS

Beside it: Claude Code as the whole agent

IN ONE SENTENCE

Exploratory, one run per model: Claude Code with Opus 5.5 solved +11.6 points more of the 86 problems than our LangGraph agent with gpt-6-luna, the only clear gap, and since both the harness and the model change, it says how good that pairing is here, not which change is responsible.

Here the whole agent is swapped. Claude Code runs headless (claude -p) inside the harness's container, with file and shell tools and a 60-turn budget, on four Claude models, one run each, on the same 86 problems and the same 480 s wall cap. Each is paired problem by problem with M3c's arm A (LangGraph with gpt-6-luna, 3 runs, 61.6%). It was not pre-registered.

paired effect against LangGraph + gpt-6-luna, points [95%]dashed = one run, exploratory
Pass@1 in each row's label. Only Opus's interval excludes zero (25 / 9 / 52 better / worse / same, p = 0.009); Sonnet's reaches just below it ([−0.4, +17.4]). The band is the base's own noise floor; a one-run arm carries that noise on top of the interval shown.
  • Not in order of model size. Opus 73.3%, Sonnet 69.8%, Fable 67.4%, Haiku 66.3%.
  • Fable is held back by the wall cap. It stopped on the 480 s cap on 17 of 86 problems, and 10 of those failed; its median wall time is 265 s against 24 to 83 s for the others. Under this cap its score is a lower bound, not a measure.
  • Two things change at once. Each arm differs from the base in both the harness and the model. The LangGraph agent with a Claude model was not run.
  • Cost is not comparable. These runs used a subscription plan, so no call has a provider-reported price. Claude Code's own estimates at API rates are in the report, labelled as estimates; they are not money spent, and are not drawn here.
  • At least one Claude model solved 74 of the 86 problems, and all four solved 45.

The problems no Claude model solved

ANALYSIS 12 of the 86 problems, 10 of them never solved by arm A either

Every attempt on these problems, by the 4 Claude models and the 3 runs of arm A, was rerun locally against the hidden tests in the harness's own simulation image, and all but one gave the same result as CI. A counterfactual rerun then changed one detail of a failing attempt: the detail the test needs and the task does not give. These reruns are diagnosis, not scores, and no model wrote the change. The finding: 7 of the 12 are benchmark-limited, with strong evidence. Two examples:

  • A file name given nowhere. In sync_serial_communication_0001 the hidden build compiles sync_serial_communication_top.sv, a name that appears nowhere in the prompt, the specification or the given testbench. Every Claude attempt passes once its RTL is put in a file of that name.
  • Default parameters the prompt never gives. In traffic_light_controller_0001 the hidden test counts cycles against default timer values of 10 and 20, while the prompt names the parameters and gives no values. Every attempt rerun with those defaults set, and nothing else changed, passes.

2 more look benchmark-limited on weaker evidence (one hidden test is not deterministic), 3 are agent-limited, and none is an environment failure. M3b's reachable.py kept the file-name problem in the evaluation set because it checked the names the hidden test reads, not the file paths it compiles.

pass@1 on all 86, and on the 79 left without the 7the 86 is the score; the 79 is beside it
Arm A 158/237 = 66.7% on the 79 against 61.6% on the 86; Opus 63/79 = 79.7% against 73.3%. Nothing passed the 7 except one arm-A run of rc5_0001, so every rate rises and none falls. The full-86 score stays the reported one.

The same report compared the 7 problems that at least 2 Claude models solved and arm A never did: in 14 of arm A's 20 valid attempts on them, it submitted without running any testbench, while the passing Claude attempts wrote or ran one and fixed what it showed. That is the question M3d tests next.

results.m3dNULL ×2

M3d: verify before submit

IN ONE SENTENCE

Forcing the agent to pass a testbench before it submits, with or without extra cases written blind from the specification, left the pass rate where it was (V − A −1.9, S − A −4.7 points, both intervals across zero): the agent now tests almost every time, and its failures move to "own testbench passed, hidden tests failed".

Our agent submits after one turn on about half its problem-runs (47% on arm A) and runs no testbench of its own on 55%, because its reflect step accepts a clean compile, lint and synthesis. Claude Code iterates: it writes or runs a testbench and fixes what it shows. Does making our agent verify before it submits close that gap? M3d adds two fixed graph steps the model cannot skip, and runs each against a fresh base A, 3 runs an arm on the same 86 problems and settings as M3c.

  • V, verify before submit. A submit is refused until the design, as it stands after the last edit, has passed a testbench the agent ran: its own, or one the task gives. After 2 refusals, or when no edit can follow, the submit goes through.
  • S, V plus specification cases. Before planning, one LLM call writes cycle-level test cases from the task and its documents only. It never sees the RTL, the given testbenches or anything the agent wrote; a unit test checks that on the recorded request. Verify applies the cases too.
paired effect on pass rate, points [97.5%] · against base A · 86 problems, 3 runs an armband = noise floor on the 86
The decision rule was pre-registered before the first scored run: each comparison at a 97.5% interval (Bonferroni over 2), better or worse only if the interval excludes zero. Both include it, so both read "no detectable effect", and each interval's upper end is the largest gain it leaves open. Pooled pass@1: A 60.9%, V 58.9%, S 56.2%. V − A is 7 / 9 / 70 better / worse / same (p = 0.80); S − A is 12 / 19 / 55 (p = 0.28).

The failure mix moves, again

258 problem-runs per arm · passed, then failures by labellabels from tools/taxonomy.py
Counts are recomputed from the failure_label column of the committed CSVs and match docs/reports/m3d/taxonomy_by_arm.md. "Other" holds llm_error: calls abandoned at the wall-cap deadline (A 2, V 14, S 9).

The step did what it was built to do. Failures with no testbench of the agent's own fell from 55 on A to 0 on V and 2 on S. They did not become passes. Failures where the agent's own testbench passed and the hidden tests still failed rose from 16 to 48 and 44, and cap stops from 7 to 27 and 43, as the extra turns ran into the 480 s wall cap. This is M3c's lesson a second time: a testbench the model writes agrees with the model's own misreading. The blind specification cases, written by the same model, carry the same misreadings.

runs with no self-check
55% → 1%
A to V, and 7% on S; median turns 2 → 3 (V) and 4 (S)
hidden pass when spec cases pass
61% vs 57%
82/135 when every case passed on the final design, 36/63 when some failed: barely better than chance
cost per solved vs A
1.6× / 2.1×
V and S: ≥ $0.0181 and ≥ $0.0234 against ≥ $0.0112; median 135 s and 247 s a problem against 74 s
  • The verify step refused a submit on 155 of V's 258 problem-runs, mostly because no testbench had run on the current files, and the agent then edited. The refusals fell mostly on problems the agent was going to get right anyway.
  • S's guard caveat. 8 of S's problem-runs were stopped by the whole-run cost guard, which charges the per-problem budget for every call whose cost was not yet reported, and S makes more calls. They count as failures, as pre-registered. Counted at A's pass rate instead, they would move S − A by about +1.9 points: still negative, and the verdict does not change.
  • Without the 7 benchmark-limited problems (79 problems, beside the full-86 result, not instead of it): A 66.2%, V 64.1%, S 61.2%; V − A −2.1 [−7.2, +2.5], S − A −5.1 [−12.7, +1.7].
  • The problems Claude Code won stay lost. On the 7 problems that 2 or more Claude models solved and M3c's arm A never did, V and S pass 1 and 1 problem-runs of 21, as A does (1): making the agent run a testbench is not what Claude Code did there. It wrote a testbench that checks the right behaviour.

What it means

On this model, changes to the agent's process are now null three times: a memory of lessons (M3b), a mutation gate and an interface check (M3c), and verify before submit (M3d). What has moved the score is the harness (Deep Agents, M3b, confirmed by a pre-registered run) and the model (the Claude Code ladder, where harness and model change together). That is one model, gpt-6-luna, on one benchmark, at a resolution of a few points. It does not say that process never matters; it says that, here, checks the model writes for itself do not catch the model's own misreadings.

WHYWhy the spec call is kept blind to the design

Cases written by a call that has seen the design tend to describe the design, not the specification, so they pass whatever was built. S's call gets the task, the files under docs/ and a port table extracted in code from the given RTL, and nothing else. A unit test checks the recorded request for markers placed inside the given module body and a given testbench, and finds neither. Blind to the design is not blind to the model: the same model reads the same specification the same way.

hidden_tb.fail565 X

Why it fails

IN ONE SENTENCE

Of 565 failures, about half are hidden-test failures where the agent never ran a testbench, a quarter are interface mismatches with names the hidden testbench uses, and when the agent did test its own work, its testbench passed on code the hidden tests failed 61 times out of 73.

Every failed problem-run in M3's 14 runs gets one label: the first of a fixed list of rules that holds, read from the harness's per-test log, the agent's trace and its summary. The rules are in tools/taxonomy.py; no model is involved.

565 failed problem-runs · one cell each · M3, 14 runsred = interface mismatch

Counts are recomputed from the failure_label column of the committed CSVs and match the M3 report.

The interface story: a handle the agent was never given

Two labels are interface failures: the hidden build failed on code that compiled for the agent (74 failures, on 8 problems), or the hidden testbench reached for a port, signal, instance or parameter by a name the design does not have (73 failures, on 9 problems). The agent cannot see either from its own checks, because the names are only in the hidden testbench.

Probe miss · csr_using_apb_interface_0001 · run A1from the per-test log
trace: compile exit=0 iverilog -g2012 -o /code/rundir/agent_tb/compile.vvp -I/code/rtl /code/rtl/csr_a
trace: lint exit=0 verilator --lint-only -Wall -Wno-fatal -Wno-MULTITOP --timing -I/code/rtl /code/
trace: synth exit=0 yosys -q -p read_verilog -sv /code/rtl/csr_apb_interface.sv; hierarchy -auto-top
trace: llm reflect decision="submit"
log:   AttributeError: csr_apb_interface contains no child object named pclk. Did you mean: 'clk'?
log:   ======================== 2 failed, 3 warnings in 1.13s =========================

For 6 of the 9 missing-name problems, the main name the hidden testbench reads is not in the prompt or in any file the agent is given. No change to the agent can be expected to match it. Those failures belong to the benchmark items, and M3b leaves them out of its evaluation set.

ProblemName the hidden testbench readsGiven to the agent?Errors
phase_rotation_0038control_fsm.state_ffNO840
phase_rotation_0031detect_sequence.curr_stateNO550
phase_rotation_0010phase_rotation_viterbi.data_i4_ffNO234
poly_decimator_0001poly_decimator.poly_branchesNO52
direct_map_cache_0001direct_map_cache.INDEX_WIDTHYES48
ttc_lite_0001ttc_counter_lite.enableYES*24
digital_stopwatch_0001dig_stopwatch_top.reset, .second_pulse; .hourNO; YES for hour12, 4; 4
csr_using_apb_interface_0001csr_apb_interface.pclkNO2
dynamic_equalizer_0008equalizer_top.uu_awgn_real, .uu_awgn_imagNO1 each

*A common word that may not name the signal. "Errors" counts every AttributeError line over the 14 runs, so a parametrised test counts many times. The search is a word search of each problem's prompt and context files; it is not yet a committed tool.

Self-check passed, hidden tests failed: 61 of 73

When a submission failed and the agent had run its own testbench on it, the last run of that testbench had passed in 61 of the 73 cases. Its testbenches check less than the hidden ones. These 61 failures are spread over 26 problems.

73 failed submissions with an own-testbench run · top: own testbench (blue = passed, ochre = failed) · bottom: hidden tests (hatched = failed)M3, 14 runs
Each pair is one failed problem-run: the upper segment is the agent's own testbench, the lower one the hidden tests.
WHYWhy deterministic rules plus hand labels, with a separate hold-out set

Rules give every failure exactly one label by a fixed precedence, from logs and traces, the same way every time, so anyone can rerun them on the committed CSVs. Hand labels check whether the rules say what a person reading the log would say. The rule-development set (15 real failures) found that the earlier rules missed name mismatches: they agreed on 12 of 15, the misses led to the signal_missing_hidden rule, and with it they agree on 15 of 15. Because that set shaped the rule, it cannot score it. So a hold-out set of 15 other failures was drawn after the rule was fixed (seed 20261024): 15 of 15 agree. It contains no signal_missing_hidden case, so the new rule is checked only on the development set, and the same person wrote both the labels and the rule.

dv.coverage_map7 CONCEPTS

Read as a verification engineer would

IN ONE SENTENCE

The agent's self-check is a testbench with no coverage and no quality measure, which is why it passed on code the hidden tests failed in 61 of 73 cases; the planned M3c milestone answers that with a mutation-score gate on the agent's testbench and an interface diff by elaboration.

The hidden cocotb tests play the role of a sign-off regression the designer cannot see. The agent's own testbench plays the designer's unit test. Mapped onto the usual verification concepts, here is what the project does and does not do.

ConceptWhat this project doesWhat it does not doStatus
Reference model and scoreboard The hidden tests compare the design with a model; a DES failure reads DUT o_data does not match model o_data. The harness's pass or fail is the only score. The agent's own testbenches are not inspected for whether they have a model; that is not measured. HIDDEN TESTS ONLY
Coverage Nothing measured. The 61-of-73 result is the symptom: a testbench that passes on wrong code did not exercise what the hidden tests exercise. No code or functional coverage on the agent's testbench. The M5 track plans functional coverage in cocotb. NOT MEASURED
Testbench quality Measured indirectly, from outcomes: the own testbench passed in 61 of 73 failed submissions where it ran (84% false passes on those). No direct measure yet. M3c plans a mutation score: does the agent's testbench catch deliberately broken copies of its own design? INDIRECT
Constrained-random stimulus Not asked of the agent; its prompt lists the checks it may run. No constrained-random generation and no seed sweep of stimulus. NOT DONE
Assertions (SVA) None. Static checks are Verilator lint and a Yosys read and synth. No SVA. The M5 track plans SVA properties checked with SymbiYosys. PLANNED (M5)
Formal: BMC, equivalence, mutation None run yet. Planned for M3c: a mutation-score gate on the agent's testbench (Yosys mutate) and an interface diff by elaboration (pyslang), both fixed steps in the graph. Formal checks of SVA properties with SymbiYosys are planned for the M5 track. No equivalence checking is planned. PLANNED
Regression triage Done: a deterministic label for each of 565 failures, checked against hand labels; a measured noise floor (flaky results: 10 problems flip between identical runs); a null-agent floor and a golden check (M0). The hidden build's own compiler message is not in the log, so the cause of each compile_fail_hidden is not shown one by one. DONE

The two M3 failure modes have verification answers. A testbench that passes on wrong code is a testbench-quality and coverage problem: a mutation score asks whether the testbench fails on mutated copies of the design, and so measures what it can catch. A name the hidden testbench needs but the design lacks is an interface problem: elaborating the design and diffing its ports, parameters and hierarchy against the specification catches it before submission, when the name is given. Neither has results yet.

published.resultsCONTEXT

How this compares with others

IN ONE SENTENCE

Three published rows use exactly these 92 problems in the same release, and they land in the same range as ours (48 to 53 of 92 against our 41 to 56); everything else published on CVDP uses other problems, other modes or commercial tools, and is context only.

Every number here was checked against its primary source on 24 October 2026. Our runs use only the free, open-tool split (92 problems, four categories), specific models, one run per setting in M2 and pass@1 from a single sample.

COMPARABLE Same 92 problems (agentic_code_generation_no_commercial), same release 1.1.0

Why these compare: the same problem file, the same release, and the same score (the hidden tests, one run, pass or fail). Why only roughly: different models and agents, two of them with no agent loop at all; all three are marked "not independently verified" on the leaderboard; only one gives any cost figure; and the leaderboard's harness and dataset commits may differ from this project's pins (harness 8e894cf, dataset revision 5b807d9). Wilson intervals on their rows are computed here, from k and n. Source: LBC-bench, data file leaderboards.json at b835413.

The plain reading: Haiku 5.5 and gpt-6-luna inside this agent (52 to 56) land where two frontier models land in a single turn on the same problems (52 and 53), and near Claude Code with Sonnet 4.6 (48). With one run each and intervals about 20 points wide, none of these differences is established.

M3b's four arms (57.8% to 65.1% pooled pass@1), its confirming run, M3c's three arms and the Claude Code ladder (66.3% to 73.3%) are not drawn beside these rows: they were scored on 86 problems, the 92 minus 6 that no agent can reach, so their rates are higher by construction and do not sit on the same 92 as the LBC-bench rows. The LBC-bench row for Claude Code (Sonnet 4.6) is a different model and a different run from our ladder.

CONTEXT ONLY Different problems, modes, tools or metrics

One further paper evaluates small models with an agentic framework on CVDP (Shankar et al., arXiv:2512.05073); its abstract gives no pass rates, and none are quoted here.

assert.validityLIMITS

Threats to validity: what this does not show

IN ONE SENTENCE

These results hold for one cheap model per ablation arm, on 92 open-tool problems (86 in M3b, M3c and M3d), at a resolution of a few points; they say nothing about smaller effects, other models, the heavy or commercial splits, or verification-writing tasks.

  • One model per arm. Every M3, M3b, M3c and M3d arm uses gpt-6-luna. An ablation that does nothing for it may matter for another model.
  • Sampling is not seeded. CVDP_SEED is a label only; OpenRouter sampling cannot be seeded across providers. Both runs of every M3 arm carry the label seed 1.
  • The free, open-tool split only. 92 problems in four categories. The verification-writing categories (testbench stimulus, checkers, assertions: cid012–014) need Cadence Xcelium and are not run.
  • 2 runs per arm resolve about ±5 points in M3, and M3b's 3 runs on 86 problems do little better. A real effect smaller than that would read as "no detectable effect". The null results are not evidence of no effect.
  • M3b makes four comparisons with three runs an arm. None of its sign tests passes a Bonferroni threshold of 0.0125, and the bootstrap intervals are not adjusted. The confirming run re-tested only B − A, as one pre-registered test (+4.7 [+1.0, +8.5], confirmed); D − C was not re-tested and stays a hypothesis.
  • The confirmation is one model and one benchmark. gpt-6-luna on the 86 free agentic problems, with one Deep Agents version. Its sign test (p = 0.093) is moderate evidence; the rule read the interval only.
  • Every Claude Code ladder arm is one run, and the ladder was not pre-registered. Read its effects against the base's run-to-run spread, on top of the interval shown.
  • The ladder changes harness and model together. Claude Code with a Claude model against LangGraph with gpt-6-luna, with a 60-turn budget against 10; it does not say which change is responsible. Its plan has no per-call price, so it has no comparable cost.
  • M3c's gate fails open when it cannot mutate. 61 of 390 gate runs were skipped and let the submit through, so M is not a pure "every submit was gated" arm.
  • Some problems are benchmark-limited. 7 of the 86 evaluation problems need a detail the task never gives (a file name, default parameters, a lookup table), shown by counterfactual reruns. No agent can be expected to pass them, so they cap every score and shrink every effect a little. They are kept in the reported scores, and the 79-problem figures are shown beside them, never in their place. reachable.py, which built the 86, checked the names the hidden test reads but not the file paths it compiles.
  • M3d's specification cases are written by the same model. The spec call is blind to the design, not to the model's way of reading a specification, so its cases share the agent's misreadings; a different, stronger model for that call was not tested. M3d also kept M3c's 480 s wall cap, and much of V's and S's loss is cap stops: a larger cap would be a different experiment.
  • M3d's S lost 8 problem-runs to the whole-run cost guard, which charges unreported in-flight calls. Counted at A's pass rate they would move S − A by about +1.9 points, not enough to change its verdict.
  • M3b tests one memory snapshot. 40 generic lessons from 87 attempts, only 19 of them passes, several near-duplicates, 6 never retrieved. A null C − A says this memory does not help, not that no memory could.
  • M3b's caching claim is inferred. Cached prompt tokens are not recorded per call, so the reading that Deep Agents' extra tokens are mostly cached rests on its cost per prompt token, not a measured cache-hit count. Its rounds are also not turns: compare the harnesses on cost and wall time, not on turns.
  • The M3b effects are paired on the 86 reachable problems. On all 92 the 6 excluded problems fail in all 72 of their runs, so every effect is a little smaller and no finding changes (B − A +4.0, C − A +1.4, D − C +5.4 points).
  • The hand-label hold-out had no signal_missing_hidden case, so the new rule is checked only on the set it was developed on, and the same person wrote the rules and the labels.
  • Problems are treated as exchangeable by the bootstrap and the sign test. cid003 (34 problems) weighs most.
  • Self-check pass or fail is read from truncated tool output in the trace.
  • The hidden build's own error text is not in the log, so a likely cause (a renamed or missing parameter on phase_rotation_0028) is not shown for each problem.
  • "Is the name given to the agent?" is a word search over prompt and context files. It cannot tell a signal from the same word in prose, and it is not yet a committed tool or done for compile_fail_hidden.
  • No per-category or AMBA effects. On the 8 AMBA problems every run passed 3 or 4; two runs give no power on 8 problems.
  • One run per runner in M2. The seeds measure the noise on 30 problems, not on 92, and the reasoning setting for each model was picked from one run on 10 problems.
  • The heavy split (75 problems) is never scored with the agent. In 46 of them the files the reference solution changes lie outside the agent's edit roots (M1 gave 53 from a check it did not commit; M3b's committed tools/learn_in_roots.py gives 46). M3b runs the agent on the other 29 only to build its lessons memory, and 3 of those (i2c 7, 46, 49) gave no test output in any attempt.
  • Some costs are lower bounds: one unreported call in M2 (DeepSeek seeds), one in M3 (arm C), 2 in the M3b confirming run, 4 in M3c and 37 in M3d.
  • Caps are soft by design: wall time by up to about 40 s, the budget by up to one call.
  • Model serving varies: DeepSeek's calls went to 15–19 providers per sweep, so its cost and behaviour mix providers.
  • One log label is wrong but harmless: tools/log_check.py called a simulation that hung "harness_error" (4 in the first two M2 sweeps); the pass rates are right.
next_stateOPEN

What's next: open questions

IN ONE SENTENCE

M3d is done and the harness effect is confirmed; a stronger testbench requirement has now been tested and was null, three questions stay open, and no milestone to answer them has been fixed.

OPEN · FROM M3C, M3D AND THE LADDER
  • The same LangGraph agent with a Claude model. Open. The ladder changed the harness and the model together, so it cannot say which moved the score. Running our LangGraph agent with a Claude model would separate the two. It is not planned.
  • The gate's skipped cases. 61 of 390 gate runs (16%, on 38 problems) could not mutate the design and let the submit through: parameters that do not resolve to integers, and designs Yosys could not read or mutate.
  • Fable under a longer wall cap. It stopped on the 480 s cap on 17 of 86 problems, so its ladder score is a lower bound.
  • Repeat runs for the ladder. Every Claude Code arm is one run, and not pre-registered; the base's own runs differ by a few points between identical sweeps.
  • A stronger testbench requirement than "has one". Tested by M3d: null. Requiring a passing testbench before submit (V − A −1.9 [−6.6, +2.3]), and adding cases written blind from the specification (S − A −4.7 [−11.2, +1.6]), moved failures to "own testbench passed" (16 → 48), as M3c's gate did (14 → 50).
reviewer.q[23:0]24 Q

Questions a reviewer might ask

IN ONE SENTENCE

The short answers, each with the file it comes from.

glossaryTERMS

Glossary

IN ONE SENTENCE

The terms used above, in plain words; dotted links in the text jump here.