Files
Andrew Grimberg 8d8fe0ad7f Feat(diagnostics): Expose slot plan state
Build per-refresh DesiredPlan diagnostics snapshots in
reconciliation.py so every managed slot's desired identity key,
actual classification, pending action, blocked reason, retry count,
and last error are captured in plan.diagnostics.  Per-reservation
entries record selected/protected/overflow status, missing_count,
assigned slot, uid_aliases, and booking_aliases without any raw
slot codes or PINs.  Optional entry_id, lockname, and start_slot
keyword arguments supply coordinator-scope metadata.  The diagnostics
building is extracted into _build_plan_diagnostics_snapshot to keep
compute_desired_plan within maintainable bounds.

Add last_error to ManagedSlot so failed-operation errors from the
apply phase survive into the next refresh cycle and propagate into
the per-slot diagnostics snapshot.

In EventOverrides, add _last_slot_errors and _diagnostics_snapshot
fields.  Record errors in _apply_clear and _apply_set on failure;
clear them on confirmed success.  update_diagnostics_snapshot builds
a structured snapshot covering matched slots, pending corrections,
blocked clear reasons, slot_retry_counts, pending_clear_slots, and
last_slot_errors, and is called automatically at the end of
async_apply_plan via the finally block.  diagnostics_snapshot and
get_last_slot_error expose the data read-only for the coordinator
and HA diagnostics collection.

In the coordinator, _observe_managed_slots now uses an explicit
persisted_mapping variable to avoid chained dict.get fallbacks,
_apply_checkin_protection resolves hass.data lookup in two explicit
steps, compute_desired_plan receives entry_id/lockname/start_slot
for metadata context, and latest_reconciliation_diagnostics merges
plan diagnostics with the EventOverrides snapshot while stripping
slot_code/pin/code keys as a safety net.

Also add .aislop/baseline.json (set at score 100 on HEAD) and the
corresponding REUSE.toml annotation to keep the REUSE Specification
3.3 compliance intact.

Tests (T091-T094):
- test_event_overrides.py: TestDiagnosticsSnapshot verifies matched
  slots, pending corrections, blocked reasons, retry counts, last
  errors, error clearing on success, no raw codes, plan_id/timestamp,
  and pending_clear_slots list.
- test_slot_reconciliation.py: TestComputeDesiredPlanDiagnostics
  verifies plan_id/generated_at, optional entry_id/lockname/start_slot,
  per-reservation selected/protected/overflow/missing_count/assigned_
  slot/uid_aliases/booking_aliases, slot_code absent, per-slot
  last_error from ManagedSlot, and overflow_details preservation.
- test_keymaster_event_diagnostics.py: TestRedactionCompatibility
  verifies the keymaster event buffer has no slot_code/PIN fields
  and both the EventOverrides snapshot and compute_desired_plan
  diagnostics exclude raw codes.
- test_refresh_cycle.py: TestDiagnosticsDesiredVsActual runs a
  focused mock integration scenario with a matched slot, overflow
  reservation, and pending-clear slot to confirm diagnostics capture
  all states and contain no raw codes; also covers the manual-drift
  (CLEAR action for wrong occupant) diagnostic path.

Co-authored-by: Claude <claude@anthropic.com>
Signed-off-by: Andrew Grimberg <tykeal@bardicgrove.org>
2026-06-20 00:43:04 -07:00
..
2026-06-10 18:18:33 -07:00