2026 03 23 Intelligence Bridge Design

Documentation for Plans

Intelligence Bridge — Sub-project 1 Design

Date: 2026-03-23 Session: S262 Status: Draft Scope: Wire MCP decision intelligence into Vitto's runtime, fix pattern mining quality, add decision categorization, sync specializations to sub-agents Depends on: Command Center single-pipe (completed in S262) Enables: Sub-project 2 (Training Pipeline), Sub-project 3 (Command Center Control Plane)


Problem

Vitto and the MCP intelligence system are two islands. 12K+ MCP decisions sit in backend-ai-api's MongoDB. Pattern mining runs every 6 hours. Agent specializations are computed. Golden decisions are curated. But Vitto never reads any of this at runtime.

The only bridge is LearningSyncService — a daily cron job at 6AM that dumps patterns into sub-agent knowledge docs. That's batch, lossy, and stale by definition.

When Vitto is about to make an architecture decision, it has no idea that 50 past sessions already solved the same problem. When it delegates to a sub-agent, the sub-agent's knowledge is 24 hours old at best.

Meanwhile, the pattern mining pipeline has a dedup bug that creates 20+ copies of the same pattern, polluting the data.

Gaps to Close (5 concrete fixes)

Gap 1: No real-time intelligence in Vitto's decision loop

Current: Vitto's agent-loop.service.ts and phase-prompt-builder.service.ts never call getLearningIntelligence(). The only intelligence fetch is the daily cron.

Fix: Inject intelligence context into Vitto's context assembly before each task execution. When Vitto starts a task, call getPyramidContext() on ai-api with the task summary. Inject the response (core rules, relevant patterns, similar decisions) into the system prompt alongside existing context (dossier, memory, skills).

Where: context-assembly.service.ts — add a getLearningContext() step to the context pipeline.

Constraint: 2-second timeout with graceful degradation (already exists in BackendAiClientService). If ai-api is down, Vitto proceeds without intelligence context — same as today, no regression.

Gap 2: Pattern mining creates duplicates

Current: pattern-mining.job.ts generates pattern IDs using a simple character sum + Date.now(). This produces unique IDs for identical patterns across mining runs. No uniqueness constraint on pattern text.

Fix:

  1. Replace generatePatternId() with a deterministic hash: crypto.createHash('sha256').update(normalizedPattern + category).digest('hex').slice(0, 16)
  2. Add a MongoDB unique index on { normalizedText: 1, category: 1 } to the learned_patterns collection
  3. Use findOneAndUpdate({ normalizedText, category }, { $set: ..., $addToSet: ... }, { upsert: true }) instead of separate find+create

Result: Each unique pattern exists exactly once. Reruns update the existing entry.

Gap 3: Decisions have no domain categorization

Current: Decisions have a type field (architecture, implementation, bugfix, etc.) and optional tags[], but no category/domain field. The LearningRouterService detects domains heuristically at routing time, but this classification is not persisted on the decision itself.

Fix:

  1. Add domains: string[] field to the Decision schema (computed at creation time)
  2. In decision.service.ts create(), call LearningRouterService.detectDomains() and store the result
  3. Add audience: string field to the Decision schema — values: developer (MCP/Cursor users), platform-builder (Space builders), admin (GoGrab internal), all
  4. Default audience based on the agent's platform type and user role

Result: Every decision is tagged with its domains and target audience at creation time. Queries can filter by domain and audience.

Gap 4: Golden decisions don't feed Vitto's context

Current: Golden decisions exist in golden_decisions collection. LearningSyncService syncs them to sub-agent knowledge docs daily. But Vitto's main agent loop never queries them.

Fix: In BackendAiClientService.getLearningIntelligence(), add a goldenDecisions field to the response. LearningService.getPyramidContext() should query golden_decisions filtered by the task's detected domains and return the top 3-5 most relevant.

Where:

Gap 5: Agent specializations don't sync to sub-agent definitions

Current: AgentSpecializationService computes per-agent domain success rates from decision outcomes. SubAgentService in vitto-api has persistent definitions with performance metrics. These are separate, never synced.

Fix: Extend LearningSyncService to also sync specialization data:

  1. Fetch specializations from ai-api: GET /ai-api/agents/specializations
  2. For each sub-agent definition in vitto-api, match by role/domain overlap
  3. Update the sub-agent's performance field with the computed success rates
  4. This runs on the existing daily cron — specializations don't need real-time sync

Result: Sub-agent definitions show real performance metrics computed from actual decision outcomes, not hardcoded zeros.

Architecture

MCP logs decision
  ↓
ai-api: decision.service.create()
  ├── Persist to MongoDB (decisions collection)
  ├── Detect domains → store on decision                    [Gap 3]
  ├── Forward to vitto-api SSE (decision.created)           [Done in S262]
  └── EventEmitter → pattern mining pipeline (async)

ai-api: pattern-mining.job.ts @Cron('0 */6 * * *')
  ├── Mine patterns from recent decisions
  └── Upsert with deterministic hash (no duplicates)        [Gap 2]

ai-api: learning.service.getPyramidContext(task)
  ├── Core rules (by domain)
  ├── Relevant patterns (deduped, by domain)
  ├── Similar decisions (semantic search)
  └── Golden decisions (top 3-5 by domain)                  [Gap 4]

vitto-api: context-assembly.service.ts
  ├── Dossier (user context)
  ├── Memory (vector recall)
  ├── Skills (available tools)
  └── Learning Intelligence (from ai-api)                   [Gap 1]
       ↓
  Agent Loop makes informed decisions

vitto-api: learning-sync.service.ts @Cron('0 6 * * *')
  ├── Sync patterns → sub-agent knowledge docs
  └── Sync specializations → sub-agent performance          [Gap 5]

Files Modified

Gap 1: Real-time intelligence in context assembly

File Change
APIs/backend-vitto-api/src/app/engine/context-assembly/context-assembly.service.ts Add getLearningContext() step that calls BackendAiClientService.getLearningIntelligence()
APIs/backend-vitto-api/src/app/connectivity/backend-ai-client.service.ts Add goldenDecisions to response type, add audience param

Gap 2: Pattern dedup fix

File Change
APIs/backend-ai-api/src/app/learning/jobs/pattern-mining.job.ts Replace generatePatternId() with SHA-256 hash, use upsert
APIs/backend-ai-api/src/app/schemas/ai-infrastructure.schema.ts Add unique compound index on { normalizedText: 1, category: 1 } for learned_patterns

Gap 3: Decision categorization

File Change
APIs/backend-ai-api/src/app/schemas/ai-infrastructure.schema.ts Add domains: string[] and audience: string to Decision schema
APIs/backend-ai-api/src/app/infrastructure/services/decision.service.ts Call detectDomains() and set audience in create()
APIs/backend-ai-api/src/app/command-center/learning-router.service.ts Export detectDomains() for use by decision service

Gap 4: Golden decisions in context

File Change
APIs/backend-ai-api/src/app/learning/learning.service.ts Add getGoldenDecisionsForTask(), include in getPyramidContext()
APIs/backend-ai-api/src/app/learning/learning.controller.ts Return golden decisions in intelligence endpoint response

Gap 5: Specialization sync

File Change
APIs/backend-vitto-api/src/app/engine/learning-sync.service.ts Add specialization fetch and sync in daily cron
APIs/backend-vitto-api/src/app/connectivity/backend-ai-client.service.ts Add getSpecializations() method

Risks

  1. Context window bloat: Adding intelligence context to every task increases token usage. Mitigate with strict token budgets (500 tokens max for intelligence context) and relevance filtering.

  2. Latency: The getLearningIntelligence() call adds 100-500ms to task startup. Acceptable — already has 2-second timeout with graceful degradation.

  3. Pattern migration: Existing 20+ duplicate patterns need a one-time cleanup script. Not blocking — new patterns will be clean, old ones can be deduped in a migration.

  4. Schema migration: Adding domains and audience to Decision schema requires backfill for existing 12K decisions. Can be done as a background job — new decisions get tagged immediately.

What This Does NOT Cover (Sub-projects 2 & 3)