Phase 1 Measurements
This table is the single place where before/after numbers for Phase 1 (and the demo baseline that precedes it) are recorded. Every slice in the evolution roadmap between now and the end of Phase 2 must land with rows here and the corresponding CSV captures under docs/captures/.
Without a filled row, a slice's exit gate has not been met. Prose claims ("feels faster", "seems healthier") do not count.
See the capturing measurements runbook for the procedure that produces these numbers.
Conventions
| Column | Meaning |
|---|---|
| Slice | Which change the row measures. demo-baseline (pre-Phase-1) for row 0. |
| Metric | One of the fixed metric names listed below. |
| Baseline | The value from the before capture. |
| After | The value from the after capture. Blank for row 0. |
| Delta | after − baseline for counters; after ÷ baseline for rates. One convention per metric. Blank for row 0. |
| Capture method | CSV filename plus scenario id (§4.1, §4.2, ...). |
| Date | ISO date of the after capture (or the baseline capture for row 0). |
Fixed metric set
Every row set must include all of these metrics, in this order. Zeros are valid values — record them.
- frames.ingested (total)
- frames.ingested rate (fps, avg over scenario duration)
- frames.dropped (total)
- telemetry.ingested (total)
- telemetry.ingested rate (Hz, avg)
- telemetry.coalesced (total)
- runs.started
- runs.completed
- runs.faulted
- working-set peak (MB)
- gen-0-gc-count (total)
- gen-1-gc-count (total)
- gen-2-gc-count (total)
- alloc-rate (bytes/sec, avg)
- cpu-usage avg (%)
- cpu-usage peak (%)
Row 0 — demo baseline (pre-Phase-1)
This is the reference point that every Phase 1 slice's delta is measured against. Captured at current simulator rates with no architectural changes.
- Scenario: §4.1 Demo baseline (10 min, Normal profile)
- Capture:
docs/captures/demo-baseline-2026-04-23.csv(687 s, includes warm-up + cool-down around the 10-minute scenario) - Commit:
7ecef05 - Date: 2026-04-23
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| demo-baseline (pre-Phase-1) | frames.ingested (total) | 492 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | frames.ingested rate (fps) | 0.72 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | frames.dropped (total) | 0 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | telemetry.ingested (total) | 3 315 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | telemetry.ingested rate (Hz) | 4.83 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | telemetry.coalesced (total) | 0 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | runs.started | 41 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | runs.completed | 41 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | runs.faulted | 0 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | working-set peak (MB) | 203.4 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | gen-0-gc-count (total) | 135 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | gen-1-gc-count (total) | 33 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | gen-2-gc-count (total) | 8 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | alloc-rate avg (B/s) | 1 524 381 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | cpu-usage avg (%) | 0.99 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
| demo-baseline (pre-Phase-1) | cpu-usage peak (%) | 4.69 | — | — | demo-baseline-2026-04-23.csv, §4.1 | 2026-04-23 |
Notes on row 0
frames.dropped,telemetry.coalesced, andruns.faultedare absent from the CSV becausedotnet-countersonly emits rows for counters that were incremented at least once. Zero-valued rows above are the correct reading of that absence: no drops, no coalesces, no faulted runs across 41 completed runs. If a future capture shows non-zero values for any of these at demo rates, that is a regression.- Capture spans 687 s (11:27) because the CSV started ~30 s before the first Start click and stopped ~60 s after the last run completed. All rate metrics are computed over the full 687 s — not the 600 s scenario — so they include app-idle periods and will read slightly lower than the in-scenario rate. Keep this convention for every future row so deltas are apples-to-apples.
Row 0a — demo baseline (automated, pre-Phase-1 reference)
This row captures the same baseline scenario as row 0 but driven by the DemoBaselineScenario automation (TASK-1.5). It serves as the reference for future automated captures so that deltas do not mix manual operator timing with programmatic run cadence.
- Scenario: §3a Demo baseline automated (10 min, Normal profile, operator-delay 0)
- Capture:
docs/captures/demo-baseline-automated-2026-04-25.csv(598 s) - Commit:
f64173f - Date: 2026-04-25
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| demo-baseline-automated (pre-Phase-1) | frames.ingested (total) | 1 150 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | frames.ingested rate (fps) | 1.92 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | frames.dropped (total) | 0 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | telemetry.ingested (total) | 2 947 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | telemetry.ingested rate (Hz) | 4.93 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | telemetry.coalesced (total) | 0 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | runs.started | 58 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | runs.completed | 57 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | runs.faulted | 0 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | working-set peak (MB) | 73.5 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | gen-0-gc-count (total) | 9 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | gen-1-gc-count (total) | 1 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | gen-2-gc-count (total) | 0 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | alloc-rate avg (B/s) | 110 889 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | cpu-usage avg (%) | 0.23 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
| demo-baseline-automated (pre-Phase-1) | cpu-usage peak (%) | 3.32 | — | — | demo-baseline-automated-2026-04-25.csv, §3a | 2026-04-25 |
Notes on row 0a
Purpose. Row 0a is the automated-capture reference; future Phase 1 slices captured via
Capture-Measurements.ps1should delta against this row, not against row 0. Row 0 remains the manual-capture reference and is not replaced.Comparability with row 0. The simulator profile is the same (Normal). The telemetry rate is the correct comparability metric: row 0 = 4.83 Hz, row 0a = 4.93 Hz, delta = +2.1% — within the ±5% acceptability window. The
telemetry.ingested ÷ runs.completedratio (80.9 vs 51.7) is NOT comparable because row 0 had operator think-time between runs (~15 s/run) while row 0a is back-to-back (no--operator-delay). This is expected and correct behaviour.Memory and GC vs row 0. Row 0a runs headless (no WPF window rendered) whereas row 0 was captured with the full UI visible. WPF's rendering loop generates significant allocation pressure; without it, alloc-rate (110 KB/s vs 1 524 KB/s) and GC counts (gen-0: 9 vs 135) are dramatically lower. Working-set peak is also lower (73.5 MB vs 203.4 MB). These differences are structural — do not treat them as improvements in the application domain logic.
runs.completed higher than row 0. 57 automated vs 41 manual in the same 10-minute window. Expected: the automated scenario starts the next run immediately after the previous one completes, whereas the manual procedure requires the operator to click Start Run within 1–2 seconds. This also explains why
frames.ingestedis higher (1 150 vs 492): more scan points executed, so more frames captured.App exit code. The app exited with
-532462766(ObjectDisposedExceptioninSimulatedTagSource.Disposeduring host shutdown). This is a pre-existing defect that fires after scenario completion and does not affect the metrics. It is noted here for traceability.Superseded by row 0b as of 2026-04-26. Row 0a captured a scenario that skipped the inter-run Home step (TASK-1.5.1 Pass 1 fixed the scenario; TASK-1.5.1 Pass 3 captured row 0b under the corrected behaviour). Row 0a is preserved unchanged.
Row 0b — demo baseline (automated, post-Home-fix reference)
This row captures the same scenario as row 0a but under the corrected DemoBaselineScenario from TASK-1.5.1 Pass 1 (inter-run Home step added) and the fixed shutdown from Pass 3 (ObjectDisposedException eliminated). It supersedes row 0a as the reference for all SLICE-1.2 and later automated captures.
- Scenario: §3a Demo baseline automated (10 min, Normal profile, operator-delay 0, post-TASK-1.5.1)
- Capture:
docs/captures/demo-baseline-automated-row-0b-2026-04-26.csv(601 s) - Commit:
2b25476 - Date: 2026-04-26
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| demo-baseline-automated-0b (pre-Phase-1) | frames.ingested (total) | 725 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | frames.ingested rate (fps) | 1.21 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | frames.dropped (total) | 0 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | telemetry.ingested (total) | 2 978 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | telemetry.ingested rate (Hz) | 4.95 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | telemetry.coalesced (total) | 0 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | runs.started | 45 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | runs.completed | 44 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | runs.faulted | 0 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | working-set peak (MB) | 72.6 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | gen-0-gc-count (total) | 8 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | gen-1-gc-count (total) | 0 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | gen-2-gc-count (total) | 0 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | alloc-rate avg (B/s) | 107 688 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | cpu-usage avg (%) | 0.22 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
| demo-baseline-automated-0b (pre-Phase-1) | cpu-usage peak (%) | 4.16 | — | — | demo-baseline-automated-row-0b-2026-04-26.csv, §3a | 2026-04-26 |
Notes on row 0b
Why row 0b exists. TASK-1.5.1 Pass 1 fixed
DemoBaselineScenarioto callops.Home.Execute(null)between runs instead of directly mutatingAppState.WorkflowState. The Home step adds ~2–4 seconds of wall-clock time per run cycle (homing delay in the Normal simulator profile). Row 0a was captured against the broken scenario that skipped this step, so itsruns.completed = 57represents an artificially high throughput that no correctly-behaved capture can reproduce. Row 0b is the reference every SLICE-1.2 and later automated capture must delta against.Which row Phase 1 deltas compare against. Use row 0b for every SLICE-1.2 onward automated capture. Row 0a is retained as historical evidence of the broken-scenario state and must not be used as a delta baseline.
runs.completed delta. Row 0b: 44 vs row 0: 41 (manual, +7%) vs row 0a: 57 (broken scenario, −23% relative to 0a). The drop from 0a to 0b is expected: the inter-run Home step from TASK-1.5.1 Pass 1 consumes ~2–4 s per cycle in the Normal simulator profile. Row 0b is closer to the manual row 0 throughput because both the manual operator and the corrected scenario now perform the same Home→Start sequence between runs.
App exit code. The app exited with code 0. The
ObjectDisposedExceptiondefect that produced-532462766in all earlier automated captures was fixed by TASK-1.5.1 Pass 3 (added_disposedguard toSimulatedTagSource.Dispose).
Phase 1 rows
Row — slice-1-3-encoder-rate-motion
SLICE-1.3 evidence row: first capture under the new EncoderRate simulator profile. Exercises the new IEncoderStream data-plane (1 kHz target, two axes, per-axis RandomWalkNoise around commanded position) running alongside the existing 50-tag MultiTag telemetry stream. The encoder pipeline service drains the bounded channel and increments encoder.samples.ingested{axis=…} without writing to AppState — the load-bearing architectural point of the slice. See "Encoder-rate cadence gap" note below.
- Scenario: §4.4 Encoder-rate soak (10 min,
EncoderRateprofile) viaMultiTagSoakFlaUi - Capture:
docs/captures/slice-1-3-encoder-rate-2026-04-30.csv(613 s) - Profile:
EncoderRate(mirrorsMultiTag: 50 tags @ heterogeneous rates, 50 ms snapshot interval, 640 × 480 × 1 frames @ 500 ms;EncoderIntervalMs = 1) - Commit:
736afac - Date: 2026-04-30
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| slice-1-3-encoder-rate-motion | frames.ingested (total) | 8 154 | 770 | −7 384† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | frames.ingested rate (fps) | 13.41 | 1.26† | —† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | frames.dropped (total) | 0 | 0 | 0 | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | telemetry.ingested (total) | 5 545 | 12 066 | +6 521† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | telemetry.ingested rate (Hz) | 9.12 | 19.68† | —† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | telemetry.coalesced (total) | 2 | 4 | +2 | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | runs.started | 141 | 70 | −71† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | runs.completed | 140 | 70 | −70† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | runs.faulted | 0 | 0 | 0 | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | working-set peak (MB) | 237.2 | 223.3 | −13.9† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | gen-0-gc-count (total) | 599 | 529 | −70 | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | gen-1-gc-count (total) | 95 | 73 | −22 | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | gen-2-gc-count (total) | 2 713 | 50 | −2 663† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | alloc-rate avg (B/s) | 35 132 285 | 6 512 796 | 0.19׆ | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | cpu-usage avg (%) | 5.43 | 4.35 | −1.08† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | cpu-usage peak (%) | 19.53 | 17.58 | −1.95† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | gc-pause-p95 (ms) | 11.76 | 7.90 | −3.86† | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | LOH-alloc-rate avg (B/s) | 1 039 966 | 23 251 | 0.022׆ | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | encoder-rate-x (Hz) | — | 656.6 | — | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
| slice-1-3-encoder-rate-motion | encoder-rate-y (Hz) | — | 656.6 | — | slice-1-3-encoder-rate-2026-04-30.csv, §4.4 | 2026-04-30 |
† Profile change drives the delta. EncoderRate mirrors MultiTag (640 × 480 × 1 frames @ 500 ms, 50 ms telemetry snapshot, 50 tags) plus EncoderIntervalMs = 1, whereas the slice-1-2 baseline used HighFrameRate (2048 × 1024 × 1 frames @ 33 ms, 100 ms telemetry snapshot). The frame, telemetry, and LOH-pressure deltas are dominated by that profile shift, not by the encoder stream.
Notes on slice-1-3-encoder-rate-motion
Baseline reference is
slice-1-2-real-frame-payloads(most recent FlaUI-captured row). The architectural delta this row isolates is the addition of theIEncoderStreamdata plane — but most of the visible numeric delta comes from the profile shiftHighFrameRate → EncoderRate. Use theencoder-rate-x/encoder-rate-yrows and the absence of run faults / frame drops as the primary evidence; treat the rest as profile context.Encoder-rate cadence gap — Windows
PeriodicTimerceiling, not a code defect. Receiver-side rate held at 656.6 Hz on both axes across the 613 s capture, well below the original criterion-7 target of 980–1020 Hz. The producer acquireswinmm!timeBeginPeriod(1)onStartAsyncso the OS timer floor is 1 ms, butPeriodicTimer(1 ms).WaitForNextTickAsyncis not a real-time mechanism: per-tick scheduling overhead plus the producer's per-tick work (two_motion._lockreads to getCurrentX/CurrentY, anImmutableArray.Builder<EncoderSample>(2)allocation, channelTryWrite, plus theNoiseModelEvaluator.Evaluateper axis) drives the effective tick to ~1.52 ms. Criterion 7 was amended on 2026-04-30 to documented-not-gated (mirroring SLICE-1.1's per-tag-rate amendment for the same Windows-timer-resolution family of constraints). The slice's load-bearing architectural point — receiver-side counter reachable through a non-AppStatechannel at hundreds-of-Hz rates without destabilizing the workflow state machine — is met (runs.faulted = 0,frames.dropped = 0,tags.active = 50throughout). Filed as a follow-up: encoder-cadence remediation — replacePeriodicTimerwith one of (a) a dedicated thread +Stopwatch.GetTimestamp()busy-yield, (b)timeSetEventmultimedia-callback, (c)CreateWaitableTimerEx(TIMER_HIGH_RESOLUTION). Each carries different CPU-cost / portability trade-offs; pick when there is a downstream consumer that actually demands 1 kHz cadence.No
AppStatewrite from the encoder pipeline (load-bearing test). Verified mechanically byEncoderStreamPipelineServiceTests.Pipeline_WhenDrainingSnapshots_NeverCallsAppStateStoreUpdate(recording-store fake assertsUpdateCount == 0). The on-machine evidence isruns.faulted = 0+ the 19.68 Hz observedtelemetry.ingested rate(matching the 50 ms snapshot publisher cadence), which together demonstrate the encoder stream did not bleed into the snapshot-publisher path or the workflow state machine even at 656 Hz × 2 axes ≈ 1 313 channel-write attempts/s.LOH and gen-2 GC dropped sharply vs the SLICE-1.2 baseline. gen-2 GC count fell from 2 713 to 50 (−98%) and LOH-alloc-rate-avg from 1.0 MB/s to 23 KB/s (−98%). Driven by
EncoderRateusing 640 × 480 × 1 frames at 500 ms (Normal-class allocation) instead ofHighFrameRate's 2 MP frames at 33 ms — i.e. nearly all of the SLICE-1.2 row's LOH pressure is gone here, by design. The encoder stream itself contributes ~1.3 K smallImmutableArray<EncoderSample>(2)allocations/s; those are gen-0-bound, not LOH (each is well under 85 KB), and show up in alloc-rate avg (6.5 MB/s) but do not move gen-2 numbers.Capture span 613 s vs scenario 600 s. The 13 s difference is the
MultiTagSoakFlaUiwarm-up and shutdown slop — consistent with the pattern seen inslice-1-2(608 s for a 600 s scenario). System sleep was disabled for the duration (powercfg /change standby-timeout-ac 0) per the SLICE-1.1 / SLICE-1.5.1 runbook discipline; the capture window contains no idle gaps.
Row — slice-1-4-chaos-monkey
SLICE-1.4 first evidence row: 30-minute capture under the ChaosMonkey simulator profile (aggressive fault injection — DefectShowerEveryMs = 3 000, AlarmBurstEveryMs = 45 000, TelemetryDropoutChance = 0.05, NetworkLatencyMeanMs = 100, ConnectionFailureProbability = 0.3, FlakySdk:Enabled = true). Exercises all four fault branches in WorkflowService to verify criterion 11 (every fault branch hit, log evidence).
- Scenario: §4.5 Chaos-monkey scenario (30 min,
ChaosMonkeyprofile) viaMultiTagSoakFlaUi - Capture:
docs/captures/slice-1-4-chaos-monkey-2026-05-01.csv(1 807 s) - Profile:
ChaosMonkey - Commit:
2108272 - Date: 2026-05-01
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| slice-1-4-chaos-monkey | frames.ingested (total) | 770 | 10 469 | +9 699†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | frames.ingested rate (fps) | 1.26 | 5.79 | 4.59׆† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | frames.dropped (total) | 0 | 0 | 0 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | telemetry.ingested (total) | 12 066 | 35 784 | +23 718†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | telemetry.ingested rate (Hz) | 19.68 | 19.80 | +0.12 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | telemetry.coalesced (total) | 4 | 2 | −2 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | runs.started | 70 | 491 | +421†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | runs.completed | 70 | 453 | +383†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | runs.faulted | 0 | 37 | +37 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | working-set peak (MB) | 223.3 | 225.3 | +2.0 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | gen-0-gc-count (total) | 529 | 2 279 | +1 750†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | gen-1-gc-count (total) | 73 | 629 | +556†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | gen-2-gc-count (total) | 50 | 1 429 | +1 379†† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | alloc-rate avg (B/s) | 6 512 796 | 14 557 990 | 2.24׆† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | cpu-usage avg (%) | 4.35 | 4.66 | +0.31 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | cpu-usage peak (%) | 17.58 | 15.04 | −2.54 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | gc-pause-p95 (ms) | 7.90 | 10.28 | +2.38 | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | LOH-alloc-rate avg (B/s) | 23 251 | 323 188 | 13.9׆† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | encoder-rate-x (Hz) | 656.6 | 199.9 | 0.30׆† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | encoder-rate-y (Hz) | 656.6 | 199.9 | 0.30׆† | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | working-set growth (MB) | — | 138.2 | — | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
| slice-1-4-chaos-monkey | fault-cycles (count) | — | 37 | — | slice-1-4-chaos-monkey-2026-05-01.csv, §4.5 | 2026-05-01 |
†† Duration and profile both differ from baseline (slice-1-3: 613 s, EncoderRate; slice-1-4-chaos-monkey: 1 807 s, ChaosMonkey). Totals scale with scenario length; only rates, runs.faulted, fault-cycles, and working-set peak carry direct architectural meaning.
Notes on slice-1-4-chaos-monkey
Baseline reference is
slice-1-3-encoder-rate-motion(most recent FlaUI-captured row). The delta isolates theChaosMonkeyprofile's footprint versus the lighterEncoderRateprofile. The encoder-rate drop (656.6 → 199.9 Hz) is expected:ChaosMonkeysetsEncoderIntervalMs = 5(200 Hz target) whereasEncoderRateusesEncoderIntervalMs = 1(1 000 Hz target, achieved ~657 Hz on this host). Working-set peak is essentially unchanged (+2.0 MB); fault injection adds no persistent allocation pressure.Criterion-11 fault-branch evidence (all four branches hit). Log inspection of
Logs/app-20260501.logconfirmed: 39CRITICAL FAULT: [CHAOS-…]lines injected, 39Fault condition cleared: [CHAOS-…]lines, 37Recovery completed.lines, and 120 defect-shower state transitions. The two unrecovered faults (39 injected − 37 recovered) are the final two chaos events that fired within the last few seconds of the scenario window before teardown — consistent with the ~45 s inter-burst interval and a 1 807 s capture. Branch coverage: (a) connect-failure path viaConnectionFailureProbability = 0.3and FlakySdkOutOfBandThrow/IgnoreCancellationmodes; (b) fault-during-home viaAlarmBurstEveryMs = 45 000firing within the ~1 s homing window; (c) fault-during-run via the same alarm burst firing while a run is active; (d) fault-clear-and-recover via the 37 full inject→clear→recover cycles.Simulator:FlakySdk:Enabledcaveat. Captured withFlakySdk:Enabled = true(manually flipped before the 2026-05-01 session). The mergedappsettings.jsonshipsEnabled = false(commit018bf29, criterion-16 reproducibility). To reproduce this row: flipSimulator:FlakySdk:Enabledtotrueinsrc/InspectionPrototype.App/appsettings.jsonbefore building, then restore tofalseafterward.FlakySdk timeout-branch fix (commit
018bf29). The ChaosMonkey capture ran against the pre-fix code (2108272). After the capture a review found the timeout branch unconditionally threwOperationCanceledExceptioneven when the caller's CT was not cancelled; the correct behaviour (fall through to the inner connection) was fixed in018bf29. The fault-cycle count is unaffected: the scenario's retry-Connect loop already handled the OCE by retrying, so the observable behaviour was the same before and after the fix.
Row — slice-1-4-soak-8h
SLICE-1.4 second evidence row: 8-hour capture under the Soak8h simulator profile (low-chaos sustained load — AlarmBurstEveryMs = 0, TelemetryDropoutChance = 0.01, ConnectionFailureProbability = 0.05, TimeCompressionFactor = 1.0, FlakySdk:Enabled = false). Intended to detect working-set growth over real time (criterion 12: last − first ≤ 50 MB). See criterion-12 gap note below.
- Scenario: §4.6 Soak scenario (8 h,
Soak8hprofile) viaMultiTagSoakFlaUi - Capture:
docs/captures/slice-1-4-soak-8h-2026-05-02.csv(28 809 s) - Profile:
Soak8h - Commit:
018bf29 - Date: 2026-05-03
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| slice-1-4-soak-8h | frames.ingested (total) | 8 154 | 71 530 | +63 376†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | frames.ingested rate (fps) | 13.41 | 2.48 | 0.18׆† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | frames.dropped (total) | 0 | 2 | +2 | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | telemetry.ingested (total) | 5 545 | 286 968 | +281 423†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | telemetry.ingested rate (Hz) | 9.12 | 9.96 | +0.84†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | telemetry.coalesced (total) | 2 | 12 | +10†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | runs.started | 141 | 5 109 | +4 968†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | runs.completed | 140 | 5 109 | +4 969†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | runs.faulted | 0 | 0 | 0 | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | working-set peak (MB) | 237.2 | 246.0 | +8.8 | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | gen-0-gc-count (total) | 599 | 31 494 | +30 895†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | gen-1-gc-count (total) | 95 | 5 551 | +5 456†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | gen-2-gc-count (total) | 2 713 | 11 185 | +8 472†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | alloc-rate avg (B/s) | 35 132 285 | 9 953 546 | 0.28׆† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | cpu-usage avg (%) | 5.43 | 4.42 | −1.01†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | cpu-usage peak (%) | 19.53 | 13.67 | −5.86†† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | gc-pause-p95 (ms) | 11.76 | 12.42 | +0.66 | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | LOH-alloc-rate avg (B/s) | 1 039 966 | 238 672 | 0.23׆† | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | encoder-rate-x (Hz) | — | 200.0 | — | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | encoder-rate-y (Hz) | — | 200.0 | — | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | working-set growth (MB) ‡ | — | 186.5 ⚠ | — | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | working-set steady-state drift (MB) | — | −2.7 | — | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
| slice-1-4-soak-8h | fault-cycles (count) | — | 0 | — | slice-1-4-soak-8h-2026-05-02.csv, §4.6 | 2026-05-03 |
†† Duration and profile both differ from baseline (slice-1-2: 608 s, HighFrameRate; slice-1-4-soak-8h: 28 809 s, Soak8h). All totals scale with the 47× duration difference; only rate metrics, working-set growth, encoder-rate, and fault-cycles carry direct architectural meaning. ⚠ Original criterion-12 metric (last − first) reads 186.5 MB, exceeding the 50 MB ceiling. Direct CSV inspection showed this is entirely the process startup ramp (47.5 → 230.9 MB in 29 s); no leak in the 8-hour plateau. Criterion 12 amended (2026-05-03) to use a startup-excluded steady-state metric; see next row. ‡ Original metric retained for historical traceability; superseded by working-set steady-state drift (MB) per criterion-12 amendment in SLICE-1.4 spec (2026-05-03).
Notes on slice-1-4-soak-8h
Baseline reference is
slice-1-2-real-frame-payloads(continuous-load FlaUI-captured row with low chaos). Bothslice-1-2andSoak8hemphasise sustained data-plane throughput with minimal intentional faults;Soak8hhasAlarmBurstEveryMs = 0so no alarm-driven fault paths fire. The primary comparison point is theworking-set growthrow (new in SLICE-1.4), not the totals (dominated by the 47× duration difference).Criterion-12 analysis — startup ramp, not a sustained leak. Criterion amended 2026-05-03. Working-set first-second = 47.5 MB; last-second = 234.0 MB;
last − first= 186.5 MB, which exceeds the original 50 MB ceiling. Direct CSV inspection (sampled across 14 timepoints from t=0 to t=8h) revealed the entire delta is the process startup ramp: working-set rose from 47.5 MB to 230.9 MB at t=29 s (full ramp in under 30 seconds — WPF rendering, 50 tag emitters, encoder pipeline initialisation, JIT). It then held a stable sawtooth between 224 MB and 240 MB for the remaining 7.5 hours. Window analysis:avg(minutes 5-30) = 235.4 MB,avg(hours 4-5) = 234.0 MB,avg(last 60 min) = 232.7 MB— the steady-state mean decreased by 2.7 MB across 8 hours. p99 = 238.1 MB; one transient max = 246.0 MB. There is no monotonic growth at any point after the startup ramp completes. Criterion 12 amended: original metricworking-set growth = last − first ≤ 50 MBis superseded byworking-set steady-state drift = avg(last 60 min) − avg(minutes 5-60) ≤ 50 MB. The 50 MB ceiling itself is unchanged; only the measurement window. Against the amended metric, the 2026-05-02 capture reads −2.7 MB — passes the ceiling by a wide margin. Same pattern as SLICE-1.1's criterion 7 amendment (per-tag rate accuracy, Windows scheduling reality) and SLICE-1.3's criterion 7 amendment (encoder receiver rate, Windows timer-resolution ceiling). Phase 1 exit gate met 2026-05-03.Gen-2 GC rate vs slice-1-2 ceiling (passes).
slice-1-2recorded 2 713 gen-2 collections in 608 s = 16 072/hr;slice-1-4-soak-8hrecorded 11 185 in 28 809 s = 1 398/hr. The 4× ceiling (64 288/hr) is satisfied by a wide margin. The lower rate reflectsSoak8h's lighter LOH pressure (640 × 480 × 1-byte frames at 500 ms vsHighFrameRate's 2 MP frames at 33 ms; LOH-alloc-rate dropped from 1.0 MB/s to 0.23 MB/s).Per-tag samples.ingested. All 50 configured tags were active throughout (aggregate
telemetry.ingested rate= 9.96 Hz ≈ 10 Hz, matching the 100 ms snapshot interval of theSoak8hprofile).telemetry.coalesced= 12 over 28 809 s (< 1 coalesce per 2 400 s), consistent withTelemetryDropoutChance = 0.01occasionally deferring a snapshot under transient load. No tag dropped by more than expected.frames.dropped = 2. Two frames dropped over 28 809 s (0.003% of 71 530 total). Within normal operating variance; the bounded frame channel absorbed transient scheduling spikes without accumulation. Not a criterion gate.
runs.faulted = 0. The
Soak8hprofile hasAlarmBurstEveryMs = 0(no alarm-driven faults). The 5%ConnectionFailureProbabilityfires onConnectAsync; the retry-Connect loop from commit2108272absorbs these at setup time. All 5 109 started runs completed.
Row — slice-1-2-real-frame-payloads
SLICE-1.2 evidence row: first HighFrameRate (30 fps, 2 MP) capture under the FlaUI rig (SLICE-1.6). Exercises SimulatedCamera's real byte[] allocation path and the WriteableBitmap update pipeline at ~2 MB × 30 fps LOH pressure. See "frames.ingested criterion gap" note below.
- Scenario: §3b HighFrameRate soak (10 min, HighFrameRate profile) via
MultiTagSoakFlaUi - Capture:
docs/captures/slice-1-2-high-fps-2026-04-27.csv(608 s) - Commit:
874946d - Date: 2026-04-27
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| slice-1-2-real-frame-payloads | frames.ingested (total) | 725 | 8 154 | +7 429 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | frames.ingested rate (fps) | 1.21 | 13.41† | —† | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | frames.dropped (total) | 0 | 0 | 0 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | telemetry.ingested (total) | 2 978 | 5 545 | +2 567 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | telemetry.ingested rate (Hz) | 4.95 | 9.12† | —† | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | telemetry.coalesced (total) | 0 | 2 | +2 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | runs.started | 45 | 141 | +96 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | runs.completed | 44 | 140 | +96 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | runs.faulted | 0 | 0 | 0 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | working-set peak (MB) | 72.6 | 237.2 | +164.6 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | gen-0-gc-count (total) | 8 | 599 | +591 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | gen-1-gc-count (total) | 0 | 95 | +95 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | gen-2-gc-count (total) | 0 | 2 713 | +2 713 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | alloc-rate avg (B/s) | 107 688 | 35 132 285 | +326× | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | cpu-usage avg (%) | 0.22 | 5.43 | +5.21 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | cpu-usage peak (%) | 4.16 | 19.53 | +15.37 | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | gc-pause-p95 (ms) | — | 11.76 | — | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
| slice-1-2-real-frame-payloads | LOH-alloc-rate avg (B/s) | — | 1 039 966 | — | slice-1-2-high-fps-2026-04-27.csv, §3b | 2026-04-27 |
† Rate metric not directly comparable to row 0b — different profile and scenario duration (§3b vs §3a).
Notes on slice-1-2-real-frame-payloads
Baseline reference is row 0b (automated DemoBaseline, Normal profile). The delta isolates the HighFrameRate profile's footprint on top of the Normal-profile reference. The HighFrameRate profile (2048 × 1024 × 1, 33 ms interval) vs Normal (640 × 480 × 1, 1000 ms interval) drives the dominant effects: alloc-rate +326×, gen-2 GC count +2 713, working-set +164 MB, cpu avg +5.2 percentage points.
frames.ingested criterion gap — scenario vs criterion model mismatch. SLICE-1.2 acceptance criterion 6 requires
frames.ingested ≥ 17 500(= 30 fps × 600 s × 0.97), which assumes the camera produces frames continuously for the full 600 s connected period.SimulatedCameraonly produces frames while a run is actively in progress (Connected + Running state); during Home, Idle, and Ready transitions the camera is not streaming. With 140 completed runs averaging ~4.3 s per cycle (including Home latency), only a fraction of the 608 s window has active frame production. The observed 8 154 frames imply ~30 fps during active scan motion — consistent withFrameIntervalMs = 33— which confirms the HighFrameRate pipeline is operating at the configured rate. The shortfall is a mismatch between the criterion's continuous-streaming assumption and the multi-cycle scan scenario structure, not a pipeline defect. The other evidence —frames.dropped = 0,runs.faulted = 0, gen-2 count 2 713 (LOH pressure confirmed), p95 pause 11.76 ms (no pause-caused drops) — confirms the pipeline is working correctly under HighFrameRate load. Filed as follow-up: amend criterion 6 to match the achievable frame count under the multi-cycle scenario, or add a dedicated single-continuous-run scenario that stays in Running state for the full 10 minutes.gen-2 GC and LOH allocation evidence. 2 713 gen-2 collections in 608 s (4.5/s) vs 0 in row 0b — the LOH allocation pressure from 2 MB frames is reaching the LOH threshold and driving significant gen-2 collection activity, confirming the frame pipeline's allocation behavior as intended by SLICE-1.2. p95 GC pause = 11.76 ms;
frames.dropped = 0confirms the channel absorbed all production without loss despite the pause overhead. LOH alloc rate 1.0 MB/s is the time-averaged rate over the full 608 s including idle periods; during active runs it tracks closer to 60 MB/s (2 MB × ~30 fps).Telemetry rate higher than row 0b. 9.12 Hz vs 4.95 Hz in row 0b — because
HighFrameRateuses the sameTelemetryIntervalMs = 50 msas theMultiTagprofile (both are 50-tag, 20 Hz snapshot configurations), whileNormaluses 200 ms (5 Hz). This is expected profile behavior.Commit hash. Row was captured against uncommitted Pass 3 code (XAML
ActiveSimulatorProfileTextfix,SIMULATOR_PROFILEenv-var wire-through inMultiTagSoakFlaUi,-Profileparameter inCapture-Measurements.ps1). Commit hash updated to the Pass 3 commit after the session commit.
Row — slice-1-1-multi-tag-telemetry
First Phase 1 row. Captures the multi-tag telemetry slice under the new MultiTag simulator profile (50 tags emitting at heterogeneous rates from 1 Hz to 500 Hz configured) via the automated MultiTagSoakScenario.
- Scenario: §4.2 Multi-tag soak (30 min, MultiTag profile, operator-delay 0)
- Capture:
docs/captures/slice-1-1-multi-tag-2026-04-26.csv(5811 s — see "Capture duration discrepancy" in Notes) - Per-tag rate distribution:
docs/captures/slice-1-1-multi-tag-2026-04-26-rate-check-2026-04-26.txt - Commit:
827a7ee - Date: 2026-04-26
| Slice | Metric | Baseline | After | Delta | Capture method | Date |
|---|---|---|---|---|---|---|
| slice-1-1-multi-tag-telemetry | frames.ingested (total) | 725 | 2 266 | +1 541 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | frames.ingested rate (fps) | 1.21 | 0.39† | —† | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | frames.dropped (total) | 0 | 0 | 0 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | telemetry.ingested (total) | 2 978 | 28 829 | +25 851 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | telemetry.ingested rate (Hz) | 4.95 | 4.96† | —† | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | telemetry.coalesced (total) | 0 | 18 | +18 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | runs.started | 45 | 175 | +130 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | runs.completed | 44 | 174 | +130 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | runs.faulted | 0 | 0 | 0 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | working-set peak (MB) | 72.6 | 80.3 | +7.7 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | gen-0-gc-count (total) | 8 | 180 | +172 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | gen-1-gc-count (total) | 0 | 23 | +23 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | gen-2-gc-count (total) | 0 | 4 | +4 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | alloc-rate avg (B/s) | 107 688 | 709 132 | +6.6× | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | cpu-usage avg (%) | 0.22 | 0.56 | +0.34 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
| slice-1-1-multi-tag-telemetry | cpu-usage peak (%) | 4.16 | 8.98 | +4.82 | slice-1-1-multi-tag-2026-04-26.csv, §4.2 | 2026-04-26 |
† Rate metric not directly comparable to row 0b — see "Capture duration discrepancy" below.
Notes on slice-1-1-multi-tag-telemetry
Baseline reference is row 0b (automated DemoBaseline, Normal profile). The delta isolates the Normal → MultiTag profile change under the same automation. Substantive findings from the comparable counters: telemetry.ingested totals are ≈10× higher (50 ms snapshot interval vs 200 ms), runs.completed is ≈4× higher (3× longer scenario × MultiTag's faster motion profile), and alloc-rate is ≈6.6× higher (50 concurrent emitters allocating per-call dimension
KeyValuePairvs row 0b's single telemetry cell).Capture duration discrepancy — system sleep, not a code bug. The scenario was configured for 1 800 s but the CSV spans 5 811 s. Investigation against
app-20260426.logshows a 63-minute gap with zero log events and zero CSV rows between11:17:59 Moving to (50.0, 25.0)and12:21:41 Camera streaming stopped. The host actually shuts down promptly (~2 s fromStopping active run before disconnecttoTag source disposed); the long wall time is the laptop sleeping mid-capture and resuming. An identical-config first run earlier the same day (10:12–10:42) finished cleanly in 30 min for 174 runs. Counter totals reflect actual work done; rate metrics in the table above are computed over the full CSV span (5 811 s) and are therefore diluted by the sleep duration. Scenario-duration-normalized rates (dividing by 1 800 s instead): frames.ingested ≈ 1.26 fps; telemetry.ingested ≈ 16.0 Hz; alloc-rate ≈ 2.3 MB/s. Action item: disable system sleep during captures (Windows:powercfg /change standby-timeout-ac 0for the duration). Filed as a runbook caveat, not a code follow-up.Per-tag rate accuracy (acceptance criterion 7, amended). All 50 configured tags appear in
samples.ingestedwith thetag.namedimension (criterion 6 met; verified byAppMetricsTagDimensionTests). With scenario-duration normalization (samples ÷ 1 800 s, since per-tag emitters are paused during the system-sleep window): ≤5 Hz tags hit within ±2% of configured (1 Hz → 1.00 Hz, 5 Hz → 4.91 Hz); 10 Hz → 9.17 Hz (-8%); 20 Hz → 16.0 Hz (-20%); 50 Hz → 32.1 Hz (-36%); 100 Hz → 63.9 Hz (-36%); 250 Hz and 500 Hz tags both cap near 64 Hz from the default Windows 15.6 ms timer tick. The CSV-span normalization in the rate-check.txtunderstates all bands by ~3.2× because of the sleep dilution. Simulator emit-rate accuracy under concurrent load is filed as a follow-up; for SLICE-1.2 onward, captures should run on a sleep-disabled session so this confound doesn't recur.
Reading this table across phases
- Row 0's
baselinecolumn is the reference for every later row'sdeltauntil Phase 2 begins. Phase 1 rows compare against row 0. - Phase 2 rows will compare against the final Phase 1 row (to be chosen when Phase 1 exits). Do not retroactively edit Phase 1 rows after Phase 2 starts.
- If a capture is re-run (for example because the scenario changed), add a new row rather than editing the old one. Old rows are historical evidence and should not be rewritten.