Skip to content

ESD-1747: Surface a pending-approval cancel from DeleteProduct and DeleteVXC - #179

Open
Phil-Browne wants to merge 3 commits into
mainfrom
feature/ESD-1747-cancel-pending-approval
Open

ESD-1747: Surface a pending-approval cancel from DeleteProduct and DeleteVXC#179
Phil-Browne wants to merge 3 commits into
mainfrom
feature/ESD-1747-cancel-pending-approval

Conversation

@Phil-Browne

@Phil-Browne Phil-Browne commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Megalith answers 202 Request accepted and pending for approval when the API files an order approval instead of canceling. CheckResponse passes any 2xx and DeleteProduct threw the response away, so that reached the caller as the same empty struct and nil error as a completed cancel. DeleteProduct now returns a new sentinel, ErrCancelPendingApproval, on 202.

  • No signature change. All six delete methods forward DeleteProduct's error, so every product type gets the signal for free. Each one names the sentinel in its doc comment, since consumers call the wrappers and not DeleteProduct.
  • Sentinel rather than a field on DeleteProductResponse: the cancel didn't happen, so it's a failed operation, not data. The field design would have meant DeleteVXC returning (*DeleteVXCResponse, error) and touching 3 call sites in the provider and 7 in the CLI.
  • Keyed on the status alone, and deliberately not scoped to CANCEL_NOW: the approval branch also needs LIVE state and a non-M2M term, neither of which the SDK can see.

Callers that pin this start getting an error where they used to get a silent success. That's the point, but it is a change. In the provider it's the right direction: the old 202-as-success dropped the resource from state while the VXC stayed live and billable, and on a RequiresReplace that left two live VXCs with Terraform tracking one. Wiring the consumers is still ESD-1748 and a matching CLI ticket.

Verified against megalith. LifecycleActionController.java:206-217 is the only 202 on POST /v3/product/{uid}/action/{action}, gated on CANCEL_NOW && LIVE && orderRequiresApproval && verifyServiceTermIsNotM2M. Everything else returns 200, 400, 404, 409, or 500. Deleting the 202 block builds and vets clean, then fails exactly the two new tests; swapping it for StatusOK fails 14 subtests across seven suites.

Pre-existing, wants separate tickets.

  • CANCEL was removed from megalith's LifecycleAction enum in 752145d81c (2026-07-06), so the SDK's DeleteNow: false path sends an action the API rejects with a 400.
  • ModifyProduct has this same bug: PUT /v2/product/{type}/{uid} returns the same 202 on a term increase, and it reports IsUpdated: true for any 2xx.
  • Ten Do calls discard the response and never close the body: product.go:281,340,367,385,431, mcr.go:573,589,677,712, service_keys.go:289.
  • OrderApprovalType is missing EARLY_TERMINATION (what a cancel approval is typed as) and ADD_ON.

govulncheck is red on main too, not from this diff. I ran the pinned checker against 846a35c and got the same four advisories, exit 3. All four are standard library, fixed in go1.26.6, and the repo pins 1.26.5.

What I could not verify

  • The spec for this endpoint documents 200, 409, and 4XX only. There's no 202 in it, so the spec can't corroborate the branch. I read the controller instead.
  • Whether deployed staging matches the megalith checkout. Local HEAD is 506f54afda (2026-08-19).
  • Whether the staging test company has approval turned on. If it does, -integration teardown deletes now error, and NotNil(deleteErr, "delete should fail with safe delete") at vxc_integration_test.go:259 passes for the wrong reason. CI never runs that suite.
  • Whether this case is common enough to justify a behavior change for callers that pin the new version.

…proval

Megalith answers 202 "Request accepted and pending for approval" when a
CANCEL_NOW lands on a live product in a company with cancellation order
approval turned on. It files an order approval and cancels nothing.
CheckResponse passes any 2xx, and DeleteProduct discarded the response,
so the caller saw the same empty struct and nil error as a completed
cancel.

DeleteProduct now reads the status and returns the new sentinel on 202.
DeleteVXC, DeletePort, DeleteMCR, DeleteMVE, DeleteIX, and
DeleteNATGateway all forward it, so every product type gets the signal
without a signature change.
The doc comments named "cancellation order approval". No such setting
exists. Megalith gates the approval on a managed account with
PARTNER_ORDERING_APPROVAL_ENABLED, then on LIVE state and a non-M2M term
(OrderWorkflowApprovalCreationService.java:174-175). The comments also
scoped the error to CANCEL_NOW while the status check is action-agnostic.

Drop the trigger conditions from godoc instead of restating them. They
belong to the API and they drift. DeleteVXC no longer carries a doc line
of its own either: all six delete methods forward the error, and the
other five say nothing.
The sentinel was documented only on DeleteProduct, which consumers do not
call directly. Name it on the six wrappers instead, in both the interface
and the implementation, matching how the cancel-later sentinels are
already documented.

Use the repo's existing term, order approval request, in place of the
invented "files an order approval", and split the CHANGELOG run-on whose
relative clause attached to the wrong antecedent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant