Make an aggregate's own events a first-class mode
An aggregate with no default_sink already left events created in it alone, but treated doing so as a failure: it reported a skip per event per cycle saying no sink was configured, as though something had gone wrong. Nothing had. An aggregate is also a calendar, and holding events of its own is a legitimate way to use one. Skipped::NoSink is replaced by a kept_local count, reported plainly. `@local` joins the routing markers, so the mode also works per-event where a default_sink is configured — which was not previously expressible. Unlike every other marker it is deliberately not stripped: the others have done their job once the event reaches its source, whereas this one never leaves, so it has to stay legible for the next cycle to reach the same decision. `local` is therefore a reserved endpoint id, and configuring one is refused. This also fixes a real defect. `retarget` rebuilds the new target from the recorded links, which cover derived events only, so an event belonging to the aggregate itself did not follow the move — it stayed on the calendar being left behind while everything around it moved on, quietly. It is now carried across, since there is nothing to re-derive it from, and the new target's scheduling rule is applied on the way: this is a write to an aggregate like any other, and a guest list carried live onto a server that schedules would mail everyone on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7607078394
commit
47ad8b4c47
9 changed files with 298 additions and 26 deletions
29
README.md
29
README.md
|
|
@ -144,6 +144,9 @@ reported in one pass:
|
|||
- `target` must not also be one of its own `sources`.
|
||||
- `sources` must be non-empty, and each must exist and be named once.
|
||||
- `default_sink`, if given, must be one of the `sources` and must be writable.
|
||||
Leaving it out is a deliberate mode, not an omission — see
|
||||
[Events of the aggregate's own](#events-of-the-aggregates-own).
|
||||
- No endpoint may be called `local`, which is reserved for the routing marker.
|
||||
|
||||
### A complete example
|
||||
|
||||
|
|
@ -256,6 +259,7 @@ aggregate `unified`
|
|||
new events go to `gcal` unless told otherwise
|
||||
to choose, put one of these on a line of its own in the event's notes:
|
||||
@gcal
|
||||
@local (keep the event here, in this calendar only)
|
||||
```
|
||||
|
||||
Read-only feeds are left out, since they cannot take an event. A marker naming
|
||||
|
|
@ -263,6 +267,31 @@ anything else is refused and reported — the event stays where it is rather tha
|
|||
being quietly filed under the default, which would put it somewhere you did not
|
||||
ask for.
|
||||
|
||||
### Events of the aggregate's own
|
||||
|
||||
An aggregate is also a calendar, and it can hold events that belong to nothing
|
||||
else. There are two ways to get one:
|
||||
|
||||
- **`@local`** on an event, exactly like any other marker, keeps it where it was
|
||||
written even though a `default_sink` would otherwise have taken it. Unlike
|
||||
every other marker it is *not* removed from the event: the others have done
|
||||
their job once the event reaches its source, whereas this one has to stay
|
||||
legible so every later cycle reaches the same decision.
|
||||
- **Leave `default_sink` out of the aggregate entirely.** Then nothing is
|
||||
configured to file a new event under, so every untagged event stays put and
|
||||
only `@`-tagged ones are sent anywhere. Routing becomes opt-in rather than
|
||||
opt-out.
|
||||
|
||||
`local` is a reserved endpoint id for this reason, and configuring an endpoint
|
||||
with that name is refused.
|
||||
|
||||
One thing to be aware of: every other event in an aggregate is derived from a
|
||||
source, so the aggregate is disposable — lose the calendar and it rebuilds
|
||||
itself on the next sync. **An event of the aggregate's own exists in exactly one
|
||||
place.** Nothing else holds a copy, so it is only as safe as that calendar is.
|
||||
`aggregate retarget` carries these events to the new target along with
|
||||
everything else, since there is nothing to re-derive them from.
|
||||
|
||||
A **category** matching an endpoint id works too, that being the field
|
||||
iCalendar intends for this. Be aware that any category on a newly created event
|
||||
is read as a routing instruction, so an event carrying an unrelated category
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue