4.7 KiB
Plan: What the ambient calendar path should be
The decision V-432 asked for. Written 04-08-2026.
Verdict: keep the endpoint, change the contract. The relay app sends structured fields, not a notification blob. The free-text parser stays as the degraded path, because there is a real case where the phone cannot produce structure. Delete the endpoint only if the answer to the one open question below is no.
First, the task's premise is out of date
V-432 states as confirmed that every ambient event lands on the day the notification was posted, because there is no date parsing at all. That was true when the task was filed and it is not true now.
4e4c917 added dayWords and dayOffset (internal/calendar/ambient.go:53), so
"завтра в 15:00" now dates to tomorrow. The same commit added ambientPastGrace, which
refuses an event landing more than two hours before the notification, on the reasoning
that the day was inferred and a stale inference is wrong rather than late. 45a5e37
(V-482, this week) fixed a second dating bug the task did not know about: the wall clock
was resolved against the notification's own zone, so every ambient meeting on a non-UTC
box landed off by the deploy's UTC offset.
What is still missing is an explicit date. "5 августа в 15:00" and "12.08 15:00" carry no day word, so they date to today and the past-grace check drops them. That is a smaller defect than the one filed, and it fails safe rather than storing a wrong meeting.
The task's third question also has an answer, and the answer is yes. internal/morning/plan.go:174
prefixes an uncertain item with "похоже, " and cmd/mavend/actions_query.go:334 carries
Confidence < 1.0 into the calendar recital. Both readers hedge.
The open question, and it is the owner's
Can the phone read Android's calendar provider, or only the notification text?
Everything follows from this and nothing in this repo can answer it.
A NotificationListenerService sees a title and a body. It cannot know a meeting's real
start, end or organiser, because those are not in the notification. So if the relay is
limited to the notification stream, free-text parsing on this side is not a choice, it is
the only thing available, and V-432's suggestion that the phone send structured JSON
cannot be honoured.
If the app may instead read CalendarContract, it has the actual event rows, and the
whole parser stops being necessary. That is the better shape by a wide margin: a real
start and end, a real title, an explicit date, no clock-reading heuristic and no
past-grace guard, because nothing is inferred.
Reading the phone's calendar provider does not break the constraint the design was built
around. The refusal in internal/calendar/ambient.go:10 is about holding a work
credential on the homelab, which is what ties the box's blast radius to the employer.
The phone already holds that session. Nothing new lands on homesrv either way.
Assumption, and it needs his answer: a managed work profile may block a third-party app from reading work calendar rows. If it does, the notification stream is all there is.
The decision
Keep the endpoint. Deleting it costs the parser, the tests and the wg-facing token,
and buys nothing while the question above is open. It is off unless -ambient-token is
set, so an unbuilt relay carries no surface today.
Make structured the primary shape. /api/ambient should accept an event with an
explicit start, end and title, and store it without parsing anything. Confidence stays
below 1.0 and the source stays ambient:notif, because the provenance claim is unchanged:
this is the phone telling Maven what it sees, not Maven reading a calendar.
Keep the free-text shape as the degraded path. It is what a notification-only relay can send, and it is already written and tested.
Delete it instead if the relay is not going to be built. That is the one answer that closes this without code, and it is his to give.
What not to do
Do not add date parsing to the free-text path yet. That is the patch V-432 explicitly refuses to accept as closure, and it is the wrong order: if the relay can send a date, no date parser is needed, and if it cannot, the parser is guessing at a date from text that was never meant to carry one.
Follow-on, unrelated to the decision
cmd/mavweb/ambient.go:33 records a known gap worth keeping visible: an ambient meeting
writes calendar_event_* and never calendar_busy, so it is good enough to recite and
not good enough to suppress a nudge. That is backwards. Suppressing a nudge is the
lower-risk use of a low-confidence signal, and reciting one is the higher-risk use. It
needs an expiry on the busy level, so it is its own task either way.