Repository navigation
feat(config): complete a target-met ramp step as a no-op and clear a stale baseline #866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bafa537
089a16f
c7a587d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||||
| package config | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||
| "time" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| "github.com/google/uuid" | ||||||||||||||||||||||||||||
| "github.com/jackc/pgx/v5" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // PreApprovalSkipRampTargetMet marks the completed no-op row a ramp step gets | ||||||||||||||||||||||||||||
| // when its cumulative target is already held (platform#631). The advance gate | ||||||||||||||||||||||||||||
| // (requireRampStepBought) is unchanged and still counts only completed or | ||||||||||||||||||||||||||||
| // partially_completed rows as bought, so a failed zero-buy fan-out can never | ||||||||||||||||||||||||||||
| // advance the ramp; only CompleteTargetMetStepTx writes this row, in the claim | ||||||||||||||||||||||||||||
| // transaction, and the marker tells it apart from a purchase. | ||||||||||||||||||||||||||||
| const PreApprovalSkipRampTargetMet = "ramp-target-met" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // CompleteTargetMetStepTx records a plan step whose cumulative target is | ||||||||||||||||||||||||||||
| // already held as a completed no-op row and advances the ramp over it, all in | ||||||||||||||||||||||||||||
| // the caller's transaction. Without a shared transaction a crash between the | ||||||||||||||||||||||||||||
| // row and the advance would leave a settled step the ramp never moves past. | ||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||
| // rootID names the pre-created empty root row of the step to complete in place | ||||||||||||||||||||||||||||
| // (compare-and-set: it must still be pending/notified and empty; otherwise | ||||||||||||||||||||||||||||
| // ErrExecutionNotInExpectedStatus), or is "" to insert a new row. The note is | ||||||||||||||||||||||||||||
| // stored as the row's error text; the number of failed rows of unknown outcome | ||||||||||||||||||||||||||||
| // that were counted as committed is appended to it so an advance taken on such | ||||||||||||||||||||||||||||
| // capacity is visible. | ||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||
| // The plan is re-read under the lock AFTER any baseline write in this | ||||||||||||||||||||||||||||
| // transaction: that write bumps updated_at, and advancing from a plan read | ||||||||||||||||||||||||||||
| // before it would lose the optimistic-lock check in UpdatePurchasePlanTx. | ||||||||||||||||||||||||||||
| func (s *PostgresStore) CompleteTargetMetStepTx(ctx context.Context, tx pgx.Tx, planID string, stepNumber int, rootID, note string) error { | ||||||||||||||||||||||||||||
| if stepNumber <= 0 { | ||||||||||||||||||||||||||||
| return fmt.Errorf("cannot complete ramp step %d of plan %s: step numbers are 1-based", stepNumber, planID) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| var unknown int | ||||||||||||||||||||||||||||
| if err := tx.QueryRow(ctx, ` | ||||||||||||||||||||||||||||
| SELECT count(*) FROM purchase_executions | ||||||||||||||||||||||||||||
| WHERE plan_id = $1 AND status = $2 AND NOT no_submission | ||||||||||||||||||||||||||||
| AND CASE WHEN jsonb_typeof(recommendations) = 'array' THEN jsonb_array_length(recommendations) ELSE 0 END > 0`, | ||||||||||||||||||||||||||||
| planID, StatusFailed).Scan(&unknown); err != nil { | ||||||||||||||||||||||||||||
| return fmt.Errorf("failed to count unknown-outcome executions of plan %s: %w", planID, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| note = fmt.Sprintf("%s; %d failed row(s) of unknown outcome counted as committed", note, unknown) | ||||||||||||||||||||||||||||
| now := time.Now() | ||||||||||||||||||||||||||||
| if rootID == "" { | ||||||||||||||||||||||||||||
| marker := PreApprovalSkipRampTargetMet | ||||||||||||||||||||||||||||
| exec := &PurchaseExecution{ | ||||||||||||||||||||||||||||
| PlanID: planID, ExecutionID: uuid.New().String(), Status: StatusCompleted, StepNumber: stepNumber, | ||||||||||||||||||||||||||||
| ScheduledDate: now, CompletedAt: &now, Error: note, | ||||||||||||||||||||||||||||
| PreApprovalSkipReason: &marker, | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| if err := s.SavePurchaseExecutionTx(ctx, tx, exec); err != nil { | ||||||||||||||||||||||||||||
| return fmt.Errorf("failed to record target-met plan step %d of plan %s: %w", stepNumber, planID, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||
| tag, err := tx.Exec(ctx, ` | ||||||||||||||||||||||||||||
| UPDATE purchase_executions | ||||||||||||||||||||||||||||
| SET status = $2, completed_at = $3, error = $4, pre_approval_skip_reason = $5 | ||||||||||||||||||||||||||||
| WHERE execution_id = $1 AND status IN ('pending', 'notified') | ||||||||||||||||||||||||||||
| AND CASE WHEN jsonb_typeof(recommendations) = 'array' THEN jsonb_array_length(recommendations) ELSE 0 END = 0`, | ||||||||||||||||||||||||||||
| rootID, StatusCompleted, now, note, PreApprovalSkipRampTargetMet) | ||||||||||||||||||||||||||||
|
Comment on lines
+60
to
+65
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win Scope the root-row compare-and-set to The Proposed fix UPDATE purchase_executions
SET status = $2, completed_at = $3, error = $4, pre_approval_skip_reason = $5
- WHERE execution_id = $1 AND status IN ('pending', 'notified')
+ WHERE execution_id = $1 AND plan_id = $6 AND step_number = $7
+ AND status IN ('pending', 'notified')
AND (jsonb_typeof(recommendations) <> 'array' OR jsonb_array_length(recommendations) = 0)`,
- rootID, StatusCompleted, now, note, PreApprovalSkipRampTargetMet)
+ rootID, StatusCompleted, now, note, PreApprovalSkipRampTargetMet, planID, stepNumber)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return fmt.Errorf("failed to complete target-met root row %s: %w", rootID, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| if tag.RowsAffected() != 1 { | ||||||||||||||||||||||||||||
| return fmt.Errorf("%w: root row %s", ErrExecutionNotInExpectedStatus, rootID) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| plan, err := s.LockPurchasePlanTx(ctx, tx, planID) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| if plan == nil { | ||||||||||||||||||||||||||||
| return fmt.Errorf("%w: purchase plan %s", ErrNotFound, planID) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| if err := advanceRampStep(ctx, tx, plan, stepNumber); err != nil { | ||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return s.persistRampPosition(ctx, tx, plan) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| //go:build integration | ||
| // +build integration | ||
|
|
||
| package config | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/jackc/pgx/v5" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // The no-op row and the ramp advance commit together, after a baseline write | ||
| // that bumped updated_at in the same transaction; a failed zero-buy fan-out | ||
| // still cannot advance through the unchanged gate. | ||
| func TestCompleteTargetMetStepTx_RealPlan(t *testing.T) { | ||
| ctx := context.Background() | ||
| f := newRampFixture(ctx, t, 1, 1, 4) | ||
| r := baselineRec(f.accounts[0], "m5.large", 100) | ||
| f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusCompleted, false, r) | ||
| failed := f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusFailed, false, r) | ||
| failed.Recommendations = nil | ||
| key := baselineKey(t, r) | ||
|
|
||
| require.NoError(t, f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| _, err := f.store.LockPurchasePlanTx(ctx, tx, f.planID) | ||
| require.NoError(t, err) | ||
| _, err = f.store.SetPlanRampBaselineTx(ctx, tx, f.planID, PlanRampBaseline{key: {Count: 100}}) | ||
| require.NoError(t, err) | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 2, "", "target already met: target 40, committed 40") | ||
| })) | ||
| assert.Equal(t, 2, f.currentStep(ctx, t)) | ||
| assert.NotNil(t, f.baseline(ctx, t)) | ||
| var reason, note, status string | ||
| require.NoError(t, f.store.db.QueryRow(ctx, | ||
| `SELECT pre_approval_skip_reason, error, status FROM purchase_executions WHERE plan_id = $1 AND step_number = 2`, f.planID).Scan(&reason, ¬e, &status)) | ||
| assert.Equal(t, PreApprovalSkipRampTargetMet, reason) | ||
| assert.Equal(t, StatusCompleted, status) | ||
| assert.Contains(t, note, "1 failed row(s) of unknown outcome counted as committed") | ||
|
|
||
| // A step whose only row failed without buying is still refused. | ||
| f.rowWithRecs(ctx, t, 3, nil, StatusFailed, true) | ||
| require.ErrorIs(t, f.store.CompletePlanStep(ctx, f.planID, 3), ErrRampStepIncomplete) | ||
| assert.Equal(t, 2, f.currentStep(ctx, t)) | ||
|
|
||
| // A root row that is no longer pending/notified is not completed in place. | ||
| done := f.rowWithRecs(ctx, t, 3, nil, StatusCompleted, false) | ||
| err := f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 3, done.ExecutionID, "n") | ||
| }) | ||
| require.ErrorIs(t, err, ErrExecutionNotInExpectedStatus) | ||
| assert.Equal(t, 2, f.currentStep(ctx, t)) | ||
| } | ||
|
|
||
| // G3: a zero-buy failed fan-out on the step refuses the target-met advance too. | ||
| func TestTargetMet_TargetMetRefusedOverFailedFanOut(t *testing.T) { | ||
| ctx := context.Background() | ||
| f := newRampFixture(ctx, t, 1, 1, 4) | ||
| f.rowWithRecs(ctx, t, 2, &f.accounts[0], StatusFailed, true) | ||
| err := f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| if _, err := f.store.LockPurchasePlanTx(ctx, tx, f.planID); err != nil { | ||
| return err | ||
| } | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 2, "", "target already met") | ||
| }) | ||
| require.ErrorIs(t, err, ErrRampStepIncomplete) | ||
| assert.Equal(t, 1, f.currentStep(ctx, t)) | ||
| var n int | ||
| require.NoError(t, f.store.db.QueryRow(ctx, `SELECT count(*) FROM purchase_executions WHERE plan_id=$1 AND pre_approval_skip_reason=$2`, f.planID, PreApprovalSkipRampTargetMet).Scan(&n)) | ||
| assert.Equal(t, 0, n) | ||
| } | ||
|
|
||
| // A pending root that already carries attached recommendations is never completed as a no-op. | ||
| func TestTargetMet_RootWithRecsNotCompleted(t *testing.T) { | ||
| ctx := context.Background() | ||
| f := newRampFixture(ctx, t, 1, 1, 4) | ||
| root := f.rowWithRecs(ctx, t, 2, nil, "pending", false, baselineRec(f.accounts[0], "m5.large", 5)) | ||
| err := f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 2, root.ExecutionID, "n") | ||
| }) | ||
| require.ErrorIs(t, err, ErrExecutionNotInExpectedStatus) | ||
| assert.Equal(t, 1, f.currentStep(ctx, t)) | ||
| var st string | ||
| require.NoError(t, f.store.db.QueryRow(ctx, `SELECT status FROM purchase_executions WHERE execution_id=$1`, root.ExecutionID).Scan(&st)) | ||
| assert.Equal(t, "pending", st) | ||
| } | ||
|
|
||
| // The unknown-outcome count excludes failed rows that never submitted. | ||
| func TestTargetMet_UnknownCountExcludesNoSubmission(t *testing.T) { | ||
| ctx := context.Background() | ||
| f := newRampFixture(ctx, t, 1, 1, 4) | ||
| r := baselineRec(f.accounts[0], "m5.large", 3) | ||
| f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusCompleted, false, r) | ||
| f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusFailed, true, r) | ||
| require.NoError(t, f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 2, "", "met") | ||
| })) | ||
| var note string | ||
| require.NoError(t, f.store.db.QueryRow(ctx, `SELECT error FROM purchase_executions WHERE plan_id=$1 AND pre_approval_skip_reason=$2`, f.planID, PreApprovalSkipRampTargetMet).Scan(¬e)) | ||
| assert.Contains(t, note, "; 0 failed row(s) of unknown outcome") | ||
| } | ||
|
|
||
| // A failed, submitted row whose recommendations are JSON null (scalar) must not break the count. | ||
| func TestTargetMet_UnknownCountScalarRecs(t *testing.T) { | ||
| ctx := context.Background() | ||
| f := newRampFixture(ctx, t, 1, 1, 4) | ||
| r := baselineRec(f.accounts[0], "m5.large", 3) | ||
| f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusCompleted, false, r) | ||
| f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusFailed, false) | ||
| var typ string | ||
| require.NoError(t, f.store.db.QueryRow(ctx, `SELECT coalesce(jsonb_typeof(recommendations),'sqlnull') FROM purchase_executions WHERE plan_id=$1 AND status=$2`, f.planID, StatusFailed).Scan(&typ)) | ||
| t.Logf("recommendations jsonb type of the failed row: %s", typ) | ||
| require.NoError(t, f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 2, "", "met") | ||
| })) | ||
| } | ||
|
|
||
| // A pre-created empty root (recommendations JSON null) completes in place. | ||
| func TestTargetMet_NullRootCompletes(t *testing.T) { | ||
| ctx := context.Background() | ||
| f := newRampFixture(ctx, t, 1, 1, 4) | ||
| f.rowWithRecs(ctx, t, 1, &f.accounts[0], StatusCompleted, false, baselineRec(f.accounts[0], "m5.large", 3)) | ||
| root := f.rowWithRecs(ctx, t, 2, nil, "pending", false) | ||
| require.NoError(t, f.store.WithTx(ctx, func(tx pgx.Tx) error { | ||
| return f.store.CompleteTargetMetStepTx(ctx, tx, f.planID, 2, root.ExecutionID, "met") | ||
| })) | ||
| assert.Equal(t, 2, f.currentStep(ctx, t)) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 3867
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 41942
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 7221
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 20481
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 8074
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 1386
🏁 Script executed:
Repository: LeanerCloud/cloud-commitments-platform
Length of output: 32773
Compare enabled services without delimiter serialization.
rampBaselineStalecan treat a service edit as unchanged. For example, one enabled AWS service withService: "ec2|1|no-upfront,aws|foo",Term: 1, andPayment: "no-upfront"produces the same string as two enabled AWS services namedec2andfoowith the same term and payment. The helper therefore returns false, soUpdatePurchasePlanleaves the oldramp_baselinepersisted after the enabled-service configuration changed.Use typed records for the comparison.
Suggested fix
The current attach resolver passes no stored baseline to
planstep.Resolve, so this leaves stale persisted state without establishing an immediate production sizing failure.🤖 Prompt for AI Agents