gatesTheBead function

bool gatesTheBead(
  1. DiscoveryFinding finding
)

Whether finding may HOLD the bead — the whole gate, in one predicate.

  1. NO CITATION, NO HOLD. An empty standard is a vibe; a vibe never gates. 1b. NO ASSERTED CONTRADICTION, NO HOLD. A finding must POSITIVELY assert a real conflict (contradicts == true). A finding that names a standard but concludes there is NO conflict — "None identified", "aligned with …" — is a non-finding and can never gate (pow-hf2). Fails OPEN: absent/false advises, never holds.
  2. THE DEPARTURE CLAUSE. A departure the bead DECLARES is not an offence.
  3. INTENT, NOT PRESENCE. A bead whose plan/acceptance REMOVES the cited offence IS the fix — it passes. (The CLASS-1 false-positive: a fix-the-violation bead necessarily HAS the offending text present at discovery time, since discovery runs pre-specify.)
  4. A RECORDED ENTRY HOLDS. A decision gates only when the cited standard is a RECORDED decision entry — a docs/decisions/ slug entry, or a legacy ADR-0000 A<n> amendment (converted with status: accepted) — which binds on write. Anything that is not a recorded entry is ADVISORY: it rides as a FLAG, never a hold (the CLASS-2 false-positive). A skill always gates when cited; a pattern needs a named precedent.

Ratified basis: the 2026-07-14 register-foot ratification ("DISCOVERY GATE: pending amendments are ADVISORY, not binding") supersedes A21(2)'s "pending A<n> amendments … they bind" clause, and adds the intent grade per A21's own principle "only an unwitting contradiction gates". Bead pow-712z NARROWS what that ruling can discriminate rather than reversing it: after the option-C legacy migration (decisions#legacy-register-migration) every converted amendment carries status: accepted, so the ADVISORY tier holds no decision entries at all. The predicate below is UNCHANGED — only its population is.

Implementation

bool gatesTheBead(DiscoveryFinding finding) {
  if (finding.standard.trim().isEmpty) return false;
  if (!finding.contradicts) return false;
  if (finding.acknowledged) return false;
  if (finding.removesOffence) return false;
  return switch (finding.kind) {
    ViolationKind.decision => finding.ratified,
    ViolationKind.skill => true,
    ViolationKind.pattern => finding.precedent.trim().isNotEmpty,
  };
}