Skip to content

feat(seed): the lead Activity tab shows logged interactions out of the box (#1258) - #1959

Merged
os-warren merged 2 commits into
mainfrom
claude/issue-1258-seed-lead-interactions
Sep 25, 2026
Merged

os-warren merged 2 commits into
mainfrom
claude/issue-1258-seed-lead-interactions

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #1258

Route A (maintainer ruling 5386129833): the lead Activity tab now shows logged interactions out of the box, through the platform's ActivityPointer (sys_activity). No app-side imitation object and no extra writer.

What changed

  • src/sales/data/activity.seed.ts: a new leadInteractionPointers dataset on sys_activity. It is derived from the same EVENT_SPECS that seed the crm_event rows. Each pointer is the row log_call / log_meeting would have written for a held lead event: type: 'completed' (the task feed kind the tab filters to), the action's own summary format, object_name/record_id pointing at the lead by email, source_object/source_id pointing at the event by subject, and the action's metadata shape. Only call/meeting events (the two writers that exist) younger than the 14d telemetry retention are included.
  • The same file adds two earlier held interactions, so each tab reads as a short history instead of a single row: CloudFirst — follow-up meeting after the Cloud Summit booth (Lisa Thompson, 8d) and EduTech Labs — referral intro call with David Kim (9d). Both leads already carry last_contacted_date: today() for their later call, so no recency clock moves.
  • src/sales/data/index.ts and objectstack.composition.ts: the dataset is exported and registered in CrmSeedData right after the event attendees, because it resolves against leads and events seeded earlier.
  • test/seed-consistency.test.ts: the sys_* guard block is deleted on purpose. Its own comment asked for this: "If a future platform release makes an ActivityPointer target seedable, delete this test deliberately — do not widen it". objectstack#11339 did that, and the 17.4.0 pin carries it. A positive pin replaces it. Every pointer must name a seeded lead and a held event on that same lead, with type: 'completed', inside 14 days. Every held lead call or meeting inside the window must have its pointer. At least 3 pointers across at least 2 leads.
  • One changeset (hotcrm: patch).

Measurement first (17.4.0, booted app, fresh DB)

I re-measured the three 17.1.0 blockers in the old guard comment before writing the final seeds. First I booted with a scratch version of the dataset (2 rows), then again with the final 4 rows. Commands: rm -rf .objectstack/data && pnpm build && objectstack start -p 4158. I read the rows from sqlite and checked them in the browser.

leg 17.1.0 (old guard) 17.4.0 (this PR)
(i) readonly strip rows land (isSystem write) rows land: timestamp, type, summary, metadata, object_name, source_object all stored, although every field is readonly: true
(ii) pointer resolution record_id stored the literal natural key record_id = the lead's runtime id (pxDFU7RFoMejXWbp = lisa.t@…, Cmp7aiCyo4Dr81PH = dkim@…). source_id = the event's runtime id (all 4 match crm_event.id by subject)
(iii) retention / shards 14d telemetry, day-sharded still 14d / 14 day-shards: rows live in sys_activity__r20260925 behind the sys_activity view. Seeds use daysAgo(1..9), and the builder filters out anything 14d or older
Activity tab empty Lisa Thompson: Activity (2) and David Kim: Activity (2), each entry with "View source". Controls: Alice Martinez (new, planned call only) and Noah Patel both show Activity (0) / No activity recorded. The console's query was GET /api/v1/data/sys_activity?filter=["and",["object_name","=","crm_lead"],["record_id","=",LEAD_ID]], and it answered 200 for all four
replay boot not measured restarted on the same DB: still 4 pointer rows, 4 distinct source_id, 0 null record_id (the composite ['source_object','source_id'] key dedupes on resolved ids)

Verification (at e0563de)

pnpm verify chain, one step at a time, exit codes captured before any pipe:
validate 0 · typecheck 0 · lint 0 · lint:i18n-gate 0 · hygiene 0 · hygiene:tokens 0 · build 0 · test 0 (Test Files 172 passed (172), Tests 3688 passed | 1 skipped (3689)).

Reverse check of the new pin, with the fix committed first. I deleted the leadInteractionPointers, registration line from objectstack.composition.ts (grep count 1, then 0). Expected direction: red. Observed: red, Tests 2 failed | 36 passed (38). The two that failed were "seeds a handful…" and "every held call or meeting … has its pointer". The per-row test stays green with zero rows, as expected, because the first test guards it. Restored with git checkout HEAD -- objectstack.composition.ts under a trap, and git diff HEAD came back empty.

Token ratchet before and after (base aa61e1d vs this branch): all 12 ceilings are unchanged and green. Seed data is outside the ratchet by ruling (src/*/data). Its out-of-scope line moved from ~95,777 to ~96,270 tokens. objectstack.composition.ts is outside src/, so the ratchet does not measure it.

Acceptance notes

  • File surface. The claim named src/sales/data/index.ts "if registration is needed", but CrmSeedData is assembled in objectstack.composition.ts, because the replay order interleaves packages. So the registration is a one-line addition there, plus the import. No open PR touches that file.
  • Brief window on first boot. On a fresh DB the pointer rows were first stored with record_id/source_id null. The loader's later seed pass filled them about 30s later (created_at 13:17:03, updated_at 13:17:33). This is the platform loader's deferral, not something this repo shapes. A tab opened in the first seconds after first boot can read empty. Noted only.
  • The entries show the actor as System, because a seed cannot name a user (actor_id / actor_name are not authored). That is the same doctrine as owner_id.
  • sys_activity retention is 14d, so on a long-running demo instance these rows age out. A replay boot re-evaluates daysAgo(), but it did not rewrite the existing rows in my replay measurement (updated_at unchanged).

Generated by Claude Code

… logged interactions (#1258)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X8U3asekbiC7yWoEPWR4Dg
@vercel

vercel Bot commented Sep 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Sep 25, 2026 1:25pm UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline configuration Build and app configuration files metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Seed logged interactions so the lead Activity tab demonstrates something out of the box

2 participants