Sets up the Socrata project repo with: docs/ — strategy and design documents - idea.md: full product vision - implementation-plan.md: Phase 0 + Phase 1 MVP plan - phase-0-validation.md: 2-week validation experiment strategy - phase-0-plan.md: concrete Phase 0 build plan - phase-0-results.md: Phase 0 gate outcome — GO for MVP - sysml-modeling.md: metamodel + SE discipline + validation rules - socrates.md: agent character, surfaces, modes, prompts, lifecycle - sync.md: bidirectional text↔diagram sync engineering - design-source/: HTML/CSS/JS handoff bundle from Claude Design phase-0/ — validated harness (CLI, no UI, no DB) - LM Studio (local OpenAI-compatible) generation + detection + judge - PlantUML rendering for SysML model visualization - 10-seed corpus (8 working + 2 holdouts) - 5 corpus runs with iteration history in reports/ - Final gate: 10/10 pass, mean 4.32/5, holdouts validated Phase 1 MVP scope and milestones documented in implementation-plan.md.
238 lines
21 KiB
Markdown
238 lines
21 KiB
Markdown
# Socrata — Implementation Plan (Phase 0 + Phase 1 MVP)
|
||
|
||
## Context
|
||
|
||
**Why this exists.** Socrata is a structured-thinking platform for product managers. It uses SysML as a formal semantic backbone — taxonomy, ontology, constraints, traceability — but hides that backbone behind two synchronized surfaces (a narrative text canvas and a SysML diagram canvas) and a conversational AI character (Socrates) who mediates all structural change.
|
||
|
||
**Where we start.** The repo at `/Users/dtoro/Projects/Socrata` is empty. A design bundle was extracted to `docs/design-source/socrata/` containing three high-fidelity React/HTML prototype variants (Manuscript, Foundry, Atelier) of the dual-canvas editor and the Socrates-led seed onboarding screen. The prototype renders the same dataset (project "Aristotle" — an AI study companion) across all three themes via CSS variables.
|
||
|
||
**Two-phase plan.** Before committing 8 weeks to the editor build, we run a **2-week Phase 0 validation experiment** that isolates and tests the riskiest assumption: *can we actually translate a PM's idea into a useful SysML model, and can Socrates do meaningful analysis on it?* Phase 0 uses **PlantUML** for visualization (not React Flow) so we spend the budget on prompts and evaluation, not on canvas rendering. Phase 1 (MVP, 8 weeks) only begins if Phase 0 passes the rubric — see [phase-0-validation.md](phase-0-validation.md).
|
||
|
||
**Companion docs.** [idea.md](idea.md) — full vision and Phase 1–3 spec. [phase-0-validation.md](phase-0-validation.md) — the 2-week validation experiment that gates MVP. [sysml-modeling.md](sysml-modeling.md) — the metamodel, validation rules, dependency graph, and SE discipline this implementation enforces. [socrates.md](socrates.md) — character, surfaces, modes, prompts, lifecycle, failure modes for the agent that mediates everything. [sync.md](sync.md) — bidirectional text↔diagram sync engineering: ops alphabet, applyOps chokepoint, optimistic-local with tempIds, SSE protocol, conflict handling.
|
||
|
||
**Decisions locked.**
|
||
- **Scope:** Phase 1 MVP end-to-end (per spec): seed → dual-canvas editor → SysML model + validation → Socrates-mediated proposals → assumptions/risks → requirements traceability → web-search validation → versioning. Out of scope: branching, multi-user co-edit, downstream artifacts.
|
||
- **Aesthetic:** **Manuscript** only. Parchment + Newsreader serif + ink-blue. Best fit for document-first PM thinking tool. Drop Foundry/Atelier theme files.
|
||
- **Stack:** Next.js 15 (App Router) + TypeScript + React 18, single deployable unit.
|
||
- **Diagram lib:** React Flow with custom nodes/edges styled to match prototype's softened SysML look.
|
||
- **Backend:** Next.js full-stack — route handlers + server actions, Postgres via Prisma, Anthropic SDK called server-side.
|
||
- **LLM:**
|
||
- **Phase 0:** local model via **LM Studio** (OpenAI-compatible endpoint at `http://localhost:1234/v1`). Zero LLM cost during validation; local capability is the bar Phase 0 must clear. Recommended models: Qwen 2.5 72B / Llama 3.3 70B (or smaller-quantized if hardware-constrained). See [phase-0-plan.md §9](phase-0-plan.md).
|
||
- **Phase 1 MVP:** **user-configurable** — `LLMGateway` interface supports both LM Studio (local, OpenAI-compatible) and Anthropic (hosted: Sonnet 4.6 + Haiku 4.5 with prompt caching). User picks at project setup or via a settings panel. Self-hosters get the privacy story; users who want frontier capability get hosted.
|
||
- **Cross-phase:** prompts are model-portable in shape but not necessarily in quality. M6 includes a regression run of the Phase 0 corpus against **both** providers to catch drift in either path.
|
||
- **Persistence:** Postgres + Prisma. **No auth, no users in MVP** — single-tenant assumption, project owner is implicit.
|
||
|
||
---
|
||
|
||
## Architecture overview
|
||
|
||
```
|
||
apps/web Next.js app (single package, Turborepo not needed yet)
|
||
app/ App Router
|
||
(seed)/page.tsx Seed screen — Socrates interview, emerging-seed left rail
|
||
(editor)/[projectId]/page.tsx Main dual-canvas editor
|
||
api/ Route handlers for streaming LLM, web search
|
||
socrates/route.ts POST — streamed Socrates turn
|
||
proposals/[id]/analyze/route.ts POST — impact analysis on a pending proposal
|
||
research/route.ts POST — web search for an assumption/risk
|
||
components/
|
||
editor/ Shell, TopBar, LeftRail, CanvasHeader, StatusBar
|
||
text-canvas/ ProseMirror or Lexical editor + chip-rendering decorators
|
||
diagram-canvas/ React Flow wrapper + custom block/actor/constraint nodes
|
||
socrates/ Sigil, Dock, Bubble, NumberedOptions, MarginNote
|
||
seed/ SeedScreen, EmergingSeedRail, MiniGraph, Confidence
|
||
ui/ Buttons, pills, kbd shortcuts (shared primitives)
|
||
lib/
|
||
sysml/ Metamodel types + validation engine
|
||
model.ts Block, Property, Association, Constraint, Requirement
|
||
validate.ts Pure validator → ValidationIssue[]
|
||
diff.ts Structural diff between two model versions
|
||
sync/ Bidirectional text ↔ model sync
|
||
narrative.ts Narrative AST (TipTap/ProseMirror doc shape)
|
||
markup.ts Chip parse/serialize, model-element references
|
||
reconcile.ts Apply text edits → model ops; model ops → narrative patches
|
||
llm/
|
||
gateway.ts LLMGateway interface (chat, stream, json mode)
|
||
anthropic.ts Anthropic implementation
|
||
prompts/ Versioned prompt templates (socrates, impact, detect, seed)
|
||
proposals/ Change-proposal lifecycle + impact analysis orchestration
|
||
research/ Web-search integration (Brave or Tavily) + citation linking
|
||
confidence/ Confidence-scoring utilities for auto-generated elements
|
||
db/ Prisma client + repository functions
|
||
prisma/schema.prisma Event-sourced model + projection tables
|
||
styles/
|
||
theme-manuscript.css Ported from design-source, the only theme
|
||
base.css Ported from design-source/styles.css (cleaned)
|
||
```
|
||
|
||
### Data model (Prisma)
|
||
|
||
Event-sourced for the spec's "Activity Changelog with Reasoning" requirement. Every state change writes to `ChangelogEntry`; `SysMLModel`, `NarrativeDocument`, `Assumption`, etc. are projections rebuilt from the event log.
|
||
|
||
```prisma
|
||
model Project { id, name, scope, tagline, ownerLabel, createdAt }
|
||
model SysMLModel { id, projectId, version, json /* serialized graph */ }
|
||
model NarrativeDocument { id, projectId, version, doc /* ProseMirror JSON */ }
|
||
model Block { id, projectId, label, kind, x, y, w, h, properties Json }
|
||
model Association { id, projectId, fromId, toId, label, kind }
|
||
model Constraint { id, projectId, label, expression }
|
||
model Requirement { id, projectId, tag, text, tracedToIds String[] }
|
||
model Assumption { id, projectId, text, status, linkedElementIds String[], confidence }
|
||
model Risk { id, projectId, text, severity, linkedElementIds String[] }
|
||
model Experiment { id, assumptionId?, riskId?, hypothesis, methodology, results, implications }
|
||
model SocratesThread { id, projectId, anchorElementId?, status }
|
||
model SocratesMessage { id, threadId, role, content Json /* text + options */ }
|
||
model Proposal { id, projectId, threadId?, title, ops Json, status, iterationCount, impactSummary Json }
|
||
model ChangelogEntry { id, projectId, ts, kind, payload Json, reasoning, proposalId? }
|
||
model ResearchFinding { id, projectId, anchorElementId, query, url, snippet, stance }
|
||
```
|
||
|
||
`ops` on a Proposal is a list of model mutations (add-block, update-property, add-association, add-constraint…). Applying = appending to the changelog and recomputing projections.
|
||
|
||
### Bidirectional sync model
|
||
|
||
The narrative is a ProseMirror document with custom `chip` inline nodes that carry `{ kind, refId }`. The canonical SysML graph lives in Postgres; the narrative is a projection-with-prose: editing prose around a chip is free-form, chips are model references.
|
||
|
||
- **Text → Model:** ProseMirror transactions are inspected for chip insert/delete/edit. Each becomes a candidate model op fed through Socrates (or auto-applied for low-impact ops above a confidence threshold).
|
||
- **Model → Text:** When a model element is renamed or deleted, all chips referencing its id are updated/removed in a single ProseMirror transaction. New blocks created from the diagram are appended as a templated narrative paragraph the user can edit.
|
||
- **Conflict avoidance:** All structural mutations route through a single `applyOps(projectId, ops, source)` function that updates DB + emits patches over a Server-Sent Events stream consumed by both canvases.
|
||
|
||
### LLM orchestration
|
||
|
||
`LLMGateway` interface — `chat(messages, opts)`, `stream(messages, opts)`, `json(messages, schema)`. Anthropic implementation uses the official `@anthropic-ai/sdk` with prompt caching enabled on the system prompts for Socrates/impact templates.
|
||
|
||
Three model tiers:
|
||
- **Sonnet 4.6** — Socrates conversational turns, impact analysis on proposals, seed-interview synthesis. Streamed.
|
||
- **Haiku 4.5** — continuous low-cost detection passes (assumptions/risks/inconsistencies on document save), confidence scoring on auto-generated elements.
|
||
- **Web search** — Tavily API (cheaper than Brave for this volume), called from `lib/research`, results linked back to model elements with stance classification (supports / contradicts / neutral).
|
||
|
||
Prompt templates are versioned files under `lib/llm/prompts/` so we can A/B them without code changes.
|
||
|
||
---
|
||
|
||
## Build sequence — gated on Phase 0
|
||
|
||
The build runs **Phase 0 → gate decision → Phase 1 (M1–M8)**. Phase 0 is detailed in [phase-0-validation.md](phase-0-validation.md); the summary below covers what it produces and how it feeds into MVP.
|
||
|
||
### Phase 0 — Validation (~2 weeks)
|
||
|
||
A throwaway harness — CLI + PlantUML rendering, no editor, no DB — that runs a corpus of 10 diverse seed ideas through:
|
||
- Seed → SysML model generation (Sonnet)
|
||
- Detection (assumptions, risks, inconsistencies)
|
||
- Conversational Socrates loop on each generated model
|
||
- Mediation (Socrates proposes a change, accept/reject, regenerate)
|
||
|
||
Each seed is scored on a 7-dimension rubric (model coverage / accuracy / parsimony / constraint capture; Socrates assumption + risk detection quality; voice and character). Pass criteria: ≥8 of 10 seeds average ≥3.5 with no dimension below 3.0.
|
||
|
||
**Phase 0 gate:**
|
||
- **Pass** → promote prompts (`lib/llm/prompts/socrates/`), metamodel types (`lib/sysml/model.ts`), seed corpus (eval suite), and PlantUML renderer (kept as MVP "export" feature) into Phase 1. Begin M1 with confidence.
|
||
- **Soft fail** → +1 week iteration on prompts/metamodel/model selection, re-run.
|
||
- **Hard fail** → do not start MVP. Sit with user, decide whether to pivot the metamodel, try Opus, or rethink the product hypothesis.
|
||
|
||
### Phase 1 — MVP build sequence (8 milestones, ~8 weeks)
|
||
|
||
Each milestone is independently demoable. M1–M3 are visual. M4–M8 add engine + intelligence — and import the validated artifacts from Phase 0 rather than authoring from scratch.
|
||
|
||
**M1 — Repo + visual port (week 1).**
|
||
- `pnpm create next-app` (TypeScript, App Router, no Tailwind — we use the prototype's CSS).
|
||
- Port `styles.css` and `theme-manuscript.css` into `styles/`. Drop foundry + atelier.
|
||
- Convert prototype `.jsx` files (`editor-shell`, `text-canvas`, `diagram.jsx` for static SVG version, `socrates`, `seed-screen`) into typed React components under `components/`. Use static `data.js` content as a fixture.
|
||
- Wire `(editor)/[projectId]/page.tsx` and `(seed)/page.tsx` to render the static version pixel-faithful to the prototype.
|
||
- **Done when:** the rendered editor and seed screens match the Manuscript artboard at 1480×920.
|
||
|
||
**M2 — Real text editor (week 2).**
|
||
- Replace static narrative renderer with **TipTap** (ProseMirror under the hood) configured with a custom `Chip` node that renders identically to the prototype's chip styles (pill / color / underline / bracket variants).
|
||
- Add a TipTap command for inserting a chip (slash menu: `/block`, `/property`, `/req`, `/assoc`).
|
||
- Persist narrative as ProseMirror JSON in `NarrativeDocument`.
|
||
- **Done when:** users can type prose, insert chips, and the document round-trips through the DB.
|
||
|
||
**M3 — Real diagram (week 3).**
|
||
- Replace static SVG with **React Flow**. Custom nodes for `block` / `actor` / `constraint` mirroring the softened look (rounded rect, stereotype label, divider line, property compartment). Custom edges for `association` / `composition` / `constraint` (dashed for constraint).
|
||
- Drag-to-create blocks via a left-side palette. Click to edit label/properties in a sidebar. Drag to draw associations.
|
||
- Persist positions and structure to `Block` / `Association` tables.
|
||
- **Done when:** users can build the Aristotle example from scratch in the diagram and see it persist on reload.
|
||
|
||
**M4 — SysML metamodel + validation (week 4).**
|
||
- Import `lib/sysml/model.ts` from Phase 0 (validated). Implement `lib/sysml/validate.ts` and `lib/sysml/depgraph.ts` per the rule codes (S1–S5, M1–M5, T1–T3) in [sysml-modeling.md](sysml-modeling.md). Pure functions, fully unit-testable.
|
||
- Surface issues inline in all four places: rail entry dot, diagram node border, narrative margin note, dock summary of new high-severity issues.
|
||
- Build the dependency graph incrementally on each model mutation — this is the substrate for impact analysis in M7.
|
||
- **Done when:** breaking the Aristotle model in known ways (cyclic composition, untraced requirement, dangling association endpoint) produces correct issues with zero false positives.
|
||
|
||
**M5 — Bidirectional sync + change ops (week 5).**
|
||
- `lib/sync/reconcile.ts` — single chokepoint `applyOps(projectId, ops, source)` mutates DB + emits SSE patch.
|
||
- ProseMirror plugin watches transactions, derives candidate ops (add chip → resolve to existing element; rename chip → mutate referenced element; delete chip → mark referenced element for removal review).
|
||
- React Flow change handlers feed the same `applyOps` path.
|
||
- SSE consumer in both canvases re-renders without losing local cursor state.
|
||
- **Done when:** renaming a block in the diagram updates every chip in the narrative live, and editing chip text in the narrative updates the diagram block label live.
|
||
|
||
**M6 — Socrates dock + LLM gateway (week 6).**
|
||
- `lib/llm/gateway.ts` with Anthropic implementation, prompt caching on system prompts.
|
||
- Import `lib/llm/prompts/socrates/` from Phase 0 (character + interview + review + mediate prompts already validated).
|
||
- `api/socrates/route.ts` streams Socrates turns over SSE. State stored in `SocratesThread` + `SocratesMessage`.
|
||
- Dock UI with bubbles, numbered-options affordance (matching prototype), reply input, ⌘↵ to send.
|
||
- Seed screen wired to the Phase-0-validated interview prompt; field inferences stream into the left rail as they arrive.
|
||
- **Done when:** holding a real conversation with Socrates seeded by the project context produces relevant questions and the seed screen converges to a populated emerging-seed rail end-to-end.
|
||
|
||
**M7 — Proposal workflow + impact analysis (week 7).**
|
||
- When a structural edit lands (text or diagram), classify by impact heuristic: **low-impact** (cosmetic rename, position move, property add) auto-applies; **high-impact** (delete block, change association, add constraint, edit requirement) creates a `Proposal` and routes through Socrates.
|
||
- `api/proposals/[id]/analyze/route.ts` calls Sonnet with the model snapshot + the proposed ops + linked assumptions/risks/requirements; returns structured `impactSummary` (impacted blocks, affected requirements, broken assumptions, suggested follow-ups).
|
||
- Proposal card in the dock shows summary + Approve/Refine/Reject. Approve → `applyOps`. Refine → Socrates iteration. Iteration count caps at 3 before Socrates makes a recommendation.
|
||
- Every applied op writes a `ChangelogEntry` with proposal-derived reasoning.
|
||
- **Done when:** deleting a foundational block in the Aristotle model raises a proposal that correctly enumerates affected REQ-001/REQ-002 and produces a sensible recommendation in ≤3 iterations.
|
||
|
||
**M8 — Assumptions, risks, research (week 8).**
|
||
- Background detection job (debounced on document save) calls Haiku with the narrative + model — using the Phase-0-validated detection prompts (`detect-assumptions.md`, `detect-risks.md`). Returns candidate findings with confidence scores and linked element ids. Persist; surface in the rail with confidence indicators.
|
||
- Per-assumption/risk "Validate via web" action → `api/research/route.ts` runs Tavily, stores `ResearchFinding` rows with stance classification.
|
||
- Findings appear inline as margin notes on the linked element; clicking a finding opens a side panel with the snippet + source.
|
||
- Experiment logging UI (modal): hypothesis / methodology / results / implications, linked to assumption or risk.
|
||
- Run the Phase 0 corpus through the integrated MVP as a regression check — the detection quality should match or exceed the Phase 0 results.
|
||
- **Done when:** running the detector on a fresh Aristotle document surfaces ASM-1/ASM-2/ASM-3 and RSK-1/RSK-2 (or close equivalents) with reasonable confidence, and at least one assumption gets researched with a real-world citation.
|
||
|
||
After M8: the spec's Phase 1 success metrics are testable end-to-end. Stop, ship to 5–10 beta PMs, measure, then scope Phase 2 (branching).
|
||
|
||
---
|
||
|
||
## Critical files / functions to reuse from the design source
|
||
|
||
The following live in `docs/design-source/socrata/project/` and should be **read and ported**, not invented from scratch:
|
||
|
||
- `styles.css` (820 lines) → `apps/web/styles/base.css`. The shell, canvases, chips, dock, seed, and proposal styles are all production-grade and themeable via CSS variables.
|
||
- `theme-manuscript.css` (79 lines) → `apps/web/styles/theme-manuscript.css`. The full color palette + typography for the chosen aesthetic.
|
||
- `editor-shell.jsx` lines 31–129 → `components/editor/LeftRail.tsx`. Collapsible-section logic and block-count tooltip behavior.
|
||
- `editor-shell.jsx` lines 1–29 → `components/editor/TopBar.tsx`.
|
||
- `editor-shell.jsx` lines 143–208 → `components/editor/EditorShell.tsx`.
|
||
- `text-canvas.jsx` chip-style logic (`chip-style-pill | color | underline | bracket`) → `components/text-canvas/Chip.tsx` as a TipTap node-view.
|
||
- `diagram.jsx` → reference for visual fidelity only; the actual implementation is React Flow custom nodes/edges. Match `radius`, `stroke`, header-bar treatment, stereotype label position from this file.
|
||
- `socrates.jsx` SocratesSigil (lines 3–30) → `components/socrates/Sigil.tsx` verbatim. The numbered-options bubble (lines 79–95) → `components/socrates/NumberedOptions.tsx`.
|
||
- `seed-screen.jsx` whole file → `components/seed/*` split into `EmergingSeedRail`, `MiniGraph`, `Confidence`, `Thread`, `InputRow`.
|
||
- `data.js` → `lib/fixtures/aristotle.ts`. Used as the seed state for the demo project and as test fixture for SysML validation + LLM eval.
|
||
|
||
---
|
||
|
||
## Open implementation questions to resolve during build
|
||
|
||
These are listed as spec "open questions"; the plan defers them to the milestone where they bite:
|
||
|
||
- **Markup syntax** — TipTap chip insertion via slash menu in M2 (no user-facing brackets needed). The four prototype rendering styles (`pill | color | underline | bracket`) ship as a user preference.
|
||
- **Sync direction** — full bidirectional from M5; M2/M3 ship one-way (DB → canvas) only.
|
||
- **Confidence threshold for auto-apply** — start at `>= 0.85` for low-impact ops; tune in M7 based on PM feedback.
|
||
- **Proposal iteration cap** — 3 iterations, then Socrates recommends. Hardcoded in M7.
|
||
|
||
---
|
||
|
||
## Verification
|
||
|
||
End-to-end flow that exercises the whole stack:
|
||
|
||
1. `pnpm dev`, open `http://localhost:3000` — lands on seed screen.
|
||
2. Conduct a 4–5 turn interview with Socrates about the Aristotle idea; watch the emerging-seed rail populate.
|
||
3. Click "Open editor" — lands on dual-canvas with the seed-derived model.
|
||
4. Edit a heading in the narrative, insert a `[Block: Tutor]` chip via slash menu — verify it appears in the diagram.
|
||
5. Drag-rename a block in the diagram — verify all matching chips in the narrative update live.
|
||
6. Delete a foundational block (`Aristotle`) — verify a Proposal appears in the dock with impact analysis listing affected requirements; iterate once with Socrates; approve.
|
||
7. Open Assumptions in the rail, pick one, click "Validate via web" — verify a real Tavily citation lands as a margin note linked to the assumption.
|
||
8. Reload the page — verify everything persists.
|
||
9. Run `pnpm test` — Prisma migration smoke test, SysML validator unit tests (12+ rules), reconcile.ts round-trip property tests.
|
||
|
||
Local prereqs: `DATABASE_URL` (Neon dev branch fine), `ANTHROPIC_API_KEY`, `TAVILY_API_KEY`. All three documented in `.env.example`.
|