# Data Model — Graph Contracts: LIST `$expand` Parity Fix ## Summary No database schema changes. This feature changes how list queries are constructed and sanitized for Microsoft Graph. ## Key entities & shapes ### Graph contract (`config/graph_contracts.php`) Per `policyType` contract keys relevant to this feature: - `resource` (string): Graph resource path (e.g. `directory/roleAssignments`) - `allowed_select` (string[]): allowlisted `$select` fields - `allowed_expand` (string[]): allowlisted `$expand` expansions (exact-match) ### Query options (caller input) Options are passed as an `array $options` into `GraphClientInterface::listPolicies($policyType, $options)`. Relevant keys: - `select` (string|string[]): optional `$select` input - `expand` (string|string[]): optional `$expand` input - `filter` (string): optional `$filter` - `top` (int): optional `$top` - `platform` (string): optional platform filter for contract-specific endpoints - plus tenant/auth context from `MicrosoftGraphOptionsResolver` ### Sanitized query (outbound) `GraphContractRegistry::sanitizeQuery($policyType, $query)` returns: - `query` (array): sanitized query map, where `$select` and `$expand` are sent as comma-separated strings - `warnings` (string[]): human-readable warnings for capability safety ### Entra role assignment record `entraRoleAssignments` list response item is expected to include: - `roleDefinitionId` (string) - `principalId` (string) - `principal` (object, when expanded) - `displayName` (string) - `@odata.type` (string) ## State transitions None. This is a read-only integration-layer capability change. ## Validation rules - `$expand` values must match `allowed_expand` exactly. - `$expand` normalization: trim, split on top-level commas only (string input; do not split inside balanced parentheses), drop empty, dedupe. - Safety caps: max 10 allowed expands; max 200 chars per token.