Skip to content

feat(plans): Plan from N selected supports any selection and binds the selected recommendations to the purchases #1746

Closed

Description

@cristim

Problem

On Opportunities, Plan from N selected is disabled unless every selected recommendation has the same provider, service, term and payment (isHomogeneousSelection, frontend/src/recommendations.ts:4174-4183). Even when it is enabled, the selection doesn't reach the purchases:

  • The plan modal prefills from the first selected rec only (frontend/src/plans.ts:1533-1535).
  • The modal sends plan.recommendations (frontend/src/plans.ts:1218-1219), but PlanRequest has no such field (internal/api/types.go:838-857), so the server drops it (decodePlanRequest, internal/api/handler_plans.go:155-164).
  • When a step runs, planstep.Resolve (internal/planstep/resolve.go:249-314) re-picks the current recommendations that match the plan's provider, service, term and payment in the plan's accounts. The plan can then buy recommendations the user didn't select, skip ones they did, or use different counts.

Expected

  • Any multi-selection can be planned.
  • The selected recommendations are the plan's purchase set (binding), and they reach the purchases.
  • A mixed selection creates one plan per provider/service/term/payment group, in one action.
  • MCP and CLI plan creation without a selection keeps today's behaviour.

Notes

Activity

  1. cristim commented on Nov 5, 2026

    @cristim
    MemberAuthor

    Claimed by claude-ui-fix-2: slice A in progress.

  2. 7 remaining items

  3. cristim commented on Nov 13, 2026

    @cristim
    MemberAuthor

    Claimed by claude-platform (coordinator priority list, 2026-11-13). Working this in a worktree; will post the landed commit or a blocker here.

  4. cristim commented on Nov 13, 2026

    @cristim
    MemberAuthor

    Plan on main (claude-platform): ~/.claude/projects/cloud-commitments-platform/plans/1746-plan-from-selected.md. Slice A is already on main (config fields, bound_groups marker, Resolve bound to identities, per-group step cap #1872, arming escalation, bound_count). The write side is open: PlanRequest has no groups field, createPlan builds only flat services, the frontend's recommendations field is dropped, and the button still needs a homogeneous selection. Eight commits, no migration. Decisions: D1 a mixed selection makes ONE plan with a group per (provider, service, term, payment); this diverges from the issue's 'one plan per group' wording and is recorded here. D2 binding by RecIdentityKey, resolved server-side. D3 cross-provider allowed. D4 any bad ID at create is a 400, no partial plan. D5 a rec that disappears before a step runs follows the A3 behaviour (no substitution). D6 flat creates unchanged. D7 group editing stays with #1057. Hard gate: the createPlan binding commit must not land until the A3 work (9de6afd) is deployed, and the refusal commit and the modal call must deploy together. The count ceiling question is logged as an owner item in owner-decisions.md. Not implemented yet.

  5. cristim commented on Nov 13, 2026

    @cristim
    MemberAuthor

    Landed on main, first slice of the plan (B1): ccda2f0 adds PlanRequest.groups with decode validation (flat fields mixed with groups, empty/null/duplicate recommendation IDs, 1000 per group and 5000 total, coverage 0..100, max_step_commitment > 0). ad96f0e refuses any request carrying groups with a 400 (plan_groups_not_supported) until the handler lands, so nothing is silently dropped on create or PUT. No behavior change for requests without groups.

    Gates: two adversarial review passes, same reviewer, against the reviewed API tree; gofmt, go build, go vet, go test ./internal/api, golangci-lint 0 issues on the rebased tip.

    Still open: B2a/B2b (bound-plan writer, gated on A3 9de6afd being deployed), B3, and the frontend slice C2a. Plan D1 divergence (one plan per mixed selection) and the owner items are unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions