Commit Graph

9 Commits

Author SHA1 Message Date
Oliver Kieselbach 88cd29d3b9 backend: lifecycle completeness nets + session-scope point-read + server-side dashboard search (audit P5/P6)
P5.1 Table lifecycle buckets: TableLifecycleBucketTests classifies every
TableNames constant (offboarding buckets via reflection, per-session set from a
real DeletionManifestBuilder run, reviewed KeptByDesign list). Fixes found by
the audit: UsageMetrics offboarding wipe matched 0 rows (PK=date/RK=tenantId)
-> new SafeWipe Variant D (RowKey-anchored, verify protects the "global" row);
PlatformStats tenant partition + ScriptNameCache never wiped -> tenant-PK bucket.

P5.2 SessionsIndex field manifest: SessionIndexFieldManifest (32 always / 18
conditional / 4 primary-only) pinned bidirectionally against
BuildSessionIndexEntity and MapToSessionSummary; full rebuilds now
TableUpdateMode.Replace (heals stale conditional columns); merge sites warn on
non-manifest keys; force-path now mirrors StalledAt write + clear heals.

P5.3/P6.1 Session scope resolution: ResolveSessionScopeAsync (RequestContext)
replaces the 16-site copy-paste fallback; ResolveSessionTenantIdAsync does a
point-read on the new SessionTenantLookup table (PK=sessionId) with legacy
index-scan fallback + self-heal, replacing the cross-partition scan; the
"Count == 0 -> rescan" heuristics are gone. Write paths gate cross-tenant
resolution on IsGlobalAdmin. RecomputeTriggerGate enforces the decided
read-only semantics API-side: reanalyze/rescan now 403 for Viewer/GlobalReader/
cross-tenant tenant roles. Lookup rows ride the deletion cascade (step 22).

P6.2 Server-side dashboard search: q= on search/sessions (+global) matching
exactly the client-side searchable fields, page-backfill loop (max 10 Azure
pages/request), q bound into the pagination fingerprint; the web dashboard's
searchAll() replaces the loadAll() full-history sweep (dedupe-merge, delegated
callers keep the legacy sweep).

P6.3 Context value memoization: TenantConfigContext + Auth/Notification/
Tenant/Theme providers (cuts the externally-triggered re-render cascade).

Verified: solution build 0W/0E; Functions.Tests 4106 (+37), DecisionCore 519,
V2.Core 2206, SummaryDialog 44; tsc/eslint clean; vitest 722 (+4). Drift
detection of both new manifest tests proven by mutation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 19:29:27 +02:00
Oliver Kieselbach d7b42ad6e1 feat(mcp-raw): make query_raw_sessions/events return literal table rows
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>
2026-05-30 13:23:23 +02:00
Oliver Kieselbach 93b3c735cf feat(mcp-events): fields= projection + GA tenantId auto-resolve for query_raw_events
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>
2026-05-29 23:10:08 +02:00
Oliver Kieselbach 51d036ece2 feat(backend,mcp): read-time error-code enrichment on event responses
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>
2026-05-28 12:31:32 +02:00
Oliver Kieselbach 70382e991b feat(backend,web,mcp,shared): MS-Graph nextLink pagination rollout
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>
2026-05-06 20:53:46 +02:00
Oliver Kieselbach 1c633b9c4d feat(backend): enriched EventTypeIndex + index-based event search endpoint
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>
2026-04-16 10:34:21 +02:00
Oliver Kieselbach 60eb841d37 updated known-issues, architecture.md and rawquery function 2026-04-06 15:12:07 +02:00
Oliver Kieselbach d824dd64fd added structured error handler 2026-04-02 22:02:09 +02:00
Oliver Kieselbach a6f552a877 added MCP capabilities 2026-03-28 04:20:50 +01:00