Contacts and calendars now disagree, and the disagreement was never decided — it is just where each half stopped.
Contacts update. A vCard whose UID a book holds, or an LDIF entry whose dn it holds, overwrites the card that is there (#242, #274).
Calendars skip. An event whose UID a calendar holds is counted and not written (#222, importIcs in web/src/store/calendar.ts).
The argument that moved contacts applies here on its face. The reporter put it on #174: the reason to import a file a second time is usually that the first one was not right, so skipping means a corrected export corrects nothing. But he scoped his answer to contacts, in as many words, and I would rather ask than assume — which is why #222 shipped skip and this exists.
Why an event is not a contact, and the answer might genuinely differ
RSVPs live on the event.participants carries participationStatus per attendee, and an .ics export usually carries ATTENDEE lines. Updating from the file would overwrite the map, resetting everyone's accepted/declined to whatever the file says — most likely needs-action. A re-import meant to fix a typo in the location would quietly discard the answers. Contacts had no equivalent: the worst a contact merge loses is a field somebody deleted at the source.
Per-occurrence edits live on the event too.recurrenceOverrides holds every "just this Wednesday" change made here. An update from a file describing the plain series would take them with it. See the entries in KNOWN-ISSUES about synthetic ids and override renumbering — this is the same data, and it is easy to destroy without a single error being returned.
Nothing is notified. Import deliberately sends no scheduling messages: filing something you already have should not mail its participants. That is right for a create and questionable for an update — changing an event's time without telling anyone leaves every attendee's own copy stale and wrong, with nothing anywhere reporting a disagreement.
If the answer is "update"
uidsInCalendar returns a Set<string>; it would need to return uid → id, the way contacts' scanBook does, since updating needs something to address.
The merge-or-replace question from #242 has to be answered again, and probably differently. Contacts merge: what the file carries wins, what it does not mention is left alone. For an event that would still overwrite participants whenever the file has attendees, which is the case that matters.
A narrower option worth considering: update everything exceptparticipants and recurrenceOverrides, so a corrected export fixes the time and the title without touching who said yes. Less principled, and it may be what anyone actually wants.
The counts want to become created/updated, as the contacts imports report them.
If the answer is "leave it"
Then #222 is right as it stands and this issue is the record of why, which is worth having — the asymmetry with contacts looks like an oversight and will keep being reported as one.
Contacts and calendars now disagree, and the disagreement was never decided — it is just where each half stopped.
- **Contacts** update. A vCard whose UID a book holds, or an LDIF entry whose `dn` it holds, overwrites the card that is there (#242, #274).
- **Calendars** skip. An event whose UID a calendar holds is counted and not written (#222, `importIcs` in `web/src/store/calendar.ts`).
The argument that moved contacts applies here on its face. The reporter put it on [#174](https://github.com/Coffey-Labs/ihasmail/issues/174#issuecomment-5508887841): the reason to import a file a second time is usually that the first one was not right, so skipping means a corrected export corrects nothing. But he scoped his answer to contacts, in as many words, and I would rather ask than assume — which is why #222 shipped skip and this exists.
## Why an event is not a contact, and the answer might genuinely differ
**RSVPs live on the event.** `participants` carries `participationStatus` per attendee, and an `.ics` export usually carries `ATTENDEE` lines. Updating from the file would overwrite the map, resetting everyone's accepted/declined to whatever the file says — most likely `needs-action`. A re-import meant to fix a typo in the location would quietly discard the answers. Contacts had no equivalent: the worst a contact merge loses is a field somebody deleted at the source.
**Per-occurrence edits live on the event too.** `recurrenceOverrides` holds every "just this Wednesday" change made here. An update from a file describing the plain series would take them with it. See the entries in KNOWN-ISSUES about synthetic ids and override renumbering — this is the same data, and it is easy to destroy without a single error being returned.
**Nothing is notified.** Import deliberately sends no scheduling messages: filing something you already have should not mail its participants. That is right for a create and questionable for an update — changing an event's time without telling anyone leaves every attendee's own copy stale and wrong, with nothing anywhere reporting a disagreement.
## If the answer is "update"
- `uidsInCalendar` returns a `Set<string>`; it would need to return uid → id, the way contacts' `scanBook` does, since updating needs something to address.
- The merge-or-replace question from #242 has to be answered again, and probably differently. Contacts merge: what the file carries wins, what it does not mention is left alone. For an event that would still overwrite `participants` whenever the file has attendees, which is the case that matters.
- A narrower option worth considering: update everything **except** `participants` and `recurrenceOverrides`, so a corrected export fixes the time and the title without touching who said yes. Less principled, and it may be what anyone actually wants.
- The counts want to become created/updated, as the contacts imports report them.
## If the answer is "leave it"
Then #222 is right as it stands and this issue is the record of why, which is worth having — the asymmetry with contacts looks like an oversight and will keep being reported as one.
Related: #173, #222, #223, #242, #274.
<sub>Rebuilt from: notification email, session transcript.</sub>
@mbunkus — flagging this rather than leaving it sitting quietly, since it is a question for you and you are not otherwise on this thread.
Contacts and calendars now behave differently on a re-import, and only one of those was decided. On #174 you said an attribute that can change is fine for matching, and that an existing entry should be updated rather than skipped — and you scoped that to contacts, in as many words. So contacts update (#242, #274) and calendars still skip (#222). The asymmetry is deliberate only in the sense that I did not want to extend your answer past what you said.
The issue above lays out why an event might honestly deserve the opposite answer to a contact, and it is not a small difference: RSVPs and per-occurrence edits live on the event, so updating from a file would overwrite participants — resetting everyone's accepted/declined — and take recurrenceOverrides with it. Import also sends no scheduling messages by design, which is right for a create and questionable for an update, since nobody would be told their meeting moved.
There is a middle option in there too: update everything except participants and overrides.
Nothing is waiting on this — no work is blocked and there is no deadline. "Leave it as it is" is a perfectly good answer and I will write it down as the reason rather than reopen it later. It is only here because you would find the asymmetry eventually and it would look like an oversight.
@mbunkus — flagging this rather than leaving it sitting quietly, since it is a question for you and you are not otherwise on this thread.
Contacts and calendars now behave differently on a re-import, and only one of those was decided. On #174 you said an attribute that *can* change is fine for matching, and that an existing entry should be **updated rather than skipped** — and you scoped that to contacts, in as many words. So contacts update (#242, #274) and calendars still skip (#222). The asymmetry is deliberate only in the sense that I did not want to extend your answer past what you said.
The issue above lays out why an event might honestly deserve the opposite answer to a contact, and it is not a small difference: **RSVPs and per-occurrence edits live on the event**, so updating from a file would overwrite `participants` — resetting everyone's accepted/declined — and take `recurrenceOverrides` with it. Import also sends no scheduling messages by design, which is right for a create and questionable for an update, since nobody would be told their meeting moved.
There is a middle option in there too: update everything *except* participants and overrides.
**Nothing is waiting on this** — no work is blocked and there is no deadline. "Leave it as it is" is a perfectly good answer and I will write it down as the reason rather than reopen it later. It is only here because you would find the asymmetry eventually and it would look like an oversight.
There is a middle option in there too: update everything except participants and overrides.
That sounds ideal to me. I would expect both mechanisms to update in general, but not overwriting changes made since for those two seems more user-friendly here. Thanks.
> There is a middle option in there too: update everything except participants and overrides.
That sounds ideal to me. I would expect both mechanisms to update in general, but not overwriting changes made since for those two seems more user-friendly here. Thanks.
Shipped in #301, merged and deployed. Live on ihasmail.com and validated there.
@mbunkus — built the middle option you picked, so a re-import now updates the event and holds back the two things that would have made updating destructive:
participants — every attendee's accepted/declined.
recurrenceOverrides — every "just this Wednesday" edit made here.
uid is held back with them, since it is what the two were matched on and is already equal by definition.
Everything else in the file wins, which is the point: a corrected export now fixes the time, the title and the location, and leaves who said yes alone. Verified end to end rather than only in tests — a file re-imported over an event carrying an accepted RSVP and a per-occurrence override updated the event in place, took the file's title, start and location, and left both untouched, even though the file carried participants of its own.
Two costs, both real, both now written down in FEATURES.md rather than left to be discovered:
An attendee added at the source does not arrive. Nothing here can tell "the file has somebody your copy doesn't" apart from "somebody answered in ihasmail since", so the rule is the simple one in both directions. Losing an answer that was given is worse than not gaining an attendee who can still be told.
Nothing is notified. An import still sends no scheduling messages, on an update as much as on a create — so an event a re-import moves is moved here, and everybody else's copy says the old time until whoever is organising sends the update from the event itself. Weighed and kept: an import is not the place to start mailing a room full of people who never asked for it.
Mechanically, the calendar scan now returns uid → id rather than a set of UIDs, since an update needs something to address, and creates and updates share one maxObjectsInSet budget the way contacts' writeCards does — batched separately, a file of 300 new and 300 changed events would go as two calls of 300, neither over a ceiling of 500 and both refused. The counts are created/updated, reported as the contacts imports report them.
Contacts and calendars now agree, and where they still differ it is because an event carries something a contact does not.
Shipped in #301, merged and deployed. Live on ihasmail.com and validated there.
@mbunkus — built the middle option you picked, so a re-import now updates the event and holds back the two things that would have made updating destructive:
- **`participants`** — every attendee's accepted/declined.
- **`recurrenceOverrides`** — every "just this Wednesday" edit made here.
`uid` is held back with them, since it is what the two were matched on and is already equal by definition.
Everything else in the file wins, which is the point: a corrected export now fixes the time, the title and the location, and leaves who said yes alone. Verified end to end rather than only in tests — a file re-imported over an event carrying an accepted RSVP and a per-occurrence override updated the event in place, took the file's title, start and location, and left both untouched, even though the file carried participants of its own.
Two costs, both real, both now written down in FEATURES.md rather than left to be discovered:
**An attendee added at the source does not arrive.** Nothing here can tell "the file has somebody your copy doesn't" apart from "somebody answered in ihasmail since", so the rule is the simple one in both directions. Losing an answer that was given is worse than not gaining an attendee who can still be told.
**Nothing is notified.** An import still sends no scheduling messages, on an update as much as on a create — so an event a re-import moves is moved *here*, and everybody else's copy says the old time until whoever is organising sends the update from the event itself. Weighed and kept: an import is not the place to start mailing a room full of people who never asked for it.
Mechanically, the calendar scan now returns uid → id rather than a set of UIDs, since an update needs something to address, and creates and updates share one `maxObjectsInSet` budget the way contacts' `writeCards` does — batched separately, a file of 300 new and 300 changed events would go as two calls of 300, neither over a ceiling of 500 and both refused. The counts are created/updated, reported as the contacts imports report them.
Contacts and calendars now agree, and where they still differ it is because an event carries something a contact does not.
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Contacts and calendars now disagree, and the disagreement was never decided — it is just where each half stopped.
dnit holds, overwrites the card that is there (#242, #274).importIcsinweb/src/store/calendar.ts).The argument that moved contacts applies here on its face. The reporter put it on #174: the reason to import a file a second time is usually that the first one was not right, so skipping means a corrected export corrects nothing. But he scoped his answer to contacts, in as many words, and I would rather ask than assume — which is why #222 shipped skip and this exists.
Why an event is not a contact, and the answer might genuinely differ
RSVPs live on the event.
participantscarriesparticipationStatusper attendee, and an.icsexport usually carriesATTENDEElines. Updating from the file would overwrite the map, resetting everyone's accepted/declined to whatever the file says — most likelyneeds-action. A re-import meant to fix a typo in the location would quietly discard the answers. Contacts had no equivalent: the worst a contact merge loses is a field somebody deleted at the source.Per-occurrence edits live on the event too.
recurrenceOverridesholds every "just this Wednesday" change made here. An update from a file describing the plain series would take them with it. See the entries in KNOWN-ISSUES about synthetic ids and override renumbering — this is the same data, and it is easy to destroy without a single error being returned.Nothing is notified. Import deliberately sends no scheduling messages: filing something you already have should not mail its participants. That is right for a create and questionable for an update — changing an event's time without telling anyone leaves every attendee's own copy stale and wrong, with nothing anywhere reporting a disagreement.
If the answer is "update"
uidsInCalendarreturns aSet<string>; it would need to return uid → id, the way contacts'scanBookdoes, since updating needs something to address.participantswhenever the file has attendees, which is the case that matters.participantsandrecurrenceOverrides, so a corrected export fixes the time and the title without touching who said yes. Less principled, and it may be what anyone actually wants.If the answer is "leave it"
Then #222 is right as it stands and this issue is the record of why, which is worth having — the asymmetry with contacts looks like an oversight and will keep being reported as one.
Related: #173, #222, #223, #242, #274.
Rebuilt from: notification email, session transcript.
@mbunkus — flagging this rather than leaving it sitting quietly, since it is a question for you and you are not otherwise on this thread.
Contacts and calendars now behave differently on a re-import, and only one of those was decided. On #174 you said an attribute that can change is fine for matching, and that an existing entry should be updated rather than skipped — and you scoped that to contacts, in as many words. So contacts update (#242, #274) and calendars still skip (#222). The asymmetry is deliberate only in the sense that I did not want to extend your answer past what you said.
The issue above lays out why an event might honestly deserve the opposite answer to a contact, and it is not a small difference: RSVPs and per-occurrence edits live on the event, so updating from a file would overwrite
participants— resetting everyone's accepted/declined — and takerecurrenceOverrideswith it. Import also sends no scheduling messages by design, which is right for a create and questionable for an update, since nobody would be told their meeting moved.There is a middle option in there too: update everything except participants and overrides.
Nothing is waiting on this — no work is blocked and there is no deadline. "Leave it as it is" is a perfectly good answer and I will write it down as the reason rather than reopen it later. It is only here because you would find the asymmetry eventually and it would look like an oversight.
That sounds ideal to me. I would expect both mechanisms to update in general, but not overwriting changes made since for those two seems more user-friendly here. Thanks.
Shipped in #301, merged and deployed. Live on ihasmail.com and validated there.
@mbunkus — built the middle option you picked, so a re-import now updates the event and holds back the two things that would have made updating destructive:
participants— every attendee's accepted/declined.recurrenceOverrides— every "just this Wednesday" edit made here.uidis held back with them, since it is what the two were matched on and is already equal by definition.Everything else in the file wins, which is the point: a corrected export now fixes the time, the title and the location, and leaves who said yes alone. Verified end to end rather than only in tests — a file re-imported over an event carrying an accepted RSVP and a per-occurrence override updated the event in place, took the file's title, start and location, and left both untouched, even though the file carried participants of its own.
Two costs, both real, both now written down in FEATURES.md rather than left to be discovered:
An attendee added at the source does not arrive. Nothing here can tell "the file has somebody your copy doesn't" apart from "somebody answered in ihasmail since", so the rule is the simple one in both directions. Losing an answer that was given is worse than not gaining an attendee who can still be told.
Nothing is notified. An import still sends no scheduling messages, on an update as much as on a create — so an event a re-import moves is moved here, and everybody else's copy says the old time until whoever is organising sends the update from the event itself. Weighed and kept: an import is not the place to start mailing a room full of people who never asked for it.
Mechanically, the calendar scan now returns uid → id rather than a set of UIDs, since an update needs something to address, and creates and updates share one
maxObjectsInSetbudget the way contacts'writeCardsdoes — batched separately, a file of 300 new and 300 changed events would go as two calls of 300, neither over a ceiling of 500 and both refused. The counts are created/updated, reported as the contacts imports report them.Contacts and calendars now agree, and where they still differ it is because an event carries something a contact does not.