package ai import ( "strings" "testing" ) // TestGraphLifecycleIntentsAreRegistered proves the three G9 lifecycle traversals are in the closed Registry, // so ValidateRegistry asserts them at boot and ExecuteIntent can run them. A missing intent means the // registration regressed. func TestGraphLifecycleIntentsAreRegistered(t *testing.T) { cases := map[string]int{ IntentProcurementSuccession: 1, // opportunity_id IntentRecompeteClock: 2, // agency, window_months IntentForecastRunway: 1, // window_months } for name, wantParams := range cases { it, ok := IntentByName(name) if !ok { t.Fatalf("intent %q must be registered in the closed Registry", name) } if len(it.Params) != wantParams { t.Errorf("intent %q must bind exactly %d params, got %d", name, wantParams, len(it.Params)) } } } // TestGraphLifecycleWindowParamsAreClamped pins that the forward window param on the recompete clock and the // forecast runway carries the bounded ParamInt Min 1 Max 60, so the structured path clamps a caller bound // window into the bounded range and an oversized or non positive value can never widen a bounded scan. func TestGraphLifecycleWindowParamsAreClamped(t *testing.T) { for _, name := range []string{IntentRecompeteClock, IntentForecastRunway} { it, ok := IntentByName(name) if !ok { t.Fatalf("intent %q must be registered", name) } var sawWindow bool for _, p := range it.Params { if p.Name == "window_months" { sawWindow = true if p.Kind != ParamInt { t.Errorf("%s: window_months must be a ParamInt, got %q", name, p.Kind) } if p.Min != 1 || p.Max != 60 { t.Errorf("%s: window_months must clamp to Min 1 Max 60, got Min %d Max %d", name, p.Min, p.Max) } } } if !sawWindow { t.Errorf("%s: must carry a window_months param", name) } } } // TestGraphLifecycleIntentsPassTheReadOnlyGuard is the load bearing security assertion: each registered // lifecycle intent passes GuardReadOnlyQuery against the real ReadAllowlist. A query that referenced a non // allowlisted table, hid a mutation, or named an eeo marker would fail here, the same gate ValidateRegistry // runs at boot and ExecuteIntent re runs at execution time. func TestGraphLifecycleIntentsPassTheReadOnlyGuard(t *testing.T) { for _, sql := range []string{ procurementSuccessionSQL, recompeteClockSQL, forecastRunwaySQL, } { if err := GuardReadOnlyQuery(sql, ReadAllowlist); err != nil { t.Errorf("a registered lifecycle intent must pass the read only guard: %v", err) } } } // TestValidateRegistryWithLifecycleIntents proves the whole closed Registry, now carrying the three G9 // intents alongside the TAG, G3, and G1 intents, validates at boot. This is the assertion the api boot runs. func TestValidateRegistryWithLifecycleIntents(t *testing.T) { if err := ValidateRegistry(); err != nil { t.Fatalf("ValidateRegistry must pass with the three G9 lifecycle intents registered: %v", err) } } // TestLifecycleAwardsArmKeysOnlyOnAgencyAndNaics is the honesty mandate, pinned statically: usaspending_awards // carries NO psc, NO set_aside, and NO pop_state column, so the only lifecycle arm that reads the award table // (the recompete clock award arm) may not select or join on those columns against the award alias. The award // arm keys ONLY on awarding_agency and the columns the table actually has. A regression that reached for a // phantom award column would fail here. func TestLifecycleAwardsArmKeysOnlyOnAgencyAndNaics(t *testing.T) { // The recompete clock is the only lifecycle intent that reads usaspending_awards. The succession and the // runway live entirely in opportunity_records and federal_mission_tags, never the award table. lower := strings.ToLower(recompeteClockSQL) if !strings.Contains(lower, "awarding_agency") { t.Error("recompete_clock: the award arm must key on awarding_agency") } // The phantom columns the award table does NOT have. None may appear qualified to the award alias a. for _, phantom := range []string{"a.psc", "a.set_aside", "a.pop_state"} { if strings.Contains(lower, phantom) { t.Errorf("recompete_clock: usaspending_awards has no %s column; the award arm must not reference it", phantom) } } // The succession and the runway must NOT read usaspending_awards at all (they are opportunity_records and // mission tag sourced), so no phantom award column risk exists on those arms by construction. for name, sql := range map[string]string{ "procurement_succession": procurementSuccessionSQL, "forecast_runway": forecastRunwaySQL, } { if strings.Contains(strings.ToLower(sql), "usaspending_awards") { t.Errorf("%s: must live in opportunity_records, not read the award table (no phantom column surface)", name) } } } // TestSuccessionTupleIsOpportunityRecordsSourced pins that the procurement succession keys on the FULL // (agency, naics, psc, pop_state, set_aside) segment tuple, which only opportunity_records carries: the // dedupe_key succession walks within that segment, so the finer slice the question needs is honestly sourced // from the one table that supports it. func TestSuccessionTupleIsOpportunityRecordsSourced(t *testing.T) { lower := strings.ToLower(procurementSuccessionSQL) for _, key := range []string{"a.agency = an.agency", "a.naics = an.naics", "a.psc = an.psc", "a.pop_state = an.pop_state", "a.set_aside = an.set_aside"} { if !strings.Contains(lower, key) { t.Errorf("the succession must key on the full segment tuple; missing %q", key) } } if !strings.Contains(lower, "a.dedupe_key = an.dedupe_key") { t.Error("the succession must link the phases on the shared dedupe_key") } } // TestLifecycleIncumbentEdgeLabeledPrimeOfRecord pins that every incumbent edge the lifecycle graph surfaces // carries the constant prime-of-record label, never the staffing subcontractor: the public data carries only // the prime recipient or the catalog recorded incumbent, so prime-of-record is the honest statement of what // the data supports. The label is a SQL constant column, so a row can never be unlabeled. func TestLifecycleIncumbentEdgeLabeledPrimeOfRecord(t *testing.T) { for name, sql := range map[string]string{ "procurement_succession": procurementSuccessionSQL, "recompete_clock": recompeteClockSQL, } { if !strings.Contains(strings.ToLower(sql), "'prime-of-record'") { t.Errorf("%s: must label every incumbent edge with the constant prime-of-record", name) } } if primeOfRecordLabel != "prime-of-record" { t.Errorf("the prime of record label constant drifted, got %q", primeOfRecordLabel) } } // TestSuccessionPrefersFixedJoinsNotRecursion confirms the procurement succession is a FIXED set of LEFT JOINs // (forecast to solicitation to predecessor award is at most three phases), NOT a recursive CTE: the dedupe_key // already links the phases, so recursion would add a determinism risk and no value. The determinism mandate // explicitly prefers fixed joins where the data carries the keys. The recompete clock and the forecast runway // are likewise plain reads, not recursion. func TestSuccessionPrefersFixedJoinsNotRecursion(t *testing.T) { for name, sql := range map[string]string{ "procurement_succession": procurementSuccessionSQL, "recompete_clock": recompeteClockSQL, "forecast_runway": forecastRunwaySQL, } { if strings.Contains(strings.ToLower(sql), "with recursive") { t.Errorf("%s: a lifecycle read must not use a recursive CTE; the data already carries the keys", name) } } // The succession positively uses the fixed LEFT JOINs over the predecessor and the forecast phases. lower := strings.ToLower(procurementSuccessionSQL) if !strings.Contains(lower, "left join predecessor") || !strings.Contains(lower, "left join forecast") { t.Error("the succession must use the fixed LEFT JOINs to the predecessor award and the forecast phases") } } // TestLifecycleNoFloatTouchesADollar is the decimal mandate, pinned statically across all three lifecycle // intents: no ::float8, no ::float, no ::double precision, and no ::real cast may touch a dollar figure. Every // dollar (estimated_value, award_amount) stays Postgres numeric end to end and is scanned into // shopspring/decimal in Go. A cast to a float type would silently lose the bit stable precision the AEDT // compliance asset requires. func TestLifecycleNoFloatTouchesADollar(t *testing.T) { intents := map[string]string{ "procurement_succession": procurementSuccessionSQL, "recompete_clock": recompeteClockSQL, "forecast_runway": forecastRunwaySQL, } for name, sql := range intents { lower := strings.ToLower(sql) for _, floatCast := range []string{"::float8", "::float", "::double precision", "::real"} { if strings.Contains(lower, floatCast) { t.Errorf("%s: a float cast %q must never touch a dollar figure (decimal mandate)", name, floatCast) } } } } // TestLifecycleEveryListOrderEndsWithAUniqueTiebreaker pins the byte stable mandate: every lifecycle intent // that returns a list ends its ORDER BY with a unique id tiebreaker (a record id), so the same inputs yield // byte identical rows. The succession returns a single anchored row, so it carries the unique tiebreaker on // its internal predecessor and forecast picks instead, also pinned here. func TestLifecycleEveryListOrderEndsWithAUniqueTiebreaker(t *testing.T) { listCases := []struct { name string sql string mustContain string }{ // The recompete clock orders by the end date then the record id, a total order. {"recompete_clock", recompeteClockSQL, "record_id"}, // The forecast runway orders by the estimated award date then the opportunity id, a total order. {"forecast_runway", forecastRunwaySQL, "o.id"}, } for _, tc := range listCases { lower := strings.ToLower(tc.sql) idx := strings.LastIndex(lower, "order by") if idx < 0 { t.Errorf("%s: the list must be ordered for byte stability", tc.name) continue } orderClause := lower[idx:] if !strings.Contains(orderClause, strings.ToLower(tc.mustContain)) { t.Errorf("%s: the ORDER BY must carry the unique tiebreaker %q, got %q", tc.name, tc.mustContain, orderClause) } } // The succession's internal single row picks are each totally ordered by an id tiebreaker, so the LIMIT 1 // pick is deterministic for the predecessor and the forecast phases. lower := strings.ToLower(procurementSuccessionSQL) if !strings.Contains(lower, "order by a.award_date desc nulls last, a.id") { t.Error("the succession predecessor pick must be totally ordered by award_date then the id tiebreaker") } if !strings.Contains(lower, "order by f.estimated_award_date desc nulls last, f.id") { t.Error("the succession forecast pick must be totally ordered by estimated_award_date then the id tiebreaker") } } // TestLifecycleIntentsAreGraphIntents proves the three G9 intents are classified as GRAPH intents (dispatched // to AnswerGraph, not AnswerTAG), so the graph evidence rendering and the graph route audit apply, and each is // also a real registered intent in the closed Registry. func TestLifecycleIntentsAreGraphIntents(t *testing.T) { for _, name := range []string{IntentProcurementSuccession, IntentRecompeteClock, IntentForecastRunway} { if !IsGraphIntent(name) { t.Errorf("%q must be a graph intent", name) } if _, ok := IntentByName(name); !ok { t.Errorf("graph intent %q must be registered in the closed Registry", name) } } }