HW Design-Space Agent

/record

Project record: how it was built and why

A living record of what has been built, how, and why, published here as an engineering log. The planner session updates it after every verified milestone; this copy is checked against the agent's repository at the commit this site vendors, and where they differed the repository won.

Last updated 2026-10-11 (the local Vivado runs merged; site part C4). Checked against HW_Design_Space_Agent at 80415c6. All three repositories are MIT-licensed.

1. Summary

The project is a LangGraph agent for hardware design-space exploration. Given a hardware spec (function, throughput, accuracy, area/power budget), it explores architecture families and parameters and converges on a Pareto-optimal design, going down a ladder of fidelity: spec → analytical model → system-level and cycle-level simulation → RTL and verification → synthesis → back-annotation.

The first design space is a CORDIC sin/cos unit on an Artix-7 FPGA, chosen because it's small enough to search exhaustively. That gives a true answer to score the agent against, which most agent demos lack.

Where it stands on 2026-10-11:

milestonestatusheadline
M1: spec intake + analytical exploration + evalmerged (0082ccd)The agent picks the right design better than NSGA-II and random search, but maps the trade-off front worse.
Site, parts A–C4A–C3 live (82e2a33, 2026-10-11); C4 (this version) re-vendored at 80415c610 pages incl. this record at /record, the write-up at /writeup and "For a hardware team" at /adoption; the ASIC target, the fleet and its A/B animated from real data; the local Vivado runs' numbers on Results and the case study; every number traced to the vendored repo commit.
M2: RTL, verification, synthesis, gate level, back-annotation, whole-curve agentmerged (9060f8f)The front-mapping gap is closed (0.96–1.09× NSGA-II hypervolume) and the agent still selects better in 8 of 9 model/spec cells. All 47 RTL configurations match the golden model in 2 simulators.
Vivado calibration anchors + L5 refitmerged (bbbf71e), verified before merge in three review rounds14 generated designs measured in Vivado 2025.2; no spec's winning design changes; M1 stays the default cost model, because the refit does no better out of sample.
M3: cycle-level and system-level simulation, campaign agentmerged (a92fe65), verified before merge in two review roundsL2 (SimPy system + cycle-accurate models, 48/48 traces identical to RTL) finds a different winner on a system-constrained spec; the Deep Agents campaign layer gained nothing over the structured graph at 1.4–2.25× the cost, so it stays experimental.
M4: ASIC cost model, fleet, write-upmerged (b119c8a), verified before merge in two review roundsA second target (sky130 via Yosys + OpenSTA, 57 measured points + 9 held out) gives the same family ranking with shallower pipelining; a code-orchestrated fleet picks better designs than one graph for Qwen (regret lower in 22/25 pairs) but maps the front no better; docs/WRITEUP.md is the final report, every number test-bound to the data.
Vivado M4 runs + refit (PR #7)merged (80415c6), verified before merge in two review roundshigh_precision m=8 measured at its own 20 ns clock misses 50 MSPS (49.88 post-synthesis, 48.31 post-route), so m=6 stays; the per-family-class path factor is rejected by a rule fixed before the fit; the first measured FPGA power (Vivado vectorless) ranks designs as the power index does (Spearman 0.98) but is off by 20.6% RMS.

2. Why this project

  • The idea. Hardware architecture is trade-off exploration: area against throughput against accuracy against power. An AI agent is the perfect environment for trade-off exploration: it can read a spec, decide which families and ranges are worth searching, interpret results and decide what to do next, around the clock, while deterministic tools do the measuring. It's a way to avoid premature optimisation: explore first, then spend effort on the critical 3% that matters (after Knuth, "Premature optimization is the root of all evil", ACM Computing Surveys 6(4), 1974).
  • The showcase. It demonstrates both production software practice (LangGraph, Python, TypeScript, tests, CI, eval harnesses, a deployed site) and deep hardware expertise (bit-exact models, RTL, formal verification, synthesis, calibration against real tool results).

3. Principles every milestone follows

  1. The LLM is never the optimiser and never produces a power/performance/area, accuracy or system-level number. It does the architect's job: choose families and ranges, interpret summaries, decide to refine, widen, map the front, declare the spec infeasible, or stop. Code produces every number: a bit-exact model, cost models, Optuna NSGA-II, Pareto/hypervolume maths, simulators and synthesis tools.
  2. Every number carries its provenance: exact (bit-accurate simulation), estimate (cost model, naming its calibration, or an L1 analytic bound), measured (tool, version) or simulated (the L2 system model, since M3).
  3. Scored against ground truth. An exhaustive grid of 635,040 designs gives the true front and the true optimum per spec. The agent is compared with NSGA-II and random search at the same evaluation budget.
  4. Results come only from real LLM runs, with model IDs, tokens and cost recorded. A scripted fake LLM is used only for tests, and the eval harness refuses it.
  5. Losses are reported first. The site's Results page opens with where the agent lost.
  6. Reproducible. Every run's trace is committed; the results file regenerates from the committed data with no diff; the site vendors the repo at a pinned commit, with hashes, and its TypeScript ports of the models match the Python fixtures exactly.

4. How the work is done

The project itself is built with AI coding agents (Claude Code), under a deliberate process:

  • A planner session reads the state, makes or asks for decisions, writes self-contained briefs, and independently verifies each result before anything merges.
  • Executor sessions do the work from a brief:
    • cloud sessions for milestones that need live LLM calls (an OpenRouter key held as an environment variable, never printed, logged, traced or committed);
    • local sub-agents for the site and for Vivado, which is installed locally. Executors open PRs; the planner merges after verification.
  • Verification gates before a merge: CI green at the PR head; tests re-run locally; a scan of the full git history and every trace for key material; the results file regenerated with no diff; the traces' cost sum matched to the results; the key's usage checked against the spend cap; numbers in prose spot-checked against the data files; for M2, an independent code review posted on the PR and a Vivado spot-check.
  • Spend cap: $5 of LLM usage per milestone.
  • Small machine discipline: one heavy job at a time under a memory cap; heavy synthesis and evals run in the cloud where possible.

5. Decision log

Every decision that shaped the project, oldest first: what was decided, by whom, what it replaced, and why. “Planner” and “executor” are the AI coding-agent sessions described in section 4; the owner takes the decisions that are his.

  1. 2026-10-07

    1. Start the LangGraph portfolio with an upgrade of an existing coding agent (Ollama provider, bounded sub-agents, MCP tools).

      Decided by:owner(owner)

      Instead of: four other project ideas

      Why: Quickest visible win; done as v0.2.0.

    2. Live LLM work runs in cloud sessions through OpenRouter; models: an open-weights model (qwen/qwen3.8-27b), a frontier model (anthropic/claude-sonnet-5.5) and a cheap open-weights MoE (deepseek/deepseek-v4.1-flash).

      Decided by:ownerplanner(planner, owner agreed)

      Instead of: local inference (no GPU here); one provider per model

      Why: One API and one key; open vs frontier vs cheap is the comparison readers care about.

  2. 2026-10-08

    1. A hardware design-space agent replaces the planned "RTL verification agent"; verification becomes its L3 stage.

      Decided by:owner(owner)

      Instead of: stand-alone verification agent

      Why: A bigger, more distinctive idea that still includes verification.

    2. The LLM never optimises or produces numbers; provenance labels on every number.

      Decided by:ownerplanner(planner, owner agreed)

      Instead of: let the LLM estimate PPA

      Why: LLM numbers can't be trusted or reproduced; the agent's value is in decisions.

    3. CORDIC sin/cos on Artix-7 as the first design space, using the owner's existing RTL and Vivado results as anchors.

      Decided by:planner(planner)

      Instead of: a larger accelerator

      Why: Exhaustively searchable, so the agent can be scored against the truth.

    4. Structured outputs via JSON schema, not forced tool calls.

      Decided by:executor(M1 executor)

      Instead of: forced tool_choice

      Why: One provider route for the frontier model rejected forced tool choice.

    5. Qwen run with reasoning off as well as on, and both recorded.

      Decided by:executor(M1 executor)

      Instead of: drop the model

      Why: With default reasoning it exhausted its token budget; reasoning off was about 15× faster by wall-clock and 8× cheaper.

    6. M1 merged with its honest finding: better selector, worse front-mapper.

      Decided by:planner(planner)

      Instead of: tune before publishing

      Why: The finding is the story; the site leads with it.

    7. The showcase site copies the house style of the owner's "explained" sites, but stays outside that family's switcher. Levels not yet built are shown ghosted with status badges; "24/7 fleet" claims are framed as what the architecture enables, with measured cost/time; the engineer-time calculator uses the reader's own numbers.

      Decided by:ownerplanner(planner, owner agreed)

      Instead of: animate the whole ladder now

      Why: The site may claim only what is true of the vendored commit.

    8. CORDIC repo relicensed MIT so its RTL can be vendored.

      Decided by:owner(owner)

      Instead of: clone at a pinned commit

      Why: Simpler, self-contained builds.

    9. Vivado anchors at 6 points (unrolled_k k=2/4, pipelined_m m=2/4, pipelined W=12/24), run locally after M2.

      Decided by:owner(owner)

      Instead of: anchors before M2

      Why: Two of the families had no RTL until M2's generator existed.

    10. The agent must cover the whole trade-off curve, not just select.

      Decided by:owner(owner)

      Instead of: keep it as a selector

      Why: A hardware architect needs the front, not one point.

    11. 5 seeds per spec and model (up from 3).

      Decided by:owner(owner)

      Instead of: 3 seeds

      Why: Agent variance was high.

  3. 2026-10-09

    1. M2's eval keeps M1's Vivado-anchored cost model as the default; the open-source synthesis refit is reported separately.

      Decided by:planner(planner)

      Instead of: recalibrate first

      Why: Keeps the ground truth fixed, so any change is the agent's, not the model's.

    2. If open-source place-and-route won't install, report resource counts with no Fmax rather than estimate timing.

      Decided by:planner(planner)

      Instead of: estimate timing

      Why: No invented numbers. (It did install, so it wasn't needed.)

    3. The whole-curve levers are tuned offline by replaying recorded M1 decisions, with one small live pilot before the full eval.

      Decided by:plannerexecutor(planner, M2 executor)

      Instead of: tune on live runs

      Why: Cheap, repeatable, and it keeps the eval itself out of the tuning.

    4. M2 review: one comment-only review on the PR; the executor fixes its own branch.

      Decided by:planner(planner)

      Instead of: planner pushes fixes

      Why: Never two sessions pushing to one branch.

    5. Add a Deep Agents "campaign" layer in M3 over the existing graph, with an A/B against the structured graph, and cross-run memory.

      Decided by:ownerplanner(owner, on the planner's recommendation)

      Instead of: replace the graph with a free-form agent

      Why: The structured graph is what makes results reproducible and comparable; long-horizon campaigns and memory are where a free-form harness may earn its keep. Measuring it is the point.

    6. Vivado work split: the local machine produces measurement data only (one commit, reports with host names redacted); the cloud session does the refit, docs and PR. Post-synthesis numbers drive the refit; post-route numbers are reported alongside.

      Decided by:plannerexecutor(M2 executor, planner agreed)

      Instead of: local session does everything

      Why: Keeps code changes in one place, and the data reproducible from committed reports.

    7. L5 refit (PR #4): keep M1 as the default cost model; post-route Vivado rows reported, not fitted; defer a per-family-class timing factor until the high_precision candidates are measured; run 6 more Vivado points to settle it.

      Decided by:ownerplannerexecutor(cloud executor proposed, planner review agreed, owner yes to the extra run)

      Instead of: adopt the refit or the class factor now

      Why: On the 14 Vivado points the refit's leave-one-out error is no better than the untouched M1 model's (LUT 15.4% vs 15.4%, Fmax 12.5% vs 11.7%), and the high_precision winner (m=6 vs m=8) hinged on a margin inside either model's error, so only a measurement could settle it. (Figures at the merged commit bbbf71e; the first review round quoted earlier, larger numbers.)

    8. After the second Vivado batch (PR #4, 51 fitted points): high_precision stays m=6; M1 stays the default cost model; the per-family-class timing factor is deferred, not rejected (then; it was rejected on 2026-10-11 by a rule fixed before the fit, below).

      Decided by:plannerexecutor(cloud executor, adjusted by the planner's review)

      Instead of: adopt the class factor (better average out-of-sample Fmax error: 7.4% against 12.5% on Vivado points)

      Why: m=6 is feasible both after synthesis and after routing. The class factor would flip the refit's winner to m=8 on a point whose measured margin (0.24%) is inside every model's error, and post-route timing says m=8 is infeasible. Revisit it with more points near the boundary, and with m=8 synthesised at the real 20 ns constraint.

    9. This record is maintained and published on the site.

      Decided by:owner(owner)

    10. Site part C: replay a real M2 run (Sonnet / low_area_control / seed 2, which picked the worked-example design) as the home animation; never animate planned levels; publish this record at /record as a site copy whose numbers are unit-tested against the vendored data; the repo wins any disagreement.

      Decided by:plannerexecutor(executor proposed, planner verified)

      Instead of: hand-drawn illustrative animation; link to an unpublished record

      Why: Every number on the site must trace to a commit; a tested copy turned up six stale figures in this record, now corrected.

    11. M3 system specs: L1 uses optimistic analytic bounds for system constraints, L2 simulates candidates; ground truth comes from the SimPy model itself (635,040 designs share only 1,092 latency/interval/Fmax combinations).

      Decided by:executor(cloud executor)

      Instead of: system metrics only at L2 (hides the winner from L1); a vectorised surrogate

      Why: Exact simulated ground truth at low cost.

    12. M3: the map_front blind-spot fix ships as a gated lever (LEVERS_M3), default only on system specs.

      Decided by:ownerexecutor(executor proposed; owner kept it off for the M2 specs)

      Instead of: unconditional fix (dds HV 0.878 → 0.781); default everywhere

      Why: Keeps M2 results comparable; the offline high_precision gain (+8.0% → +4.0% regret) comes from a single run.

    13. M3 A/B scope: campaign arm on Qwen + DeepSeek for all specs, Sonnet on multiaxis_control only; the full Sonnet arm (~$6.9) is skipped.

      Decided by:ownerexecutor(executor (spend cap), owner confirmed)

      Instead of: raise the key limit and run it

      Why: The two cheaper models showed no gain; little to learn for the money.

  4. 2026-10-10

    1. M3 review B1: L2 checks every L1-feasible design, not just the front's top k; live runs re-scored offline rather than re-run.

      Decided by:plannerexecutor(planner review found it; executor fixed)

      Instead of: extend the shortlist to 20

      Why: On multiaxis_control the true winner (m=4) is dominated at L1 by m=5, so a front-only shortlist could never reach it. Simulation is cached, so checking all is cheap; L1 evaluations were unchanged, so no new spend.

    2. M3: numbers in the campaign LLM's free-text memory notes are masked before storage and before reaching the inner architect.

      Decided by:plannerexecutor(planner review found it; executor fixed)

      Instead of: drop notes altogether

      Why: One note carried a mis-scaled error figure (~19% where the data implied +36%); the LLM must not originate numbers.

    3. Keep the campaign agent experimental (optional, off by default); rework only if the M4 fleet design needs it.

      Decided by:owner(owner)

      Instead of: invest in it in M4; drop it

      Why: No gain on HV or regret, higher cost, Qwen loops in 4/30 campaigns, memory showed no benefit.

    4. M4 ASIC target: sky130_fd_sc_hd at TT 25 °C 1.80 V, Yosys 0.33 + OpenSTA 3.1.0, post-synthesis with a wire-load model; 9 measured points never fitted, kept as a validation set.

      Decided by:ownerexecutor(cloud executor; owner kept the hold-out)

      Instead of: other PDKs/corners; fold the held-out points into the fit

      Why: An open, pinned flow anyone can rerun; held-out points are the only honest check on the ASIC ground truth.

    5. M4 fleet: code coordinates several structured graphs (split by contract class, two phases, phase 2 by merged-front share); no LLM coordinator.

      Decided by:executor(cloud executor)

      Instead of: one member per family; an LLM coordinator from the campaign layer

      Why: The coordinator's decisions are arithmetic over numbers code already has, and M3 showed what an LLM layer costs.

  5. 2026-10-11

    1. M4 review: fix the fleet's write-only shared store and unspendable small budgets, then re-run the Qwen fleet (~$0.32) rather than run the full Sonnet arm (~$3.7).

      Decided by:ownerplanner(owner, on the planner review's evidence)

      Instead of: full Sonnet arm; fix without re-running

      Why: A cheap re-run tests whether the cold restart caused the fleet's loss (it did not); Sonnet would only repeat a result two models already show.

    2. OpenROAD only via its own pinned release binaries or digest-pinned image, never Anaconda's commercial channel; kept planned for now.

      Decided by:owner(owner)

      Instead of: install from the commercial channel

      Why: Its terms have no open-source exemption, which would pass an obligation to anyone following the repo's recipe.

    3. 07V/07R: the owner's local Vivado run first (20 ns high_precision, report_power), data only to a branch, then a local compare/refit PR (no LLM spend), before any after-M4 item.

      Decided by:owner(owner)

      Instead of: after-M4 items first (need a higher key limit)

      Why: Settles the two items left open since PR #4 at no API cost.

    4. Per-family-class path factor: adopt into the (non-default) M4 refit only if (a) Vivado Fmax leave-one-out improves and (b) it puts m=8 infeasible and m=6 feasible as measured. (a) held (12.5 → 7.4%), (b) failed (m=8 at 52.51 MSPS against 49.88 measured): rejected.

      Decided by:plannerexecutor(planner set the rule before the fit; executor applied it)

      Instead of: judge it after seeing the numbers

      Why: A rule fixed in advance can't be tuned to the result.

    5. A design re-run under a different clock constraint is counted once in the refit (the 10 ns row kept); the M4 refit then equals vivado-2025.2. A per-family power activity calibration is kept non-default.

      Decided by:plannerexecutor(planner review found the double count; executor fixed)

      Instead of: fit both rows

      Why: Counting twins twice made leave-one-out look better than it was (12.2% on 16 vs 12.5% counted once).

    6. A public "For a hardware team" page on the site (pros and cons against general-purpose agents, deployment, improvements).

      Decided by:owner(owner)

      Instead of: a private note only

    7. Site C4: the FPGA power check shows the repository's Spearman (0.982, ties ranked by order) with the tie-averaged value (0.988) beside it; two designs tie at 22.0 mW post-synthesis. The repository is not changed.

      Decided by:executor(site executor)

      Instead of: report one figure only

      Why: The site claims only what the vendored commit says, and says where a convention changes a number.

    8. Keep the ASIC calibration as scored; no refit on the held-out points; state the asic_multiaxis_control winner's measured deadline miss plainly.

      Decided by:owner(owner, on review evidence)

      Instead of: refit on all 66 points, with an unrolled_k term

      Why: No winner moves under any refit, none fixes the miss, and refitting would end the validation set. A measure-and-re-explore loop is the real fix.

6. Results

M1 (merged 0082ccd; 48 live runs, 3 seeds)

  • Selection regret (how far the chosen design is from the true optimum on the spec's metric): the agent beat both baselines on every spec (best +1.6% / +3.1% / +1.6% against NSGA-II's +12.3% / +12.4% / +8.0%).
  • Hypervolume: NSGA-II won on two of three specs (0.800 and 0.905, against the agents' 0.16–0.70). The agents dived at the spec's corner and a 1% hypervolume-gain stopping rule ended the run early.
  • Infeasible spec: every model, on every seed, declared it infeasible and named throughput as the binding constraint (the true maximum is 291.5 MSPS against 400 asked for).
  • Cost: $1.74 provider-reported; about $2.50 by the key's usage.

M2 (merged 9060f8f; 60 live runs, 5 seeds)

  • L3 verification: generated RTL for all four families matched the bit-exact golden model in 47 configurations × 2 simulators (Verilator and Icarus) with zero mismatches, exhaustive up to 16 bits. 7/7 formal proofs at 8 bits. 22 gate-level simulations of the synthesised netlist, zero mismatches.
  • L4 synthesis: 39 points through Yosys + nextpnr-xilinx, every one labelled with tool versions and command lines.
  • Hypervolume relative to NSGA-II: 0.97–1.09 on the two specs where M1 lost (M1: 0.18–0.87).
  • Selection: the agent still beat NSGA-II in 8 of 9 model/spec cells. It lost on Qwen high_precision (+17.5% ± 27.2 against +10.3%, one bad seed).
  • What it cost: DeepSeek's selection got worse (2.2% → 7.6% and 1.6% → 5.1%), and the agent now always uses the full 400-evaluation budget, so M1's "fewer evaluations" advantage is gone.
  • Spend: the key's usage rose by $1.66 between the before and after readings (provider-reported $1.67 including the pilot; the two readings' timing cannot fully separate the pilot).

M3 (merged a92fe65; structured arm 30 new runs, campaign arm 65 runs, 5 seeds)

  • L2 vs RTL: the cycle-accurate model matched the RTL on 48/48 traces (28,424 clock edges, 8 designs × 3 seeds, Verilator and Icarus).
  • M2 comparability: all 60 M2 runs replay identically under M3 code, down to byte-identical architect prompts, so the A/B reuses them.
  • System specs (ground truth simulated, exhaustive): on multiaxis_control the system winner is pipelined_m m=4 (1,072 LUT+FF), where the MSPS-only view picks m=7 and even peak-rate sizing picks m=5. On bursty_offload the simulated winner differs from an average-rate view but equals peak-rate sizing, so L2 adds nothing there. A third spec (dds_sfdr) changes nothing and is kept as a negative result.
  • Structured agent on the system specs: HV 0.84–0.87 against NSGA-II's 0.81–0.84; regret +3.2% to +15.8% against NSGA-II's +16.0% / +26.7%.
  • A/B, structured → campaign (pooled): DeepSeek HV 0.905 → 0.893, regret +7.3% → +7.7%, cost 1.62×; Qwen HV 0.872 → 0.819, regret +9.2% → +19.0%, cost 1.44×, 4/30 campaigns failed by looping; Sonnet (one spec) HV 0.839 → 0.833, regret +3.2% → +5.7%, cost 2.25×. In 52 of 65 runs the campaign agent's plan came down to a single 400-evaluation call to the structured graph.
  • Memory on vs off (Qwen, 3 seeds): no benefit; the run-to-run noise is as large as any effect.
  • Spend: $3.58 by the key's usage (ledger $3.49), under the $5 cap; the before reading preceded the first run.

M4 (merged b119c8a; ASIC eval 45 runs, fleet A/B 55 + 55 paired runs + 25 re-run, 5 seeds)

  • ASIC flow (measured): Yosys 0.33 + OpenSTA 3.1.0 on sky130_fd_sc_hd (TT, 25 °C, 1.80 V, 10 ns), 57 fitted points across all four families plus 9 held out; CI re-measures all 57 identically.
  • ASIC model (estimate): leave-one-out error 8.7% area, 4.6% FFs, 10.6% Fmax, 5.8% power index. Held out: area within 5% on 9/9, Fmax −14.9% to +39.6% (optimistic by more than 1% on 5 of 9).
  • ASIC specs (exhaustive ground truth): the family ranking matches the FPGA's on all three, but pipelining is shallower (m=3 vs m=7; m=2 vs m=5). On asic_multiaxis_control L2 changes the winner (m=2 W17 N16) — and that winner misses its deadline at its measured 72.2 MHz (p99 0.567 µs against 0.5), which the model did not predict.
  • ASIC eval (regret, low area / power / multiaxis): Sonnet +0.8 / +3.5 / +17.9%; NSGA-II +6.1 / +54.0 / +23.4%; 45/45 selections meet spec.
  • Fleet vs single graph (same specs, seeds, 400 evaluations; runs not overlapping): the fleet maps the front worse (pooled HV loss, sign test p = 0.014; significant for DeepSeek). After the store and budget fixes, Qwen's fleet picks better designs: regret +6.3% against +14.8%, lower in 22 of 25 pairs (p = 0.0002), with HV still no better, so the cold restart did not explain the HV loss. Caveat: the re-run was hours after the single arm.
  • Throughput (measured; 24 h figures labelled projections): 16,094 designs/hour for the fixed Qwen fleet against 25,212 for one graph.
  • L2→L1 feedback: never fires on the committed specs (0/92 recorded, 0/60 live); on a constructed spec it fires in 3 of 15 searches and recovers 3 of 3, against 1 of 3 without it.
  • FPGA path untouched: all 60 M2 and 30 M3 runs replay identically.
  • Spend: $4.15 by the key ($3.83 first pass + $0.32 fleet re-run), under the $5 cap.

Vivado M4 runs + refit (merged 80415c6, PR #7; local Vivado 2025.2, no LLM spend)

  • high_precision at its own 20 ns clock (measured): m=8 49.88 MSPS post-synthesis (WNS −0.05 ns), 48.31 post-route; m=6 65.39 and 53.96. m=8 misses 50 MSPS in both views; the winner stays m=6.
  • Path factor (rejected by the pre-set rule): one factor per family class would cut Vivado Fmax leave-one-out from 12.5% to 7.4%, but it predicts m=8 at 52.51 MSPS (+5.3%), i.e. feasible, which the measurement contradicts.
  • Refit: counted once per design it is the vivado-2025.2 fit (51 points; Vivado leave-one-out LUT 15.4%, FF 3.7%, Fmax 12.5%; M1 15.4 / 3.1 / 11.7%). No spec's winner changes; M1 stays the default.
  • First measured FPGA power (Vivado report_power, vectorless, Low confidence): the power index ranks the 14 designs well (Spearman 0.982 post-synthesis, 0.969 post-route) with 20.6% / 36.3% log-RMS error; it reads unrolled_k low (0.61–0.97× post-synthesis, 0.48–0.85× post-route). A per-family activity factor gets 10.2% in-sample, 13.9% leave-one-out (non-default).
  • Routed vs synthesised Fmax: 0.675× (pipelined) to 1.056× (unrolled_k); every model throughput is an unrouted figure.

7. What review found (M2)

An independent review (no high-severity bugs; 3 medium, 5 low; posted on the PR) found:

  • the final front-mapping round can exceed the spec's per-round and round-count limits (the 400 total is respected);
  • the per-family recalibration overfits (leave-one-out error 12.9% against 9.0% in-sample on LUTs), and its unweighted fit lets 37 open-source points outvote the 2 Vivado anchors;
  • a Vivado spot-check of the generated pipelined design: 720 LUT / 751 FF / 327.4 MHz against the reference RTL's 745 / 784 / 272.9. Generated and reference RTL agree on area but not on timing, which the Vivado anchor work must account for;
  • prose claims to correct: two marked wrong (the dense-sweep angle count above W = 16, and an unrolled_k conclusion drawn from one comparison) and three to soften.

All were fixed on the PR. M2 itself was merged before the planner's re-check of the fixes (a check after the merge found nothing wrong); from the Vivado refit on, every PR has been verified before merge.

7b. What review found (M3)

Two planner review rounds before merge, both posted on the PR (round 1, round 2). Round 1: 1 blocking, 6 should-fix, 12 nits.

  • Blocking: L2 shortlisted only from the L1 front, so it could not reach the multiaxis_control winner; its test passed only because it hand-built a front. Fixed (all L1-feasible designs), with a regression test on a real front.
  • Campaign tests were skipped in CI (dependency missing); now required on Python 3.11+.
  • Overclaims corrected: L2 did re-select in 4/65 campaign runs; the campaign's "whole ladder" mostly had no RTL or synthesis data; bursty_offload's winner change holds only against an average-rate view.
  • LLM-written memory notes carried self-computed numbers; now masked.
  • The cost table compared different spec sets for Sonnet; fixed.

Round 2 found everything fixed and 2 optional nits, which the executor also fixed before merge.

7c. What review found (M4)

Two planner review rounds before merge, both posted on the PR (round 1, round 2). Round 1: no blocking, 7 should-fix, 15 nits; every data claim reproduced.

  • The write-up's number test let 59% of deliberately altered numbers pass; it now binds every number in order to a named fact, and all 658 mutants fail. The tighter test found two real errors, both fixed.
  • The A/B wording overclaimed the HV loss and called Qwen's regret gain "mixed"; paired sign and t tests now set it.
  • The fleet's shared store was never read and a 10-evaluation member budget could not be spent; fixed and re-run.
  • The Vivado power parser double-counted core power; the constructed feedback spec used a 1 MS/s floor against a 130 MS/s stream; three doc slips. All fixed.

Round 2: one doc fix (a ruled-out refit still listed as planned), fixed before merge.

7d. What review found (PR #7, Vivado M4 runs + refit)

Two planner rounds, both posted on PR #7. Round 1: no blocking, 1 should-fix, 3 nits; every output regenerated byte-identically.

  • The two 20 ns post-synthesis rows duplicated the 10 ns rows and escaped the duplicate filter by their tool label, so the refit counted two designs twice and its leave-one-out looked better than it was. Now counted once, in code, with a test.
  • A cached calibration made the first decision run score a refit with stale constants and print "adopted"; the cache is cleared after a refit, the test now fails on the bug itself, and the history is recorded.

Round 2: verified, all items fixed. The path factor's rejection held under both counts.

8. Known limitations

  • One design space (CORDIC); one FPGA family and one ASIC library (sky130, typical corner, post-synthesis only — no place and route).
  • The default cost model is still M1 (two Vivado anchors), by choice: the Vivado-weighted refit on 14 measured points did not predict unseen points better, so it is reported, not adopted. Its error is about 15% RMS on LUTs and 12% on Fmax.
  • Vivado post-synthesis Fmax is the cost model's timing scale; routed Fmax is lower, by up to about a third on the short-path pipelined designs.
  • The power figure is a relative index, not watts. It is now checked against Vivado's report_power, which is itself a vectorless estimate, not a measurement of real switching.
  • Natural-language spec intake has only been tested with a scripted model.
  • 5 seeds is still a small sample; some cells overlap within one standard deviation.
  • The A/Bs are incomplete for the frontier model: Sonnet's campaign arm (M3) and fleet arm (M4) each cover one spec.
  • The ASIC model's Fmax is optimistic by more than 1% on 5 of 9 held-out points (by 0.7% on a sixth), and the asic_multiaxis_control winner fails its deadline at its measured clock.
  • The fixed fleet ran hours after the single-graph arm it is compared with, so provider drift is not ruled out.
  • M3's wall-clock figures were measured with 3–4 runs in parallel (M4's were not).
  • System-level metrics come from a SimPy model, not from hardware: its interface contract is checked against the RTL cycle by cycle, but it runs each design at its estimated Fmax, and it aligns requests to the next clock edge with no synchroniser (a real clock-domain crossing would add about two cycles).
  • Only one of the two evaluated system specs needs the system model (multiaxis_control, by a 1.5% margin); on bursty_offload a peak-rate throughput floor gives the same winner.

9. What's next

  1. M2 done (9060f8f); Vivado anchors and the L5 refit done (bbbf71e, PR #4): 14 generated designs in Vivado 2025.2, no spec's winner changes, M1 stays the default cost model.
  2. Site part C1 live 2026-10-09 (ad6101a): L3, L4, gate level and L5 animated from real data; this record.
  3. M3 done (a92fe65): SimPy system-level and cycle-level simulation; the campaign agent and its A/B; cross-run memory.
  4. Site part C2 live 2026-10-10 (d195189): L2 and the A/B on the showcase site; this record synced.
  5. M4 done (b119c8a): ASIC cost model on sky130, a code-orchestrated fleet and its A/B, L2→L1 feedback, the write-up (docs/WRITEUP.md).
  6. Site part C3 live 2026-10-11 (82e2a33): the ASIC target, the fleet A/B and the write-up on the showcase site.
  7. Local Vivado run done (80415c6, PR #7): m=8 misses at 20 ns, the class path factor rejected, first measured FPGA power.
  8. Site part C4 (this version): a "For a hardware team" page (/adoption: pros and cons against general-purpose agents, a proposed deployment, improvements) and the PR #7 numbers; this record synced.
  9. After M4: an ASIC measure-and-re-explore loop; OpenROAD place and route from pinned binaries.

See the results and the roadmap for the same story in numbers and milestones.