Classify custom non-IANA TZID as calendar_unsupported, not dependency_unavailable #53

Closed
opened 2026-09-22 22:37:51 +00:00 by yuris · 0 comments
Owner

Context

Raised as "finding 2" during the #14 review (PR #52). A calendar resource whose TZID is a custom, non-IANA zone (the #14 illustrative fixture uses TZID=Custom-Timezone) is reported as dependency_unavailable rather than calendar_unsupported, according to that review — which would make the fixture unusable over HTTP and classifies a capability gap as a backend outage.

docs/technical/verification.md C07 requires exactly the opposite: "Exact deployment conformance or explicit calendar_unsupported/partial; no unsupported window labeled free". An unsupported zone is not an outage, and exit 5 tells an agent to retry a dependency that is in fact healthy.

Why this is a follow-up and not part of #14

Reading the code, the classification looks correct already, so the claim needs a reproduction before anything changes:

  • src/calendar/report.rs:374 — Tz::from_str(tzid) failure → CalendarError::CalendarUnsupported.
  • src/api/items.rs::live_read_failure — CalendarUnsupported/Preservation → ApiFailure::calendar_unsupported; everything else → dependency_unavailable.
  • src/api/agenda.rs is_outage — CalendarUnsupported/Preservation/LimitExceeded are explicitly not outages (#13's refinement).

So either there is a path that loses the distinction before it reaches those mappers, or the original observation was about a different failure (e.g. a Preservation error from timezone resolution rather than CalendarUnsupported).

What to build

  • Reproduce: feed a resource with a DTSTART;TZID=Custom-Timezone:… (plus a matching VTIMEZONE block) through life agenda, life item get, life task update and life item get-based flows, and record the actual HTTP status / error code / exit code for each.
  • If any path reports dependency_unavailable (HTTP 503 / exit 5) for an uninterpretable zone, fix it to calendar_unsupported (HTTP 422 / exit 2) — same mapping #14 just reconciled.
  • Decide explicitly whether src/calendar/report.rs should map an unresolvable TZID to CalendarUnsupported (capability, 422) or Preservation (interpretation, also 422 after the #14 mapping) — today both end up at calendar_unsupported, so record the choice.
  • Add a test per affected route asserting the code and exit code, including the #14-style fixture with a custom TZID.

Acceptance criteria

  • A resource using a custom non-IANA TZID is reported as calendar_unsupported (HTTP 422 / exit 2) on every read and mutation path that can encounter it, never dependency_unavailable.
  • A genuinely unreachable backend still reports dependency_unavailable (HTTP 503 / exit 5) — C01 is preserved.
  • The #14 illustrative fixture (custom TZID) is exercised over HTTP, not only at the patcher level.
  • Each affected route has a test pinning the error code and exit code.

Notes

  • Reviewed by an independent reviewer agent; verdict went REQUEST CHANGES → APPROVE across two heads.
  • The reproduction found a different defect than the issue suspected. report.rs and live_read_failure were already correct; the all-collections-failed fan-out aggregation collapsed a known capability failure into an outage. Every affected route answered 503 dependency_unavailable while its own message read "All configured CalDAV collections are unavailable: Calendar unsupported: Unsupported TZID 'Custom-Timezone'" — the interpretation failure was known and then discarded by the aggregation. Pre-fix, nine routes answered 503/exit 5 for the custom-zone fixture; post-fix they answer 422 calendar_unsupported/exit 2.
  • Reviewer finding 1 (major), fixed before merge: the first fix decided by first failure, so an all-failed mixed fan-out (one collection with the uninterpretable zone, one genuinely down) returned 422 and told the caller not to retry while a dependency was in fact broken. The aggregation now decides by failure class — outage precedence — and the capability gap is still named in the message and carried as an incomplete_calendar warning rather than dropped.
  • Reviewer finding 2 (minor), fixed: the C01 test asserted the exit code on four of its five routes; the next row is now pinned with exit_code_for as well.
  • Also added: a genuinely connection-refused backend (bind, release, point the config at the dead port) asserting 503/exit 5 on five routes plus the CLI, so C01 is proven for the unreachable case and not only for a 500.
  • Adjudicated exception (reviewer agreed, no change): the agenda read keeps degrading to partial (200 / exit 6) when its fan-out failed for all-non-outage reasons, because two pre-existing C07 acceptance tests pin that (recurrence_tests.rs::c07_an_unsupported_collection_is_partial_and_never_declared_free, ::c07_an_unresolvable_vtimezone_is_reported_as_unsupported). The author restored the pinned behaviour rather than rewriting acceptance tests to match its own taxonomy; agenda still refuses an all-outage fan-out, and the mixed all-failed case reports the down collection as coverage unavailable and the uninterpretable one as unsupported.
  • Recorded decision: an unresolvable TZID is CalendarUnsupported (capability: this deployment cannot interpret the wall-clock time), not Preservation, documented in src/calendar/report.rs's module header.
  • Test count: 752 passed / 0 failed across 43 test result lines.

Blocked by

None. Distinct from #49 (not_found exit-code unification) and #45 (pagination materialization).

## Context Raised as "finding 2" during the #14 review (PR #52). A calendar resource whose `TZID` is a custom, non-IANA zone (the #14 illustrative fixture uses `TZID=Custom-Timezone`) is reported as `dependency_unavailable` rather than `calendar_unsupported`, according to that review — which would make the fixture unusable over HTTP and classifies a capability gap as a backend outage. `docs/technical/verification.md` C07 requires exactly the opposite: *"Exact deployment conformance or explicit `calendar_unsupported`/partial; no unsupported window labeled free"*. An unsupported zone is not an outage, and exit 5 tells an agent to retry a dependency that is in fact healthy. ## Why this is a follow-up and not part of #14 Reading the code, the classification looks correct already, so the claim needs a reproduction before anything changes: - `src/calendar/report.rs:374` — `Tz::from_str(tzid)` failure → `CalendarError::CalendarUnsupported`. - `src/api/items.rs::live_read_failure` — `CalendarUnsupported`/`Preservation` → `ApiFailure::calendar_unsupported`; everything else → `dependency_unavailable`. - `src/api/agenda.rs` `is_outage` — `CalendarUnsupported`/`Preservation`/`LimitExceeded` are explicitly *not* outages (#13's refinement). So either there is a path that loses the distinction before it reaches those mappers, or the original observation was about a different failure (e.g. a `Preservation` error from timezone resolution rather than `CalendarUnsupported`). ## What to build - Reproduce: feed a resource with a `DTSTART;TZID=Custom-Timezone:…` (plus a matching `VTIMEZONE` block) through `life agenda`, `life item get`, `life task update` and `life item get`-based flows, and record the actual HTTP status / error code / exit code for each. - If any path reports `dependency_unavailable` (HTTP 503 / exit 5) for an uninterpretable zone, fix it to `calendar_unsupported` (HTTP 422 / exit 2) — same mapping #14 just reconciled. - Decide explicitly whether `src/calendar/report.rs` should map an unresolvable `TZID` to `CalendarUnsupported` (capability, 422) or `Preservation` (interpretation, also 422 after the #14 mapping) — today both end up at `calendar_unsupported`, so record the choice. - Add a test per affected route asserting the code and exit code, including the #14-style fixture with a custom `TZID`. ## Acceptance criteria - [x] A resource using a custom non-IANA `TZID` is reported as `calendar_unsupported` (HTTP 422 / exit 2) on every read and mutation path that can encounter it, never `dependency_unavailable`. - [x] A genuinely unreachable backend still reports `dependency_unavailable` (HTTP 503 / exit 5) — C01 is preserved. - [x] The #14 illustrative fixture (custom `TZID`) is exercised over HTTP, not only at the patcher level. - [x] Each affected route has a test pinning the error code and exit code. ## Notes - Reviewed by an independent reviewer agent; verdict went REQUEST CHANGES → APPROVE across two heads. - **The reproduction found a different defect than the issue suspected.** `report.rs` and `live_read_failure` were already correct; the *all-collections-failed fan-out aggregation* collapsed a known capability failure into an outage. Every affected route answered 503 `dependency_unavailable` while its own message read "All configured CalDAV collections are unavailable: Calendar unsupported: Unsupported TZID 'Custom-Timezone'" — the interpretation failure was known and then discarded by the aggregation. Pre-fix, nine routes answered 503/exit 5 for the custom-zone fixture; post-fix they answer 422 `calendar_unsupported`/exit 2. - **Reviewer finding 1 (major), fixed before merge:** the first fix decided by *first* failure, so an all-failed mixed fan-out (one collection with the uninterpretable zone, one genuinely down) returned 422 and told the caller not to retry while a dependency was in fact broken. The aggregation now decides by failure class — outage precedence — and the capability gap is still named in the message and carried as an `incomplete_calendar` warning rather than dropped. - **Reviewer finding 2 (minor), fixed:** the C01 test asserted the exit code on four of its five routes; the `next` row is now pinned with `exit_code_for` as well. - Also added: a genuinely **connection-refused** backend (bind, release, point the config at the dead port) asserting 503/exit 5 on five routes plus the CLI, so C01 is proven for the unreachable case and not only for a 500. - **Adjudicated exception (reviewer agreed, no change):** the agenda read keeps degrading to `partial` (200 / exit 6) when its fan-out failed for all-non-outage reasons, because two pre-existing C07 acceptance tests pin that (`recurrence_tests.rs::c07_an_unsupported_collection_is_partial_and_never_declared_free`, `::c07_an_unresolvable_vtimezone_is_reported_as_unsupported`). The author restored the pinned behaviour rather than rewriting acceptance tests to match its own taxonomy; agenda still refuses an all-outage fan-out, and the mixed all-failed case reports the down collection as coverage `unavailable` and the uninterpretable one as `unsupported`. - Recorded decision: an unresolvable `TZID` is `CalendarUnsupported` (capability: this deployment cannot interpret the wall-clock time), not `Preservation`, documented in `src/calendar/report.rs`'s module header. - Test count: 752 passed / 0 failed across 43 `test result` lines. ## Blocked by None. Distinct from #49 (`not_found` exit-code unification) and #45 (pagination materialization).
yuris closed this issue 2026-09-23 05:30:41 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/life-service#53
No description provided.