The "raw" tools were oversold: query_raw_sessions returned curated
SessionSummary DTOs and its fields= ran through a hard-coded whitelist
(ProjectFields) that silently dropped ~20 real SessionsIndex columns
(OsEdition, ImeAgentVersion, GeoRegion/City/Loc, FailureSource,
CurrentPhaseDetail, LastEventAt, ResumedAt, StalledAt, DeletionState, ...),
and it accepted fewer filters than search_sessions -> a strict subset.
The raw endpoints are the deliberate "fall back to the real stored bytes"
escape hatch; the enriched views already live on search_sessions/get_session
and search_events/get_session_events. So both raw tools now return the
LITERAL stored rows: every column verbatim, PascalCase, incl.
PartitionKey/RowKey/Timestamp, with fields= a pure pass-through (narrows,
never silently drops a real column; always keeps PartitionKey/RowKey).
- New RawEntityProjection helper: ToDictionary(TableEntity) + Project(rows, fields)
- 3 new ISessionRepository methods returning IReadOnlyDictionary<string,object?>
(no Azure types leak into Shared); reuse BuildSearchScanFilter +
MatchesScanClientFilters for the predicate, emit the raw entity
- query_raw_sessions: delete ProjectFields; add filter parity (manufacturer,
model, enrollmentType, deviceName, osBuild, geoCountry, isPreProvisioned,
isHybridJoin) -- already covered by the continuation fingerprint
- query_raw_events: literal rows, drop ErrorCodeEnricher + EventFieldProjection
(DataJson raw string, Severity/Phase raw ints); severity/source/date filters
reimplemented on raw dicts preserving prior match semantics
- EventFieldProjection kept for the enriched get_session_events; doc-comment fixed
- MCP admin.ts: rewrite both tool descriptions, add the new query_raw_sessions
inputs, PascalCase pass-through fields= docs; prompts.ts hint updated
Note: contract change for these two tools (camelCase curated keys -> PascalCase
literal columns). deviceProperties join stays out of raw (owned by
search_sessions); query_table remains the generic literal escape hatch.
Tests: new RawEntityProjectionTests (8); full backend suite 2134 passed;
MCP tsc clean + vitest 149 passed/41 skipped; tools-raw.test.ts updated to
the PascalCase contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two contract gaps in the raw-event MCP readers, surfaced by an MCP-server review:
1. No fields= projection. query_raw_events/get_session_events returned full
EnrollmentEvent rows including the heavy Data dict (a single app_install_failed
event can be tens of KB), so lean counting/aggregation was impossible. Add a
shared EventFieldProjection helper (mirrors query_raw_sessions fields=) wired
into both endpoints; Data is dropped unless explicitly requested, and
ErrorCodeEnricher is skipped when Data will be projected away.
2. tenantId contract inconsistency. query_raw_events hard-rejected a sessionId
query without tenantId, while get_session_events auto-resolves it for GA. Now
query_raw_events resolves tenantId via FindSessionTenantIdAsync on the global
scope only (tenant scope keeps its JWT-bound tenantId). The resolved tenantId
is NOT echoed into nextLink, keeping the filterTenantId=null continuation
fingerprint stable across pages.
Adds EventFieldProjectionTests; updates MCP tool schemas/descriptions and the
docs row. Backend 2127/2127, MCP 145 pass, web tsc clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Walks each EnrollmentEvent.Data for known error-code keys (errorCode,
exitCode, hresult, hresultFromWin32, failureCode, code, lastError) and
injects a sibling *Info entry { description, confidence, source } via
the shared ErrorCodeCatalog. Applied in GetSessionEvents (legacy +
paginated), SearchEvents (used by search_events_semantic +
deep_search_events MCP tools) and QueryRawEvents (both session-scoped
and cross-session paths).
Idempotent + read-only on storage — alte gespeicherte Events erhalten
die Anreicherung on-the-fly. MCP-Konsumenten (Claude/Copilot) bekommen
ab jetzt automatisch die kuratierten Descriptions mit Confidence-Level,
nicht nur den rohen HRESULT. 14 enricher tests; 2058/2058 backend tests
green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lands the planned 6-PR pagination rollout (project_mcp_pagination_rollout)
as one tested batch covering session_events, audit+ops, session_reports,
search_sessions/list, and query_raw_events. Backend builds clean; Backend
1024 / Agent V2 1007 / Web 249 tests green.
Primitives (Shared/Pagination):
- ContinuationToken with fingerprint binding (tenantId, dateFrom/To, filters)
so a forged or cross-tenant token fails validation on the next page.
- PaginatedResult<T> + RawPage<TEntity> as the canonical wire shapes.
Backend (AutopilotMonitor.Functions/Pagination):
- AzureTablesPaginator drives single-partition + per-partition pages.
- DateWindowPagination sweeps day-buckets for global audit/ops queries
(the backend resolves "last 30d" once and echoes dateFrom/dateTo on
nextLink so follow-up calls don't recompute "now" and break the token).
- PerPartitionFanOutMerge stable-merges N partition cursors for cross-
tenant session search.
- Per-feature plans (SessionEventsPagination, SearchSessionsPagination,
SearchSessionsByEventPagination, SessionListPagination,
SessionReportsPagination, QueryRawEventsPagination).
- Functions adopt nextLink: GetSessionEvents, GetAuditLogs (tenant +
global), GetOpsEvents, GetSessionReports, SearchSessions,
SearchSessionsByEvent, GetSessions, GetAllSessions, QueryRawEvents.
- Repository contracts (ISessionRepository, IOpsEventRepository,
INotificationRepository, IMaintenanceRepository) gain *PageAsync
variants returning PaginatedResult; legacy GetSessionsAsync becomes
a drain-all helper used by maintenance/feedback/SLA paths that still
need bounded full-list semantics. SessionPage DTO removed.
- PlatformMetricsService now drains all date-bounded sessions via
GetAllSessionsAsync (previous maxResults:500 was a silent truncation).
Web:
- lib/paginationLink.ts + ?? api.ts wrappers expose follow-nextLink in
hooks (useSessionEvents, useDashboardSessions) and pages (audit,
fleet-health, session detail, OpsEvents, SessionReports admin).
- Session list uses Pattern B2 (load-more append); audit + ops + reports
use Pattern B1 (click-next replace); session detail timeline keeps
Pattern A (eager-fetch full set).
MCP:
- followNextLink helper accepts either an opaque continuation OR the
whole "/api/?" path the backend emitted, and follows the latter
verbatim so server-resolved query params (tenantId fingerprint,
resolved dateFrom/dateTo, page size) round-trip correctly. Without
this, get_audit_logs / get_ops_events / list_session_reports / sessions
follow-ups would silently fail token validation.
- get_audit_logs, get_ops_events, list_session_reports, and the session
tools migrate to pageSize + continuation/nextLink, with tool docs
spelling out the round-trip rule so external MCP clients pass the
full nextLink instead of stripping it down to "continuation".
Tests:
- New: ContinuationTokenTests, DateWindowPaginationTests,
PerPartitionFanOutMergeTests, AuditLogRowKeyOrderingTests,
SessionEventsPaginationTests, SessionListPaginationTests,
SearchSessionsPaginationTests, SearchSessionsByEventPaginationTests,
SessionReportsPaginationTests, QueryRawEventsPaginationTests, and
TestSetup helpers.
- Web: paginationLink.test.ts + sessionListLoadMore.test.ts.
- PlatformMetricsServiceWindowTests adjusted for the drain-all change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Enrich EventTypeIndex with MaxSeverity/Sources for server-side pre-filtering,
add GetSessionEventsByTypeAsync for OData-filtered event fetch (eliminates N+1),
and new /api/raw/events/search endpoint for MCP search tool pre-filtering.
- EventTypeIndex now stores MaxSeverity, MaxSeverityName, Sources per session-eventType
- GetSessionEventsByTypeAsync: OData filter on EventType within a session partition
- SearchEventsByTypesAsync: combines index lookup + filtered fetch across sessions
- SearchEventsFunction: GET /api/raw/events/search + global variant
- QueryRawEventsFunction: uses filtered fetch instead of full partition scan
- Routes registered in EndpointAccessPolicyCatalog (MemberRead + GlobalAdminOnly)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>