Release assignments when plans drop licenses - #2348
Conversation
Automatically unassign entity licenses when a plan transition removes their license pool, preserve ambiguous-transition safeguards, and warn affected entities in the attach review.
There was a problem hiding this comment.
All reported issues were addressed across 18 files
Confidence score: 5/5
- Safe to merge after the addressed issues were fixed.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
|
||
| const keepsAnyLicense = | ||
| planLicenses.length + (formValues.addLicenses?.length ?? 0) > 0; | ||
| if (keepsAnyLicense) return []; |
There was a problem hiding this comment.
[🟡 Medium] [🔵 Bug]
The new guard returns no warning whenever the incoming plan still has any license, which hides real assignment loss when a transition drops only some pools (e.g. keeps license A, drops license B). That creates a misleading review step: backend execution still releases dropped assignments, but the UI shows no affected entities. Remove the keepsAnyLicense short-circuit and compute affected entities from previewDiff.outgoingLicenses so partial drops are surfaced.
// vite/src/components/forms/attach-v2/hooks/useLicenseLossEntities.ts
const keepsAnyLicense =
planLicenses.length + (formValues.addLicenses?.length ?? 0) > 0;
if (keepsAnyLicense) return [];|
Capy auto-review is paused for this organization because the usage-cycle auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews. |
There was a problem hiding this comment.
1 issue found across 17 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="vite/src/components/forms/attach-v2/hooks/useLicenseLossEntities.ts">
<violation number="1" location="vite/src/components/forms/attach-v2/hooks/useLicenseLossEntities.ts:21">
P2: useLicenseLossEntities derives outgoingLicenseIds from previewDiff.outgoingLicenses/previewDiff.hasOutgoingPlans without checking previewDiff.isDiffLoading, so right after the user changes product/version/items the warning can briefly reflect the previous selection's outgoing licenses before the diff recomputes. Consider gating on `!previewDiff.isDiffLoading` (return [] while loading) to avoid a stale/incorrect flash of the license-loss warning.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| planLicenses.length + (formValues.addLicenses?.length ?? 0) > 0; | ||
| if (keepsAnyLicense) return []; | ||
|
|
||
| const outgoingLicenseIds = new Set( |
There was a problem hiding this comment.
P2: useLicenseLossEntities derives outgoingLicenseIds from previewDiff.outgoingLicenses/previewDiff.hasOutgoingPlans without checking previewDiff.isDiffLoading, so right after the user changes product/version/items the warning can briefly reflect the previous selection's outgoing licenses before the diff recomputes. Consider gating on !previewDiff.isDiffLoading (return [] while loading) to avoid a stale/incorrect flash of the license-loss warning.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vite/src/components/forms/attach-v2/hooks/useLicenseLossEntities.ts, line 21:
<comment>useLicenseLossEntities derives outgoingLicenseIds from previewDiff.outgoingLicenses/previewDiff.hasOutgoingPlans without checking previewDiff.isDiffLoading, so right after the user changes product/version/items the warning can briefly reflect the previous selection's outgoing licenses before the diff recomputes. Consider gating on `!previewDiff.isDiffLoading` (return [] while loading) to avoid a stale/incorrect flash of the license-loss warning.</comment>
<file context>
@@ -0,0 +1,45 @@
+ planLicenses.length + (formValues.addLicenses?.length ?? 0) > 0;
+ if (keepsAnyLicense) return [];
+
+ const outgoingLicenseIds = new Set(
+ previewDiff.outgoingLicenses.map((license) => license.license_plan_id),
+ );
</file context>
There was a problem hiding this comment.
1 issue found across 17 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="server/src/internal/billing/v2/actions/sync/compute/computeSyncImmediatePhase.ts">
<violation number="1">
P1: Removing the computeCustomerLicenseReleases call from computeSyncImmediatePhase leaves the sync/backsync flow with no mechanism to release active license assignments when a synced plan transition drops a license pool, which contradicts the PR's stated goal of applying the same release/restore logic across attach, sync/backsync, activation, and expiry. Please confirm release logic for sync is now handled elsewhere (e.g. via a shared executeAutumnBillingPlan step) — if not, dropped license pools during Stripe sync will leave stale/active assignments un-released.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Summary
billing.preview_attachImplementation
Testing
cd server && bunx tsgo --build --noEmitcd vite && bun run tsSummary by cubic
Automatically release assigned licenses when a plan drops its license pool, scoped to the exact customer and pools. Restores capacity, preserves exact/group successors, and still blocks ambiguous mappings with clearer guidance.
New Features
computeCustomerLicenseChangesandcomputeCustomerLicenseReleases; execute via shared plan withreleaseCustomerLicenseAssignments; remove redundant release flow.CustomerLicenseAssignmentReleasein@autumn/shared; added toAutumnBillingPlanand deduped/merged inmergeAutumnBillingPlans.useLicenseLossEntities;billing.preview_attachis unchanged.Bug Fixes
internalCustomerIdand exact pool (id+linkId) so only the intended customer and pool are modified.Written for commit e44cdb7. Summary will update on new commits.
Greptile Summary
This PR releases assignments when billing-plan transitions remove license pools. The main changes are:
Confidence Score: 4/5
The release query and partial-drop warning need fixes before merging.
server/src/internal/licenses/repos/licenseAssignmentRepo.ts; vite/src/components/forms/attach-v2/components/AttachLicenseLossWarning.tsx
Security Review
The release update is not scoped by customer or organization. A license-link collision can modify assignments and pool capacity belonging to another customer.
Important Files Changed
Sequence Diagram
sequenceDiagram participant Flow as Attach/Sync/Activation participant Compute as Plan Compute participant Execute as Plan Executor participant DB as License Repository Flow->>Compute: Outgoing and incoming products Compute->>Compute: Match license successors Compute-->>Execute: Dropped license link IDs Execute->>DB: Release active assignments DB->>DB: Clear entity bindings DB->>DB: Restore pool capacityPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix(billing): release assignments for dr..." | Re-trigger Greptile
Context used: