PR2 of the safe cascade-delete plan
(.claude/plans/session-deletion-cascade-safe.md). Adds the per-table
delete primitives the cascade worker will use in PR4 plus the §17
SessionInventoryContributions side-row that makes per-session inventory
counter increments at-most-once and exactly reversible. No production
caller invokes the cascade primitives yet; the inventory rewrite IS a
call-site change in VulnerabilityCorrelationService and ships in this PR.
== Cascade delete helpers (TableStorageService.Deletion.cs) ==
DeleteByExactKeysInBatchesAsync(tableName, keys) is the load-bearing
helper: groups by PartitionKey (Azure batch transactions are
partition-scoped), chunks at 100 actions per batch, falls back to
per-row DeleteEntityAsync with 404-ignore on whole-batch rollback.
Returns (Attempted, DeletedNow, AlreadyMissing) for accurate progress
accounting on idempotent re-runs of partial cascades. Plus 9 thin
wrappers per the §3 taxonomy: 7 keyed (EventTypeIndex, CveIndex,
SessionsByTerminal, SessionsByStage, DeadEndsByReason,
ClassifierVerdictsByIdLevel, SignalsByKind), 1 single-row
(DeviceSnapshot), and 2 enumerate-then-delete (Signals,
DecisionTransitions for the PK_BY_SESSION class). All fail-loud per
memory feedback_storage_helpers_fail_soft.
== SoftwareInventory side-row (TableStorageService.Inventory.cs) ==
Plan §17 design: each inventory-correlated session contributes ONE
SessionInventoryContributions row (PK=tenantId, RK=sessionId) with the
normalized software keys it added. Increments to SoftwareInventory
counters are now driven by deltas against this row, so:
- WG sessions that fire software_inventory_analysis 4× no longer
over-count by 4× per software per session
- Cascade decrement is exact: the side-row is the source of truth
for which counters this session contributed to
- Pre-side-row sessions (created before this deploy) have no
contributions row → cascade skips inventory entirely for them
(drift accepted on the historical backlog, ages out via 90d
retention).
Helpers (all fail-loud, all bounded retry per §12-Q10 = 10 attempts /
60s wall-clock cap, all ETag-CAS):
- GetSessionInventoryContributionsAsync: returns prior key list or
null on 404
- UpsertSessionInventoryContributionsAsync: side-row CAS that
computes (added, removed) delta against the new key set
- DeleteSessionInventoryContributionsAsync: 404-ignore tombstone
- IncrementSoftwareInventoryEntryAsync: ETag-CAS +1 with first-time
AddEntity that writes full metadata
- DecrementSoftwareInventoryEntryAsync: ETag-CAS -1, clamp >= 0,
deletes the row when count hits zero
Codec: SoftwareKeysJsonCodec encodes the key list as raw JSON below
30 KB, gzip+Base64 above. Same shape DeletionManifestBuilder (PR1)
already reads at preflight, so the cascade decrement reads back what
the increment wrote with no schema gap. Plus deterministic ComputeDelta
(case-insensitive composite key) so concurrent correlations on the
same session collapse to a single counter update.
== VulnerabilityCorrelationService rewrite ==
The Task.Run fire-and-forget at the old line 246 now calls the new
ApplyInventoryContributionsAsync helper instead of
UpsertSoftwareInventoryAsync. Each Increment / Decrement is wrapped
in its OWN try/catch so one counter failure does NOT abort the rest
of the loop (Plan §17.3 + §17.8): without that, the side-row would
already promise the new key set while subsequent runs see an empty
delta and never retry the under-counted keys. Each individual failure
emits an `inventory_counter_write_failed` audit entry with operation
+ vendor + name + version + exception type/message via the existing
LogAuditEntryAsync. IMaintenanceRepository was added as an OPTIONAL
constructor param (positional default null) so existing 8-arg test
factories keep compiling unchanged.
ParseSoftwareInventoryItems exposed as internal static for testability;
preserves the same dedup + cpe-mapping behaviour as the old
UpsertSoftwareInventoryAsync path. The legacy method is left in place
on TableStorageService.Rules.cs for now (no remaining callers; PR7
cleanup can remove if desired).
== Tests (39 new) ==
- SoftwareKeysJsonCodecTests (12): raw vs gzip+Base64 paths,
determinism, malformed-input rejection, delta cases (added /
removed / identity / case-insensitive), composite-key shape.
- TableStorageDeletionBatchTests (8, SDK-mocked via internal test
ctor): empty input, PK grouping (one batch per PK), chunking at
100, batch 404 + all per-row 404, mixed batch 404 (2 succeed +
3 missing) with accurate accounting, non-404 propagates, no
over-deletion, ETag.All on every action.
- TableStorageInventoryCasTests (9): Increment first-create with
full metadata, CAS +1 on existing row, 412 retry, 409 first-create
race fall back to Update, empty-triple skip; Decrement 404 no-op,
clamp-at-zero deletes the row, count>1 subtract, 0-count clamp,
412 retry.
- VulnerabilityCorrelationServiceContributionsTests (10): Parser
correctness, end-to-end add/remove flow with Mock.Verify counts,
empty-input no-op, side-row exhaustion swallowed, per-counter
failure does not abort + audits the failed key (both increment
and decrement variants).
Backend suite: 1290/1290 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Autopilot Monitor
Advanced monitoring and troubleshooting solution for Windows Autopilot deployments. Gain full visibility into every enrollment session with a detailed event timeline, fleet health dashboards, and session reporting. Define custom analysis rules to automatically detect issues and gather rules to collect targeted evidence. Retrieve diagnostics packages on demand, configure agent settings like auto-reboot behavior and automatic timezone adjustment — all managed centrally from the web dashboard.
Private Preview
Autopilot Monitor is currently running as a Private Preview. Visit autopilotmonitor.com to request access and learn more.
Overview
Autopilot Monitor provides real-time tracking, intelligent diagnostics, and automated troubleshooting for Windows Autopilot enrollment processes. It consists of:
- Bootstrap Script — PowerShell script deployed via Intune that starts monitoring early in the enrollment process
- Monitoring Agent — Lightweight .NET application that collects telemetry and evidence during enrollment
- Backend API — Azure Functions-based ingestion and processing pipeline
- Web Dashboard — Next.js application for real-time monitoring and fleet analytics
Architecture
For detailed information about the system architecture, components, and data flow, see Architecture Documentation.
Documentation
Full documentation is available at autopilotmonitor.com/docs
License
This project uses a split licensing model:
- MIT License — Agent (
src/Agent/) and Shared library (src/Shared/) — unrestricted use on end-user devices - AGPL-3.0 — Backend (
src/Backend/), Web Dashboard (src/Web/), and MCP Server (src/McpServer/) — server-side components remain open source
See LICENSE for full details.



