Calendar editor timezone
Calendar display and the built-in event editor use the same resolved Calendar settings. Explicit personal timezone takes precedence over workspace timezone; when neither is explicit, the canonical resolver detects the browser timezone. The editor’s date/time picker inherits those settings instead of resolving its own browser timezone. This applies to the shared Calendar surface in Web and the standalone Calendar app. It does not change saved user or workspace settings. Timed edits represent an instant and serialize as UTC ISO timestamps. A date-only all-day choice represents midnight in the resolved calendar timezone with an exclusive end boundary. A browser in another timezone must still display the chosen calendar date, including when its local date is the previous day. Existing Google-backed events are patched immediately using their stored external event identifier. Imported recurring occurrences retain the provider’s instance identifier; changing an occurrence must preserve that identifier and calendar source. The patch sends updates to guests. Verify the stored event and the same Google occurrence independently after an edit; a local toast is not provider read-back evidence. The current Google write mapper usesdateTime
fields and does not provide native Google date-only all-day writes. Native
Tuturuuu all-day events do not require that provider path.
Tasks and Calendar planning
Calendar and Tasks keep cross-product API calls on the active browser origin so host-only app cookies remain available. TheirbeforeFiles rewrites forward only
the other product’s API families, before Tasks’ API catch-all can intercept them.
The source proxy refreshes the host session and forwards its signed bearer token;
Calendar routes explicitly accept Calendar and Tasks audiences while retaining
workspace membership and permission checks. Do not route these APIs through Web:
Web no longer owns the Calendar events or Tasks endpoints.
Tasks’ session verifier also accepts Calendar for routes that explicitly accept
Tasks, including labels, projects, task detail dependencies, and workspace task
preferences. It preserves required scopes and does not widen unrelated app
audiences. Calendar forwards /api/v1/users/me/workspaces/:wsId/configs/* to
Tasks so those preferences use the verified planning actor and membership guard.
Collection rewrites must have an exact path before their /:path* variant.
Vercel can retain a trailing slash when the wildcard is empty, causing the owning
app to return a 308 to the same browser URL and loop. Verify both collection and
nested resource requests on the deployed host.
Both satellite apps expose local planning views without changing workspace or
requiring a cross-app login handoff:
The shared sidebar retains locale and personal/internal workspace aliases,
including on mobile. Calendar also serves
/tasks/boards,
/tasks/boards/{boardId}, and /tasks/{taskId} within the workspace. Task views
hide the calendar-only mini-month sidebar to leave more room for task work.
Tasks’ embedded calendar uses the shared scheduling, connection, event, and task
controls and enforces manage_calendar. Each host resolves its own app-session
actor. Keep the task route context and dialog manager prefix aligned: Tasks uses
an empty prefix, while Calendar and Web use /tasks. Tasks already owns a dialog
provider, so its embedded calendar disables the additional dialog wrapper.
When validating this integration, check both locales, personal and team workspace
links, board/task detail return paths, and mobile navigation with the sidebar
closed. Mutations continue through the existing protected product APIs.
Overview
apps/calendar and the Calendar experience inside apps/web are paired
Calendar hosts. They must stay 1:1 for product features, data behavior,
mutations, permissions, and user-facing workflow updates.
- Calendar UI and logic should live in shared packages, primarily
@tuturuuu/ui/calendar-app/*, with app route files acting as thin auth and workspace-context wrappers. - Task-aware Calendar controls (task creation, task scheduling, habits, and
task time tracking) live in
@tuturuuu/tasks-ui/calendar/*. The generic Calendar shell accepts those controls through typed component seams, keeping@tuturuuu/uiindependent from task-only code and preserving narrow Turbo rebuilds. apps/calendarowns its standalone workspace shell, local/login, and local/verify-tokencompletion route.apps/web /{wsId}/calendarrenders the same shared Calendar product surface inside the normal platform dashboard shell.- Dashboard navigation in
apps/webshould link to the local/{wsId}/calendarroute, not to the standalone Calendar origin.
Auth Model
Calendar does not create local Supabase Auth sessions. It uses centralapps/web login plus a Calendar app-session cookie:
/logininapps/calendarnormalizes a safenextpath.- If both the Calendar app-session cookie and Web-issued app-session cookie are
already present,
/loginredirects to that localnextpath immediately. - Otherwise
/loginredirects toapps/web /loginwith a return URL pointing back to Calendar/verify-token?nextUrl=.... /verify-tokenposts the handoff token to the Calendar-local verifier, which validates through central Web and sets host-local app-session cookies.
sb-*-auth-token cookies. A valid
Calendar session is represented by Tuturuuu app-session cookies, not by a local
Supabase browser session.
Calendar timezone boundaries
Event start/end values are UTC instants. Display and picker controls resolve personal calendar timezone first, workspace timezone second, and device timezone when both inherit withauto. A browser-local Date used by a date-only calendar
widget is a calendar-day carrier, not an event instant: project its year, month
and day in the resolved timezone before passing selection, today or bounds.
Compare end-time options on that same calendar day and derive minimum/maximum
clock values in the same timezone. This matters when the browser and calendar
are on different dates, for example Los Angeles and Ho Chi Minh City.
Quick previews use the same resolved timezone and clock format as the event
form, localized to the current locale. Date/time edits must round-trip the requested wall time; nonexistent
DST times must not silently normalize into another hour. Reselecting an unchanged
ambiguous time or date preserves the original UTC instant. Tests cover these
boundaries; they do not establish exhaustive correctness for every IANA history
or changed ambiguous-time choice.
Native all-day persistence and the outer calendar Today/header date contract
remain separate concerns. Do not infer all-day intent solely from a 24-hour
elapsed duration, and do not publish a DST duration helper in isolation from the
persistence/rendering contract. Imported recurring provider events require
exact-instance and neighboring-instance readback after an authorized UI edit.
Never use real user calendar screenshots as public regression fixtures.
API Ownership
apps/calendar owns the Calendar product APIs. Its local handlers cover events
and calendars, categories and preferences, hours and default sources,
scheduling and sync, Calendar connections, Google and Microsoft provider OAuth,
Calendar media/generation helpers, and Calendar-owned cron work. Host-local
auth/session and build-info routes are local as well.
- Exact local handlers win before the fallback
/api/:path*rewrite. The fallback remains for cross-product routes that Calendar uses but does not own, including workspace encryption and task, board, habit, and time-tracking families; typed task helpers may target the Tasks app directly. - Central platform login, social-provider callbacks, and cross-app token issuance remain Web-owned. Calendar-provider OAuth initiation and callbacks are Calendar-local, even though their configured redirect origins retain Web compatibility for existing provider registrations.
- Calendar-only routes use
targetApp: 'calendar'. Shared cross-product routes must name the exact accepted app audiences, such astargetApp: ['calendar', 'tasks'], rather than accepting generic satellite sessions. - Keep workspace membership checks and Calendar/task permissions on the owning route before admin-backed reads or writes. The Calendar proxy guard and app-session refresh do not replace route-level authorization.
- Prefer typed
packages/internal-apihelpers. Browser calls remain same-origin so Calendar-local handlers are selected first; server calls to a different owning app must use its configured API base URL with forwarded authentication.
Calendar settings authorization
Personal calendar preferences are scoped to the authenticated user. Settings updates accept supported IANA timezone names orauto inheritance; invalid
names and fixed-offset strings are rejected before storage. Workspace
calendar settings are readable by members, but updates require
manage_workspace_settings. Check that permission explicitly on the owning
PATCH route: a verified signed app session can use an admin-backed database
client, so membership and table RLS alone do not enforce editing rights.
Native clients reach the Calendar owner through the authenticated mobile gateway.
The settings allowlist permits only GET and PATCH on
/api/v1/users/calendar-settings and
/api/v1/workspaces/:wsId/calendar-settings; upstream ownership, workspace
permission checks, credential isolation and response limits remain enforced.
Native preference GETs use a dedicated Infrastructure guard bucket so calendar
event/account fan-out cannot consume their read allowance. The shared guard
still enforces the same default anonymous/authenticated limits, verified-session
keying, MFA, and IP blocks; PATCH and other gateway requests retain the existing
bucket. A preferences 429 emits only policy/caller/window/reason diagnostics,
without actor, workspace, IP, credentials or response bodies. This does not
bypass an IP block or make an exhausted preferences bucket unlimited.
Regression coverage: preference-guard.test.ts exact route/method boundaries
and gateway.test.ts upstream diagnostic isolation. Actual authenticated
mobile recovery must be verified after deployment. Mobile’s API error retains
only fixed known reason, policy, caller and window values from a 429 response,
and includes those safe fields in its diagnostic log. Unknown values become
unknown; URLs, actor/workspace identifiers, IPs, cookies, credentials and
response bodies are never included in that diagnostic. This preserves the
server rejection and cooldown rather than treating an unavailable preference as
success. Regression: api_client_error_contract_test.dart exercises the HTTP
boundary and rejects private or arbitrary header values.
OAuth Token Safety
Calendar OAuth credentials live incalendar_auth_tokens. RLS restricts
selects to user_id = auth.uid(), but admin/service-role reads bypass RLS.
Calendar server pages must therefore:
- Check
manage_calendarbefore loading calendar integration state. - Scope token reads to both
ws_idand the authenticateduser_id. - Never pass
access_tokenorrefresh_tokeninto client components. SSR props should use the sharedfetchUserWorkspaceCalendarGoogleTokenForClient()helper from@tuturuuu/utils/calendar-auth-token, which projects only connection metadata (id, account email/name, provider, active state, expiry). - Keep token refresh and provider API calls on Calendar-local server routes; never expose provider credentials to client components.
select('*') on calendar_auth_tokens.
When adding new Calendar UI that needs protected data, update the shared
Calendar component or helper first, then wire both host wrappers in the same
change. Extend the route family in its owning app and expose a typed
packages/internal-api seam instead of creating a host-local product API fork
or adding direct client Supabase reads.
Calendar OAuth And Connections
Google Calendar OAuth initiation and callback handlers are owned byapps/calendar. The local /api/v1/calendar/auth route builds its callback URL
from a browser-safe configured origin and ignores wildcard listener addresses
such as 0.0.0.0 or ::. Existing provider registrations may still configure
the central Web origin; if no safe configured origin is available, the fallback
origin is https://tuturuuu.com.
After Google returns to the callback, the flow always sends the user to the
central Web Calendar page at
https://tuturuuu.com/{wsId}/calendar?provider=google&connected=true. Valid
local development callback URLs such as
http://localhost:7803/api/v1/calendar/auth/callback may still be configured
through GOOGLE_REDIRECT_URI, but wildcard listener URLs must never be emitted
as Google redirect_uri values or browser redirects.
Normal Google Calendar connect and reconnect URLs request
access_type=offline and include_granted_scopes=true, but they must not force
prompt=consent by default. Google may return a refresh token only during the
first authorization, so the callback must preserve an existing stored
refresh_token when a reconnect returns only a new access token. If neither the
callback nor the existing token row has a refresh token, the flow must fail
before saving an active Google connection because provider sync cannot refresh
offline.
Standalone apps/calendar also exposes the shared Calendar connections manager
inside its settings dialog under Calendar -> Integrations. It should fetch the
initial connection state through @tuturuuu/internal-api/calendar and render the
shared Calendar connections UI inside CalendarSyncProvider rather than
forking host-local connection controls.
CI And Deployment
Calendar deploys through dedicated GitHub Actions workflows, not Vercel-owned GitHub auto-builds:- Preview deployments use
.github/workflows/vercel-preview-calendar.yaml. - Production deployments use
.github/workflows/vercel-production-calendar.yaml. - The Vercel project id is provided through the environment-scoped
VERCEL_CALENDAR_PROJECT_IDsecret. apps/calendar/vercel.jsonmust keepgit.deploymentEnabledandgithub.enabledset tofalseso GitHub Actions builds withvercel buildand deploys prebuilt artifacts withvercel deploy --prebuilt.
apps/infrastructure/vercel.json.
Infrastructure authenticates the scheduler and forwards through the private
Calendar gateway; Calendar validates the scheduler credential again.
Provider Sync
Infrastructure hosts the provider-sync schedule (*/15 * * * *). Both apps’
proxies recognize validated cron credentials independently of browser sessions;
invalid credentials still fail authentication. If hosted runs return 401 before
Calendar logs a request, check the Infrastructure proxy and matching production
CRON_SECRET configuration before investigating provider tokens.
The Calendar cron wrapper invokes Calendar’s workspace sync handler
locally, preserving cron authentication, running locks, cooldown behavior and
calendar_sync_dashboard audit rows. It must not send sync requests to the former
Web owner through INTERNAL_WEB_API_ORIGIN or a protected preview URL.
Both Tasks and Calendar show Sync needs attention beside the calendar picker
when a sync stalls, data becomes stale, a provider needs reconnection, or status
cannot be loaded. Open it for a persistent explanation and a Sync now,
Check again, or provider-specific Reconnect action. Stored events remain
visible during provider outages. Ordinary access-token expiry is not itself a
reconnection failure: Google refreshes those tokens automatically.
Sync health polls every 30 seconds (every 5 seconds during a run or cooldown).
A running entry older than five minutes is stalled; a successful sync older than
45 minutes is stale. Partial provider failures are recorded as failed runs rather
than successful syncs. Successful runs use the database’s completed status;
completion writes must be checked so a constraint failure cannot leave a run
stuck at running. Provider rate limits and transient outages offer retry,
while authentication failures offer reconnection. Operators should inspect the
Calendar cron execution and dashboard run when retries continue to fail.
Recovering individual calendar failures
The warning names each failed Google calendar after a sync attempt. Pause sync for this calendar turns off only its inbound import; it preserves its saved events and visibility, and does not disconnect the account or affect other calendars. This action is available during the manual retry cooldown. Restore provider access when applicable, then re-enable inbound sync from the calendar’s sync controls. Sync now retries the remaining enabled calendars. The sync handler stores sanitized version-1failedCalendars diagnostics in the
existing calendar_sync_dashboard.error_stack_trace text field. Each entry has
only connectionId, calendarName, and a classified code. Never store OAuth
credentials, provider response payloads, or headers there. The status API parses
this format, filters disabled/paused connections, and returns failedCalendars;
it never returns the raw diagnostic field. Older unstructured errors still show
an aggregate warning and gain calendar-specific details on the next attempt.
Per-calendar failure diagnostics and the pause shortcut currently cover Google inbound sync. Microsoft failures retain account-level reconnect/retry guidance; individual Microsoft calendar failure identification is not yet available.
Views and keyboard support
Calendar views share behavior across Calendar, Tasks, and embedded Web calendars. Use D, 4, W, M, Y, or A for day, four days, week, month, year, or agenda. These page shortcuts are inactive inside editors, menus, and dialogs, during input composition, or alongside Cmd/Ctrl/Alt. Month selection updates the host’s controlled state and is restored from the saved view preference. Month provides event previews and day details; year opens the selected month or day; agenda searches titles and locations across its 30-day window. Event queries must cover the entire year or all 30 agenda days, not just the first day. The event route reads ordered 1,000-row pages so busy years are not truncated by the database response limit. Shared settings list the shortcuts alongside command search, app launcher, and sidebar commands. Verify modified shortcuts in Calendar and Tasks and check typing, modifiers, modal focus, and mobile overflow when changing these views. Global command/app launchers remain available while editing. Calendar view shortcuts are intentionally suppressed throughout editor descendants, including non-editable embedded content, to prevent unexpected view changes while working in an editor.Two-Way Sync Controls
Calendar sync has two layers of user control:- Workspace-user preferences in
private.calendar_user_workspace_preferencesenable or disable inbound imports, outbound Tuturuuu-to-provider mirroring, the default outbound provider calendar, and the conflict policy. calendar_connectionscontrols each external calendar’s import, outbound write, and provider-delete behavior.
direction: "outbound" or "both" may
also catch up local-only or previously failed Tuturuuu events in the active sync
window.
Inbound provider deletes are controlled per connection through
sync_delete_enabled. User-initiated deletion of a synced external event still
deletes the provider event directly because it is explicit CRUD, not passive
provider import cleanup.
After adding or changing two-way sync columns, prepare migrations in
apps/database; do not run production Supabase push commands from agent
sessions. Apply locally with bun sb:up when feasible, then regenerate database
types only after the local schema reflects the migration.
Installation and caching
Calendar and Tasks serve their own/serwist/sw.js workers and installable
app manifests. Client instrumentation captures the install event before hydration;
these hosts explicitly transpile @tuturuuu/ui for that bootstrap entry point.
The Settings → Install app control uses the browser prompt when
available and gives Home Screen instructions otherwise. /offline.html is a
public, bilingual fallback that bypasses authentication middleware.
These productivity hosts use cacheNavigations: false and
staticAssetsOnly: true: private HTML, APIs, and private images are never
persisted by the worker. Installation precaches only the fallback, icons, and
manifest. Hashed Next assets cache on demand, with at most 160 runtime entries.
This avoids downloading the entire application at installation.
Loaded data remains available in an open app through memory caches. Calendar
snapshots are keyed by workspace and date range and limited to 12 ranges; event
lookups pre-index date intervals and memoize at most 400 day results. Private
snapshots are not persisted across app restarts. Reopening a workspace, syncing,
and saving changes require connectivity; this release does not add a durable
offline write queue. The offline indicator communicates that limitation.
Verify worker registration, install manifest, cached asset reuse, offline
fallback, and the absence of API/private-page entries in Cache Storage on both
Calendar and Tasks. Re-run both app builds when changing the worker routes or
tracing configuration.
Calendar regression tests
Calendar owns a workspacetest script, so bun test and CI coverage include
its provider, authorization, cron and event-route suites automatically. Run
ttr resources run -- bun run --cwd apps/calendar test --maxWorkers=2 for the
complete focused suite. Manual provider smoke tests supplement these regressions;
they do not replace the automated suite or prove that closed-client scheduling
is active in production.
Invitation delivery API
Explicit invitations use the events collection POST with aninvitation
containing guest email addresses, optional-attendee flags and an IANA time zone,
plus a UUIDv7 requestId. Choose a writable connected Google or Microsoft
calendar. Provider-owned RSVP status is never accepted as organizer input.
The same request ID must survive retries. The server binds it to the actor,
workspace, source and complete invitation details. It reserves an encrypted
local event before sending, then records the provider identity. Google uses a
stable event ID and a private request fingerprint; Graph uses transactionId.
A duplicate Google event with a different fingerprint is rejected. A timeout
does not authorize a fresh send or a new request ID.
Calendar requires server-only CLOUDFLARE_COORDINATION_URL and
CLOUDFLARE_COORDINATION_TOKEN for its Durable Object request lease. The token
has an encrypted backup in the Infrastructure vault. Missing storage fails closed.
Only request hashes and completion state enter the Durable Object; provider credentials and
guest lists do not. New reservations are accepted for 15 minutes, with one minute
of forward clock tolerance. An older request can only resume its existing
actor-bound reservation with identical details and the original provider
idempotency key. This also recovers pending delivery after provider exceptions
or missing responses; an expired request never recreates a deleted reservation.
A 409 or ambiguous failure must leave the client in a
review/retry state. Check the calendar before creating a replacement request.
Pending deliveries cannot be edited or deleted through the event API.
POST /api/v1/workspaces/:wsId/calendar/events/:eventId/response accepts
accepted, declined or tentative. The selected connected account must
actually be an attendee; organizer identity, provider concurrency and workspace
authorization are checked before writing. Native clients use the authenticated
infrastructure gateway, which permits only POST on this route. Responses are
private and uncached.
This is the delivery foundation. Scheduling surfaces and assistant tools must
present the exact meeting and recipients for user confirmation before calling
the send operation. These API tests do not establish live Gmail/Outlook delivery;
verify invitations and RSVP updates using explicitly authorized test accounts
before claiming provider interoperability.
Google color identity and inheritance
Google inbound sync preserves the provider’s explicit event color ID, calendar-scoped label ID, inherited-color intent and resolved opaque RGB inscheduling_metadata.google_color. The existing canonical event-color foreign key
remains a compatibility value, not an exact Google color definition. Google labels
take precedence over legacy event color IDs; an event with neither inherits the
connected calendar’s current RGB color. Calendar custom RGB takes precedence over
its calendar palette ID, which belongs to a different palette from event IDs.
Active sync refreshes the matching connection’s source color even when no events
changed. Missing provider metadata remains unresolved and observable rather than
inventing a custom color. Label-definition changes without an event delta can leave
an explicit event’s resolved RGB snapshot stale until the event is fetched again.
Unrelated title/time updates read the current Google event, preserve its exact
color or label identity and use its ETag to reject concurrent changes. Native
creates map their canonical color argument to the Google event palette.
The capability-gated shared web picker uses exact event IDs, calendar-scoped
label IDs, and inherited color; its choices preserve opaque provider RGB.
Microsoft and disabled-candidate surfaces keep their canonical palette. These
source paths require the recovery schema and exact-commit build validation before
activation. Sync never rewrites a calendar’s label array or implicitly publishes
a private native calendar to Google.
Recoverable Google color operation development
Exported-route overlap tests model the authoritative provider-series read-only RPC separately from operation-ledger RPCs. A writable fixture returnsfalse;
read-only and unavailable states must still reject PUT/DELETE before reservation
or provider dispatch. google-color-operations/route-overlap.test.ts covers these
states alongside delayed-request fencing and recovery. When adding an admission
lookup, update shared route fixtures to its actual result contract so a fixture
failure cannot masquerade as a provider or operation conflict.
The same-calendar color-write followup has a server-only operation ledger,
immutable prepared patch/ETag and private operation marker. Conditional replay
uses the original ETag; it never refreshes an old operation’s precondition. A
provider 412 fences the old attempt, then current provider state is fetched and
settled by its operation marker. Matching color alone is not completion proof.
An authorized resumption must recheck Calendar management permission, connection
owner and exact token/calendar/event identity. Only definitely-unsent reserved or
prepared operations can cancel. Local commit failures remain recoverable.
This is an unpublished implementation stage. A bounded route slice now connects
same-calendar color PUT, encrypted content/time/local-lock PUT and conditional
DELETE to reservation, immutable conditional dispatch and atomic finalization.
The generic operation stores sensitive request content only in an authenticated
encrypted journal. Finalization encrypts the authoritative provider projection;
route callers do not perform a second local write. Conditional deletion settles
habit skips and task/habit links in the same transaction and retains an authorized
tombstone for recovery after the event row is gone. Dedicated authenticated color-operation GET/POST/DELETE
handlers expose only operation ID/phase, execute recovery, or safely cancel an
unsent operation. Recovery bodies accept only operationId; source, generation,
prepared patches and force-clear overrides are never caller inputs. Reservation
state is private and never added to generic event scheduling metadata.
The candidate slice is disabled unless the server-only
CALENDAR_GOOGLE_COLOR_OPERATIONS_ENABLED setting is true. That candidate
mode supports same-source color, content/time/local-lock edits, invitation
responses and deletion through the shared generation boundary. RSVP uses only
the authenticated connected account’s self attendee, seals the response against
the original provider version, and projects the resulting event before reporting
delivery. Cancelled meetings and superseded responses return a conflict. Supported source movement uses the durable provider saga described below.
Unsupported move types return 409 before side effects. A pending operation blocks
content, color and delete successors. Attendee updates are all for content/time
edits and deletion; color/local-lock-only edits use none. Recovery executes the
server-stored operation kind and original conditional request, never a new
caller-supplied mutation. Status GET may accept a strict operationId query to
reauthorize an already-deleted event’s retained operation. Native/Microsoft routes
retain their existing behavior. This mode remains disabled by default and is not
approved for normal production mutation behavior: every provider writer must
cooperate before enabling it; mixed enabled/disabled API versions are unsafe.
The private RPC and transaction capability atomically merge Google color into
latest metadata and commit sync/completion together. Generation persists after
completion. Prepared import changes capture it before provider GET/list, apply
through guarded transactions and durably defer conflicting identities before a
sync token advances. Deferred replay captures again and fetches fresh provider
state, rather than saving old content or credentials. The new SQL/types and
combined route/import contracts still require isolated validation.
Do not release either migration or enable the candidate setting on its own.
Complete adoption by Web, Tasks, outbound sync, RSVP and all other competing
writers, plus the source move/create saga, before enabling writes. Regression
evidence is in mutation-routes.test.ts, route-overlap.test.ts, the encrypted
mutation executor/provider suites and calendar-google-mutation-replay.sql. The sync coordination cooldown is
not a lock. Google ETags are opaque equality tokens, not sortable revisions.
Google moves lack a documented conditional fence and remain a separate recovery
scope. Synthetic controlled overlapping routes demonstrate the intended
ordering against an atomic storage double; they do not substitute for SQL,
import, owning build or deployment proof.
Event rendering and provider identity
Web event surfaces render opaque provider fills with the higher-contrast black or white foreground. Mobile agenda, day/three-day/week cards, all-day chips and month indicators blend the same read-only provider hue into the active theme. Completed mobile events (end at or before the shared projected wall clock) use a weaker background tint and accent; foreground text remains fully opaque with at least 4.5:1 contrast. All-day ends remain exclusive, so an event stays active until its final midnight boundary. A shared minute clock refreshes completion styles while the Calendar screen is visible. This presentation never changes the stored provider RGB, explicit/inherited intent or event times. Persistedgoogle_color RGB is used when available; only
known inherited intent uses a valid current source RGB. Authenticated list/item
reads join the current stored connection RGB only for a persisted source calendar
link in the actor’s active Google accounts. Unbound legacy rows, mismatched source
links, and ambiguous or unavailable account matches retain the event snapshot. Active sync
refreshes that connection even without an event delta. This read join does not
fetch or mutate Google and does not infer intent for legacy rows. Native and legacy events
without resolved provider metadata retain their canonical event color. Rendering
does not infer old color intent, fetch a provider palette, or rewrite events.
Web timed, all-day, agenda, month/year, location and drag previews use the same
read-only color policy. Past web events fade with an overlay over their opaque
fills; optimistic/preview status uses outlines. Hovering an overlapped lower card
hides upper cards instead of blending their fills, and restores them when the
hover ends. Focus/drag/resize states retain opaque backgrounds. The existing
preservePastEventOpacity adapter option suppresses this fade. Past external
provider events follow the same policy; previews, pending writes and active
drag/resize states keep full intensity.
Regression coverage for the policy and hover treatment lives in
past-event-treatment.test.ts and event-card.test.tsx. Mobile source RGB survives date projections and local cache
serialization. Regression coverage lives in calendar-event-colors.test.ts,
event-card.test.tsx, calendar-views.test.tsx, dynamic-island.test.tsx and
mobile event_colors_test.dart. These checks do not establish full palette
editing, legacy-row refresh, or completed Google write reconciliation.
Calendar navigation dates and query boundaries
The legacy calendar treats its selected date and visible grid dates as calendar days: their local year, month, and day fields identify the selection. An explicitYYYY-MM-DD navigation value preserves that day when the effective timezone
changes. Timestamp navigation values and Today project the actual instant into
the resolved calendar timezone. The Calendar host supplies that timezone to its
navigation provider; shared calendar content also supplies it to the event sync
provider. Web’s calendar route redirects to the Calendar host. Deep links apply
once using the first available resolved timezone so later settings updates cannot
reset a user selection. A timestamp link applied before personal settings finish
loading retains that initially projected day; following the pending instant until
settings settle needs a separate selection ownership contract.
Headers, sidebar selection, day/week/month/year/agenda labels, and Today markers
use these day fields consistently. A shared minute clock updates Today and the
current-time indicator without changing the selected day. Timed event lookup
projects event instants into the resolved timezone before grouping by day.
Fetch ranges independently construct the first day’s midnight and the midnight
after the last day in the effective timezone. This supports 23-hour and 25-hour
days across daylight-saving changes. Calendar cache keys include the timezone
and the selected calendar-day fields, so a timezone change cannot reuse a range
from another timezone.
These changes preserve existing event storage, recurrence, and all-day identity
contracts. All-day lookup retains its legacy browser-local day identity, so its
month/year grouping may still differ from the configured-zone bar for legacy
midnight payloads. All-day bar drag and location create/resize/split callbacks retain
their existing timestamp conversion: their inferred all-day classification cannot
safely represent zoned 23-hour or 25-hour midnight spans without a persistent
intent contract. They do not establish a persistent all-day intent flag or verify
live provider writes. Focused mounted tests exercise navigation, labels, grouping,
and fetch boundaries; deployed browser verification and exact-head CI remain
separate release checks.
Recoverable creation and calendar transfers
The candidate mode remains disabled by default. New event, label, and inherited provider-color commands return 409 while it is disabled. The shared web picker readsproviderColorWrites from the actor-scoped color-options response and
shows the legacy native palette until that capability is enabled; unsupported
Microsoft sources retain the legacy palette. Color-only saves send only their
color command and do not notify guests. Native mobile resolves the Google
connection from fresh, uniquely matching canonical source options. Its full
palette requires the same capability; provider-color commands are online only,
and combined content/date/color changes must be saved separately. Missing or
ambiguous source mapping preserves the legacy mobile palette.
Activation requires draining existing
legacy writer activity after the schema and retained guards are deployed.
Its routes support deterministic
Google creation, source-only movement between two calendars of the same Google
account, native-to-Google creation, and conditional Google-to-native transfer.
Google move preserves the provider event identity and iCalendar UID; a move may
include a local lock change, but combined content/color/time changes return 409
before provider effects. A lost move response remains ambiguous: a matching ID and
UID at the destination cannot distinguish this operation from an independent copy.
Only a successful response from the attempted move permits that invocation to
finalize; resumption never attributes an unmarked destination to the operation.
Google-to-native transfers reject recurring masters and instances before admission
because a single native snapshot cannot preserve the source recurrence. Cross-account copy/delete and Microsoft sagas return 409
before admission because their retry and compensation fences are not established.
Google-to-Google moves of events with a calendar-scoped label also return 409
before key resolution or admission because that label cannot be carried safely
to another calendar. This restriction applies to legacy and candidate moves.
Creation uses a UUIDv7 request ID retained across retries for the same draft. That
ID owns the local event, encrypted intent and deterministic Google event ID.
The manual draft and every generated draft each retain a separate ID in state.
An uncertain draft cannot reuse its ID after edits; recover the submitted intent
before deliberately starting a new draft. Independent creation calls allocate
new IDs unless their caller supplies an explicit retry ID. An unresolved existing
calendar source never defaults to another account during an ordinary edit.
Reusing an ID for a different payload is a conflict. Recovery exposes only the
operation ID and phase, including terminal native transfers and deleted
placeholders, and never returns sealed intent.
Retained event generations are consulted independently of the feature flag. A
pending generation blocks competing writes; a completed native transfer uses a
native generation comparison for subsequent edits and deletion. Disabling the
candidate cannot reopen legacy provider writes for a retained event. Legacy batch
sync preflights every event before dispatch, and invited creation and automatic
outbound mirroring remain blocked in candidate mode until they adopt the same
boundary. With candidate mode disabled, ledgerless ordinary native behavior remains unchanged. When enabled, native edits use generation zero as their initial compare-and-set fence, so a concurrently admitted transfer rejects the stale edit. Native-to-Google admission compares the complete stored native row under the event lock before creating its retained generation. A concurrent ledgerless edit returns a conflict without a provider write, without depending on a native mutation timestamp. The transient encrypted row comparison never enters the public binding or persisted journal; route/service regressions and calendar-provider-saga.sql cover stale rejection and fresh admission.
Synthetic Google acceptance established stale-version delete and move rejection,
identity-preserving movement, duplicate insert rejection, and rejection of late
recreation after a tombstone. This does not establish Microsoft behavior or
permission on customer events. Source regressions cover stable draft request IDs,
lost-response retry, unsupported operation rejection before keys/admission, and
public native recovery without private intent.
The admission and provider adapter label-move regressions live in
provider-saga-request-service.test.ts and provider-saga-adapter.test.ts.
Mobile wall-clock display and timezone preference recovery
Mobile parses offset-bearing API timestamps into UTC instants once, then projects those instants into the selected Calendar timezone once. Agenda labels consume the projected wall-clock fields directly, including when the device timezone differs; they must not call nativetoLocal on a projected event. Existing UTC date-only
all-day identity and DST-aware midnight bounds remain unchanged. Regression
coverage lives in agenda_view_test.dart, calendar_date_time_test.dart and
calendar_event_presentation_test.dart.
Personal and workspace timezone preferences load independently. A successfully
loaded scope remains editable if the other scope or the native timezone lookup
fails. Saving a named personal preference can resolve Calendar without a device
lookup. Workspace saving still requires permission and a loaded workspace scope.
Failed reads retain Unknown with an explicit retry; they never imply an automatic
preference or cause an implicit save. Failed saves retain the prior preference and
allow retry. Account/workspace changes invalidate in-flight replies and editors.
timezone_settings_http_contract_test.dart and
timezone_settings_http_widget_test.dart exercise production gateway paths,
Bearer serialization, failure/retry and explicit saving with synthetic data.
Those checks do not prove a real provider session or explain a particular user’s
failed authenticated request without runtime evidence.
Calendar’s local authentication rejections classify existing IP blocks as
ip-already-blocked and upstream authentication backpressure as
backend-auth-rate-limit. The native gateway preserves these fixed categories
for safe timezone diagnostics. Neither branch invents a limiter policy, caller
class or exhausted window; unavailable fields remain Unknown. Status 429,
Retry-After, authentication, bans and quotas retain their existing behavior.
api-auth-rate-diagnostics.test.ts exercises the real personal preference GET
and gateway; api_rate_limit_local_auth_test.dart checks the safe mobile copy.
These classifications do not establish the cause of a past rejection without
an exact deployed runtime receipt.
Mobile Calendar completion styling refreshes at wall-clock minute boundaries.
Timed events without an end use the same 30-minute fallback as rendered cards.
Timezone retry repeats a failed explicit save for its original scope; read failures
reload preferences. Unknown device zones stay unresolved until native lookup
succeeds, including after workspace changes during rate-limit cooldown.
calendar_minute_clock_test.dart and the HTTP settings tests cover these rules.
The shard-zero mobile test job additionally runs agenda_view_test.dart with
TZ=Asia/Ho_Chi_Minh and CALENDAR_NATIVE_TZ_REGRESSION=1; its explicit native
UTC+07 offset assertion prevents a UTC runner from silently weakening the
wall-clock double-conversion regression.
Creation recovery on the shared Calendar form keeps the original submitted request
ID and body immutable after an uncertain failure. Automatic original retry is available
only when the initially submitted Google source advertised durable provider writes;
legacy/native or unknown-capability failures require checking the calendar first.
An unavailable capability cannot later turn an uncertain legacy create into a retry.
The original retry action preserves
the edited form. Only a confirmed creation ID allows its next explicit Save to update
that event; edited drafts never silently start another creation. This applies to
shared web Calendar forms; legacy creation payloads keep optional IDs while explicit
recoverable Google payloads require a UUIDv7 ID validated at enabled admission.
Regression: use-calendar-draft-save.test.tsx and calendar-creation-request.test.ts.
For copy-delete compensation, authoritative fresh absence at both bound endpoints
settles a persisted target-removed checkpoint as a superseded tombstone under the
current generation. Linked habits and cascading links are skipped. Retained generation
and retired identities prevent a stale import from recreating the event. Regression:
calendar-provider-saga.sql and provider saga projection tests.
Mobile continuous dates and offline refresh
Mobile Day, Three days, and Week timelines scroll through adjoining dates with one continuous horizontal offset. Date headers, all-day rows, and time columns move together; the time gutter stays fixed. A bounded backing window recenters only after scrolling settles, preserving the visible dates and pixel position. Date picking and Today still move to the requested date. Month and Year retain their calendar-grid navigation. The mobile Calendar displays its actor/workspace-scoped encrypted snapshot first, then awaits a fresh repository read even when that snapshot is still fresh. Transport failures retain authorized events and pending edits. Pagination stores its extended range for offline revisits. Account/workspace changes fence pending responses and cache writes; definitive access denial clears Calendar snapshots, while MFA verification challenges preserve the last authorized snapshot. Regression coverage:continuous_date_scroll_test.dart and
calendar_cubit_test.dart cover intermediate drag offsets, synchronized columns,
fresh revalidation, workspace races, revoked access, and MFA retention. Exact
commit mobile CI and authenticated device verification remain required for
release evidence.
Native recurring series
The Calendar API stores native Tuturuuu recurring events as one canonical series and a bounded set of exceptions. It expands instances for the requested viewport; it does not pre-create duplicate event rows or stop at a materialization horizon. Daily, weekly, monthly and yearly rules use a named timezone and preserve local wall-clock dates across daylight-saving changes. All-day ends are exclusive. Counts include cancelled occurrences, but exclude nonexistent DST times./api/v1/workspaces/{wsId}/calendar/series creates and lists native series.
A viewport read supplies from, to and optional limit (maximum 1,000).
Reads reject oversized results instead of returning a silently incomplete list.
The detail endpoint adds /{seriesId}. All routes require workspace membership
and manage_calendar, including after a permission or membership change.
A mutation supplies a unique requestId, the last expectedRevision, and
scope (this, all, or future). Instance scopes additionally supply the
immutable originalStartLocal, even if that instance has moved. Revision
conflicts return 409; repeating the same completed request returns its receipt
without another write. Encryption is applied to titles, descriptions and locations.
Missing encryption keys fail closed instead of exposing encrypted strings.
An edit to this changes only the exception at its original slot. An edit to
all changes the master; changing the generating rule or anchor resets its
exceptions. A future edit splits the series transactionally, preserves remaining
COUNT, and resets exceptions at and after the split, returning their discarded
count. A first-occurrence future edit behaves as all. Deletes use the same
scope and concurrency contract.
This API stage accepts native series only. Google and Outlook imports and writes
retain their existing behavior until their recoverable series integration ships;
unsupported provider rules must remain preserved and read-only. The canonical
Google RRULE and Microsoft Graph adapters explicitly reject lossy conversions.
Regression evidence: calendar-native-recurrence.sql tests authorization,
idempotency, revision conflicts and atomic splitting. recurrence/service.test.ts
and calendar-recurrence-edit.test.ts cover encrypted retries, immutable identity,
DST slot counts, cancellation, exception edits and truthful bounded reads.
Outlook snapshot completeness
Outlook calendar synchronization follows everycalendarView continuation before
reconciling removed events. Reads request UTC on every page and preserve the
provider’s opaque continuation query. Duplicate event identities across pages
collapse to the latest returned version. A failed, malformed, looping or oversized
snapshot fails the sync; a partial snapshot must never authorize deletion.
Reads are bounded to 50 pages and 25,000 distinct events. Continuations must remain
on the same Microsoft Graph calendar collection. This applies to existing Outlook
single events, recurring occurrences and moved exceptions; it does not enable
canonical series writes by itself. Regression coverage:
packages/microsoft/src/calendar/pagination.test.ts.
Recoverable provider series admission
The provider operation endpoints reserve an encrypted, actor-bound intent before remote effects and publish the canonical native result only after every provider step has a durable checkpoint. They preserve Google event IDs and Outlook immutable IDs, use revision preconditions, and keep original occurrence slots separate from moved start times. A partial “this and future” operation resumes from its completed trim instead of blindly repeating both provider writes.POST /api/v1/workspaces/{wsId}/calendar/series/provider-operations accepts
requestId, source (provider and connectionId), action, and the native
series creation or mutation fields. An update/delete also supplies seriesId.
GET .../provider-operations/{operationId} returns actor-scoped status;
POST to that detail endpoint retries the retained intent. A pending operation
returns HTTP 202 with its operationId, not a false success. An applied operation
returns the hydrated result. Journals, OAuth credentials and raw SDK errors never
appear in those responses. Workspace membership, manage_calendar, current
connection ownership and outbound-sync permission are checked again during
recovery. Native mutation routes cannot bypass provider-bound series or a pending
provider operation.
New admission defaults to disabled unless
CALENDAR_PROVIDER_SERIES_OPERATIONS_ENABLED=true. Keep it disabled until the
canonical inbound reconciliation and provider UI integration have shipped and
been verified together; the operation protocol alone is not full provider parity.
Retained operations remain readable/retryable when new admission is disabled.
Unsupported provider patterns are rejected rather than converted lossily; mailbox
timezone support remains authoritative. Provider delivery and organizer receipts
still require authenticated Google/Outlook verification.
Regression evidence: calendar-provider-series.sql, provider plan.test.ts and
writer.test.ts, plus calendar-provider-series.test.ts in Internal API cover
permission revocation, leases, publication ordering, idempotent create recovery,
revision conflicts, immutable identities, scope splitting and pending status.
Provider inbound recurrence observations
Canonical provider import uses the same default-disabled admission flag as recoverable external series operations. When enabled for verification, the live Google and Outlook sync paths reconcile supported recurring masters before persisting ordinary expanded instances. This is a staged integration, not a claim that provider editing or full recurrence parity is enabled in production. Google reads complete non-expandediCalUID exception lists, including cancelled
and moved instances outside the viewport. Outlook expands master exceptions and
reads complete bounded immutable-ID views twice. Separate occurrence snapshots
and the master revision are compared before publication. Windows timezone names
use CLDR’s default territory mapping to IANA; unknown/custom names and nonzero
fractional occurrence precision fail closed. There is no machine-timezone fallback.
Reconciliation rechecks the token-owning actor, workspace membership,
manage_calendar, source ownership and inbound permission throughout the read
and before commit. The transaction compares the captured local binding ETag and
defers while an outbound operation is pending. It publishes encrypted native
fields and actor/source-bound encrypted provider metadata before suppressing
explicitly represented legacy identities. Other calendars and unrepresented
provider rows remain untouched. Outlook cancellations proven inside the complete
view replace that covered range; known cancellations outside it survive if their
original slots still belong to the current rule. Deleted bound masters are
rechecked even when the Outlook view contains no remaining occurrences.
Unsupported masters retain encrypted raw snapshots and visibly read-only projections;
a previous canonical rule is hidden until safely supported again. Incomplete reads
reject the refresh; see read-only rules. Keep
admission disabled until metadata-preserving future splits, full legacy identity
suppression across ranges, provider UI, and authenticated Google/Outlook
verification are completed together.
Regression evidence: calendar-provider-reconciliation.sql applies the actual
migration and covers actor/source revocation, pending-operation deferral, stale
observations, replay, deletion, rollback and scoped legacy suppression. Provider
inbound reader/connection/service tests cover complete snapshots, independently
changed exceptions, immutable identity bridging, encrypted metadata, cancellation
coverage and the disabled default. Microsoft pagination/timezone and shared
recurrence-edit tests cover continuation authorization, Windows zones and DST
interval boundaries.
Future provider split metadata
A provider this and following edit reads and revision-checks the fresh master before reserving its trim. It retains supported writable metadata in the encrypted create step: guest identities/options, reminders, visibility/privacy, free-busy, Google guest rights and non-operation custom properties, or Outlook categories and response-request settings. Old organizer IDs, attendee RSVP replies, provider IDs and recovery markers are not copied to the new invitation. Outlook HTML notes keep their content type when unchanged; an explicitly edited description uses text. The current preflight rejects Google conferences, attachments, special event types, omitted attendee lists or a non-organizer copy, and Outlook online meetings, attachments, hidden guests or a non-organizer copy. It rejects malformed metadata instead of silently replacing privacy/reminder settings with provider defaults. These exceptions are rejected before any trim. Other edit scopes patch the existing provider event and do not create a replacement metadata copy. New external admission remains disabled; provider UI and authenticated end-to-end verification are still required before rollout. Regression evidence:create-metadata.test.ts, future-admission.test.ts and
provider writer.test.ts cover preserved metadata, omitted replies/identities,
HTML notes, strict journal shape, preflight-before-reservation, revision conflicts,
source mismatch and actual provider create payloads. Recovery fingerprints include
the retained metadata so retries cannot silently substitute a different tail.
Google future-series attachment references
A future split preserves up to 25 Google attachment references from the freshly read organizer-owned master. The replacement event uses Google’ssupportsAttachments request option and excludes read-only file IDs. This copies
links and display metadata, not file content or Drive permissions. Incomplete
references fail before the original series is trimmed. Google conference
reuse remains blocked because it can change access and expose meeting details;
Outlook attachment and online-meeting splits also remain blocked. Provider
editing admission stays disabled until the remaining parity checks pass.
Regression coverage: create-metadata.test.ts, future-admission.test.ts, and
writer.test.ts verify reference validation, preflight ordering, and create
request options. See the Google event resource
for attachment limits and conference reuse restrictions.
Outlook legacy recurring-instance identity verification
When provider-series admission is explicitly enabled, inbound reconciliation verifies older stored Outlook IDs outside the current viewport against their exact connected calendar. The bounded read-only pass selects IDs only, reads up to 1,000 source rows in batches of 20 with at most three batches in flight, and uses an explicit regular-to-immutable ID translation before requesting event and master identities. The translation requires the already requestedUser.Read
Microsoft scope. Current source authorization is
checked before each batch. Only explicitly verified IDs join the existing atomic
canonical publication and legacy cleanup; single events, other masters, and
missing remote resources are not attributed to the series. An incomplete batch,
permission failure, throttling, or source overflow fails closed without
publishing a partially verified series. This performs no provider mutation or
calendar-wide deletion and does not enable provider editing.
Regression coverage: graph-legacy-identities.test.ts verifies source filters,
old-slot linkage, permission revocation, receipt completeness, foreign-master
isolation, provider failures, and batch bounds.
Editable monthly and yearly weekday patterns
The shared web recurrence editor supports first, second, third, fourth, or last weekday patterns for monthly and yearly native series. Yearly patterns have an explicit month. Selecting multiple weekdays uses the earliest matching date in the selected ordinal week, following the canonical Google/Outlook adapter semantics (Graph recurrence patterns); the initial local date must match the pattern. The form does not silently move the first occurrence when the pattern changes. Absolute month-day rules offer skipping missing dates or using the month’s last day. Details-only edits preserve imported month-end behavior, yearly month and weekly week-start boundaries without adding optional normalization that would reset exceptions. This-occurrence edits do not modify the rule; future edits retain the remaining occurrence count and immutable original slot. Unsupported provider rules stay read-only, and outbound provider admission remains disabled. Regression coverage:native-recurrence-pattern-model.test.ts checks all five
ordinals against both provider serializers, multi-weekday patterns, inclusive end
dates, imported week boundaries and month-end behavior, invalid input, and edit
scopes. native-recurrence-pattern-fields.test.tsx covers the interactive monthly,
yearly, month-end and weekly controls.
Smart-scheduling startup enrichment
Calendar server startup loads the current actor’s accessible tasks first. Once those IDs are known, list/workspace metadata and actor-scoped scheduling settings are read concurrently. Empty task sets do not trigger broad enrichment reads; missing settings and list metadata retain their existing defaults. This removes one sequential database stage without changing task visibility or provider admission. The actual production latency benefit still requires authenticated post-deployment timing; focused tests are not a browser performance measurement. Regression coverage:load-smart-scheduling-tasks.test.ts holds list metadata
unresolved while proving that actor-filtered scheduling settings have already
started, verifies accessible IDs and deduplicated lists, and covers empty/missing
responses, settings defaults, and rejected reads.
Calendar’s dashboard permission check uses the UUID returned by the verified
workspace read while retaining the exact satellite actor. This avoids resolving
personal again inside the permission helper. Membership, roles and default
permissions still use the same helper; denied navigation retains its URL slug.
The page’s scheduling reads begin only after workspace and permission verification.
Coverage: dashboard page.test.tsx exercises aliases/UUIDs, actor preservation,
verification ordering, permission denial, missing records and rejected reads;
workspace-helper tests verify that UUID normalization needs no alias lookup.
For notification/event deep links, the page starts token and scheduling reads
alongside the scoped event-date lookup after permission verification. A valid
explicit date skips the lookup as before; invalid or missing dates use a valid
stored event instant when available. Date-query errors retain their original
precedence, and concurrent resource failures are handled while that lookup is
pending. No resource reads begin before authorization. Coverage:
page-date-loading.test.tsx uses an unresolved event response to verify overlap,
actor/workspace filters, date-only and DST-offset links, fallbacks and both error
paths. Browser latency improvement still requires post-deployment measurement.
Mobile continuous schedule geometry
Mobile three-day and week timelines retain their continuous buffered date window. Dragging remains continuous; releasing settles header, all-day strip and timed grid on the same day boundary. Selected-date navigation and window recentering preserve that alignment without replacing the loaded event range or cache. Timed event widths use connected overlap groups with half-open time intervals. Transitive overlaps share columns; an event starting exactly when a group ends belongs to a new group. Isolated groups receive the full available date-column width. This shared layout also applies to the mobile day timeline. All-day span backgrounds retain their date extent while their title and optional working-location icon stay inside the span’s intersection with the current viewport, clear of the fixed time gutter. Labels truncate when the visible portion is narrow; offscreen spans do not expose duplicate visible labels. All-day rows reserve enough height for the current text scale. These are display rules and do not change event dates, actor permissions, recurrence, providers or cache scope. Regression coverage:calendar_viewport_test.dart,
date_snap_scroll_physics_test.dart and continuous_date_scroll_test.dart cover
connected groups, visible clipped labels, native scroll settling, synchronized
surfaces, continuous month traversal and programmatic date navigation. Widget
coverage is separate from native-device gesture and provider verification.
Mobile timeline overlap geometry
Mobile day and multi-day timelines reserve columns for the painted minimum card height as well as timestamp overlap. This keeps adjacent short events and their tap targets separate, including enlarged text, while isolated groups still use the full column width. Card positions and durations retain sub-minute precision so rounded pixels cannot create an untracked overlap. Event timestamps, recurring rules, and provider writes remain unchanged. The fixed all-day gutter label stays on one ellipsized line; the complete localized label remains available to accessibility services.calendar_rendered_overlap_test.dart checks actual card bounds and bottom-edge
taps at normal and enlarged text sizes, and the fixed all-day gutter. These
widget checks require device gesture verification after delivery.
Mobile timeline zoom
Day, three-day, and week timelines support smooth two-finger pinch zoom from 65% to 250%, defaulting to 100%. The fractional time under the pinch stays under the fingers; shell-owned Timeline zoom controls offer accessible zoom in, zoom out, and reset actions with the same anchored geometry. One-finger scrolling, date swipes and snapping, event taps, and long-press creation keep their existing behavior. Event timestamps, durations, and all-day/date column widths do not change. Completed zoom is stored in the existing account/workspace-scoped Calendar cache and reused across timeline modes and dates. Workspace/account switches cancel unfinished pinches and reject retained control callbacks, including return-to-same scope and logout races; unavailable preference storage leaves zoom usable locally. Month, year, and agenda views retain their existing layout. Shared minimum card height remains part of both painting and overlap grouping at every zoom level.calendar_timeline_zoom_test.dart, calendar_zoom_lifecycle_test.dart, and
calendar_timeline_zoom_state_test.dart cover gesture coexistence, focal anchors,
bounds, accessible controls, and scoped preference restoration.
Day highlighting, all-day spans and past events
Mobile multi-day headers, timeline columns, month and year date fills highlight only the current civil calendar day in the resolved timezone. The first visible or selected navigation day remains neutral when it is not today; selection still drives navigation. All-day materials retain occurrence identity through row and viewport changes, using workspace, event identifier and start/end boundaries so recurring instances with reused provider identifiers stay distinct. Web and mobile preserve the stored UTC calendar dates of untagged legacy UTC-midnight all-day imports. Their original provider dates/timezone are absent from the current API. Other all-day boundaries project into the resolved display timezone; the end remains exclusive, including 23/25-hour DST days and long spans. This rendering policy does not rewrite provider data or claim date-only provider write support. Past events fade consistently across native, Google and Microsoft providers on Web using an overlay over the opaque fill. All-day spans fade only after their displayed exclusive end, including merged spans, using the shared calendar clock. Explicit adapter preservation, interaction, previews and pending optimistic writes remain exceptions. Mobile keeps its existing past-event presentation. Regression coverage iscalendar_day_identity_test.dart, calendar_viewport_test.dart,
all-day-event-layout.test.ts and past-event-treatment.test.ts.
Mobile selected-view reset
Tapping the selected floating Calendar view item resets its date and scroll position without changing the exact view mode. Day and three-day views start at today. Week starts at the current week’s boundary using the effective first-day preference (personal, workspace, then locale); it does not force today into the first column. Timed views restore the current-time viewport. Agenda returns to today, month to the current month, and year to the current year. The reset and Today action use Calendar’s projected timezone clock for both date selection and range loading. Repeated taps while already at today still reset scroll position. Reduced-motion settings use immediate scroll positioning. Other apps retain the shell’s existing scroll-first and section-reset behavior; Calendar’s existing explicit section reset still restores its default view. Coverage:calendar_view_reselect_test.dart exercises the real Calendar page and
shared floating shell; calendar_scroll_reset_test.dart covers repeated resets,
week preferences, timezone/year boundaries, reduced motion, and disposal. These
source checks do not establish native-device or deployed runtime verification.