The Invitations That Almost Went Out
Writing a past meeting into a calendar is harmless. Writing it with attendees is not.
An agent logging completed meetings into a calendar had an obvious field available: attendees. Filling it would have sent real invitations to real people for meetings that had already happened, days or weeks earlier. The field was banned outright rather than used carefully, because carefully is not a property a field has.
Symptom
The agent writes completed activities into a calendar — a retrospective record, so the week can be reconstructed later. Meetings, trips, anything over 30 minutes away from the desk.
The event format has an attendees field. Populating it is the obvious move: the record is more complete, and the names are right there in the source.
Populating it sends invitations. Real ones, by email, to real people, for meetings that already happened.
Root cause
The calendar API does not distinguish recording an event from scheduling one. Same endpoint, same object, and the attendee list is what turns the second into an outbound action.
The agent was not doing anything unusual. It was filling in the fields the object offered, which is what filling in an object means. Nothing in the field name signals that this one has an external side effect while the other eleven do not.
That is the general shape: an irreversible action hidden behind a field rather than behind a verb. Nobody audits fields for side effects.
Cost
Zero, because it was caught while writing the rule rather than after. The counterfactual is what makes it worth recording: a backdated invitation is not merely embarrassing, it is unrecallable — it lands in someone's inbox and calendar simultaneously, and a follow-up apology reaches fewer people than the original.
Fix
The field is banned outright:
attendees — never populated, under any circumstance. Participants go in the description as text.
Not used carefully. Banned. The distinction matters because carefully is not a property a field has — it is a property of whoever is filling it in at the time, which under time pressure is not a property at all.
Prevention
Two rules came out of it.
Enumerate side effects per field, not per endpoint. An API surface is usually audited at the level of what does this call do. That is one level too coarse: within a single write, some fields are inert and some reach the outside world, and only the second kind matters for an autonomy boundary.
When a field has an irreversible side effect and a safe alternative exists, take the alternative and remove the choice. Participants as text lose nothing a reader needs. Keeping the field available for the cases where it would be correct preserves an option that is worth less than the failure it enables.