Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/integration/mag_train_eval_integration_test.go |
| Original SHA-256 | bbd8f6877720f4a9ca6b61c648c2d60049c2d9215542d23daeddc88ebc900951 |
| Git blob SHA | 29d099aafc6aba21f49cef19ff541a2f40b301f8 |
| Reading-copy SHA-256 | bbd8f6877720f4a9ca6b61c648c2d60049c2d9215542d23daeddc88ebc900951 |
Every recorded occurrence
These 10 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | feature/opportunity-to-outcome | 720d47fae476b0d38477ae4401697d372b1ea2bc | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
| Janady13/missionmatch / internal/integration/mag_train_eval_integration_test.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓290 lines · 14.3 KB
//go:build integration
// MAG learning loop integration. Proves at runtime against a REAL Postgres and the migrated 0036 coefficient
// store what the unit tests cannot: the offline TRAINER fits a learned win probability challenger from the
// pooled decided bid_outcomes labels, the EVALUATOR compares it to the prior only champion on a held out split,
// a human promotion flips the champion, and the EXISTING serve path (IntentOpportunityWinProbability through the
// orchestrator) then reflects the LEARNED coefficient, moving the served probability off the prior only base
// rate toward the seeded market signal, with the frozen decimal engine untouched (no candidate score anywhere).
//
// The seeded signal is honest market structure: a HIGH win rate agency segment (mostly wins) and a LOW win rate
// segment (mostly losses), pooled, so the segment base rate feature genuinely predicts the label and the fitted
// coefficient is positive. NONE of it is a protected attribute.
//
// Run: go test -tags=integration ./internal/integration/ -run MAGLearningLoop -v
// Env: MM_APP_DSN, MM_MIGRATOR_DSN, MM_COMPLIANCE_DSN (compliance optional; the fairness read is skipped without
// it). The orchestrator applies migration 0036 (goose v36) first.
package integration
import (
"context"
"strconv"
"strings"
"testing"
"time"
"github.com/google/uuid"
"github.com/missionworkforce/missionmatch/internal/modules/ai"
"github.com/missionworkforce/missionmatch/internal/modules/bidoutcomes"
"github.com/missionworkforce/missionmatch/internal/modules/eeo"
"github.com/missionworkforce/missionmatch/internal/platform/audit"
"github.com/missionworkforce/missionmatch/internal/platform/magstore"
"github.com/missionworkforce/missionmatch/internal/platform/tenant"
)
// seedSegmentOutcomes records n wins and m losses for one org tied to a single agency segment, the real
// recording path under RLS. It is the honest market signal the trainer learns from.
func seedSegmentOutcomes(t *testing.T, svc *bidoutcomes.Service, org uuid.UUID, agency string, wins, losses int) {
t.Helper()
req := seedRequirementWithAgency(t, org, agency)
for i := 0; i < wins; i++ {
recordOutcome(t, svc, org, req, bidoutcomes.ResultWin)
}
for i := 0; i < losses; i++ {
recordOutcome(t, svc, org, req, bidoutcomes.ResultLoss)
}
}
// servedProbability serves the win probability MAG intent for an org and agency through the orchestrator with a
// nil inference client (so the answer is the deterministic rendering) and returns the calibrated probability the
// answer states, parsed from the "for the segment: <p>." rendering.
func servedProbability(t *testing.T, org uuid.UUID, agency string) (string, string) {
t.Helper()
orch := ai.NewOrchestrator(appDB, nil, audit.New(appDB))
resp, err := orch.Answer(ctxOrg(org), "", ai.IntentOpportunityWinProbability, []any{agency, ""})
if err != nil {
t.Fatalf("win probability answer: %v", err)
}
if resp.Refused {
t.Fatalf("an authenticated win probability question must not be refused, got %+v", resp)
}
return parseServedProbability(t, resp.Answer), resp.Answer
}
// parseServedProbability pulls the calibrated probability out of the deterministic rendering, which reads
// "Calibrated opportunity_score for the segment: 0.xx. Drivers ...".
func parseServedProbability(t *testing.T, answer string) string {
t.Helper()
const marker = "for the segment: "
i := strings.Index(answer, marker)
if i < 0 {
t.Fatalf("the served answer must render the calibrated probability, got %q", answer)
}
rest := answer[i+len(marker):]
// the probability renders as 0.xx followed by a period and a space before "Drivers"; take the value token up
// to the first space and drop the trailing sentence period.
if k := strings.Index(rest, " "); k >= 0 {
return strings.TrimSuffix(rest[:k], ".")
}
return strings.TrimSpace(rest)
}
// mustFloat parses a probability token the served answer rendered, failing the test on a malformed value.
func mustFloat(t *testing.T, s string) float64 {
t.Helper()
f, err := strconv.ParseFloat(s, 64)
if err != nil {
t.Fatalf("could not parse the served probability %q: %v", s, err)
}
return f
}
// TestMAGLearningLoopTrainsEvaluatesPromotesAndServes drives the whole loop end to end on the real database.
func TestMAGLearningLoopTrainsEvaluatesPromotesAndServes(t *testing.T) {
const modelKey = "opportunity_win_probability"
const priorOnlyVersion = 1 // migration 0036 seeds v1 as the prior only champion
run := uuid.NewString()[:8]
highAgency := "HIGHSEG " + run
lowAgency := "LOWSEG " + run
// Staging persists prior promotions, so force the champion back to the prior only v1 first, making the
// before and after comparison deterministic and the test idempotent across re runs.
if _, err := magstore.PromoteChampion(context.Background(), migrator, modelKey, priorOnlyVersion); err != nil {
t.Fatalf("reset champion to prior only v%d: %v", priorOnlyVersion, err)
}
priorChampion, err := magstore.ChampionVersion(context.Background(), migrator, modelKey)
if err != nil {
t.Fatalf("champion version: %v", err)
}
if priorChampion != priorOnlyVersion {
t.Fatalf("the champion must reset to the prior only v%d, got v%d", priorOnlyVersion, priorChampion)
}
// This test promotes a learned challenger to champion on the shared staging store. Restore the prior only v1
// as champion when the test ends (however it ends), so it never leaks a learned champion into the other MAG
// tests, which assume the prior only base rate. The default production champion is the prior only v1; a
// learned model becomes champion only by a deliberate human promotion through cmd/eval-model.
t.Cleanup(func() {
if _, cerr := magstore.PromoteChampion(context.Background(), migrator, modelKey, priorOnlyVersion); cerr != nil {
t.Logf("cleanup: could not restore the prior only champion v%d: %v", priorOnlyVersion, cerr)
}
})
// Serve BEFORE training for the high segment, the prior only baseline (near 0.60, betas zero).
orgHigh := seedOrg(t)
orgLow := seedOrg(t)
svc := bidoutcomes.NewService(appDB, nil)
// A strong, honest signal: the high segment wins far more than it loses, the low segment the reverse. This
// dominates any residue from other tests, so the pooled fit learns a POSITIVE segment_base_rate coefficient.
seedSegmentOutcomes(t, svc, orgHigh, highAgency, 30, 5)
seedSegmentOutcomes(t, svc, orgLow, lowAgency, 5, 30)
probBeforeStr, answerBefore := servedProbability(t, orgHigh, highAgency)
probBefore := mustFloat(t, probBeforeStr)
t.Logf("served probability before training (prior only): %s", probBeforeStr)
// The prior only segment_base_rate coefficient is zero, so the driver contributes zero regardless of the
// gathered value; the prior only calibrated probability is near the 0.60 base rate.
if !strings.Contains(answerBefore, "segment_base_rate contributes 0") {
t.Errorf("the prior only answer must show a zero segment_base_rate contribution, got %q", answerBefore)
}
if probBefore < 0.5 || probBefore > 0.7 {
t.Errorf("the prior only probability must be near the 0.60 base rate, got %v", probBefore)
}
// TRAIN: fit a challenger over the pooled decided labels. min-events 10 so the seeded 70 clears the floor.
res, err := magstore.Train(context.Background(), migrator, modelKey, 1.0, 10, false)
if err != nil {
t.Fatalf("train: %v", err)
}
if res.Skipped {
t.Fatalf("the fit must not be skipped with %d seeded decided bids: %s", res.N, res.SkipReason)
}
if res.Version <= priorChampion {
t.Fatalf("the challenger version %d must be newer than the prior champion %d", res.Version, priorChampion)
}
// The learned segment_base_rate coefficient must be POSITIVE: a higher segment win rate predicts a win.
idx := -1
for i, name := range res.FeatureNames {
if name == magstore.SegmentBaseRateFeature {
idx = i
}
}
if idx < 0 {
t.Fatalf("the fit must include the segment_base_rate feature, got %v", res.FeatureNames)
}
if res.Coeffs[idx] <= 0 {
t.Fatalf("the learned segment_base_rate coefficient must be positive, got %v", res.Coeffs[idx])
}
t.Logf("challenger v%d learned segment_base_rate coefficient %.6f over %d bids", res.Version, res.Coeffs[idx], res.N)
// The challenger stays a challenger until promotion: the champion must NOT have moved yet.
stillPrior, err := magstore.ChampionVersion(context.Background(), migrator, modelKey)
if err != nil {
t.Fatalf("champion version after train: %v", err)
}
if stillPrior != priorChampion {
t.Fatalf("the trainer must NOT flip champion; champion moved from %d to %d", priorChampion, stillPrior)
}
// EVALUATE: the held out replay must compute AUC and ECE for both, and the learned challenger must rank
// strictly better than the constant prior only champion (whose AUC is 0.5 on any split).
champ, err := magstore.LoadModel(context.Background(), migrator, modelKey, priorChampion)
if err != nil {
t.Fatalf("load champion: %v", err)
}
chal, err := magstore.LoadModel(context.Background(), migrator, modelKey, res.Version)
if err != nil {
t.Fatalf("load challenger: %v", err)
}
quality, err := magstore.EvaluateHeldOut(context.Background(), migrator, champ, chal, 0.30)
if err != nil {
t.Fatalf("evaluate: %v", err)
}
t.Logf("held out %d bids, AUC champion %.4f vs challenger %.4f, ECE champion %.4f vs challenger %.4f",
quality.HeldOut, quality.ChampAUC, quality.ChalAUC, quality.ChampECE, quality.ChalECE)
if quality.HeldOut == 0 {
t.Fatal("the held out split must be non empty")
}
if quality.ChalAUC <= quality.ChampAUC {
t.Errorf("the learned challenger must rank better than the constant prior only champion, AUC challenger %.4f vs champion %.4f", quality.ChalAUC, quality.ChampAUC)
}
if !quality.Pass {
t.Errorf("the learned challenger must clear the quality gate, got %+v", quality)
}
// The FAIRNESS read must be callable through the compliance pool (the only path to the eeo schema). The
// win probability model is opportunity level and cannot change candidate selection, so a clean seed shows no
// flagged group. Skip when no compliance DSN is configured.
if compliance != nil {
eeoSvc := eeo.NewService(tenant.New(compliance))
if _, ferr := eeoSvc.AdverseImpact(tenant.WithOrg(context.Background(), orgHigh.String()), time.Now().UTC()); ferr != nil {
t.Fatalf("the fairness read must be callable through the compliance pool: %v", ferr)
}
}
// PROMOTE: the human governance action flips the champion and records an append only audit row.
from, err := magstore.PromoteChampion(context.Background(), migrator, modelKey, res.Version)
if err != nil {
t.Fatalf("promote: %v", err)
}
if from != priorChampion {
t.Errorf("the promotion must replace the prior champion %d, reported replacing %d", priorChampion, from)
}
nowChampion, err := magstore.ChampionVersion(context.Background(), migrator, modelKey)
if err != nil {
t.Fatalf("champion version after promote: %v", err)
}
if nowChampion != res.Version {
t.Fatalf("the champion must be the promoted challenger v%d, got v%d", res.Version, nowChampion)
}
// The promotion audit row exists (global governance action, no org).
var auditCount int
if err := migrator.QueryRow(context.Background(),
`SELECT count(*) FROM audit_logs WHERE action='aedt.model.promoted' AND entity_id=$1 AND (new_values->>'to_version')::int=$2`,
modelKey, res.Version).Scan(&auditCount); err != nil {
t.Fatalf("read promotion audit: %v", err)
}
if auditCount == 0 {
t.Fatal("the promotion must append an aedt.model.promoted governance audit row")
}
// SERVE AFTER PROMOTION: the EXISTING serve path now reflects the learned coefficient. The segment_base_rate
// driver must gather the real 0.857 segment win rate (proving the pgtype.Numeric decode fix) and contribute a
// non zero positive term, and the served probability must move UP off the prior only 0.60 baseline toward the
// high segment signal.
probAfterStr, answerAfter := servedProbability(t, orgHigh, highAgency)
probAfter := mustFloat(t, probAfterStr)
t.Logf("served probability after promotion (learned): %s", probAfterStr)
if strings.Contains(answerAfter, "segment_base_rate contributes 0 ") {
t.Errorf("the learned answer must show a non zero segment_base_rate contribution, got %q", answerAfter)
}
if !strings.Contains(answerAfter, "value 0.8") {
t.Errorf("the serve path must gather the real high segment win rate near 0.857, not zero; got %q", answerAfter)
}
if probAfter <= probBefore {
t.Errorf("the served probability must move up once the learned model is champion, before %v after %v", probBefore, probAfter)
}
// NO HISTORY under the LEARNED champion: a segment with no decided bids must rest on the base rate (the
// feature is imputed at the model training mean), NOT extrapolate off a misleading zero to a spuriously low
// number. Serve a fresh agency with no bids and assert the probability stays in a plausible base rate band.
noHistoryAgency := "NOHIST " + run
noHistOrg := seedOrg(t)
probNoHistStr, answerNoHist := servedProbability(t, noHistOrg, noHistoryAgency)
probNoHist := mustFloat(t, probNoHistStr)
t.Logf("served probability for a no history segment under the learned champion: %s", probNoHistStr)
// The imputed value must rest in a plausible base rate band, distinctly NOT the low extrapolation a zero
// feature would produce (which lands near 0.04 for this signal). The imputed mean surfaces as the value the
// segment_base_rate driver is scored at.
if probNoHist < 0.3 || probNoHist > 0.75 {
t.Errorf("a no history segment must rest on the base rate under a learned champion, got %v in %q", probNoHist, answerNoHist)
}
if strings.Contains(answerNoHist, "segment_base_rate contributes 0 ") {
t.Errorf("a no history segment under a learned champion must impute the training mean, not a zero contribution, got %q", answerNoHist)
}
// The frozen engine path stays untouched: the answer is an opportunity_score, discloses it is not a per
// candidate match score, and leaks no engine score.
if !strings.Contains(answerAfter, "opportunity_score") {
t.Errorf("the served answer must remain an opportunity_score, got %q", answerAfter)
}
if !strings.Contains(strings.ToLower(answerAfter), "not a per candidate match score") {
t.Errorf("the served answer must disclose it is not a per candidate match score, got %q", answerAfter)
}
for _, scoreWord := range []string{"total_score", "band=", "scorecandidate"} {
if strings.Contains(strings.ToLower(answerAfter), scoreWord) {
t.Errorf("the win probability answer must leak no engine score, found %q in %q", scoreWord, answerAfter)
}
}
}