Value 40 stays reserved and a stored one is refused, like value 1. The three fixed ops
slots and their synthesis are gone. A customer submission reaches a channel through its
ops event and an alert rule, so the functions that raise one now require the service.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Taking it apart left part of a password containing =, ; or :// in the log and the event.
A proxy string has no defined form for credentials, so there is nothing safe to parse.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agent log had no proxy line at all, and proxy_configuration could not tell auto-detect
from direct.
ProxyObserver logs the settings and the route .NET chooses before the first request, every
change with its time, the route in each failed upload, one finding per failure series that
ties it to a change or says nothing changed, and a summary when the run stops while failing.
It compares with the start instead of judging a value.
proxy_configuration uses the same reader. It knows auto-detect and the real WinHTTP proxy,
drops credentials and PAC query strings, and is sent again on a change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Download and Install heads were one button holding the skipped, pending
and no-download toggles: invalid HTML that hid them from screen readers. The
head is now a div that takes the mouse click, so the whole area still toggles,
with the chevron as the real button (ProgressPanelHeader). The tab order
changes: the panel toggle now follows the pills.
Community submissions had the same flaw with span role=button, which the
keyboard could not reach at all. Title, Show all and Pending only are sibling
buttons now.
At 390 px the session page ran up to 630 px wide. The event type, the event
message and the install error detail hold long words without a break point;
the event row wraps now and those texts break inside a word. Desktop rows stay
on one line. The clone between the two panel heads is gone from the baseline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the uploads of an unfinished session stopped, its app and script rows kept a
ticking timer until the session timed out hours later, and read like a hanging package.
They now freeze at the agent's last report and say No data, and the next data brings
them back to live. The session status does not change.
Silence is measured on the server clock (lastIngestAt, every event's receivedAt), since
device clocks can be hours off. A Stalled session counts without a timestamp; an agent
that reported the stall itself keeps its timer until it goes quiet too. A session that
has ended keeps Incomplete and its wording.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IME rolls a log with File.Move at 3 MB. The tracker kept positions per path, took the
archive for a new file and read it from 0, so every line played again: finished apps
fell back to Installing, the subgraph line of an older app marked the running app as
skipped with a wrong start, and the app summary jumped.
A position now belongs to the file (volume serial plus file index). It follows the file
to its new name, only the unread tail is read, and the live name starts at 0. Invocation
markers and a held tail move along: reading the archive again used to restore the marker
of a platform script in flight by accident. A new file longer than the old position no
longer loses lines after a restart. An unreadable identity keeps the old behaviour.
OnAllAppsCompleted had no subscriber and is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The NETWORK fail line only said "An error occurred while sending the request",
so DNS, connect timeout, proxy and TLS looked the same. It now carries the
WebException status, the socket error or native code and the innermost message,
which on .NET Framework names the endpoint; a destination other than the backend
means a proxy. The distress and emergency channels get the same text.
The "same logical network" line keeps every occurrence on Debug: when it happened
is the information.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reset sat next to Save and discarded a card's edits with one click and no
confirmation. The bar is now SaveBar; the Reset handlers go with it, as does the
Reset button on the Global Admin settings card. A failed save shows its reason
until the next Save.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NetworkChangeDetector "same logical network" (16x) and the DeviceInfo "payload unchanged" line
(3x) stayed on Debug in session 080a3016, measured against the D-394 contract.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent Settings was the only page with two cards on one Save bar, so a change in the top card
read as auto-saved and was lost. Agent Parameters and Agent Collectors are now their own
sections: Save and Reset touch only their card, unsaved edits in the other card stay (D-395).
A failed save showed a green "Saved!" on every tenant settings card, because saveConfiguration
reports a failure as false and the bar only caught exceptions; the reason was only in the banner
at the top of the page. A failure now throws and the bar shows "Save failed: <reason>" next to
the button until the next Save or Reset (D-396).
The Contact card showed "Read-only" and locked Reset on invalid input. saveBlockedReason now
blocks only Save and names the reason; canSave means a read-only viewer and nothing else.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- TenantIdAwaiter re-checks silently. The bootstrap's own probe has already written
the resolver's miss block, which used to appear twice in a row whenever the
TenantId was missing at start (the wait is on by default). A hit re-probes with
the logger for the source line; an internal overload makes this testable.
- Handler and callback faults are logged at Warning: HelloCompleted (it carries the
Hello resolution to the decision engine), the upload orchestrator's five events
(one RaiseSafely helper), the AAD user-joined callback and ConsoleBypassWatcher's
WatcherArmFailed.
- Faults on per-signal and per-event paths are logged at Debug with a repeatKey:
the hand-off of signals and transitions to the upload spool, the SignalPosted and
back-pressure observers, and timeline subscribers.
- Comments that still named a level from before D-394 are corrected; two German
comments in SignalIngress are replaced.
D-394
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- AgentLogger documents the four levels and takes an optional repeatKey on
Info/Debug/Verbose: an identical repeat under the same key goes to Trace.
- To Trace: the IME registry watcher's arm/fire cycle (the only watcher wired
to Debug), spool enqueue and ingress per item, informational pass-through,
classifier-tick and no-op decision steps, idle DO polls, the Hello policy
poll and the upload send.
- Decision-stage changes are Info; other effect-bearing steps and dead ends
stay Debug.
- To Verbose: the upload success record (now with firstId, lastId, bytes),
adapter mappings, download progress, per-file diagnostics entries and raw
provisioning JSON.
- To Debug: "how" lines of start and end loops, duplicate Info lines, the
OOBE update registry snapshot, caught exceptions that were logged below
Debug, and IME lines read from a previous enrollment's log.
- Repeats at Info (re-collections, interval gather rules, recurring health
scripts, IME policy and session lines) carry a repeatKey.
- Stop followed by Dispose logs "Stopped" once, Hello COMPLETED is logged only
when it completed, and the await-enrollment poll no longer warns every 5 s.
- The Shared LogLevel doc and the portal hint describe the levels the same
way; manifests and wire types regenerated.
D-394
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the IME log line that first marks a failure carries no code (installer
timeout and similar), the agent reports the failure without one. IME's code
follows seconds later, but the app is already Error, so no second event goes
out and FailureCode stays empty; "Top Failure Codes" skipped such rows.
At session end the backend now fills an empty FailureCode on failed IME rows
from the latest registry_app_state error of the same AppId (canonical through
ErrorCodeCatalog.NormalizeCode). Fill only: a code or failureType from the
event stays, and a registry error older than the row's last attempt start is
never used. It runs at the terminal seam, after the agent's shutdown batch and
from the sweep, next to the ESP-blocking resolution; idempotent and fail-soft.
The session row-range filter, now used three times in the file, moves into
SessionAppRowsFilter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IME checks an app right after its installer; only that check's verdict reaches the ESP and
Intune. The agent now reports its result as its own informational event (D-392):
- IME-POST-INSTALL-DETECTION marks the check ("expected to have enforcement state:
Detected", logged only for the app just installed); the app's next detection result line
becomes app_post_install_detection (postInstallDetection, afterReboot) and detectionResult
stays the check before the install.
- After an exit code mapped to SoftReboot/HardReboot the check right after the install is not
reported; IME-POST-REBOOT-DETECTION (InProgressPendingReboot -> Success) marks the check
after the restart instead.
- The mark is transient and the marker action app-mutating, so a marker from a previous
enrollment's log or without its result line never turns a later check into this one. No
state transition, no decision signal; historic replay is suppressed like DO telemetry.
- Install Progress, the timeline, the diagnosis tile (DiagnosisCulprit.PostInstallDetection)
and the MCP event catalog show the check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IME checks every app before the install (NotDetected starts it) and right after the
installer; only the second check's verdict reaches the ESP and Intune. app_install_completed
comes at IME's provisional "Success", so detectionResult on app events is the check before
the install. The apps banner, ANALYZE-APP-001 and the diagnosis read it as the result after
the install and flagged healthy installs (D-392).
- IME-ERROR-REPORT captures EnforcementErrorCode as errorCode (-2016345060 = 0x87D1041C).
- AppInstallSummaries.FailureCode is stored canonical (ErrorCodeCatalog.NormalizeCode); one
HRESULT parser serves the catalog lookup, the diagnosis and the ingest.
- The apps banner counts failed installs IME did not detect after the installer
(DetectionFailureCount, renamed from DetectionLiesCount), with its own advice for Store
apps; the app page uses the generated AppAnalyticsResponse.
- ANALYZE-APP-001 v2 matches the code in any enrollment outcome; ANALYZE-APP-013 picks its
app by the code; ANALYZE-APP-010 is retired (APP-001 reports the same event).
- Diagnosis, Install Progress and the timeline read the code: IME's verdict turns an
installed row into a detection failure, error codes read as hex, and the timeline shows the
check before the install.
- The summary column DetectionResult and DiagnosisCulprit.DetectionResult are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RequestBody checked its byte cap only against the Content-Length header and then buffered the
whole body. A chunked body carries no Content-Length and a gzip body's header names the compressed
size, so a route with an 8 KB cap read whatever Kestrel's unpinned default allowed once inflated.
Every read now counts the bytes the handler receives, after request decompression, and stops one
byte past the cap; a site that names no cap reads under 1 MiB, and the error stays the 400
"Request body too large". The agent routes that parse with their own reader (session
registration, error report, distress, upload URL) and the Azure Monitor alert webhook read through
the same counted buffer and keep their responses. The telemetry ingest shares the counting, so a
body refused at the worker limit gets its 413 instead of a 500.
The worker's request body limit is pinned at 20 MiB, the largest route cap. Kestrel and the
decompression stream both enforce it, and a PostConfigure keeps registration order and app
settings from lifting it. A guard test keeps every body read inside the counted reader.
Session report and diagnostic-file uploads (up to 20 MiB each) run at most three at a time per
instance. A fourth gets 429 with Retry-After, and the portal dialogs keep their input. The first
refusal per instance and hour raises the new ReportUploadLimitReached ops event, which an alert
rule can route.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Top Manufacturers and Top Models counted enrollment sessions without saying so, so a device
reset and enrolled again read like several devices. The lists still rank and share by sessions;
every row now also carries the distinct devices behind them (HardwareCount.DeviceCount), keyed
like device journeys: the normalized serial number per tenant, and a session without a usable
serial counts as its own device. The page groups both lists under a Hardware heading that says
so. Fleet Health's Health by Device Model labelled its session count "devices"; it now says
"enrollments". The get_usage_metrics description names the unit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Help-menu feedback, ratings and farewell comments each carry a FeedbackId: 12 lowercase hex
characters, the shape of a session report id. The feedback repository mints it when a row is first
written and keeps it on every later write (the rating and farewell rows are rewritten whole); a
help-menu row's RowKey ends in it. It is stored as a column in every kind, so one filter finds an
entry across all partitions.
FeedbackEntryWire.FeedbackId is that id for every kind (it was the help-menu RowKey).
FeedbackReceived, FeedbackRatingReceived and OffboardingFeedbackReceived carry feedbackId and a
portal path to the single entry, and the "New Feedback" / "New Rating" bells link it too.
The User Feedback page shows the id with a copy button on every card and follows ?feedbackId= to
the entry's tab and page, highlighting the card; an unknown id is named in the error banner.
Rows written before get their id from a one-time backfill after this backend is live.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>