Skip to content

Flag Rollout: `matching_shipto_resolver_v1`

Owner: david@boonetek.com Created: 2026-06-17 Default: false (disabled, fail-safe) Policy: docs/feature-flag-policy-erp-writes.md — §1 “Customer/item matching → customer resolution” Seed config: infrastructure/flagsmith/configs/flags.json

The CK ship-to customer resolver — the resolve_customer_by_shipto activity in apps/temporal-worker/activities/typesense.py. The resolver picks the DC-granular WhereFour customer from (sender_domain + extracted ship-to) before the name-based match_customer fallback runs.

This is the outer of two gates, both DEFAULT-OFF and both required:

  1. Outer (this flag): matching_shipto_resolver_v1, evaluated per-org via Flagsmith identity = the bare Clerk org id (already org_-prefixed). Policy gate on the shared activity, so it covers both call sites — workflows/pdf_extraction.py (PR #1721) and workflows/email_processing.py (PR #1734) — and the feature can never be half-enabled on one path.
  2. Inner (unchanged): the connection’s matchingConfig.customerResolution.enabled config flag + the CK org belt-and-suspenders guard (_is_resolver_enabled).

When either gate is off — or the resolver can’t confidently resolve — the activity returns None and the caller falls back to today’s name-match path, byte-for-byte.

get_feature_flag(..., default=False) returns the default on any error or when Flagsmith is unreachable, so an absent or unreachable flag resolves to OFF. Landing this PR changes nothing in any environment until the flag is created and enabled for a targeted org.

Follows the three-stage protocol in the policy. Because the inner CK org guard still refuses any non-CK org, the realistic targets are below — the flag’s job is to be the auditable, instantly-reversible kill switch on top of that guard.

Stage 0 — Create the flag (before merge)

Section titled “Stage 0 — Create the flag (before merge)”
  • Create matching_shipto_resolver_v1 in the Flagsmith UI (staging and production environments), boolean, default OFF, owner + description per the entry in infrastructure/flagsmith/configs/flags.json.
  • Leave it OFF everywhere. Merge is safe (fail-safe OFF).
  • Enable the flag for org_internal_test only.
  • Smoke-test the gate plumbing: with flag-ON-but-non-CK-org, confirm the resolver still abstains (inner CK guard holds) and orders flow through the name-match path unchanged.
  • Gate: zero ERP submission failures in 24h; no errors in the resolver logs (shipto-resolver: lines).
  • Enable the flag for the CK org. The inner CK guard (CK_ORG_IDS in apps/temporal-worker/activities/typesense.py) originally only recognized the WhereFour Sandbox eval org (org_3DisstYyUfNutmFA68xw5hxXfq1, used for this canary stage) — it never covered CK’s real production org (org_3FVE59k9pBxf7fJBJKNCAPNEQaW), so the resolver could never actually protect real CK orders. Fixed as part of ENG-560; both org ids now pass the guard. Enabling the flag + the connection’s customerResolution.enabled for CK’s real WhereFour prod connection is still a separate, un-taken ops step.
  • Monitor resolver hit rate, resolved-vs-abstained ratio, and downstream ERP submission success on CK orders. Compare resolved customers against the name-match result for the same orders.
  • Gate: no customer-reported issues in 72h; error rate within baseline; no wrong-customer binds attributable to the resolver.
  • Set the flag default to true. The resolver remains effectively CK-only until the inner CK org guard and per-connection config are generalized in a follow-up — so GA here means “the outer policy gate is no longer the limiter.”
  • Continue monitoring for 1 week.
  • Gate: error rate within ±5% of pre-change baseline.
  • Toggle the flag OFF in Flagsmith — instant, no deploy. The resolver abstains and every order falls back to the name-match path. This is exactly the flag-absent behavior, so rollback restores pre-change behavior fully.
  • Escalate to OFF immediately if the error rate spikes >10% above baseline at any stage.

Per the policy §5 table — for this flag specifically:

MetricSourceAlert threshold
ERP submission success rateTemporal workflow completion<95% (baseline ~99%)
Resolver errors / abstainsCloud Run logs shipto-resolver:New error pattern
Wrong-customer bindsCSR/support channelAny within 24h of flag
Error rate (500s)Cloud Run logs>2x baseline

After 2 weeks at GA with no issues, the flag can be marked permanent and a cleanup ticket created to remove the flag check (and, separately, to revisit the CK org guard) within 30 days.