S210.4 Dossier Proactive Dispatcher

Documentation for Sessions

S210.4: Making Vitto a 24/7 Jarvis-Like Super Agent

What This Is

This document explains, in plain language, what was built in Session 210.4 and why it matters. It's written for anyone on the team — developers, product, leadership — to understand the progress toward making Vitto a true "Jarvis" that's always available, always proactive, and reaches users wherever they are.


The Vision

Imagine this: you ask Vitto to build a new module for your platform. You close your laptop and go grab lunch. Ten minutes later, your phone buzzes with a WhatsApp message from Vitto: "Your player-management module is ready. 4 files generated, quality score 0.85." You reply on WhatsApp: "Great, now change the sidebar color to blue." Vitto understands, executes, and confirms — all through WhatsApp, without you ever opening the web app.

That's the Jarvis vision. Session 210.4 makes it real.


Timeline of Changes

Phase 1: Foundation — Dossier Enhancement (Tasks 1-3)

What changed: We taught Vitto to remember each user's notification preferences, skill preferences, subscription tier, and sync status — all stored in their "dossier" (Vitto's knowledge file about each user).

Why it matters: Before this, Vitto knew about users (their name, expertise, work patterns) but didn't know how they wanted to be contacted. Now, each user's dossier includes:

We also implemented:

Phase 2: The Dispatcher — Centralized Notification Governance (Tasks 4-5)

What changed: We created the ProactiveDispatcherService — a single gateway that ALL Vitto notifications pass through before reaching the user.

Why it matters: Before this, different parts of Vitto sent notifications through different paths with no unified rules. Health alerts went one way, milestone celebrations another, scheduled digests a third. There were no quiet hours, no frequency limits, no deduplication.

Now, every notification passes through 5 safety guards:

  1. Master toggle: User can disable all proactive notifications
  2. Per-trigger opt-out: User can disable specific alert types (e.g., "don't tell me about cost spikes")
  3. Quiet hours: Respect the user's sleep schedule (e.g., no alerts between 10 PM and 8 AM)
  4. Frequency cap: Maximum alerts per day (default: 5) to prevent spam
  5. Deduplication: Same alert can't fire twice within 1 hour

Critical alerts (production failures, build breaks) bypass quiet hours and frequency caps — because those truly need immediate attention.

We also built a Quality Drop Trigger — an hourly check that compares the last 24 hours of task success rates against the 7-day average. If success rate drops more than 15%, Vitto alerts the team. This is the first "self-aware" monitoring trigger.

Phase 3: The Sync — Bidirectional Data Flow (Task 6)

What changed: Created DossierSyncService — a 15-minute cron job that pushes enrichment data from Vitto back to the main GoGrab platform.

Why it matters: Vitto learns things about users that the main platform doesn't know — what technologies they prefer, their communication style, facts about their work. This service pushes those learnings back so the platform can personalize its own UX. Platform data always wins on conflicts (platform is source of truth for identity; Vitto is source of truth for behavioral insights).

Phase 4: Wiring Everything Together (Tasks 7-8)

What changed: Connected all the dots:

Phase 5: The Critical Missing Link (Post-plan fixes)

What was caught: After building all the pieces, we traced the full end-to-end flow and found the most important connection was missing: when Vitto finishes a task (like generating a module), the engine wasn't calling the dispatcher. Notifications would never reach WhatsApp.

What we fixed:

  1. Engine → Dispatcher wiring: Task completions and failures now route through ProactiveDispatcherService
  2. Smart severity: Module generation completions are "warning" severity (reaches WhatsApp/Slack). Quick chat replies are "info" severity (web toast only). Failures are always "warning".
  3. Auto-setup notification preferences: When a linked WhatsApp user sends their first message, Vitto automatically creates their notification preferences — no manual setup needed. Same zero-friction pattern as the existing magic link account linking.

What Works Now (After Deploy)

Scenario Before S210.4 After S210.4
User starts module generation, closes laptop Nothing happens until they reopen the app WhatsApp message: "Your module is ready"
System health check fails at 2 AM Alert logged, maybe email Respects quiet hours — holds until morning (unless critical)
Same alert fires 10 times in an hour 10 notifications 1 notification (dedup suppresses repeats)
User hasn't set up WhatsApp notifications Manual curl command needed Auto-created on first WhatsApp message
Vitto doesn't know what the user works with Never asks Naturally asks during first 3 conversations
Task success rate drops sharply Nobody notices Hourly quality monitor alerts the team

How the WhatsApp Loop Works (End-to-End)

1. USER LINKS ACCOUNT (one-time, already existed before S210.4):
   User sends WhatsApp message → Vitto sends magic link → User taps link →
   Logs into web app → Account linked → Done

2. AUTO-SETUP (NEW in S210.4, happens automatically):
   Next WhatsApp message from linked user →
   ensureNotificationPrefs() checks if prefs exist →
   If not: creates with preferredChannel='whatsapp', channelId=phone →
   Sends confirmation: "I'll now send you important alerts here" →
   Never runs again

3. OUTBOUND NOTIFICATIONS (NEW in S210.4):
   Vitto finishes task → VittoEngineService calls ProactiveDispatcherService →
   Dispatcher reads dossier preferences →
   Checks safety guards (quiet hours, frequency cap, dedup) →
   Resolves channel (WhatsApp) + phone number from UserNotificationPrefs →
   ChannelGatewayService.sendResponse() → TwilioService → WhatsApp delivery

4. INBOUND RESPONSES (already existed):
   User replies on WhatsApp → Twilio webhook → ChannelGatewayService →
   ChannelProcessingService → Agent loop → Response back via WhatsApp

Files Created/Modified

New Files (7)

File Purpose
proactive-dispatcher.service.ts Centralized notification dispatch with 5 safety guards
triggers/quality-drop.trigger.ts Hourly task success rate regression detection
dossier-sync.service.ts 15-minute outbound enrichment sync to main platform
proactive-dispatcher.spec.ts 8 unit tests for dispatcher (all guards + routing)
quality-drop-trigger.spec.ts 3 unit tests for quality trigger
user-dossier-enhanced.spec.ts 9 unit tests for dossier enhancements
dossier-sync.spec.ts 3 unit tests for sync service

Modified Files (9)

File Change
user-dossier.schema.ts 4 new field groups (proactive prefs, skills, tier, sync)
user-dossier.service.ts Dialectic enrichment, staleness re-hydration, dirty field tracking
space-intelligence.service.ts Space brief implementation (was a stub returning '')
context-assembly.service.ts Space brief + dialectic hints wired into LLM prompt
vitto-engine.service.ts Task completion/failure → dispatcher with context-aware severity
channel-processing.service.ts Auto-setup notification prefs for linked channel users
proactive-monitor.service.ts Routes health alerts through dispatcher
heartbeat.service.ts Routes heartbeat alerts through dispatcher
proactive.module.ts Registers dispatcher + quality trigger
users.module.ts Registers DossierSyncService
backend-api-client.service.ts pushProfileEnrichment() for outbound sync

Test Coverage


Commits (12)

Commit Type Description
ea7a57a feat Dossier schema: proactivePreferences, skillPreferences, subscriptionTier, syncMetadata
(T2) feat getMissingCriticalFields, staleness re-hydration, markFieldDirty
18fcc0c feat getSpaceBriefForPrompt — space context for LLM prompts
4bf76ee feat ProactiveDispatcherService — centralized multi-channel dispatch
(T5) feat QualityDropTrigger — hourly regression detection
22d12a7 feat DossierSyncService — 15-min outbound enrichment sync
6fe2066 feat Wire space brief + dialectic enrichment into context assembly
067681d feat Register dispatcher + trigger, wire triggers through dispatch
36c852c fix Automatic dedup cache pruning
342ec51 feat Wire task completion/failure to ProactiveDispatcher
a2223dd fix Route significant task completions as 'warning' for WhatsApp
d4ca73e feat Auto-setup notification prefs for linked WhatsApp users

What's NOT in This Session (Future Work)

Item Status Why Not Now
Frontend settings UI for notification preferences Nice-to-have Auto-setup covers MVP; power users can use API directly
PUT /api/users/:userId/profile-enrichment endpoint on backend-api Needed for outbound sync DossierSyncService gracefully degrades (logs, doesn't crash)
WhatsApp Business template approvals Twilio/Meta admin task Sandbox mode works for testing; templates needed for production scale
Skills Closed Loop (confidence tiers, anti-pattern mining) ~70% done Separate v2 spec section, separate session
Golden Path Tests (28 behavioral contracts) ~15% done Separate v2 spec section, separate session
Cost Improvements (per-feature budgets) ~40% done Separate v2 spec section, separate session

Key Lessons Learned

  1. Trace the full flow before claiming "done." We built the dispatcher with passing tests but hadn't connected it to the engine — no notification would have reached WhatsApp.

  2. Don't rebuild what already works. WhatsApp delivery infrastructure has been operational since Session 117. We needed governance (safety guards), not plumbing (Twilio integration).

  3. Reuse proven UX patterns. The magic link account-linking flow was the perfect template for auto-creating notification preferences — same detect→create→confirm pattern.

  4. Severity routing is the gatekeeper. The difference between info (web only) and warning (WhatsApp/Slack) determines whether the Jarvis vision works or doesn't.

  5. Mongoose defaults don't backfill. New schema fields with @Prop({ default: ... }) only apply to newly created documents. Existing documents need undefined-safe code.


Architecture Overview

                    ┌─────────────────────────────┐
                    │     Trigger Sources          │
                    │  ┌────────────────────────┐  │
                    │  │ VittoEngineService      │  │  ← Task complete/fail
                    │  │ ProactiveMonitorService │  │  ← Health checks
                    │  │ HeartbeatService        │  │  ← 30-min daemon
                    │  │ QualityDropTrigger      │  │  ← Hourly quality check
                    │  └──────────┬─────────────┘  │
                    └─────────────┼────────────────┘
                                  │
                                  ▼
                    ┌─────────────────────────────┐
                    │  ProactiveDispatcherService  │  ← NEW in S210.4
                    │  ┌────────────────────────┐  │
                    │  │ 1. Master toggle        │  │
                    │  │ 2. Per-trigger opt-out   │  │
                    │  │ 3. Quiet hours          │  │
                    │  │ 4. Frequency cap        │  │
                    │  │ 5. Deduplication        │  │
                    │  └──────────┬─────────────┘  │
                    │             │                 │
                    │  ┌──────────▼─────────────┐  │
                    │  │ Severity-based routing  │  │
                    │  │ critical → all channels │  │
                    │  │ warning  → preferred    │  │
                    │  │ info     → web only     │  │
                    │  └──────────┬─────────────┘  │
                    └─────────────┼────────────────┘
                                  │
                    ┌─────────────┼────────────────┐
                    │             ▼                 │
                    │  Channel Resolution           │
                    │  UserDossier.proactivePrefs   │
                    │  + UserNotificationPrefs      │
                    │  (preferredChannel + channelId)│
                    └─────────────┼────────────────┘
                                  │
              ┌───────────────────┼───────────────────┐
              ▼                   ▼                   ▼
        ┌──────────┐       ┌──────────┐        ┌──────────┐
        │ WhatsApp │       │  Slack   │        │   Web    │
        │ (Twilio) │       │  (API)   │        │ (SSE     │
        │          │       │          │        │  Toast)  │
        └──────────┘       └──────────┘        └──────────┘
              │                                       │
              │     ┌─────────────────────┐           │
              └────▶│  User's Phone       │◀──────────┘
                    │  (or browser)       │
                    └─────────────────────┘

Document created: 2026-03-12 | Session: S210.4 | Author: Claude Code