Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Glossary
  • Metrics Reference
  • Formal Cheat Sheet
  • Formal Foundations19
  • Properties and SVA16
  • Property Development and Constraints19
  • Proof Engines and Convergence23
  • Formal Applications20
  • Equivalence Checking14
  • Formal Coverage and Signoff15
    • Cover Properties, Vacuity and Reachability
    • Formal Coverage Metrics
      • Proof Core and Cone Coverage
      • Assumption Influence and Coverage
      • Mutation-Based Formal Coverage
      • What the Numbers Do Not Say
    • Bounded Proof Signoff
    • The Formal Signoff Package
  • Methodology and Debug13
  • Interview Prep15
  • Capstone: A Chip-Block Verification Lab24
Loading lesson

←Formal Coverage Metrics
  1. Topics
  2. Formal Verification
  3. Formal Coverage and Signoff
  4. Formal Coverage Metrics
  5. What the Numbers Do Not Say
On this page

    Part 7 of 10, lesson 8 of 15Part 7 of 10/Formal Coverage and Signoff/Lesson 8 of 15All levels

    What the Numbers Do Not Say

    Pair every coverage number with its bound and assumption context, or refuse to sign.

    Why it matters

    Two blocks report full cone coverage. One is proven unboundedly; the other is bounded to 12 with its induction step still open and several assumptions it leans on. The numbers match and the evidence does not. This lesson is the sceptic's checklist that stops the first block's number being spent on the second block's proof.

    The core idea

    Coverage numbers do not measure proof depth or assumption quality, and they cannot, because they count what was examined, not how hard it was examined. Every coverage claim therefore travels with companions: the bound each proof reached with its justification, the assumption list with its influence table, and the mutation score. A sign-off row with coverage but no bound is rejected by the ledger check below, automatically and without debate.

    Metric

    What it shows

    What it hides

    Companion it needs

    Cone coverage

    Which logic any proof could see

    How hard it was examined

    Bound per property plus justification.

    Proof-core share

    What the proof actually used

    Whether the unused part matters

    Mutation result for the unused region.

    Assumption count

    How constrained the environment is

    How much behaviour was deleted

    Influence table with excluded classes.

    Mutation score

    That the checks bite

    Deep faults past the bound

    Kill depth per mutant against the sign-off bound.

    Worked example: the same number, different evidence

    Two illustrative designs, both at full cone coverage. One proved every property by induction; the other is bounded to 12 with the induction step still open. The script rejects any sign-off row that claims coverage without a bound, and rejects bounded rows without a justification. The numbers are illustrative; the gate is the point.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    # illustrative: sign-off gate rejects coverage without a bound
    rows = [
        {"block": "alu-a", "cone_cov": 1.0, "status": "proven", "bound": None,
         "just": "k-induction proof", "mut": 1.0},
        {"block": "alu-b", "cone_cov": 1.0, "status": "bounded", "bound": 12,
         "just": None, "mut": 0.8},
    ]
    
    def gate(row):
        if row["cone_cov"] < 1.0:
            return "incomplete coverage"
        if row["status"] == "bounded" and row["bound"] is None:
            return "coverage without a bound"
        if row["status"] == "bounded" and not row["just"]:
            return "bounded without justification"
        if row["status"] == "proven" and not row["just"]:
            return "proven without an argument"
        if row["mut"] < 1.0:
            return "surviving mutants"
        return "ok"
    
    assert gate(rows[0]) == "ok"
    # the bounded row fails the gate: no justification is recorded
    assert gate(rows[1]) == "bounded without justification", gate(rows[1])
    # a bounded row with no bound at all is coverage without a bound
    assert gate(dict(rows[1], bound=None)) == "coverage without a bound"
    # a proven row with no argument is rejected too
    assert gate(dict(rows[0], just=None)) == "proven without an argument"
    # with a justification the row passes the bound rules and now fails only on its mutation score
    fixed = dict(rows[1], just="reset 1 + trigger 6 + latency 4 + 1 = 12")
    assert gate(fixed) == "surviving mutants", gate(fixed)
    # and with every mutant killed it ships
    assert gate(dict(fixed, mut=1.0)) == "ok"
    print("PASS: proven row accepted; unjustified, unbounded and surviving-mutant rows each rejected")

    What the reviewer looks for

    • No coverage number appears without its bound, its assumption count, and its mutation score on the same row.

    • Bounded rows carry a justification reference; unproven rows carry a waiver, never a bare number.

    • Two identical coverage numbers with different companions are never treated as equal evidence.

    Verify and debug

    Audit the report, not the design: pick three rows and reproduce each companion by hand. Re-run one proof at its stated bound, remove one load-bearing assumption and watch the result move, and re-inject one killed mutant. If any companion does not reproduce, the row is decoration and the sign-off stops until it is repaired.

    Counting reached lines as coverage: symptom is a high coverage number beside a shallow proof depth. Cause is measuring what the tools visited rather than what the proofs established under which assumptions. Fix is the companion rule: coverage travels with bound, justification, influence, and mutation score, enforced by the ledger gate. It is found by asking for the bound behind any coverage number and watching the silence.

    Expect the probe: two blocks both claim full coverage, which sign-off do you trust? Answer with the companions: bounds with justifications, assumption influence, mutation kills with depths. The number never decides; the evidence behind it does.

    Check yourself A block shows full cone coverage, a bound of 30 with a diameter argument, and a mutation score of 1.0. What remains?

    The assumption review: confirm the influence table is attached, the excluded classes are covered elsewhere, and every result is tied to the final source hash. Then it is sign-off grade.

    Related topics

    • Bounded Proof Signoff: The Proof Status Ledger

    • The Formal Signoff Package: The Signoff Checklist in Full

    Previous

    124 / 183

    Next: Bounded Proof Signoff

    Up next

    Up nextBounded Proof Signoff

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Proof Core and Cone Coverage
    • Assumption Influence and Coverage