- Shipped
- August 24, 2026 at 9:54 PM UTC
- Author
- Kamo
- Commit
- 7a2209e
POS mapped to ECOMMERCE_SYNC (BLOCKED_NO_BAA) and the whole commerce surface hangs off POS, so an org with handlesPhi=true could not switch commerce on at all — no market, no /commerce, and no clinical vertical built on it. The ten retail sync adapters are the thing that leaves the boundary, not the commerce spine. POS now maps to COMMERCE_CORE (permitted) and ECOMMERCE_SYNC scopes down to the RETAIL child. Same correction for MEET (live conference vs the summary pipeline that mails transcripts to external inference) and VOIP (telephony vs stored recordings and transcripts). MEETING_RECORDING and VOIP_RECORDING now have no ServiceType at all: they are capabilities reachable only through code, and PhiModule's javadoc now states the rule that such a constant MUST be checked by PhiCapabilityGuard at its call site. Reclassifying an app as permitted without guarding the capability inside it reads as compliant while enforcing nothing. AI_ASSISTANT and RAG_SEARCH deliberately stay blocked: KlusterServices has embeddings, whisper-asr and translation but no generative LLM, and RAG shares one Qdrant collection isolated by a payload filter. Splitting those would be a paper change. Two tests encoded the app-grained model and are updated rather than extended: PhiServiceTypeMappingTest's blocked-app assertion, and FeatureServicePhiGateTest, whose blocked exemplar moves from VOIP to RETAIL — VOIP is no longer refusable at enable time.