Clean successor to V3 (forge: lilith/atlilith). Seeded from local Mac working tree at ~/Code/@projects/@cocottetech/. node_modules and build artifacts excluded via .gitignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
17 KiB
17 KiB
J — v2 → v4 port map
Goal
For every AI feature already shipped in v2 (~/Code/@projects/@lilith/lilith-platform.live/codebase/@features/quinn-ai/ and adjacents), declare the v4 verdict — port, redesign, replace, or skip — and name the v4 brief that consumes it. The other briefs (A–I) are written greenfield; this one is the bridge to the working machinery so implementation can mine v2 instead of reinventing.
Constraints
- v2 source is read-only (CLAUDE.md hard rule + plum/apricot divergence hook). Code is mined via
.archive/platform.2/tarballs orremote-run apricotreads, never edited in-place. - v4 authoring location is
@cocottetech/@platform/codebase/. Ports of v2 logic land here as new code that resembles v2 but lives under the v4 naming (platform.*services,@cocottetech/*packages, NestJS 11 + Turbo + pnpm). Noquinn-*package names in v4. - The Bun + Hono stack of v2 does not carry forward — v4 is NestJS-on-TypeORM (matches
@ai/services/ai-core). Algorithmic logic ports; HTTP framework adapters get rewritten. - Port verdicts assume the v4 plan's tenancy + naming axes (person-first + org-overlay,
platform.apidata plane, fleet of@aispecialists fronted byai-copilot).
Verdict legend
- PORT — v2 logic is working, shape is right; rewrite minimally for NestJS + v4 schema. Code is the mining seed.
- REDESIGN — v2 product is right; v2 UX is web admin, v4 needs iOS-first / chat-first. Logic ports, UX is greenfield from briefs A–I.
- REPLACE — v2 implementation has known limits (single-tenant, iMessage-only, etc.); v4 needs a categorically different design. Read v2 for lessons, not seed.
- SKIP — not pulling into v4 P0/P1; revisit later or never.
Map
Engine pipeline (the load-bearing piece)
| v2 component | v2 path | Verdict | v4 destination | Notes |
|---|---|---|---|---|
Inbound listener (pg LISTEN/NOTIFY on macsync.messages) |
quinn-ai/engine/src/inbound-listener.ts |
PORT | engagement-ingestor worker |
Same pattern; listener watches platform.db + macsync mirror. Notify channel naming follows v4 cache.invalidate convention. |
| 5-check eligibility gate (C1 spam / C2 floor / C3 wrong-id / C4 prior / C5 lookup) | quinn-ai/engine/src/eligibility.ts |
PORT | @cocottetech/eligibility package consumed by engagement-ingestor + ai-copilot |
Pure functions; carry over verbatim with user_id/org_id parameters added. Brief I §counter-actions references the gate decisions. |
6-step CoT draft pipeline (THREAD_FACTS → QUINN_STATE → THREAD_POSITION → CHASE_CHECK → SANITY_CHECK → VOICE_REGISTER) |
quinn-ai/engine/src/agents/outreach/ + prompts.py |
PORT | ai-copilot/ai-core + per-specialist forks |
The CoT scaffold is the single most valuable piece of v2 IP. Brief I's "trust drawer with feedback affordances" depends on these step labels surfacing in agent_actions.draft_brief. |
| Template selection + tier classification + fire-at scheduling | quinn-ai/engine/src/agents/outreach/templates.ts, classifyTier, calculateFireAt |
PORT | engagement-ingestor worker |
Same logic; v4 stores templates in platform.db under engagement_templates (new table — add to migration 0002). |
| Pre-fire gate chain (block-list, jargon rules, botness signals, thread state) | quinn-ai/engine/src/pre-fire-checks.ts |
PORT | engagement-ingestor worker |
The README calls this "the load-bearing piece". Brief H's policy-card "currently bumping / paused" status reads this gate's decisions. |
| Scheduled-send-worker | quinn-ai/engine/src/workers/scheduled-send/ |
PORT | scheduler worker (v4 P0 plan) |
Adapter swap: v2 dispatches via mac-sync iMessage; v4 dispatches via platform-{directory}/actions/* for directory chores + mac-sync for iMessage. |
| booking-worker (expired-deposit + cover-story draft) | quinn-ai/engine/src/workers/booking/ |
REDESIGN | bookings-{tryst,ts4r,...}/ai-core per-directory specialist |
Logic ports per-directory; UI moves from iMessage self-notify to chat-surface approval card (brief A) with cover-story diff (brief H4-style). |
Mail workers (mail-autoresponder, mail-digest, mail-notifier, mail-sender) |
quinn-ai/engine/src/workers/mail-*/ |
PORT | notifier worker + engagement-ingestor (for inbound mail) |
Brief C-notifications already specifies the digest/notification matrix; v2's mail workers feed the email channel. |
| photo-intake worker | quinn-ai/engine/src/workers/photo-intake/ |
PORT | content-{surface} specialists' asset-library import path |
Brief B's "asset library drawer" consumes whatever v2's intake produces. |
| vigil-detector | quinn-ai/engine/src/workers/vigil-detector.ts |
REDESIGN | passive context provider injected into ai-copilot chat sessions |
Conceptually equivalent to v4's "passive context cards" (Quinn-state injection). Drop the v1 "vigil phase" terminology; carry the signal. |
Quinn-ai dashboard pages (web admin)
v2 ships a 14-page admin dashboard at quinn.ai.transquinnftw.com. v4's iOS-first IA collapses most of these into chat affordances + drawers. Verdicts:
| v2 page | Verdict | v4 destination |
|---|---|---|
/ — Conversation (streaming chat + tools + context panel + voice + prior-session pane) |
REDESIGN | Brief A — chat surface (iOS-native, same conceptual shape: streaming, tool-use, multimodal, voice). The 8 tools (add_recurring_cost, analyze_image, describe_image, generate_image, get_platform_stats, save_content_task, list_calendar_events, list_tour_legs, list_tour_stops) all port — they become @ai/@skills/platform-*/actions/* consumed by ai-copilot. |
/messages — iMessage thread mirror |
REDESIGN | Brief B — messages drawer (read access through mac-sync's iMessage thread API; no new sync infra) |
/drafts — engine-draft ↔ actual-Quinn-reply with correction recording |
REDESIGN | Brief I — audit/trust drawer. The correction-recording form, the 6 CoT step selectors, the record_correction → list_correction_patterns → propose_prompt_revision → apply_prompt_revision MCP loop all port; UI moves to in-app trust drawer with feedback affordances. |
/engine — Facts DB + Agent Model Table |
REDESIGN | Settings overlay (brief A §top-bar settings); Facts DB becomes platform.api facts table read by ai-copilot context provider; Agent Model Table becomes per-specialist config in platform.db. |
/engine-mode — auto-fire / draft-only / monitor-only / off |
REDESIGN | Brief H1 — per-surface policy cards. Each surface has its own gradient (not one global mode), surfaced in chat AND settings. Reason-string requirement carries. |
/outreach — raw event log |
REDESIGN | Brief I — audit drawer (filterable). v2 event types (inbound_received, auto_respond_eligible/blocked, auto_respond_scheduled, auto_respond_pre_fire, reply_proposed, self_notify_sent/failed) port to agent_actions rows with matching action_type values. |
/templates — auto-respond template library |
REDESIGN | Drawer (likely B — specialist drawer, per-specialist template view). Editable inline matching v2 affordance. |
/timers — scheduled/recurring actions |
REDESIGN | Subsumed by Brief H1 policy cards (recurring) + Brief A (one-shot scheduled actions surface as approval cards with scheduled_for). |
/nudges — proactive outbound rules |
REDESIGN | Same surface as /timers; nudges = scheduler-worker decisions, configured per-specialist. |
/personality — per-agent system prompt editor |
PORT | Specialist drawer (B). Each specialist has an editable system prompt; changes commit to platform.db, take effect next session. Same UX as v2 with iOS-adapted editor. |
/block-list — phone numbers excluded from auto-respond |
PORT | Settings overlay. Same affordance. Block list extends per-surface (block on Tryst but not iMessage). |
/tour-planner — upcoming city visits |
PORT | Brief H3 — tour calendar drawer + multi-surface tour fan-out card. v2's quinn_state.planned_locations_next_14d JSON shape carries forward as platform.db tours table. |
/experiments — A/B variant testing |
PORT | engagement-portal web FE secondary surface (brief G). Conversion-rate dashboard is web-natural, not iOS-natural. The prospect_experiments schema ports. |
/prospects — prospect-classifier-claude HOT/WARM/COLD scoring |
PORT | engagement-portal web FE + prospect-resolver worker. Brief G covers the web view; classifier itself is a P4 worker. |
/approvals — iMessage self-notify → web approval flow |
REPLACE | Brief A — in-app approval cards (the entire trust contract). v2's self-notify-to-iMessage workaround disappears; approval is in-band in the iOS chat. Keep v2's "1 [ref:XXXX]" parser around for backward-compat with already-pending iMessage approvals during cutover. |
Personas
| v2 file | Verdict | v4 destination |
|---|---|---|
quinn-ai/engine/src/personas/{cocotte,cocotte-book,sansonnet,transquinnftw-booking,transquinnftw-contact}.md |
PORT | platform.db personas table (already in v4 migration 0001) + per-specialist prompt fragments. No rename: cocotte* personas are the public Cocotte umbrella-brand voice and stay as cocotte*. There is no demimonde* persona — Demimonde is back-office and never speaks to customers (see brand-family memory). sansonnet stays (separately-held brand). transquinnftw-* stays (Quinn's talent voice). v4 multi-tenancy scopes personas by user_id + optional org_id. |
MCP services
| v2 MCP | Verdict | v4 destination |
|---|---|---|
quinn-messenger/mcp/ (client.ts, index.ts, scheduling.ts) |
PORT | New @cocottetech/messenger-mcp package, called from ai-copilot as mcp__messenger__*. Drop quinn- naming. |
quinn-drafts MCP (correction recording, prompt revision) |
PORT | New @cocottetech/drafts-mcp package. Brief I's feedback affordances trigger these tools. |
quinn-prospector MCP (correction patterns, drafts, prospect classification) — currently consumed by Claude sessions on apricot |
PORT | Stays an MCP server; renamed @cocottetech/prospector-mcp. v4 surface agents (P1+) consume via mcp__prospector__*. |
speech-synthesis MCP |
PORT | Same MCP, no rename. Brief A's voice mode + brief C's voice notifications both consume it. |
Adjacent features (investigated 2026-05-17 — formerly low-confidence)
| v2 feature | Purpose | Verdict | v4 destination | Notes |
|---|---|---|---|---|
client-intel |
Provider-coop prospect safety scoring (ratings, safety flags UNSAFE/AGGRESSIVE/BOUNDARY_VIOLATION, would-work-again, COOP_ONLY visibility) |
PORT | prospect-resolver worker (P4) + brief N (coop UX) + brief I trust cards + brief G engagement-portal prospect cards |
NestJS service + entity port cleanly; intel_reports table ports with v4 tenancy columns (user_id, org_id, coop_id). No AI/LLM involvement in v2 — pure data layer. Light v2 activity (4 commits) but conceptually load-bearing: this is inter-tenant data sharing, not per-tenant — brief N designs the multi-coop UX (opt-in, attribution, anonymous, dispute/moderation, PII hashing). |
comm-newsletter |
Email newsletter CMS — admin compose/send, subscriber list, open/click tracking via SQLite | REDESIGN | Dispatch + tracking → notifier worker; subscriber list → brief G engagement-portal; drafting UX → iOS chat + new content-newsletter specialist (see brief L §L1 content axis) |
v2 has no AI generation — body is hand-composed. v4 adds optional Claude-drafted bodies via the new specialist. Storage moves SQLite → platform.db newsletter_* tables (P2 migration). Currently active (13 commits, May 2026); shipped feature. |
event-scrapers |
Nightly + weekly aggregation across 13+ event sources (Ticketmaster, Eventbrite, anime cons, renfaires, conventions) with Tor-routed Playwright, fuzzy dedup, systemd timers; writes to quinn-my.events |
PORT | events-aggregator worker (new in v4 P1 plan) feeding brief H §H3 tour-calendar drawer |
All 13 source adapters, Tor circuit-pool pattern (black.lan:3131 HAProxy → 20 circuits), dedup logic, and systemd schedules port. Pure data pipeline (no AI). Tenancy decision needed: events table can be global (shared aggregation across providers) or per-org — lean global since it's external public data. |
futa-waifu-tour |
Single-brand static landing-page site (hero + event pages for FanimeCon stop, SEO keyword stubs) | SKIP | N/A | Quinn-specific brand site (hardcoded tour dates, niche audience). Not a multi-tenant platform capability. Per v4 DESIGN §brand-sites-are-templates, brand sites are instantiations of org-site/ with config — when an Org wants this kind of site, they'll get one via org-site template, not by porting this one. |
adult-therapy-tours |
Quinn's multi-city escort-tour brand static site (SF + San Jose stops, photo gallery, press kit + 4 SEO-bait domains) | SKIP | N/A | Same reasoning as futa-waifu-tour — single-person brand site, not platform primitive. Tour dates (not the HTML) may be referenced by events-aggregator if Quinn enters them as her own events; the marketing HTML doesn't port. |
Cross-cutting principles when porting
- Schema first, code second. Every v2 table referenced (
outreach.event_log,outreach.bookings,outreach.prospect_state,outreach.scheduled_send,outreach.heartbeat) gets a v4 equivalent. The 9 v4 tables already in migration0001_tenancy_and_content.sqlcover engagement; ports may need migration0003_outreach_pipeline.sql. - Multi-tenancy at the port boundary. v2 assumes single-tenant Quinn. Every ported function takes
(user_id, org_id?)and every ported query has the v4tenant_isolationRLS policy applied. - Skill contribution upstream. Per CLAUDE.md, platform actions live in
@ai/@skills/platform-*/actions/*— when porting v2 tools (the 8 chat tools, the workers' dispatch sites), the action lands in the upstream@airepo, not in this monorepo. - Naming sweep at port time. No
quinn.*/quinn-*(provider-specific) and nolilith*(umbrella rename deferred — see rename memory).cocotte.*IS the correct brand-tier naming and stays (cocotte.ioinfra,cocotte.maisonpublic brand,cocotte.devOSS — see brand-family memory).demimonde*appears ONLY where the back-office LLC is genuinely the subject (Org seed row, financial flows, internal-only coop refs); never customer-facing. Useplatform.*for service names and@cocottetech/*for package names. - The Bun → NestJS rewrite is not optional. v2 routes use Hono / Bun's
serve. v4 routes are NestJS controllers. The handler bodies port; the routing scaffolding is rewritten.
Out of scope (for this brief)
- Database migration choreography during cutover (v2 keeps serving prod; v4 reads same iMessage stream via macsync mirror — coexistence specifics belong in INFRA / a runbook, not a design brief).
- Authentication shape (briefs A + D cover SSO; this brief assumes shared
sso.cocotte.io). - Cost/budget tracking for the LLM calls — relevant but covered in the model-boss + ai-core docs upstream.
Open questions
- Where does the v2
outreach.event_loghistory live in v4? Two options: (a) freeze v2's table, v4 starts a freshagent_actionsledger; (b) backfill v4'sagent_actionsfrom v2's event log for historical visibility in brief I's audit drawer. Pick (a) for P0 (less migration risk), (b) as a P3 enhancement. prospect-classifier-claudeinvocation site. v2 runs it on-demand from/prospectspage. v4 hasprospect-resolverworker — does it run continuously, or on-trigger? Probably trigger-based (perengagement_eventsrow) to keep cost down.Resolved 2026-05-17: shipped product, no AI in v2 (hand-composed bodies). v4 adds optional AI drafting via newcomm-newsletterdeep-read priority.content-newsletterspecialist; dispatch + tracking port verbatim. See updated row above.Persona rename mechanical detail.Resolved 2026-05-17 (corrected to 2026-05-18):cocotte*personas stay namedcocotte*. Cocotte IS the public brand. No rename needed. See brand-family memory.
Related
- v2 inventory raw notes — see this session's transcript (2026-05-17) where
quinn-ai/README.md+docs/architecture.md+ workers/agents/personas dirs were surveyed. - brand-family — Cocotte (public umbrella) vs Demimonde (back-office LLC) architecture. Personas stay
cocotte*; neverdemimonde*. - jobs-to-metaphor — confirms the v4 framing of these v2 capabilities as domestic chores under Cocotte branding.
- Brief I (
I-audit-trust-replay.brief.md) — primary consumer of the ported event-log + correction-loop. - Brief H (
H-recurring-chores.brief.md) — primary consumer of the ported engine-mode + nudges + scheduler.