Repository navigation
fix(config): upsert recommendations on the 11-column index with platform and tenancy - #819
Conversation
…orm and tenancy Point the recommendations upsert ON CONFLICT arbiter at recommendations_natural_key_az_tp_idx (the 9 existing key columns plus the generated platform and tenancy columns from migration 000111). The insert column list is unchanged and the generated columns are never written or updated. Add TestPostgresStore_UpsertRecommendations_PlatformTenancyArbiter (same-key re-upsert in place, regional non-EC2 rows with empty platform/tenancy, pre-PR-C row found). Give the legacy-row case in the AZ arbiter test the platform and tenancy the old collector always stored in details. Bump the Azure pricing integration test from migration 109 to 111, the only pinned-schema test that calls the recommendations store. Refs #806 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 3 billable files and costs up to $0.75.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 54 minutes for your next included review. View limit details
Comment |
Gate verdict (Opus 5.5, claude-opus-5-5): CHANGES REQUESTED at 3ca3721Not merged. The code change itself is correct; one real, reproduced regression in the both-indexes window is undocumented and the PR body claims the switch is not observable. Verified OK
Finding 1 (blocking until documented and the rollout decided): cross-run platform/tenancy flip fails every collection while both indexes are live, and stays failing Probe (schema 111, i.e. dev after this merges and prod between runbook steps 3 and 4): run 1 upserts an EC2 rec
The 11-col arbiter finds no conflict, the insert hits the 9-col index, and the whole This is different from the documented limit (multi-platform batch in ONE run, which already fails on main with 21000): single-platform-per-9-tuple accounts that collect fine today can start failing after this merge. The PR body sentence "by itself, the arbiter switch is not observable by a test until 000112" is incorrect. Requested:
Not verified
Mutation testing: not run (store SQL arbiter change, not a money/auth path; optional per policy). |
|
Corrected the PR body: the 'not observable' claim was wrong. The transitional 23505 (Linux then Windows on one 9-tuple while both indexes are live) is now stated with its effect, the accepted window, and the dev/prod sequencing. No code change; head SHA unchanged (3ca3721). No test added for the transitional failure; PR-E removes the cause. |
Gate re-check (Opus 5.5, claude-opus-5-5): CONDITIONAL APPROVAL at 3ca3721, not mergedFinding 1 closed, per the coordinator ruling. The transitional window is accepted, as it was for #810. The body now:
Minor wording inconsistency, non-blocking: the transitional section says "steps limited to 1", while runbook step 2 says "the true pending count". Step 2 is the correct rule. Step 4's "Only then" should be read as "immediately after", which matches the transitional section. State at this SHA: all checks green, including Unit Tests, Integration Tests, E2E, Security Scanning and CI Success. mergeStateStatus CLEAN. Labels match #806 exactly (priority/p1, severity/high, urgency/this-sprint, impact/many, effort/m, type/bug, triaged). Local PG17 evidence is in the previous gate comment. Dev verification (public read-only
Conditions to merge:
|
|
Independent Sol-medium review, two adversarial passes, exact head 3ca3721: no blocking findings within the previously accepted PR-E sequencing. Source checks: the 11-column conflict target in internal/config/store_postgres_recommendations.go:231 exactly matches migration 000111:33. Insert and update omit generated columns. Scheduler conversion and persistence preserve platform, tenancy and AZ. Fresh macOS evidence: build passed; focused race-enabled store integration cases passed on native PostgreSQL 17. An independent Recommendation -> real converter -> persistCollection -> PostgreSQL upsert -> store-read scenario preserved Windows/dedicated/AZ fields, updated savings from 10 to 25, and retained one row. After removing only the scratch 9-column index, exact-head code passed; substituting the parent store failed with SQLSTATE 42P10; restoring exact-head code passed again. Production source was byte-compared against the head afterwards. The Azure provider regression uses mocks. Scratch server stopped. This is synthetic-fixture database evidence, not live provider collection or DEV writes. Separate actual AWS DEV read-only evidence: BEGIN READ ONLY, bounded timeouts, SELECT-only queries and ROLLBACK through an existing SSM route. Schema 118, dirty=false. Both natural-key indexes are valid and unique; the 11-column index matches the exact target. Armed multi-step Savings Plans aggregate count is zero. Owned session cleanup completed; no credential files or data writes. Current PR state rechecked: OPEN, CLEAN, head unchanged; CI Success and Run pre-commit hooks completed successfully. The retained 9-column index can still cause SQLSTATE 23505 for cross-platform or cross-tenancy changes until PR-E lands. The existing accepted sequence requires PR-E immediately after PR-C deploys to DEV and joint production release. Its migration must be renumbered beyond main's occupied versions; local 000119 preparation is reviewed but unpublished. The affected scenario is the SQL persistence path. Actual DEV schema/index inspection and the native PostgreSQL production-store roundtrip with provider-model-shaped records cover it. Synthetic inputs and mocked provider execution are labelled above; this SQL fix does not require a real purchase or cloud write. Two additional source-check passes confirmed the representative record against pinned common model revision 9dae64b216d4: pkg/common/types.go:201,232 defines Recommendation and typed details; :555-560 defines ComputeDetails JSON platform/tenancy/scope/availability_zone. providers/aws/recommendations/parser_services.go:159-172 preserves the platform and derives tenancy/scope/AZ; :97-105 accepts dedicated tenancy. Windows/dedicated/us-east-1a therefore match the production model. All eleven identity dimensions match the SQL target and migration index; account normalization, AZ derivation, platform and tenancy use the existing migration expressions. The reviewer approves normal merge at the named head under the accepted PR-E deployment sequence. |
Summary
PR-C of #806. The recommendations upsert now uses
ON CONFLICT (account_key, provider, service, region, resource_type, engine, term, payment_option, availability_zone, platform, tenancy), i.e. the 11-columnrecommendations_natural_key_az_tp_idxadded by migration 000111 (#815). The insert column list is unchanged; the generatedplatformandtenancycolumns are never written and are not inDO UPDATE SET.ReplaceRecommendationshas no ON CONFLICT. This is the only ON CONFLICT / natural-key SQL on the table ininternal/,scripts/,cmd/,tests/.Tests (real PostgreSQL 17, local throwaway cluster):
TestPostgresStore_UpsertRecommendations_PlatformTenancyArbiter: same-key re-upsert updates in place and the generated columns carry the payload values; regional non-EC2 row (platform='',tenancy='') updates in place; a row written by pre-PR-C code (platform/tenancy only in details) is the conflict target, not duplicated.TestPostgresStore_UpsertRecommendations_AZArbiterlegacy-row case: its seeded payload had onlyavailability_zonein details, which now maps to platform''and no longer matches the rec it upserts (23505 on the 9-col index). The seed now includes platform/tenancy, as the old collector always stored on zonal EC2 recs.internal/purchase/azure_pricing_integration_test.go:106:MigrateToVersion109 -> 111 (R7). Re-grep of everyMigrateToVersionuser outsidemigrations/: that file (105, 106, 111),internal/api/nullable_purchase_cost_integration_test.go(100, 101; never calls the recommendations store), and the testhelpers skip-guard tests (version 42; no store). Only the Azure test needed the bump.Known transitional defect (accepted window, until 000119)
With both indexes live (schema 111, before 000119), the 11-col arbiter does not cover the 9-col index. Reproduced on PG17 at schema 111: one collection run upserts EC2 m5.large as Linux, a later run upserts the same 9-tuple as Windows. The second insert hits
recommendations_natural_key_az_idx(23505), the transaction aborts (eviction runs after the insert in the same tx), soUpsertRecommendationsfails on every later run and the recommendation cache is not refreshed until migration 000119 drops the 9-col index. Main does not fail this probe. The same window was accepted and documented for #810 in the AZ chain.The window is short: merge PR-E (000119) to dev right after PR-C is deployed to dev; in prod, PR-C and PR-E release together (apply only the prerequisite migrations through 000111 using the true pending count, release PR-C, then apply the drop-index migration). The multi-platform/tenancy batch test belongs to PR-E (R1). No test pins the transitional failure here; PR-E removes the cause.
Release runbook (PR-C and PR-E release together)
database-migration.ymlwithstepsset to the true pending count so that only 000111 applies. The workflow's default (stepsempty/0) isalland would also apply 000119 once PR-E is on main.Rollback
Once 000119 is applied, rolling back PR-C code needs
downsteps=1 on 000119 first; otherwise the old code runs without a 9-col arbiter.Refs #806
🤖 Generated with Claude Code