feat(home-feed): emitFeedEvent helper + same-id action in-place [JARVIS-512]#25586
Conversation
…IS-512] New assistant/src/home/emit-feed-event.ts — the "force-write" entry point for background jobs to append activity-log entries. Opinionated defaults: type=action, author=assistant, source required, no expiresAt by default, priority 50 (above platform baseline, below assistant nudge default). Optional dedupKey derives a deterministic "emit:<source>:<dedupKey>" id so repeat emits for the same logical event update in place instead of appending duplicates. To support dedupKey end-to-end, teach the writer's mergeIncoming to treat same-id action items as an in-place update (matching thread semantics). Distinct-id actions still append without collapsing by (type, source). Tests cover: defaults + persistence, dedupKey determinism + in-place update, no-dedupKey distinct ids, expiresAt round-trip, priority override, schema validation failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff1d679919
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| function deterministicId(source: FeedItemSource, dedupKey: string): string { | ||
| return `emit:${source}:${dedupKey}`; |
There was a problem hiding this comment.
Sanitize dedupKey before building deterministic IDs
The deterministic ID path uses the raw dedupKey (emit:<source>:<dedupKey>), but feed item IDs are later used as URL path segments (PATCH /v1/home/feed/:id and POST /v1/home/feed/:id/actions/:actionId). If a caller provides a key with reserved path characters (notably /), the item can be written and returned by GET but becomes unreliable to patch/act on because routing splits that segment. Since dedup keys are expected to come from external event identifiers, this should be normalized to a URL-safe form (or hashed/validated) before composing the ID.
Useful? React with 👍 / 👎.
Summary
Second step of JARVIS-512, stacked on #25584 (merged).
emit-feed-event.ts— the "force-write, not taught-write" entry point for background jobs.emitFeedEvent({ source, title, summary, ... })persists an assistant-authoredactionitem with opinionated defaults (type, author, priority, no expiry) so instrumented jobs have a single grep target. OptionaldedupKeyderives a deterministicemit:<source>:<dedupKey>id so repeat emits for the same logical signal update in place instead of appending duplicates.mergeIncoming. Matches the thread in-place semantics. Distinct-id actions still append without collapsing by(type, source)— the append-without-replace behavior from feat(home-feed): action append semantics + per-source cap [JARVIS-512] #25584 is preserved for the normal case.No background jobs are instrumented yet — that's the next PR. This one just lands the helper + writer support so the instrumentation PR is a pure set of
import { emitFeedEvent } from ...callsite additions.Test plan
bun test src/home/— 144/144 pass (new: 6 emit-feed-event tests, 1 writer same-id test)bun run typecheck— cleanbun run lint— clean🤖 Generated with Claude Code