warn('No graph contracts configured.'); return self::SUCCESS; } $tenant = $this->option('tenant'); $failures = 0; foreach ($contracts as $type => $contract) { $resource = $contract['resource'] ?? null; $select = $contract['allowed_select'] ?? []; $expand = $contract['allowed_expand'] ?? []; if (! $resource) { $this->error("[$type] missing resource path"); $failures++; continue; } $queryInput = array_filter([ '$top' => $this->isSingletonContract($contract) ? null : 1, '$select' => $select, '$expand' => $expand, ], static fn ($value): bool => $value !== null && $value !== '' && $value !== []); $query = $registry->sanitizeQuery($type, $queryInput)['query']; $requestOptions = [ 'query' => $query, 'tenant' => $tenant, ]; $graphVersion = $this->contractGraphVersion($contract); if ($graphVersion !== null) { $requestOptions['graph_version'] = $graphVersion; } $response = $graph->request('GET', $resource, $requestOptions); if ($response->failed()) { $code = $response->meta['error_code'] ?? $response->status; $message = $response->meta['error_message'] ?? ($response->errors[0]['message'] ?? $response->errors[0] ?? 'unknown'); $this->error("[$type] drift or capability issue ({$code}): {$message}"); $failures++; continue; } if (! empty($response->warnings)) { $this->warn("[$type] completed with warnings: ".implode('; ', $response->warnings)); } else { $this->info("[$type] OK"); } } return $failures > 0 ? self::FAILURE : self::SUCCESS; } /** * @param array $contract */ private function isSingletonContract(array $contract): bool { return ($contract['response_shape'] ?? null) === 'singleton'; } /** * @param array $contract */ private function contractGraphVersion(array $contract): ?string { $version = $contract['graph_version'] ?? null; if (! is_string($version) || trim($version) === '') { return null; } $version = trim($version); return preg_match('/^(?:beta|v\d+(?:\.\d+)?)$/', $version) === 1 ? $version : null; } }