Also clears payment-instrument.text. Every writer busts by customer alone,
which reaches no field tag, yet each write may change the text a cached
transaction q page matched on.
ProtectedsearchTags for a page: the scope its query searched (each customer's membership
tag, else the collection tag), so an empty page is bustable too, plus the
records it projects and the fields that chose or ordered its rows.
Root of the payment-instrument class hierarchy: it owns the one read cache both surfaces share and the single seam that busts it.
payment_instrumenthas twelve writer classes — ten per-rail instrument services,PaymentInstrumentAdminService, andPaymentInstrumentVendorBackfillService. Rather than hand each writer a separate buster collaborator, every writer extends this class and callsinvalidateCache. A writer that forgets is a visible omission in one place, not a silently-stale cache. See SearchCache for why the cache lives at the root rather than beside each service.The ten rail services are writers only: they extend this class for the bust seam, not for a read surface. Anything needing to read instruments holds a
PaymentInstrumentQueryService(or the admin query service) — a rail service must never become the read path for a different rail's rows.Both surfaces project exactly the same row shape, so one value type serves the whole namespace. Their filters still differ (the consumer search excludes deprecated REDEMPTION-kind rows and restricts to
SUPPORTED_TYPES; the admin search does neither), so an identical filter set from each service would select different rows — which is why each surface gets its own key space, while both keep the shared membership-tag vocabulary.