diff --git a/internal/proxy/codex_primer_plan.go b/internal/proxy/codex_primer_plan.go index 0df040a..84fd7bb 100644 --- a/internal/proxy/codex_primer_plan.go +++ b/internal/proxy/codex_primer_plan.go @@ -54,6 +54,11 @@ func planCodexPrimerTargetsWithPolicy(descriptors []codex.WindowDescriptor, over } byEpoch := make(map[int64][]codex.WindowDescriptor) for _, descriptor := range descriptors { + // Reserve is a separate, hidden model activated by the backend's + // luna_reserve banner after ordinary quota exhaustion, not proactively. + if descriptor.ScopeKind == codex.WindowScopeModelFamily && descriptor.Scope == "gpt-reserve" { + continue + } if descriptor.ResetAt.IsZero() { continue } diff --git a/internal/proxy/codex_primer_plan_test.go b/internal/proxy/codex_primer_plan_test.go index c870377..513157b 100644 --- a/internal/proxy/codex_primer_plan_test.go +++ b/internal/proxy/codex_primer_plan_test.go @@ -287,3 +287,20 @@ func equalPrimerStrings(left, right []string) bool { } return true } + +func TestPlanCodexPrimerTargetsSkipsBackendGatedReserve(t *testing.T) { + reset := time.Unix(1774569600, 0) + descriptors := []codex.WindowDescriptor{ + {RawLimitName: "primary_window", WindowName: quota.Window7Day, Period: 7 * 24 * time.Hour, ScopeKind: codex.WindowScopeShared, ResetAt: reset}, + {RawLimitName: "gpt-reserve", WindowName: "7d:gpt-reserve", Period: 7 * 24 * time.Hour, ScopeKind: codex.WindowScopeModelFamily, Scope: "gpt-reserve", ResetAt: reset}, + {RawLimitName: "unknown-pool", WindowName: "7d:unknown-pool", Period: 7 * 24 * time.Hour, ScopeKind: codex.WindowScopeModelFamily, Scope: "unknown-pool", ResetAt: reset}, + } + entries := append(primerRegistryEntries(), modelregistry.Entry{Provider: modelregistry.ProviderCodex, ID: "gpt-reserve", Visibility: "hide"}) + targets, unresolved := PlanCodexPrimerTargets(descriptors, nil, entries) + if len(targets) != 1 || targets[0].ModelID != "gpt-5.4" || len(targets[0].Windows) != 1 { + t.Fatalf("ordinary priming targets = %+v", targets) + } + if len(unresolved) != 1 || unresolved[0].RawLimitName != "unknown-pool" { + t.Fatalf("unresolved = %+v, want only unknown pool", unresolved) + } +} diff --git a/internal/proxy/codex_primer_store.go b/internal/proxy/codex_primer_store.go index c18d95a..9bfac57 100644 --- a/internal/proxy/codex_primer_store.go +++ b/internal/proxy/codex_primer_store.go @@ -197,8 +197,14 @@ func (s *CodexPrimerStore) ClaimDormant(account codex.AccountKey, target CodexPr continue } switch record.State { - case PrimerStateClaimed, PrimerStateAdmitted, PrimerStateAmbiguous, PrimerStateVerifying, PrimerStateVerified: + case PrimerStateClaimed, PrimerStateAdmitted, PrimerStateAmbiguous, PrimerStateVerifying: return false, nil + case PrimerStateVerified: + // A confirmed sliding window can follow an early quota reset. The + // verified previous epoch must not suppress priming that new window. + if !target.ResetAt.After(record.ResetAt) { + return false, nil + } case PrimerStateRejected: priorAttempts = max(priorAttempts, record.Attempts) } diff --git a/internal/proxy/codex_primer_store_test.go b/internal/proxy/codex_primer_store_test.go index 5491a7f..c2b9e9a 100644 --- a/internal/proxy/codex_primer_store_test.go +++ b/internal/proxy/codex_primer_store_test.go @@ -506,3 +506,29 @@ func TestCodexPrimerStoreWriteFailureDoesNotAdvanceMemory(t *testing.T) { t.Fatalf("retry did not persist journal: %v", err) } } + +func TestCodexPrimerStoreVerifiedEpochDoesNotReplayEarlierWindow(t *testing.T) { + store, err := OpenCodexPrimerStore(fsutil.NewMemFS(), "/state/primer.json", "/state/primer.key") + if err != nil { + t.Fatal(err) + } + verified := testPrimerTarget() + now := verified.ResetAt.Add(-time.Hour) + if err := store.Observe("account-secret", verified); err != nil { + t.Fatal(err) + } + if err := store.Mark("account-secret", verified, PrimerStateVerified, "dormant_epoch_stable"); err != nil { + t.Fatal(err) + } + for _, offset := range []time.Duration{0, -time.Minute} { + target := testPrimerTarget() + target.ResetAt = target.ResetAt.Add(offset) + target.Windows[0].ResetAt = target.ResetAt + if err := store.Observe("account-secret", target); err != nil { + t.Fatal(err) + } + if claimed, err := store.ClaimDormant("account-secret", target, now); err != nil || claimed { + t.Fatalf("offset %v claim = %t, %v", offset, claimed, err) + } + } +} diff --git a/internal/proxy/codex_primer_test.go b/internal/proxy/codex_primer_test.go index 3ce872f..358b4d7 100644 --- a/internal/proxy/codex_primer_test.go +++ b/internal/proxy/codex_primer_test.go @@ -512,3 +512,70 @@ func TestCodexPrimerAutomaticallyCorrectsDormantSharedModelCapability(t *testing t.Fatalf("corrected lineage not verified: %+v", store.Records()) } } + +func TestCodexPrimerPrimesEarlyResetAfterVerifiedWindow(t *testing.T) { + for _, restarted := range []bool{false, true} { + t.Run(fmt.Sprintf("restarted=%t", restarted), func(t *testing.T) { + now := time.Unix(20000, 0) + probe := 5 * time.Second + oldReset := now.Add(3 * 24 * time.Hour) + newReset := now.Add(7 * 24 * time.Hour) + usage := &queuedPrimerUsage{observations: []codex.UsageObservation{ + primerObservation(newReset), + primerObservation(newReset.Add(probe)), + primerObservation(newReset.Add(probe)), + primerObservation(newReset.Add(probe)), + }} + requester := &recordingPrimerRequester{result: PrimerRequestResult{State: PrimerRequestAdmitted}} + primer, store := testPrimerScheduler(t, usage, requester) + oldTargets, unresolved := PlanCodexPrimerTargets(primerObservation(oldReset).Windows, nil, primer.Models()) + if len(unresolved) != 0 || len(oldTargets) != 1 { + t.Fatalf("old targets = %+v, %+v", oldTargets, unresolved) + } + oldTarget := oldTargets[0] + if err := store.Observe("account-1", oldTarget); err != nil { + t.Fatal(err) + } + if claimed, err := store.ClaimDormant("account-1", oldTarget, now); err != nil || !claimed { + t.Fatalf("old claim = %t, %v", claimed, err) + } + if err := store.Mark("account-1", oldTarget, PrimerStateVerified, "dormant_epoch_stable"); err != nil { + t.Fatal(err) + } + if restarted { + var err error + primer.Store, err = OpenCodexPrimerStore(store.fs, store.path, store.keyPath) + if err != nil { + t.Fatal(err) + } + } + if _, err := primer.RunOnce(context.Background(), now); err != nil { + t.Fatal(err) + } + if requester.calls != 0 { + t.Fatal("primed before confirming sliding reset") + } + if _, err := primer.RunOnce(context.Background(), now.Add(probe)); err != nil { + t.Fatal(err) + } + if requester.calls != 1 { + t.Fatalf("new dormant window requests = %d, want 1", requester.calls) + } + if _, err := primer.RunOnce(context.Background(), now.Add(2*probe)); err != nil { + t.Fatal(err) + } + if requester.calls != 1 { + t.Fatal("replayed newly primed window") + } + verified := 0 + for _, record := range primer.Store.Records() { + if record.State == PrimerStateVerified { + verified++ + } + } + if verified != 2 { + t.Fatalf("verified windows = %d, want old and new", verified) + } + }) + } +}