Milestone v1.0: FamilySync MVP #1

Merged
luckberg merged 376 commits from gsd/v1.0-milestone into main 2026-06-10 17:39:19 -04:00
Showing only changes of commit 5b720ffdb8 - Show all commits
+18
View File
@@ -65,6 +65,17 @@ export async function updateCalendarEvent(
icsString: string,
etag: string | null,
): Promise<Response> {
// WR-03: a missing etag maps to NO If-Match header → an UNCONDITIONAL PUT, which
// defeats D-08 conflict detection for exactly the rows most likely to be stale (an
// event cached before an etag was captured, or one Fastmail omitted the etag for).
// We do not block the write (it would strand the user's edit), but we make the
// unconditional-write path observable so it can be diagnosed instead of silently
// overwriting a concurrent external edit with no 412.
if (etag == null || etag === '') {
console.warn(
`[write] updateCalendarObject dispatching with NO If-Match (unconditional PUT) — conflict detection disabled for url=${calendarObjectUrl}`,
)
}
return client.updateCalendarObject({
calendarObject: {
url: calendarObjectUrl,
@@ -87,6 +98,13 @@ export async function deleteCalendarEvent(
calendarObjectUrl: string,
etag: string | null,
): Promise<Response> {
// WR-03: see updateCalendarEvent — a missing etag is an unconditional DELETE that
// bypasses D-08 conflict detection. Log so the path is observable rather than silent.
if (etag == null || etag === '') {
console.warn(
`[write] deleteCalendarObject dispatching with NO If-Match (unconditional DELETE) — conflict detection disabled for url=${calendarObjectUrl}`,
)
}
return client.deleteCalendarObject({
calendarObject: {
url: calendarObjectUrl,