What a waiver is, exactly
In a typical signoff flow you accumulate hundreds to thousands of findings: lint warnings, structural warnings from synthesis, CDC tool reports, formal inconclusives, coverage holes, simulation regressions whose root cause is a known stub. A waiver is the structured record that says: this finding is known, the team has decided not to fix it before tapeout, and here is why. The minimum fields are
- rule_id — the specific check being waived (for example inferred_latch, width_mismatch, cdc.no_synchronizer).
- file, line, and ideally a target (signal, instance, or assertion path) so the waiver only applies to the specific finding, not the whole rule class.
- reason — why it is being waived. "Known false positive" is not a reason. "Latch is intentional and held by
opcode_en; tracked in SOC-3401" is. - submitted_by, reviewed_by, and expires_at — who proposed it, who signed off, and when it auto-fails again.
Treat the waiver record as evidence the same way you treat a regression report. It needs to be searchable, diff-able in code review, and tied to a tracking issue. The field set above maps onto the .chipverify/waivers.yaml file ChipVerify reads on every pipeline run, but the principle applies regardless of tool.
Why waivers matter at tapeout
You cannot fix every finding before tapeout. A modern SoC accumulates tens of thousands of lint warnings, hundreds of CDC reports, formal inconclusives on properties whose proof depth would take a week, and synthesis advisories on legacy IP nobody owns. The fixes for some of these are real bugs you must repair. The fixes for others are either irrelevant (a lint rule that does not apply to your style), intentional (a latch in a power-island controller), or risky to touch this close to tapeout (a refactor of a battle-tested module).
The team has to make a decision on each finding: fix, defer, or accept. Waivers are the artifact of an accept decision. Without them, the only way to ship is to lower the noise floor — turn rules off, raise thresholds — which destroys the signal you need to catch the next class of bug. With waivers, the noise floor stays where it should be and individual exceptions are explicit.
The ChipVerify model
ChipVerify treats waivers as a first-class object on the project. Every finding emitted by every engine carries a stable (rule_id, file, line, target)tuple. A waiver is a record that matches one or more of those tuples; when it matches, the finding stays visible in the report but is tagged waived rather than counted against the project’s closure score. The score and the closure dashboard read this status directly — see verification plan for how that flows into the tapeout gate.
A typical waivers file looks like this. Each entry is keyed by a stable id so it can be referenced from a tracking issue and cross-linked from the report:
# .chipverify/waivers.yaml
version: 1
waivers:
- id: WV-2026-0142
rule_id: inferred_latch
file: rtl/legacy/uart_ctrl.v
line: 87
target: uart_ctrl.opcode_q
reason: >
Legacy UART controller. Latch is intentional and held by opcode_en;
original always_latch rewrite tracked in JIRA SOC-3401. Will be
replaced when the bus refactor lands in Q3.
submitted_by: ananya@chipverify.ai
reviewed_by: rohit@chipverify.ai
submitted_at: 2026-04-22T13:11:00Z
expires_at: 2026-07-22T00:00:00Z
issue: SOC-3401
- id: WV-2026-0148
rule_id: width_mismatch
file: rtl/dsp/mac_array.sv
line: 213
target: mac_array.acc_q[31:24]
reason: >
Top byte of the accumulator is intentionally truncated; saturation
logic in mac_sat.sv guards the overflow. Verified by sva_sat_pass.
submitted_by: ling@chipverify.ai
reviewed_by: ananya@chipverify.ai
submitted_at: 2026-04-30T09:42:00Z
expires_at: 2027-01-30T00:00:00Z
issue: SOC-3517Workflow: from finding to waiver to closure
The lifecycle on a typical project run:
- Pipeline runs (lint, simulation, synth-lint, design-structure, CDC, formal). Each engine emits findings with a stable rule_id + location.
- On the issue panel, an engineer reviews a finding, decides it is acceptable, clicks "Waive", types a reason, and sets expires_at. The UI writes the entry into .chipverify/waivers.yaml on a feature branch.
- The waiver goes through the team’s normal pull-request review. The reviewer is the second pair of eyes — this is where blanket-waiver and missing-reason patterns are caught.
- Pipeline re-runs. The finding is now reported as status: waived with a link back to the waiver record and the reviewer.
- CI policy (configured per-project) decides whether waived findings count toward the build status. A common choice is "honor waivers, but fail the build the day they expire".
- Quarterly, the team reviews open waivers, extends or retires them, and feeds the patterns back into the rule-tuning process.
CI policy: honor or ignore?
The CI integration lets you decide what a waived finding means. Two policy modes cover most teams:
- Honor. Waived findings do not count against the build. The CI light is green if every remaining open finding is fixed or waived. This is the right mode for active development — engineers can ship features behind an explicit accept decision.
- Ignore. Waivers are advisory only; CI fails on any finding that is not fixed. This is the right mode immediately before signoff — you want every waived item to come back into focus so you can decide whether it needs a real fix or an extended waiver.
Either way, an expired waiver is an expired waiver: it stops counting as accepted the day expires_at passes. The policy file is the single source of truth for what the build treats as a passing waiver:
# .chipverify/policy.yaml
version: 1
ci:
honor_waivers: true # CI green if all remaining issues are waived
fail_on_expired_waiver: true # an expired waiver counts as a fresh failure
require_reviewer: true # waivers without reviewed_by are rejected
block_on_blanket: true # waivers without file+line are rejected
max_extension_count: 2 # how many times a waiver can be re-issued
signoff_gate:
forbid_rules:
- x_propagation
- clock_domain_crossing.no_synchronizer
forbid_waivers_for_rules:
- x_propagation # cannot be waived; must be fixedBest practices
- Always set an expiry. A waiver with no expires_at outlives the engineer who wrote it. Three months is the default most teams converge on for active development; six months for stable IP.
- Require a reviewer. The engineer closest to the bug is the worst person to decide it is not a bug. Two-eye review on every waiver is cheap insurance.
- Tie waivers to issues. Every waiver should reference a tracking ticket. The ticket is where the unfix lives; the waiver is the temporary acceptance that lets the project move on while the ticket is open.
- Re-review on a cadence. Quarterly. Look at every waiver. Extend, retire, or fix. A team that has not retired a waiver in two quarters is sleepwalking.
- Forbid waivers on the highest-risk rules. Some findings are not waivable. x_propagation and cdc.no_synchronizer are good candidates — a waiver on either is a silicon failure waiting to happen. Encode this in policy so the UI rejects the waiver before the reviewer sees it.
Anti-patterns
- Blanket waivers. A waiver with no file (or worse, no rule_id) silences a whole class of finding. Disable the rule in policy if you do not want to see it; do not pretend it is waived.
- Infinite expiry. A waiver with expires_at: 9999-01-01 is a silenced rule with extra paperwork. If the finding is truly permanent (a vendor IP that ships with a known warning), capture that in a per-file rule disable, not a waiver.
- Undocumented reasons. "Reviewed, OK to ship" is not a reason. The reason needs to survive the engineer leaving the team. If the next person reads the waiver and cannot reconstruct why it was accepted, the waiver is broken.
- Waiver-as-fix. Waiving a finding because the fix is hard, with no tracking issue and no plan, is technical debt with extra steps. The waiver should buy you time, not absolve you.
How commercial signoff tools handle waivers
Synopsys VC SpyGlass, Cadence Conformal/JasperGold, and Siemens Questa each have their own waiver schema. SpyGlass uses a TCL-style .swl file with waive -rule declarations; Questa uses a directive set inside the lint database; Conformal’s approach is closest to ChipVerify’s in that waivers carry rule, signal, and reason. The shapes differ, but the data model is the same: rule + locator + reason + reviewer + expiry.
Where ChipVerify positions itself differently: the commercial tools are signoff. They are the last line of defence and the artifact the foundry expects to see. ChipVerify is pre-tapeout evidence — it runs every push, every commit, and surfaces the findings while they are cheap to fix. The waivers you produce here are the same shape you will need at signoff, which means a clean ChipVerify run is a strong predictor of a clean first-pass through SpyGlass.
Related reading
- Verification plan — how waivers feed into closure %.
- Tapeout readiness — the gate every waiver eventually has to pass through.
- Auto-fix verify loop — how to reduce the volume of findings that need a waiver in the first place.
- Inferred latches — the canonical example of a finding that is sometimes a real bug and sometimes legitimately waivable.
Try it on your project
Paste a GitHub URL at chipverify.ai/tinytapeout (free) for a one-shot scan, or sign in at chipverify.ai/dashboard to set up the full waiver workflow with reviewer rules, expiry policy, and audit trail.
Manage findings with an audit trail
Sign in and ChipVerify AI tracks each finding with rule, locator, reason, reviewer, and expiry, so accepted risk stays visible and dated — pre-signoff evidence and workflow, not a foundry signoff.