diff --git a/cmd/multi_service_stats.go b/cmd/multi_service_stats.go index 4ef161865..ba44abcad 100644 --- a/cmd/multi_service_stats.go +++ b/cmd/multi_service_stats.go @@ -167,6 +167,10 @@ func printSuccessRate(success, failed int) { } } +// archeraSignupURL is the Archera signup link with CUDly attribution, shared +// with the web interface (frontend ARCHERA_SIGNUP_URL). +const archeraSignupURL = "https://www.archera.ai/cudly" + // printFinalMessage prints the final message based on mode and results func printFinalMessage(isDryRun bool, riSuccess int) { if isDryRun { @@ -175,9 +179,32 @@ func printFinalMessage(isDryRun bool, riSuccess int) { } else if riSuccess > 0 { AppLogger.Println("\nšŸŽ‰ Purchase operations completed!") AppLogger.Println("ā° Allow up to 15 minutes for RIs to appear in your account") + printArcheraPitch() } } +// printArcheraPitch prints a soft, non-blocking suggestion to insure the +// just-purchased commitments through Archera, followed by the two Archera +// partnership disclosures CUDly commits to keeping visible everywhere the +// integration is surfaced (see project_archera_partnership memory): +// 1. Non-gating: CUDly works fully without Archera. +// 2. Sponsorship: Archera funds part of CUDly's development. +// +// Shown only after a successful real purchase. Archera is a third-party +// service independent of CUDly. +func printArcheraPitch() { + AppLogger.Println("\nšŸ›”ļø Want to push your coverage to 100% without the risk that a future") + AppLogger.Println(" capacity decrease leaves you paying for commitments you no longer use?") + AppLogger.Println(" You can buy underutilization insurance for Reserved Instances and") + AppLogger.Println(" Savings Plans from Archera by signing up at:") + AppLogger.Printf(" %s\n", archeraSignupURL) + AppLogger.Println(" within the first 7 days of the purchase.") + AppLogger.Println("\n This is entirely optional. CUDly's purchase and management features") + AppLogger.Println(" work fully without Archera.") + AppLogger.Println("\n For full disclosure, Archera sponsors CUDly's Open Source development") + AppLogger.Println(" from a fraction of their insurance premiums.") +} + // printSavingsPlansSection prints the Savings Plans summary section func printSavingsPlansSection(allRecommendations []common.Recommendation, spStats ServiceProcessingStats) { AppLogger.Println("\nšŸ“Š SAVINGS PLANS:") diff --git a/cmd/multi_service_stats_test.go b/cmd/multi_service_stats_test.go index 2af805ff5..f654e9cad 100644 --- a/cmd/multi_service_stats_test.go +++ b/cmd/multi_service_stats_test.go @@ -504,3 +504,57 @@ func TestPrintComparisonSection(t *testing.T) { }) } } + +func TestPrintFinalMessage(t *testing.T) { + tests := []struct { + name string + isDryRun bool + riSuccess int + wantOutput []string + notWanted []string + }{ + { + name: "Dry run shows no Archera pitch", + isDryRun: true, + riSuccess: 5, + notWanted: []string{"Archera", archeraSignupURL}, + }, + { + name: "No successful purchases shows no pitch", + isDryRun: false, + riSuccess: 0, + notWanted: []string{"Purchase operations completed", "Archera", archeraSignupURL}, + }, + { + name: "Successful purchase shows Archera pitch with URL and disclosure", + isDryRun: false, + riSuccess: 3, + wantOutput: []string{ + "Purchase operations completed", + "underutilization insurance", + "https://www.archera.ai/cudly", + "first 7 days", + // Non-gating partnership disclosure (project_archera_partnership memory). + "entirely optional", + "work fully without Archera", + // Sponsorship partnership disclosure (project_archera_partnership memory). + "sponsors CUDly's Open Source", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + output := captureAppOutput(t, func() { + printFinalMessage(tt.isDryRun, tt.riSuccess) + }) + + for _, want := range tt.wantOutput { + assert.Contains(t, output, want) + } + for _, notWant := range tt.notWanted { + assert.NotContains(t, output, notWant) + } + }) + } +} diff --git a/frontend/src/archera.ts b/frontend/src/archera.ts index 1a7ee5518..85981db65 100644 --- a/frontend/src/archera.ts +++ b/frontend/src/archera.ts @@ -18,13 +18,13 @@ * email links). * * Signup link is carried in both surfaces: - * https://archera.ai/signup?mode=cudly + * https://www.archera.ai/cudly * * No backend, routing, or IaC changes (frontend-only). */ /** Canonical Archera signup URL with CUDly attribution. */ -export const ARCHERA_SIGNUP_URL = 'https://archera.ai/signup?mode=cudly'; +export const ARCHERA_SIGNUP_URL = 'https://www.archera.ai/cudly'; /** * Frontend URL path for the Archera education page.