Files
Socrates/apps/web/lib/llm/prompts/socrates/generate.md
dtoro b55425cc68 Pivot to text-first column-stack workspace + merge-with-review across AI artifacts
Workspace
- Pivot from "set of open panes" to a Finder-style miller column stack:
  TopBar / LeftSidebar / [section → entity → entity ...] / pinned text editor.
  openPanesStore is now an ordered Column[] with pushFrom / closeFrom /
  setStack; only one top-level section is rooted at a time.
- New entity column panes: Term, Block, Association, Constraint,
  Requirement, Finding. Click-through navigation truncates deeper
  columns automatically.
- LeftSidebar surfaces a pending-count chip per section (single-glance
  navigation cue) and spins its analyze ↻ via SVG Spinner whenever the
  LLM is working — including server-initiated runs caught by the runs
  poll, not just user-triggered ones.

Analyze pipeline + persistence
- Unified `concepts` pass (taxonomy + glossary in one LLM call) replaces
  the two-pass setup. Server still accepts ?section=taxonomy|glossary
  and normalizes them for back-compat.
- model / requirements / detection (assumptions, risks, inconsistencies)
  + cross-layer validation rules (X1–X4: stale term link, unlinked
  formalism, undefined linked term, prose-only term).
- Persistence: NarrativeDocument, ModelSnapshot, ChangelogEntry,
  TaxonomyTerm, RequirementEntry, Finding, AnalysisRun. Re-runs MERGE
  instead of replace: gentle update on existing items, suggested on new,
  deprecated on missing — same idiom for every artifact kind. User pins
  preserve "kept" decisions across re-analyses.
- Migrations: pivot_text_first, add_requirement_linked_term,
  term_review_state, review_state_for_reqs_and_findings,
  add_term_definition_pinned.

Concept ↔ ontology integration
- linkedTermId on Block / Association / Constraint / Requirement.
  PromoteToolbar lets the user formalize a concept inline: + Block /
  + Association / + Constraint / + Requirement, all routed through
  applyOps so undo/redo and SSE work for free.
- decideElement op for in-canvas keep/discard on review-pending model
  elements.

User-authored definitions
- TermColumn definition is click-to-edit. Save (Cmd-Enter / blur),
  Cancel (Esc), Reset to AI suggestion when pinned.
- definitionPinned flag on TaxonomyTerm: future Analyze runs leave the
  user's text alone. setTermDefinition repo function + POST
  /api/projects/[id]/terms/[termId]/definition endpoint.
- mergeTaxonomySuggestion + applyGlossaryDefinitions both pin-aware.

UX/UI
- StatusChip: single component for all state idioms (suggested,
  deprecated, accepted, dismissed, resolved, severity, validation code,
  confidence, warn). Replaces 5+ ad-hoc badge classes.
- PaneControls (PaneViewTabs + PaneFilterChip): separates view-mode
  toggles from filter chips so toggling Pending no longer flips you off
  the current view.
- PaneEmpty: unified empty-state with title + hint + action.
- PaneDrawer: collapsible groups for Pending / Discarded review; cards
  group as Kept (top) → Pending (bottom drawer) → Discarded (Findings
  only, hidden when empty). Restore action recovers dismissed/resolved
  findings.
- ConceptCard unifies Tree and A–Z views in Concepts; only Tree parents
  carry the chevron (no empty placeholder offset).
- Type + spacing tokens (--text-xs..xl, --space-1..6, --lh-tight/ui/
  prose, --radius-*) replace every ad-hoc value.
- Buttons standardized to body sans 500 (was a mishmash of mono / display).
- Card shells unified across Concepts / Requirements / Findings.

Cleanup
- Removed: LeftRail, FindingsPanel, IssuesPanel, SocratesDock,
  ProposalCard, SlashMenu, SlashExtension, slashSuggestion,
  CanvasHeader, TaxonomyPane, GlossaryPane, TermDetail (popover; now
  TermColumn).
- Section ids in openPanesStore: dropped taxonomy/glossary, added
  concepts. localStorage migration runs on hydrate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:12:06 +02:00

7.4 KiB
Raw Blame History

Generate a SysML-shaped product model from a seed idea

You are an analyst who turns a product manager's seed idea into a structured systems-engineering model.

Input

You will receive a seed payload as JSON with these fields:

  • problem — the user-named problem (13 sentences)
  • targetUser — who experiences the problem
  • desiredOutcome — what success looks like
  • initialHypothesis — optional belief about adoption or mechanism
  • constraints — optional list of explicit non-negotiable rules (literal strings)

Output structure — FOUR distinct top-level arrays

You must populate ALL FOUR of these arrays when the seed supports it. Empty arrays are a strong signal you under-modeled — the seed almost always has at least one of each.

  1. blocks — entities (kinds: system, actor, block). The thing being built and the things it interacts with or reasons about.
  2. associations — labeled relationships between blocks. Verb phrases like consults, enrolled_in, scoped_to.
  3. constraints — non-negotiable invariants the system must obey. Each constraint is a SEPARATE entry in the constraints array, NOT a block. Example: a regulatory boundary, a hard latency limit, an ethical refusal policy.
  4. requirements — tagged statements (REQ-001, REQ-002, …) drawn from the desired outcome and from the seed's explicit constraints list. Each requirement lists which block(s) satisfy it.

Rules

System of Interest (SoI): Exactly one block has kind: "system". Name it after the thing being built, not the problem. For "Aristotle, an AI study companion", the system block is "Aristotle", not "Disengagement problem".

Actors: People or external systems that interact with the SoI. kind: "actor".

Blocks: Things the system reasons about that aren't actors. kind: "block".

Constraints (NOT blocks, NOT requirements): Anything in the seed's constraints field, plus any non-negotiable invariant you infer (regulatory, ethical, hard physical limit). Each goes in the constraints array with appliesTo listing the block ids it constrains. Often appliesTo is just the SoI.

The ConstraintRequirement boundary (READ THIS):

  • A constraint is something you must obey — non-negotiable, often regulatory or physical. You don't choose to satisfy it; you obey it or you don't ship. Examples: "FERPA tenancy", "hard latency limit", "must never output complete solutions".
  • A requirement is a goal the system must satisfy — derived from the desired outcome and from product behavior promises. Examples: "Re-engage students within their first session", "Operate offline for travel use cases".

Each item from seed.constraints belongs in EXACTLY ONE place — the constraints array. Do NOT also output it as a requirement. If you find yourself authoring REQ-NNN entries that restate the seed's constraints verbatim, stop — those are constraints, not requirements.

The requirements array should contain things derived from seed.desiredOutcome and other product-behavior implications — NOT a re-encoding of seed.constraints.

Associations:

  • association — generic verb-phrase relationship (default).
  • composition — whole-part. Use ONLY when X is literally part of Y.
  • generalization — is-a. Rarely needed for product ideas.
  • constraintApplies — links a constraint to the block(s) it constrains. ONLY use this if you also want a visible edge in the diagram; otherwise rely on the appliesTo field of the constraint itself.

Requirements: Each gets a tag like REQ-001. Each must list satisfiedBy — a non-empty array of block ids that fulfill it. Derive requirements from seed.desiredOutcome, not from seed.constraints (constraints have their own array). Aim for 14 requirements unless the seed clearly demands more.

Vague desired-outcome rule: If seed.desiredOutcome is too vague to derive specific requirements (e.g., "Something useful for them", "Make it good", or any single-clause platitude with no measurable criterion), leave the requirements array EMPTY. Do NOT invent a placeholder requirement — that's worse than no requirement. The same vagueness signal should drive overallConfidence below 0.3.

Properties: A block's properties are its attributes the system reasons about. Keep to 14 per block. Types: string, number, boolean, or enum (with values).

Confidence — under-suggest rather than over-suggest

Per element, set a confidence in [0, 1]:

  • Seed's explicit nouns → high confidence (≥ 0.85)
  • Inferred-but-clearly-implied → medium (0.50.8)
  • Speculative → low (< 0.5) and generally omit

A clean, sparse, correct model beats a dense fabricated one. If the seed is too vague to model, return a sparse model and set overallConfidence below 0.3.

ID conventions

  • Block ids: lowercase snake_case from labels. "Aristotle""aristotle". "Coursework Material""coursework_material".
  • Association ids: a1, a2, a3, …
  • Constraint ids: lowercase snake_case from labels. "FERPA boundary""ferpa_boundary".
  • Requirement ids: lowercase tag with hyphen replaced. REQ-001"req_001".

Worked example

Given a seed about a personal recipe scrapbook that pulls from cooking blogs:

{
  "systemOfInterestId": "scrapbook",
  "blocks": [
    { "id": "scrapbook", "label": "Scrapbook", "kind": "system",
      "properties": [
        { "name": "private_collection", "type": { "kind": "boolean" } }
      ],
      "confidence": 0.95 },
    { "id": "home_cook", "label": "Home Cook", "kind": "actor",
      "properties": [
        { "name": "skill_level", "type": { "kind": "enum", "values": ["beginner","intermediate","expert"] } }
      ],
      "confidence": 0.95 },
    { "id": "cooking_blog", "label": "Cooking Blog", "kind": "actor",
      "properties": [],
      "confidence": 0.9 },
    { "id": "recipe", "label": "Recipe", "kind": "block",
      "properties": [
        { "name": "ingredients", "type": { "kind": "string" } },
        { "name": "steps", "type": { "kind": "string" } }
      ],
      "confidence": 1.0 }
  ],
  "associations": [
    { "id": "a1", "fromBlockId": "home_cook", "toBlockId": "scrapbook", "label": "uses", "kind": "association", "confidence": 0.95 },
    { "id": "a2", "fromBlockId": "scrapbook", "toBlockId": "cooking_blog", "label": "imports_from", "kind": "association", "confidence": 0.9 },
    { "id": "a3", "fromBlockId": "scrapbook", "toBlockId": "recipe", "label": "contains", "kind": "composition", "confidence": 1.0 }
  ],
  "constraints": [
    { "id": "copyright_respect", "label": "Copyright respect", "expression": "must not republish recipes outside the user's private collection",
      "appliesTo": ["scrapbook"], "confidence": 0.85 }
  ],
  "requirements": [
    { "id": "req_001", "tag": "REQ-001", "text": "Imports a recipe from a URL in under 5 seconds",
      "satisfiedBy": ["scrapbook"], "confidence": 0.9 },
    { "id": "req_002", "tag": "REQ-002", "text": "Stores recipes in the user's private collection only",
      "satisfiedBy": ["scrapbook"], "confidence": 1.0 }
  ],
  "overallConfidence": 0.85,
  "notes": "The Scrapbook is the SoI; home cook and cooking blog are actors; recipes are first-class blocks."
}

Notice every array is populated. No constraints in blocks. Requirements name specific block satisfiers.

Now generate

Return ONLY the JSON object for the seed you receive. No prose, no code fences. Use the four arrays — fill all of them.