package iace // P3: pin accepted proposer decisions into the GT gate. // // When a human accepts a proposal from the offline proposer (a dedup // supersession, a foreign-framing gate, a vocab→tag mapping, a coverage hazard), // they record an AcceptedPin. A pin is a tiny, machine-scoped invariant — "this // pattern MUST (or must NOT) fire for this machine" — that a test re-checks on // every run. This is what makes the library's growth COMPOUND into the gate // instead of silently eroding it: a future change that re-introduces a dropped // duplicate, un-gates a foreign pattern, or removes a coverage hazard breaks the // pin and fails CI. // // A single boolean covers all four proposal types: // - dedup supersession accepted → DropPattern MustFire=false // - foreign-framing gate accepted → foreign pattern MustFire=false // - vocab→tag / coverage hazard accepted → the enabled pattern MustFire=true // AcceptedPin is one regression invariant for an accepted proposal. type AcceptedPin struct { Pattern string `json:"pattern"` MustFire bool `json:"must_fire"` Reason string `json:"reason"` FromProposal string `json:"from_proposal,omitempty"` } // PinSet is the accepted-pin registry for one machine (testdata/accepted_pins_*.json). type PinSet struct { Machine string `json:"machine"` Pins []AcceptedPin `json:"pins"` } // PinResult is the verdict for one pin against an engine run. type PinResult struct { Pin AcceptedPin OK bool Detail string } // VerifyPins checks every pin against the set of pattern IDs the engine actually // fired for the machine. A pin holds iff the pattern's presence equals MustFire. func VerifyPins(pins []AcceptedPin, firedPatternIDs []string) []PinResult { fired := make(map[string]bool, len(firedPatternIDs)) for _, id := range firedPatternIDs { fired[id] = true } out := make([]PinResult, 0, len(pins)) for _, p := range pins { got := fired[p.Pattern] ok := got == p.MustFire detail := "ok" if !ok { if p.MustFire { detail = "expected to fire but did NOT — coverage/mapping regressed" } else { detail = "expected to be suppressed but FIRED — gate/supersession regressed" } } out = append(out, PinResult{Pin: p, OK: ok, Detail: detail}) } return out } // GenerateDedupPin turns an accepted (verdict=duplicate) dedup candidate into the // pin that protects the supersession: the dropped pattern must no longer fire. func GenerateDedupPin(c DedupCandidate) AcceptedPin { return AcceptedPin{ Pattern: c.DropPattern, MustFire: false, Reason: "accepted duplicate of " + c.KeepPattern + " (" + c.Category + ")", FromProposal: "dedup " + c.DropPattern + " -> " + c.KeepPattern, } }