Skip to content

Accept policy_holder_id as an alias for id on policy-holder objects - #106

Closed
fuhrysteve wants to merge 1 commit into
masterfrom
fuhry/ph-id-fallback
Closed

Accept policy_holder_id as an alias for id on policy-holder objects#106
fuhrysteve wants to merge 1 commit into
masterfrom
fuhry/ph-id-fallback

Conversation

@fuhrysteve

Copy link
Copy Markdown
Contributor

What

resolvePolicyHolderId() accepts policy_holder_id as an alias for id on policy-holder objects, applied at the three boundaries where an id-less PH can enter the SDK:

  • setStep4 normalizes integrator-passed policyHolder objects before storing them in state
  • getPolicyHolder() backfills id on the single-PH GET response (the backend serializes policy_holder_id but not id on that endpoint), so the post-submit refresh paths keep a usable object in state
  • PolicyHolderDetail degrades to a summary-less status card instead of fetching when no id resolves

StreamPolicyHolderShort gains an optional policy_holder_id field documenting the alias.

Why

A customer portal drives the wizard programmatically via the step callbacks (doneStep2choosePolicyHolder) and passes PH objects carrying policy_holder_id but no id. Verified in production traffic (nginx ES index, correlated with X-SDK-Version from SDKLogger):

  • Starting exactly with their 0.8.2 upgrade (staging 2026-07-06, prod 2026-07-07), the new status view fetched .../policy_holder/undefined — a routing 404 on the CORS preflight, ~50/week across 18 member IPs. Silent to the member (the summary fetch is non-fatal) but the claim-sync summary never rendered.
  • Worse and predating 0.8.2: with policyHolder.id undefined, a credential re-submit falls back from PUT (update-in-place) to POST (create). The backend POST upserts on (username, payer, user), so same-username fixes work — but a changed username creates a new PH and strands the original broken one as permanently "Invalid". That tenant shows 0 PUTs in 30 days (every other SDK customer PUTs routinely) and 842 duplicate member+payer PH groups.

The one-line fix on the integrator side is to include id, but any integrator round-tripping our own single-PH GET response hits the same trap, so the SDK should tolerate the alias.

Testing

  • npm test (biome + tsc) green
  • No behavior change for objects that already carry id: resolvePolicyHolderId prefers id and only falls back when it's null/undefined

The backend's single-PH GET serializes policy_holder_id but not id,
and customer portals that drive the wizard programmatically via the
step callbacks (doneStep2 -> choosePolicyHolder) pass PH objects
keyed the same way. With no id:

- the 0.8.2 status view fetched .../policy_holder/undefined (routing
  404 on the CORS preflight, summary silently missing)
- credential re-submits fell back from PUT (update-in-place) to POST
  (create), stranding the original broken PH and accumulating
  duplicates

Observed in production traffic from a customer portal starting with
their 0.8.2 upgrade (2026-07-07); the PUT->POST fallback predates it.

Fix: resolvePolicyHolderId() falls back to policy_holder_id, applied
at the three boundaries where an id-less PH can enter:

- setStep4 normalizes integrator-passed policyHolder objects before
  storing them in state
- getPolicyHolder() backfills id on the single-PH GET response so the
  post-submit refresh paths keep a usable object in state
- PolicyHolderDetail degrades to a summary-less status card instead
  of fetching when no id resolves
@fuhrysteve

Copy link
Copy Markdown
Contributor Author

Wrong repo - dev PRs go to LakeEriePartners/stream-connect-js-sdk; this repo takes release PRs only. Re-opened there.

@fuhrysteve fuhrysteve closed this Jul 16, 2026
@fuhrysteve
fuhrysteve deleted the fuhry/ph-id-fallback branch July 16, 2026 19:53
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