Add kb-update-events for batch event editing (tags, addressed-by)
Problem
Events have no edit path. The original need is marking multiple events addressed-by a shared reference (the five #784 events). The generic edit path injects assertion fields onto events and fails validation (#815).
Context
Part of the per-type record architecture epic (#848): Layer 2 introduces per-type commands, so events get their own edit path rather than reusing the assertion-biased generic engine. The KbEvent type and the type-blind note I/O layer (#849) are the foundation. The event command family adopts the kb- toolchain namespace; renaming the already-shipped capture-event to kb-capture-event is tracked separately (#863).
Proposed solution
Add kb-update-events, built on KbEvent and the type-blind note I/O layer — read → parse to KbEvent → mutate the typed record → render → atomic overwrite. It bypasses the generic frontmatter writer, so it does not reproduce #815.
- Batch by design: accepts one or more explicit event IDs plus a required
--store (resolved by registry name or @default); each ID resolves to that store's event file. Each event is written atomically and independently; the result reports per-event success or failed-with-reason, and one bad ID never aborts the rest.
- Operation surface is the event mutable set only:
--add-addressed-by (append references, de-duplicated) and --retag (replace with the canonicalized tag list). The operations are mutually exclusive — one per invocation, matching kb-edit.
- Promote
tags and addressed-by to typed fields on KbEvent, so the command reads and writes them as the typed contract rather than from an untyped field map.
- No timestamp: events are write-once;
addressed-by and tags are append-only/curatorial annotations, so marking does not stamp a timestamp (KbEvent has no updated).
Closes #815.
Acceptance criteria
Must have
Add kb-update-events for batch event editing (tags, addressed-by)
Problem
Events have no edit path. The original need is marking multiple events
addressed-bya shared reference (the five #784 events). The generic edit path injects assertion fields onto events and fails validation (#815).Context
Part of the per-type record architecture epic (#848): Layer 2 introduces per-type commands, so events get their own edit path rather than reusing the assertion-biased generic engine. The
KbEventtype and the type-blind note I/O layer (#849) are the foundation. The event command family adopts thekb-toolchain namespace; renaming the already-shippedcapture-eventtokb-capture-eventis tracked separately (#863).Proposed solution
Add
kb-update-events, built onKbEventand the type-blind note I/O layer — read → parse toKbEvent→ mutate the typed record → render → atomic overwrite. It bypasses the generic frontmatter writer, so it does not reproduce #815.--store(resolved by registry name or@default); each ID resolves to that store's event file. Each event is written atomically and independently; the result reports per-event success or failed-with-reason, and one bad ID never aborts the rest.--add-addressed-by(append references, de-duplicated) and--retag(replace with the canonicalized tag list). The operations are mutually exclusive — one per invocation, matchingkb-edit.tagsandaddressed-byto typed fields onKbEvent, so the command reads and writes them as the typed contract rather than from an untyped field map.addressed-byandtagsare append-only/curatorial annotations, so marking does not stamp a timestamp (KbEventhas noupdated).Closes #815.
Acceptance criteria
Must have
kb-update-eventsmarks one or more eventsaddressed-bya reference in a single invocation, de-duplicating entries.kb-update-eventsretags one or more events.tagsandaddressed-byare typed fields onKbEvent, not read from an untyped field map.kb-update-events.