feat(ai-sdk): pin accepted proposer decisions into the GT gate (P3)
CI / detect-changes (push) Successful in 12s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 9s
CI / validate-canonical-controls (push) Successful in 8s
CI / loc-budget (push) Successful in 21s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Successful in 59s
CI / iace-gt-coverage (push) Successful in 19s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 12s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 9s
CI / validate-canonical-controls (push) Successful in 8s
CI / loc-budget (push) Successful in 21s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Successful in 59s
CI / iace-gt-coverage (push) Successful in 19s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
When a human accepts a proposer proposal, an AcceptedPin records a machine-scoped invariant — a pattern MUST fire (coverage/vocab→tag) or must NOT fire (dedup/framing) — that a test re-checks on every run. This makes the library's growth COMPOUND into the gate instead of eroding it: a change that re-introduces a dropped duplicate, un-gates a foreign pattern, or removes a coverage hazard breaks a pin and fails CI. One boolean covers all four proposal types. Seeded testdata/accepted_pins_warewashing.json with the accepted P1 supersessions (HP016/HP018/HP013 must NOT fire; their clean equivalents HP2201/HP144 must fire). TestWarewashing_AcceptedPins re-checks 5/5 against the live engine output; GenerateDedupPin turns an accepted dedup verdict into its pin. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package iace
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVerifyPins(t *testing.T) {
|
||||
pins := []AcceptedPin{
|
||||
{Pattern: "HPa", MustFire: true},
|
||||
{Pattern: "HPb", MustFire: false},
|
||||
}
|
||||
res := VerifyPins(pins, []string{"HPa", "HPb"})
|
||||
if !res[0].OK {
|
||||
t.Errorf("HPa must_fire=true and it fired -> should be OK")
|
||||
}
|
||||
if res[1].OK {
|
||||
t.Errorf("HPb must_fire=false but it fired -> should be VIOLATED")
|
||||
}
|
||||
res2 := VerifyPins(pins, []string{})
|
||||
if res2[0].OK || !res2[1].OK {
|
||||
t.Errorf("expected HPa violated + HPb ok, got %+v", res2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateDedupPin(t *testing.T) {
|
||||
pin := GenerateDedupPin(DedupCandidate{KeepPattern: "HP144", DropPattern: "HP013", Category: "electrical_hazard"})
|
||||
if pin.Pattern != "HP013" || pin.MustFire {
|
||||
t.Fatalf("want pin {HP013, must_fire=false}, got %+v", pin)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarewashing_AcceptedPins re-checks every accepted P1 supersession against the
|
||||
// live warewashing engine output. A future change that un-suppresses HP013/016/018
|
||||
// or drops HP2201/HP144 breaks a pin here — the gate compounds, not erodes.
|
||||
func TestWarewashing_AcceptedPins(t *testing.T) {
|
||||
raw, err := os.ReadFile(filepath.Join("testdata", "accepted_pins_warewashing.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("read pins: %v", err)
|
||||
}
|
||||
var ps PinSet
|
||||
if err := json.Unmarshal(raw, &ps); err != nil {
|
||||
t.Fatalf("parse pins: %v", err)
|
||||
}
|
||||
|
||||
_, _, kept := warewashingEngineOutput()
|
||||
firedIDs := make([]string, 0, len(kept))
|
||||
for _, pm := range kept {
|
||||
firedIDs = append(firedIDs, pm.PatternID)
|
||||
}
|
||||
|
||||
ok := 0
|
||||
for _, r := range VerifyPins(ps.Pins, firedIDs) {
|
||||
if r.OK {
|
||||
ok++
|
||||
continue
|
||||
}
|
||||
t.Errorf("PIN VIOLATED: %s (must_fire=%v) — %s [%s]", r.Pin.Pattern, r.Pin.MustFire, r.Detail, r.Pin.Reason)
|
||||
}
|
||||
t.Logf("accepted pins for %q: %d/%d hold", ps.Machine, ok, len(ps.Pins))
|
||||
}
|
||||
Reference in New Issue
Block a user