Repository navigation
Release v3.1.0-rc14 - #15
Merged
Merged
Conversation
- New tests/test_strings_icu_escape.py with 4 module-level tests
- test_caldav_event_title_template_is_icu_escaped: asserts '{street}'/'{time}'/'{side}'
wrap counts on line 115 tooltip + no raw placeholders remain (RED — current state)
- test_caldav_invalid_template_is_icu_escaped: same shape against line 132 error
string (RED — current state)
- test_strings_and_en_json_byte_identical: Phase 31 byte-identity guard (GREEN today;
catches one-file-only edits in Task 2)
- test_no_raw_curly_placeholders: belt-and-suspenders regex scan of both files (RED)
- No HA imports, no pytest markers — picked up by the offline suite filter
- No .py file other than the new test touched; no JSON files modified
- Wrap every literal {street}/{time}/{side} on lines 115 and 132 with ASCII U+0027
single quotes so HA frontend FormatJS (intl-messageformat) treats them as quoted
literals instead of i18n argument slots
- Tooltip 'caldav_event_title_template': 4 placeholders wrapped
('{street}','{time}','{side}','{street}')
- Error string 'caldav_invalid_template': 3 placeholders wrapped
('{street}','{side}','{time}')
- Same byte-identical edit applied to translations/en.json (Phase 31 discipline)
- All 4 unit tests in tests/test_strings_icu_escape.py now GREEN
- Python DEFAULT_CALDAV_EVENT_TITLE_TEMPLATE in const.py UNCHANGED (raw {street}
is correct for str.format_map runtime path)
Fixes the formatjs MISSING_VALUE error overlay that masked the CalDAV options-flow
tooltip and validation-error message.
- 35-01-SUMMARY.md created at .planning/phases/35-caldav-tooltip-fix-formatjs-icu-escape/ - Documents the 2-line x 2-file ICU single-quote-wrap edit applied - Records 4 unit tests in tests/test_strings_icu_escape.py - Confirms full pytest suite green (570 passed / 0 failed) after the edit - Notes Task 4 (human UAT) still pending — checkpoint returned to orchestrator - Confirms const.py:78 DEFAULT_CALDAV_EVENT_TITLE_TEMPLATE unchanged (Pitfall 5) Note: .planning/ is gitignored in this repo; force-add used so the orchestrator can lift the SUMMARY from the worktree before the worktree is removed (#2070).
…3.x is sync `calendar()` is a local constructor in caldav 3.x; awaiting it raised TypeError which was silently swallowed, preventing all calendar event writes. Updated tests to use MagicMock instead of AsyncMock to match the now-correct sync call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README.md: correct diagnostic sensor count (Ten → Eleven; adds ASPIndexLastRebuiltSensor) - ARCHITECTURE.md: remove phantom sensor.asp_schedule_summary entity (schedule_summary is an attribute on ASPNextMoveTimeSensor, not a standalone sensor) - All six GSD-managed docs refreshed with latest codebase state Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove stale HTML comments, add table of contents with anchor links, and add horizontal rule dividers between major sections for better visual structure in the narrow HACS panel. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…elper - Valid index passes (rtree + graph.json.zst) - Corrupt segments.dat (4-byte garbage) raises IndexIntegrityError - Garbage graph.json.zst raises IndexIntegrityError - Plain graph.json (uncompressed) variant passes when readable Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-opens the rtree by stem and decompresses 1 byte of graph.json.zst (or reads 1 byte of plain graph.json) so the coordinator can distinguish "files present" from "files usable" at startup. Forces a bbox query to defeat rtree's lazy page-load so truncated segments.dat surfaces here rather than later inside the coordinator. - IndexIntegrityError module-level exception - _sync_verify_index(index_dir) -> None raises on rtree/zst failure - Reuses existing rtree_index + zstandard imports (no new deps) - Missing graph file treated as Level 4 unavailable (not corrupt) — matches StreetGraph.load contract Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t safety Three new defence-in-depth layers in async_setup_entry. Each layer surfaces a previously silent failure mode as a HA Repair issue and auto-dismisses on the next successful setup. Layer 1 — _async_ensure_index integrity check: After existence check passes, call _sync_verify_index in executor. On IndexIntegrityError, log WARNING, wipe INDEX_DIR (via _sync_cleanup_stale + shutil.rmtree), and fall through to the existing download path. Other exception types still propagate. Layer 2 — retry-aware Repair: New constants _SETUP_RETRY_COUNT_KEY_TPL and _RETRY_LIMIT_ISSUE_ID. Wrap _async_ensure_index in try/except ConfigEntryNotReady; increment per-entry counter, create Repair at >=5, re-raise. Counter cleared on next success after _async_ensure_index returns; Repair dismissed at top of every async_setup_entry. Layer 3 — async_start safety wrapper: New constant _ASYNC_START_FAILURE_ISSUE_ID. Wrap coordinator.async_start() in try/except Exception; log ERROR, create distinct Repair (separate issue_id from import + retry Repairs), bare re-raise. Translations: Two new keys under "issues" in translations/en.json — setup_retry_limit and async_start_failure — with user-facing title + description. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Five new tests in tests/test_init.py verify the contract added by
260601-aru-02:
Layer 1 (integrity check):
test_corrupt_index_triggers_redownload — IndexIntegrityError from
_sync_verify_index wipes INDEX_DIR and schedules a fresh download.
Layer 2 (retry-limit Repair):
test_setup_retry_creates_repair_after_5_failures — preset counter=4,
one more CENR brings count to 5 and creates the Repair issue.
test_setup_success_clears_retry_counter_and_repair — clean setup
after counter=7 pops the key and dismisses the Repair.
Layer 3 (async_start safety wrapper):
test_async_start_failure_creates_repair_and_reraises — RuntimeError
from coordinator.async_start surfaces async_start_failure Repair.
test_setup_success_clears_async_start_repair — pre-existing Repair
is removed by a clean setup.
All tests mirror the test_repair_issue.py conventions: ha_integration
marker, self-contained _make_entry helper, patches target the imported
binding at custom_components.asp_parking.* (not the source module).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…heck Adds _index_has_graph_file() helper and removes graph.json from INDEX_FILES so _async_ensure_index no longer enters a ConfigEntryNotReady boot-loop after an auto-rebuild replaces graph.json with graph.json.zst. Root cause identified and fixed by debug session gps-no-update-after-car-move. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolves conflict: worktree's _sync_verify_index (Layer 1) supersedes the simpler _index_has_graph_file existence check; both imports kept in test_index_io.py to cover both behaviours. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…flag to coordinator - Add _gps_stale_unsub and _last_pipeline_error attributes in __init__ - Add _gps_watchdog_cancel and _gps_watchdog_rearm methods (mirrors _boundary_timer_cancel pattern) - Set _last_pipeline_error=True in ValueError and bare Exception pipeline branches - Clear _last_pipeline_error=False on pipeline success path - Call _gps_watchdog_rearm() in _async_on_gps_update after last_gps_update set - Add _gps_watchdog_cancel() call in async_stop to prevent unsub leak - Sync strings.json with en.json (pre-existing drift from 260601-aru quick task)
…unit tests - Add ASPGpsPipelineHealthBinarySensor class in binary_sensor.py (mirrors ASPIndexRebuildingBinarySensor pattern) - is_on True when last_gps_update is recent (< stale_timeout hours) AND _last_pipeline_error is False - extra_state_attributes exposes 'last_pipeline_error' bool for diagnostics - Register new sensor in async_setup_entry list - Add 'gps_pipeline_healthy' translation key to translations/en.json and strings.json - Add 11 unit tests in tests/test_gps_pipeline_health_binary_sensor.py (SimpleNamespace stub pattern)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- coordinator: retain existing 311-sourced suspension on poll failure instead of unconditionally resetting to not-suspended; only fail open when no prior suspension is active - suspension/load: catch CancelledError from _fetch_ics, populate fallback dates, and set _loaded=True before re-raising so is_suspended() never silently returns false negatives after a cancelled HA startup - merge.py docstring: document ha_nyc311 as a valid source mapping to suspended_emergency alongside emergency Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…CK_2026 NYC DOT's ICS calendar endpoint returns HTTP 403 for the integration's custom User-Agent (Akamai bot protection), so every refresh silently fell back to FALLBACK_2026 — which itself was wrong and missing real suspension dates, including 2026-07-03 (Independence Day observance). Sensors reported cars must move on suspended days as a result. - Switch _FETCH_HEADERS User-Agent to a standard browser UA so the fetch succeeds (403 -> 200). - Regenerate FALLBACK_2026 from the authoritative NYC DOT ICS (36 exact entries) so the fallback safety net is correct if the fetch ever fails again. Debugged in .planning/debug/friday-move-not-suspended.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ividers polish Resolves the release/v3.1.0-rc14 <-> main merge conflict by keeping main's accuracy fixes (eleven diagnostic sensors, Installation restructure) and re-applying this branch's Table of Contents + section dividers on top. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Owner
Author
Code reviewFound 4 issues:
GPS2ASP-Resolver/custom_components/asp_parking/coordinator.py Lines 2163 to 2189 in efcd067
GPS2ASP-Resolver/custom_components/asp_parking/__init__.py Lines 306 to 322 in efcd067
GPS2ASP-Resolver/custom_components/asp_parking/coordinator.py Lines 1607 to 1622 in efcd067
GPS2ASP-Resolver/custom_components/asp_parking/coordinator.py Lines 1615 to 1630 in efcd067 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
- Issue 1 (suspension fallback): Gate fallback_info on source in
("ha_nyc311", "emergency") so a prior holiday suspension is never
retained into the next day when the 311 API call fails.
- Issue 2 (retry counter leak): Pop _SETUP_RETRY_COUNT_KEY_TPL in
async_unload_entry so the counter resets on each disable/reload
cycle, preventing premature Repair issue on subsequent failures.
- Issue 4 (lazy imports in @callback): Add pn_create/pn_dismiss at
module level; remove the lazy imports from _gps_watchdog_rearm
and its nested _on_gps_stale @callback methods.
Issue 3 (startup notification dismiss) was a false positive — the
grep confirmed _gps_watchdog_rearm is only called from GPS update
events, not from async_start.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced Jul 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Test plan
pytest tests/test_suspension.py tests/test_ha_integration.py— 111 passedis_suspended(2026-07-03)returnsTrue("Independence Day") on the reloaded integration in the running Home Assistant container🤖 Generated with Claude Code