Files
msd-core/docs/how-to/resolve-edge-coverage-findings.md
Rezolv c70842b6df enhance(spec-phase): edge-probe precision probe should name tie-breaking / rounding-mode (#1108)
* feat(spec-phase): name tie-breaking/rounding mode in the edge-probe precision probe (#1102)

The precision edge probe fired on numeric-range requirements but its text never
named the most common rounding failure mode — tie-breaking / rounding mode
(half-up vs half-to-even, ceil/floor/truncate). In an A/B experiment the weak
tier (haiku) false-passed 50% of tie-class defects against the surfaced-
unresolved spec; naming the rule in the probe text drove honest abstention
83%→100% (false-pass 17%→0%, haiku 50%→0%) with no category regression
(precision still fires only on numeric-range).

Sharpen the single TAXONOMY probe string and update every rendering together so
the doc↔fixture↔machine contract (edge-probe-docs-fixtures.test.cjs) stays green:
src/edge-probe.cts, the edge-probe.md taxonomy table + 2 worked examples, the
01-round-half-even and 04-money-rounding fixtures, and the resolve-edge-coverage
how-to. Prose-only — no consumer keys on the probe text; SHAPE_CUES firing
unchanged; fully backward compatible.

* chore(changeset): Changed fragment for edge-probe precision probe text (#1108)
2026-06-12 13:04:31 -04:00

5.5 KiB

How to resolve edge-coverage findings while writing a spec

Goal: Turn each domain-boundary edge the spec phase surfaces into an explicit, verifiable spec decision — so omitted boundaries (rounding ties, touching ranges, grapheme truncation) become checkable requirements before any code exists, instead of silent blind spots the verifier is confidently wrong about.

Prerequisites: A phase whose /gsd-spec-phase run has passed the ambiguity gate. The edge-completeness probe (Step 5.5) then runs automatically and presents its findings — you do not invoke it separately.

For the category taxonomy and the reasoning behind front-of-pipeline edge analysis, see Spec-Phase Edge-Completeness Probe. This guide covers only how to act on the findings.


Read a finding

Each finding is one applicable edge for one requirement — a boundary the probe's relevance filter decided is in scope for that requirement's shape, and that you have not yet addressed. A finding is phrased as a probe question, for example:

R3 · precision — Where can precision loss, overflow, or rounding/tie-breaking occur — and what is the exact contract (e.g. half-up vs half-to-even, ceil/floor/truncate)?

You must resolve each finding into exactly one of four states. Claude presents them as a numbered choice (or an AskUserQuestion menu).


Specify it — write an acceptance criterion

Choose this when you can state the correct behaviour as a pass/fail check. This is the strongest resolution: it produces a concrete assertion the planner and verifier can enforce.

Claude writes a new line into the spec's Acceptance Criteria and marks the edge covered. For the precision finding above:

  • Monetary amounts round half-to-even to 2 decimal places; 2.005 → 2.00

Prefer this state whenever a defensible criterion can be written. A covered edge is lifted into the plan's must_haves.truths, so the verifier checks it.


Dismiss it — record why it does not apply

Choose this when the edge genuinely cannot occur — and say why. A dismissal requires a non-empty reason; silence is rejected. The reason is the audit trail.

⛔ dismissed — input is a bounded enum; no boundary value exists

A wrong dismissal is the exact silent failure this probe exists to prevent, so dismiss only when the reason is solid.


Backstop it — defer the contract to a held-out test

Choose this when you know the edge matters but cannot fully articulate the correct behaviour in prose yet. Claude marks the edge backstop and notes that a held-out / property-based test stands in for the missing assertion.

🧪 backstop — held-out property test: dedupe output order is stable under input permutation

A backstop edge is also carried into the plan's must_haves.truths as a non-inferable check — the planner records the intent, and the test body is authored later during execution.


Defer it — leave it unresolved and flagged

Choose this only when you are not ready to decide. The edge stays unresolved and is flagged. Unlike a dismissal, deferring makes no claim that the edge is safe — it is an explicit, visible assumption the planner must surface, not silently drop.


Clear the soft gate

After you have worked through the findings, the probe runs a soft gate:

  • All applicable edges resolved → the spec proceeds to the next step.
  • One or more still unresolved → Claude asks what to do:
    • Resolve now — loop back and resolve the remaining edges.
    • Write the spec anyway — the spec is written with those rows marked ⚠ Edge unresolved — planner must treat as assumption. Use this deliberately; you are choosing to ship a known gap.

The gate is soft: it never blocks you, but every unresolved edge remains visible in the spec's ## Edge Coverage section.


Let Claude resolve them for you

If the edges are low-stakes or already implied by earlier phases, run the spec phase in auto mode:

/gsd-spec-phase 3 --auto

In --auto, Claude marks an edge covered where it can write a defensible acceptance criterion, and backstop otherwise. It never auto-dismisses — dismissing an edge requires a human reason, because a wrong auto-dismissal is precisely the silent failure being eliminated. Claude logs the tally, for example:

[auto] edge coverage: 4 covered, 2 backstop, 1 unresolved

Review the logged choices afterwards; auto mode is a fast first pass, not a substitute for judgement on edges that carry risk.


What happens to resolved findings downstream

When you next run /gsd-plan-phase, the planner reads the spec's ## Edge Coverage section and:

  • lifts every covered edge's acceptance criterion into must_haves.truths,
  • carries every backstop edge into must_haves.truths as a non-inferable check (needing a held-out/property test),
  • surfaces every unresolved edge as an explicit assumption.

This is the payoff: a resolved edge becomes a unit the goal-backward verifier actually checks, extending its reach to boundaries the requirement prose never stated.