S204 Handoff
Documentation for Sessions
S204: Generation Pipeline E2E — Handoff Document
Session Summary
Goal: Verify the full code generation pipeline E2E (UI → Vitto → GitLab → MongoDB) and fix every gap found.
Result: 21+ sub-commits (S204.1–S204.21). Pipeline works end-to-end — code generates, commits to GitLab, and persists rich metadata to MongoDB. Major architectural improvements to local fallback, universe data persistence, chat UI streaming, and deprecated code removal.
Status: Generation pipeline is FUNCTIONAL. GitLab commits succeed. Chat UI fix (S204.21) and universe slug fix need frontend recompile + backend restart to verify.
What Was Done
Phase 1: Deprecation & Consolidation (S204.6, S204.9)
- ai-generation-hub: Gutted
GenerationHubServicefrom 1334 → 70 lines (deprecated stub) - Route:
/ai-generation-hubnow redirects to/vibe - Removed from tool orchestration:
ToolTypeunion +CANONICAL_JOURNEY - Rewired:
ChatModulePanelComponentfromGenerationRouterService→WorkflowStateService - Deprecated:
WorkflowSSEClientService,GenerationRouterService(headers added) - Net: -1247 lines of dead code
Phase 2: Bug Fixes (S204.7–S204.17)
| Sub | Bug | Root Cause | Fix |
|---|---|---|---|
| .7 | CastError on generationHistory | modules changed from number to array in S200, 3 callsites still did || 0 |
Array.isArray(m) ? m.length : ... |
| .8 | SSE events not forwarded to chat | Only 3 event types forwarded, terminal events silently dropped | Expanded to 9 event types |
| .11 | "5 modules, 0 files" — no GitLab repo | universeId lost in 5-layer context chain (extracted from plain text pageContext) |
Pass explicitly through all 5 layers |
| .12/.16 | Vitto ignores missing context, searches memories | Soft instruction in tool response — LLM treats as suggestion | Hard error + explicit tool blocklist + doNotRetry flag |
| .13 | ESLint "lexical declaration in case block" | const in switch case without braces |
Wrapped case bodies in { } |
| .14 | Empty chat cards after generation | task.completed with empty response created empty message |
Guard: response || toolCalls.length > 0 + filter non-phase events |
| .15 | GitLab 400 on group name "Space: {slug}" | Colon : rejected by GitLab API |
sanitizeGitLabPath() at 3 levels |
| .15 | Vitto auto-retries failed generation | No stop signal | doNotRetry: true in tool response |
| .16 | "Untitled" memories | VittoMemory has summary but no title |
Derive title from first 80 chars of summary |
| .17 | GitLab commit duplicate files + N+1 API calls | Template + LLM produce same paths | Map<path, FileCommit> dedup + optimistic create-all |
Phase 3: UX Polish (S204.10, S204.14)
- Phase timing:
phaseStartTimes+phaseDurationsMaps in chat engine - Vitto personality: Random quips per phase completion ("Got it, loud and clear! (2.3s)")
- Duration labels:
>= 1000ms→ seconds, else milliseconds
Phase 4: Architecture Improvements (S204.18–S204.20)
- User preferences: Replaced
SAVE_GENERATED_LOCALLYenv var withGenerationPreferencessub-schema onUserPreferences - Local fallback isolation: Writes to
~/.gograb/generated/{space}/{universe}/(standalone project, not monorepo) - Generation manifest: Rich
generationManifestfield on universe document — modules, entities with fields, routes, files, quality metrics
Phase 5: Chat UI & Naming (S204.21)
- Chat UI stuck on "Thinking...": Two streaming paths existed —
VittoChatStreamingServicecontrolled the label butVittoChatEngineServicehandled chat SSE events. Engine never updated streaming service phase → label always said "Thinking...". Fixed by wiringstreamingService.setPhase()from the engine on every phase event andstreamingService.state.update({ currentTool })on tool.starting events. VittoPhaseexpanded: Added ENHANCE, DECOMPOSE, INTEGRATE, DEPLOY to the type (was only ANALYZE/PLAN/EXECUTE/VERIFY)thinkingContextupdated: Maps all 7 generation phases to human-readable labels ("Analyzing business domain...", "Generating code...", "Deploying to GitLab...")TOOL_CONTEXT_MAP: Addedstart_module_generation→ "Generating your platform..."- Cleanup on completion:
streamingService.stopStream()ontask.completedandtask.failed - GitLab universe naming: Was using raw
universeIdas slug →universe_1772912869184_w1y1ktx. Now resolves human-readable slug from backend-api at PRE-FLIGHT time (vitto-uni-test-1). - Stale feature branches: Each generation creates a
feature/generation-{timestamp}branch. Multiple runs accumulate branches. Future: auto-close stale MRs on new generation.
Architecture State After S204
Generation Flow (Single Path)
UI (vibe-universe) → WorkflowStateService.startWorkflow()
→ GET /vitto-api/module-generation/start (SSE)
→ 7-phase pipeline: ENHANCE → ANALYZE → DECOMPOSE → PLAN → EXECUTE → INTEGRATE → DEPLOY
→ DEPLOY: GitLab commit + MR + universe manifest update
→ On GitLab failure (admin/dev + opt-in): ~/.gograb/generated/ fallback
Chat UI Streaming Architecture
Backend SSE: tool.progress { eventType: 'module-gen.phase-start', phase: 'EXECUTE', ... }
→ VittoChatEngineService.onmessage():
1. streamingService.setPhase('EXECUTE') → drives thinkingContext label
2. streamingService.state.isStreaming = true → activates thinkingContext
3. Creates progress card message (role: 'task') with tool metadata
→ VittoChatStreamingService.thinkingContext:
'EXECUTE' → "Generating code..." → shown in UI thinking indicator
→ On task.completed:
streamingService.stopStream() → resets phase, clears label
Context Chain (5 Layers)
Frontend: UniverseContextService.universeId()
→ Controller: vitto.controller.ts (universeId, spaceSlug, universeSlug in body)
→ Engine: vitto-engine.service.ts (prefers explicit over pageContext)
→ AgentLoop: agent-loop.service.ts (forwards to executeTool)
→ Tool: tool-registry.service.ts (reads from context?.universeId)
Inter-Service Communication
vitto (3003) → backend-api (3000): BackendApiClientService (users, spaces, prefs, universe slug)
vitto (3003) → backend-ai-api (3001): BackendAiClientService (handoffs, learning, modules)
ai-api (3001) → backend-api (3000): PlatformApiClientService (platform queries)
Auth: BACKEND_API_INTERNAL_TOKEN as Bearer header (same as SYSTEM_TOKEN)
Dev: localhost:{port} | Prod: {service}.gograb.space (public HTTPS)
Universe Document (After Generation)
universe {
structure: V2StructureNode[] // Navigation tree (sidebar + modules + pages)
gitConfig: { repoPath, commitSha } // GitLab repo info
deploymentStatus: 'generated' // Updated from 'draft' after successful generation
generationManifest: { // S204.20 — rich platform representation
version: '1.0',
systemName: 'Sports League Manager',
modules[]: {
name, slug, category,
entities[]: { name, fields[]: { name, type, required } },
routes[]: { path, title, pageType },
embeddables[], actions[]
},
navigation[]: { label, route, icon, order },
files: { total, paths[]: { path, language, module }, byModule[] },
quality: { score, moduleCount, entityCount, totalTokens, durationMs },
deployment: { gitLab: { commitSha, branch }, persistedModuleIds[] }
}
}
Known Gaps & Pending Work
Must Verify (Immediate — needs restart)
Chat UI "Thinking..." fix (S204.21): Frontend recompile needed. The streaming service phase wiring should replace "Thinking..." with per-phase labels. Verify by triggering generation and watching the indicator change through all 7 phases.
GitLab universe slug fix (S204.21): Backend-vitto-api restart needed. Verify that new generations create repos named
vitto-uni-test-1instead ofuniverse_1772912869184_w1y1ktx. The existing repo won't rename — only new repos use the resolved slug.Generation manifest persistence (S204.20): Verify
generationManifestappears on the universe document in MongoDB after a successful generation. Check viadb.universes.findOne({ slug: 'vitto-uni-test-1' }).
Must Fix (Next Session)
gitConfig 500 error:
PUT /spaces/{spaceId}/universes/{universeId}fails whenuniverseIdis a generated string (not MongoDB ObjectId). Backend-api expects ObjectId. Need to either: use actual universe ObjectId from creation, or make the endpoint accept slug-based IDs.Memory title field: Currently using stopgap (derive from first 80 chars of summary). Should add optional
titlefield to VittoMemory schema and populate at write time.Stale GitLab feature branches: Each generation creates a new
feature/generation-{timestamp}branch. Old branches from failed/superseded runs accumulate. Add cleanup: on new generation, close stale MRs and delete old feature branches for the same universe.
Should Improve (Near-term)
Service organization:
module-gen-phase.executor.tsis ~3000 lines. Split into focused services:GitLabDeployService(commit, MR, fallback, stale branch cleanup)UniverseManifestService(structure, manifest, gitConfig persistence)LocalFallbackService(disk write, preference check)
Module filtering: Vitto memories aren't properly scoped by userId/spaceId.
recall_vitto_memoryshould filter by the current user's space.Generated code quality: The standalone output at
~/.gograb/generated/needs anangular.jsonand proper tsconfig forng serveto work. Currently haspackage.jsonbut no Angular workspace config.Frontend generation preferences UI:
GenerationPreferencesexists in the schema but there's no UI to togglelocalFallbackEnabledor changeoutputMode. Add a section to the user settings page.
Strategic (Future Sessions)
Generation history on universe: Track multiple generation runs — each
generationManifestshould be versioned, with the latest one active and previous ones in agenerationHistory[]array. This enables diffing and rollback.Post-generation validation: After GitLab commit, trigger a CI pipeline that runs
ng buildon the generated code. Report build success/failure back to the universe document.Vitto reads manifest for context: When a user asks Vitto "what modules does my platform have?", Vitto should read
universe.generationManifestinstead of searching memories. Add aread_universe_manifesttool or enhancequery_platform.Railway internal networking: All inter-service calls go through public HTTPS domains. Railway supports private networking (
{service}.railway.internal) which would reduce latency and bypass TLS overhead.Sub-agent personality layer: Use a cheaper/faster model (Haiku) to generate Vitto's personality responses during generation phases — fun commentary, progress narration, etc. — while the main pipeline uses the full model for code generation.
Key Files Modified
| File | Lines | What Changed |
|---|---|---|
module-gen-phase.executor.ts |
~3000 | Local fallback rewrite, manifest persistence, gitCommitInfo tracking, universe slug resolution |
vitto-chat-engine.service.ts |
~830 | Phase timing, personality quips, universe context, S204.21: streaming service phase wiring |
vitto-chat-streaming.service.ts |
~200 | S204.21: expanded thinkingContext with 7 generation phases + generation tools |
chat.types.ts |
~220 | S204.21: VittoPhase expanded with ENHANCE, DECOMPOSE, INTEGRATE, DEPLOY |
task-progress-card.component.ts |
~80 | S204.21: phaseLabel map updated with all 8 phases |
user-preferences.schema.ts |
~390 | Added GenerationPreferences sub-schema |
backend-api-client.service.ts |
~270 | Added getGenerationPreferences() |
tool-registry.service.ts |
~1200 | SSE forwarding, hard error, doNotRetry, memory titles |
vitto-engine.service.ts |
~600 | universeId/slugs in params |
agent-loop.service.ts |
~400 | Forward spaceSlug/universeSlug to executeTool |
vitto.controller.ts |
~200 | Accept universeId/slugs in POST body |
universe-git.service.ts |
~500 | Slug sanitization, file dedup, optimistic commits |
generation-hub.service.ts |
73 | Deprecated stub |
chat-module-panel.component.ts |
105 | Rewired to WorkflowStateService |
Conventions Established
- Local fallback: NEVER write generated code inside monorepo.
~/.gograb/generated/only. Gated by role + preference + GitLab failure. - Generation manifest: Universe doc MUST have
generationManifestafter generation. This is Vitto's primary platform understanding. - Inter-service auth:
BACKEND_API_INTERNAL_TOKEN=SYSTEM_TOKEN. Dedicated client services inconnectivity/. - LLM tool errors: Hard
error+ explicit blocklist +doNotRetry. Never soft instructions. - GitLab slugs:
sanitizeGitLabPath()before ANY API call. Group names reject:and special chars. - Context chains: All 5 layers must explicitly pass
universeId,spaceSlug,universeSlug. Never rely on pageContext extraction. - Chat streaming: Both streaming paths (SSE engine + streaming service) must stay in sync. Engine must call
streamingService.setPhase()on phase events andstopStream()on completion. - GitLab repo naming: Always resolve human-readable universe slug from backend-api. Never use raw universeId as the repo name.
MCP Intelligence Captured
- 3 architecture decisions logged (S204.18, .19, .20) with alternatives and reasoning
- 3 outcomes reported (all successful, ratings 4-5)
- 3 conventions added (generation-pipeline x2, inter-service-communication x1)
- 1 reflection with 9 synthesized lessons
- Session context updated in auto-memory (s204-generation-pipeline.md)
Quick Start for Next Agent
# 1. Restart backend to pick up all changes
# Kill existing backend-vitto-api process, then:
yarn serve:backend-vitto
# 2. Verify frontend recompiled (Angular dev server should auto-detect changes)
# If not, restart:
yarn serve:space
# 3. Test generation E2E
# - Go to /vibe on port 6200
# - Enter a universe, type a generation prompt
# - Watch the "Thinking..." label — should cycle through phase names
# - Check GitLab: repo should use universe slug, not ID
# - Check MongoDB: universe doc should have generationManifest
# 4. Key log lines to watch in vitto-api terminal:
# [ModuleGen:Executor] PRE-FLIGHT: Resolved universe slug: "xxx"
# [ModuleGen:Executor] DEPLOY: Persisted generation manifest to universe
# [ToolRegistry] start_module_generation: Waiting for session xxx