From 4726ed250d27a4e81072d95c291cdab3b8bbe139 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Fri, 29 May 2026 12:16:51 +0530 Subject: [PATCH] chore(crypto): rename JWT plan field to suggested_plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OnboardingClaims `SuggestedPlan` field carried JSON tag "plan" — a trust-boundary trap (API FINDING-2 from the 2026-05-29 QA round). The field is advisory only: server-side tier assignment derives from teams.plan_tier (hardcoded 'free' on claim) and the Razorpay subscription.charged webhook, never from this JWT field. Renaming to "suggested_plan" makes that intent explicit at the wire-format layer so a future engineer doesn't mistakenly trust a JWT-supplied tier. No call sites in the api repo read claims.SuggestedPlan today; the field continues to be emitted by api/internal/handlers/provision_helper.go for downstream upsell-hint surfaces. Refs: API FINDING-2 (downgraded from P0 → P1 after UI walkthrough + code analysis converged on "JWT plan field is never read by /claim"). Co-Authored-By: Claude Opus 4.7 (1M context) --- crypto/jwt.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crypto/jwt.go b/crypto/jwt.go index 118c53f..a0facb8 100644 --- a/crypto/jwt.go +++ b/crypto/jwt.go @@ -23,7 +23,15 @@ type OnboardingClaims struct { OrgName string `json:"org"` Tokens []string `json:"tok"` ResourceTypes []string `json:"rt"` - SuggestedPlan string `json:"plan"` + // SuggestedPlan is an advisory upsell hint computed at provisioning + // time. It is NOT a tier grant: every server-side tier decision flows + // through teams.plan_tier (hardcoded 'free' on claim) and the + // Razorpay subscription.charged webhook — never through this field. + // Renamed 2026-05-29 from json:"plan" -> json:"suggested_plan" + // (API FINDING-2, P1 hygiene) to keep a future engineer from + // trusting a JWT-supplied tier. See api/internal/handlers/onboarding.go + // — `claims.SuggestedPlan` has zero call sites in production code. + SuggestedPlan string `json:"suggested_plan"` jwt.RegisteredClaims }