Story-3037 · EPIC-3034 D2

Colleagues see the number. Strangers stay masked.

The deciding line: colleague-visible → full number; stranger → masked.

A channel binding is visible only to its owner and administrators in that person’s own firm. Those readers are colleagues. Hiding most of a colleague’s number does not protect it from an outsider; it only prevents counsel from recognising which of their own numbers is bound. Story-3037 removes that fake privacy while retaining the real third-party boundary.

The visibility test, surface by surface

Surface Who reads it Example Result
Binding API payload Owner and their firm administrators providerSubject: "+15550001234" Full
Binding and anomaly audit label, snapshot, metadata The same firm’s colleagues Number: +15550001234 Full
Refusal accounting ledger Internal abuse-control accounting +15550001234 Full internal key
Refusal audit, digest, and response surfaces Staff controls for unregistered senders •••1234 Masked display
CloudWatch refusal/anomaly fields Operators; may describe third parties •••1234 Masked

Why the refusal ledger is different

A binding proves the number belongs to a colleague. A refused inbound sender has failed that test: it may be any third party on the public channel. Its internal ledger keeps the full sender as the accounting key so rate caps, spend caps, backoff, and alert deduplication remain isolated per sender. Masking that key to four digits would merge unrelated senders into one abuse-control bucket. Refusal audit labels, snapshots, metadata, digests, responses, and CloudWatch fields expose only the short •••1234 display.

Bound-number anomaly audit is not the same surface. It belongs to the binding’s firm feed, so it carries the full bound number. Its CloudWatch field remains masked because operator logs are outside the colleague-facing product boundary.

The API contract says what it does

providerSubjectMasked is deleted from the binding DTO and OpenAPI contract. The replacement is providerSubject, whose value is the full bound number. There is no compatibility alias or dual-truth response. The paired pramaan-app consumer update is tracked by pramaan-io/pramaan-spec#3044.

What the tests prove

Operational boundary

This is an application contract and data-handling change only. It adds no cloud capability, IAM grant, tracing span, deploy workflow, or model call. Live app verification follows the paired consumer sync in Story-3044; this change does not claim that cross-repository UAT.