Grand Diomande Research · Full HTML Reader

Data Models

```prisma model User { id String @id @default(uuid()) email String @unique name String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt

Agents That Account for Themselves architecture technical paper candidate score 62 .md

Full Public Reader

Data Models

Database Schema

TrajectoryOS uses Prisma ORM with PostgreSQL (production) or SQLite (development).

Schema File

Location: `services/trajectory-core/prisma/schema.prisma`

Core Models

User

prisma
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // Relations
  lifestates    LifeState[]
  projects      Project[]
  skills        SkillEvidence[]
  sessions      Session[]
}

Purpose: User accounts

Key Fields:
- `email` - Authentication identifier (unique)
- `name` - Display name

Relations:
- One user → many life states (time series)
- One user → many projects
- One user → many skill evidence entries
- One user → many interview sessions

---

LifeState

prisma
model LifeState {
  id        String   @id @default(uuid())
  userId    String
  timestamp DateTime @default(now())

  // Latent vector (stored as JSON)
  latentVector Json

  // Derived physics variables
  thrust        Float
  alignment     Float
  gravity       Float
  mass          Float
  escapeIndex   Float

  // Metadata
  notes         String?

  // Relations
  user          User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, timestamp])
}

Purpose: Snapshot of life trajectory at a point in time

Key Fields:
- `latentVector` - High-dimensional representation (z_t) stored as JSON array
- `thrust`, `alignment`, `gravity`, `mass` - Derived physics variables
- `escapeIndex` - The critical η metric
- `timestamp` - When this state was computed

Queries:

typescript
// Get current state
const current = await prisma.lifeState.findFirst({
  where: { userId },
  orderBy: { timestamp: 'desc' }
});

// Get history (last 30 days)
const history = await prisma.lifeState.findMany({
  where: {
    userId,
    timestamp: { gte: thirtyDaysAgo }
  },
  orderBy: { timestamp: 'asc' }
});

---

Skill

prisma
model Skill {
 id          String   @id @default(uuid())
  name        String   @unique
  domain      String
  description String?
  createdAt   DateTime @default(now())

  // Relations
  evidence    SkillEvidence[]
  edges       SkillEdge[]     @relation("SkillFrom")
  edgesTo     SkillEdge[]     @relation("SkillTo")
}

Purpose: Global skill taxonomy

Key Fields:
- `name` - Skill name (e.g., "Python", "Choreography")
- `domain` - Category (e.g., "Programming", "Creative")

Relations:
- One skill → many evidence entries (from different users)
- One skill → many outgoing edges (skill graph)
- One skill → many incoming edges

Example Skills:

typescript
const skills = [
  { name: "Python", domain: "Programming" },
  { name: "Choreography", domain: "Creative" },
  { name: "System Design", domain: "Engineering" },
  { name: "Leadership", domain: "Management" }
];

---

SkillEdge

prisma
model SkillEdge {
  id            String   @id @default(uuid())
  fromSkillId   String
  toSkillId     String
  weight        Float    @default(0.5)
  description   String?

  fromSkill     Skill    @relation("SkillFrom", fields: [fromSkillId], references: [id], onDelete: Cascade)
  toSkill       Skill    @relation("SkillTo", fields: [toSkillId], references: [id], onDelete: Cascade)

  @@unique([fromSkillId, toSkillId])
}

Purpose: Directed edges in skill graph (transfer learning)

Key Fields:
- `weight` - Transfer strength (0-1), e.g., Python → JavaScript = 0.7
- `description` - Why this edge exists

Example Edges:

typescript
const edges = [
  { from: "Python", to: "JavaScript", weight: 0.7, description: "Programming concepts transfer" },
  { from: "Choreography", to: "Animation", weight: 0.6, description: "Movement principles" },
  { from: "System Design", to: "Architecture", weight: 0.8, description: "Structural thinking" }
];

Graph Traversal:

typescript
// Get all skills reachable from Python within 2 hops
const reachable = await prisma.$queryRaw`
  WITH RECURSIVE skill_path AS (
    SELECT to_skill_id, 1 AS depth
    FROM skill_edges
    WHERE from_skill_id = ${pythonId}
    UNION
    SELECT e.to_skill_id, p.depth + 1
    FROM skill_edges e
    JOIN skill_path p ON e.from_skill_id = p.to_skill_id
    WHERE p.depth < 2
  )
  SELECT DISTINCT s.* FROM skills s
  JOIN skill_path sp ON s.id = sp.to_skill_id
`;

---

SkillEvidence

prisma
model SkillEvidence {
  id          String   @id @default(uuid())
  userId      String
  skillId     String
  timestamp   DateTime @default(now())

  // Evidence data
  level       Float    // Estimated level (0-10)
  confidence  Float    // Confidence (0-1)
  source      String   // "interview", "artifact", "echelon", etc.
  sourceRef   String?  // Reference to source
  notes       String?

  // Relations
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  skill       Skill    @relation(fields: [skillId], references: [id], onDelete: Cascade)

  @@index([userId, skillId, timestamp])
}

Purpose: Observations of user skill levels

Key Fields:
- `level` - Estimated competency (0-10 scale)
- `confidence` - How certain we are (0-1)
- `source` - Where evidence came from
- `sourceRef` - Link to interview transcript, document ID, etc.

Source Types:
| Source | Description | Typical Confidence |
|--------|-------------|-------------------|
| `interview` | User stated in conversation | 0.5-0.7 |
| `artifact` | Code, document analysis | 0.7-0.9 |
| `echelon` | Embodied flow state | 0.8-1.0 |
| `external` | Resume, portfolio | 0.4-0.6 |

Bayesian Update:

typescript
// When new evidence arrives
const evidence = await prisma.skillEvidence.create({
  data: {
    userId,
    skillId,
    level: 7.5,
    confidence: 0.8,
    source: "interview",
    sourceRef: sessionId,
    notes: "Built 3 production apps in Python"
  }
});

// Trigger Bayesian update in Python model
await fetch('http://skill-model:5001/update', {
  method: 'POST',
  body: JSON.stringify({ userId, skillId, evidence })
});

---

Project

prisma
model Project {
  id          String   @id @default(uuid())
  userId      String
  name        String
  description String?
  status      String   @default("active")
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  // Project metadata
  embedding   Json?    // Vector embedding
  metadata    Json?    // Flexible metadata

  // Relations
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, status])
}

Purpose: User's projects and commitments

Key Fields:
- `status` - "active", "paused", "completed", "archived"
- `embedding` - Semantic embedding for alignment computation
- `metadata` - Flexible JSON for tags, links, time allocation, etc.

Metadata Example:

json
{
  "tags": ["web-dev", "side-project"],
  "hoursPerWeek": 10,
  "priority": "high",
  "repository": "https://github.com/user/project",
  "relatedSkills": ["Python", "React", "System Design"]
}

Alignment Computation:

typescript
// Get all active projects
const projects = await prisma.project.findMany({
  where: { userId, status: 'active' }
});

// Compute alignment (cosine similarity of embeddings)
const alignment = await fetch('http://alignment-model:5002/compute', {
  method: 'POST',
  body: JSON.stringify({ projects })
});

---

Session

prisma
model Session {
  id          String   @id @default(uuid())
  userId      String
  type        String
  startTime   DateTime @default(now())
  endTime     DateTime?
  status      String   @default("active")

  // Session data
  transcript  String?
  artifacts   Json?
  metadata    Json?

  // Relations
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId, startTime])
}

Purpose: Interview and generation sessions

Key Fields:
- `type` - "interview", "background_generation", etc.
- `transcript` - Full conversation history
- `artifacts` - Generated content (plans, insights)
- `metadata` - Additional context

Transcript Format (JSON):

json
{
  "messages": [
    { "role": "agent", "content": "Tell me about your recent work.", "timestamp": "..." },
    { "role": "user", "content": "I've been building a choreography app.", "timestamp": "..." },
    { "role": "agent", "content": "What technologies are you using?", "timestamp": "..." }
  ]
}

---

Memory

prisma
model Memory {
  id          String   @id @default(uuid())
  userId      String?
  content     String
  embedding   Json
  source      String
  sourceRef   String?
  timestamp   DateTime @default(now())
  metadata    Json?

  @@index([userId, timestamp])
}

Purpose: Semantic memory for RAG (Retrieval-Augmented Generation)

Key Fields:
- `content` - Text snippet
- `embedding` - Vector for similarity search
- `source` - "interview", "document", "plan", etc.
- `userId` - Optional (some memories are global knowledge)

Usage:

typescript
// Store memory from interview
await prisma.memory.create({
  data: {
    userId,
    content: "User is interested in computational choreography and has experience with Python and creative coding.",
    embedding: await embed(content),
    source: "interview",
    sourceRef: sessionId
  }
});

// Later, retrieve relevant memories
const query = "What are my main interests?";
const queryEmbedding = await embed(query);

const relevant = await vectorStore.search(queryEmbedding, {
  filter: { userId },
  limit: 5
});

---

Domain Types (TypeScript)

Location: `services/trajectory-core/src/domain/types.ts`

LifePhysics

typescript
export interface LifePhysics {
  thrust: number;
  alignment: number;
  gravity: number;
  mass: number;
  escapeIndex: number;
}

SkillBelief

typescript
export interface SkillBelief {
  skillId: string;
  mean: number;          // Posterior mean level
  variance: number;      // Posterior variance
  confidence: number;    // Confidence interval width
  utilization: number;   // How actively used (0-1)
  lastEvidence: Date;
}

EchelonSummary

typescript
export interface EchelonSummary {
  sessionId: string;
  userId: string;
  startTime: Date;
  endTime: Date;

  // Aggregated metrics
  avgTension: number;
  avgDrift: number;
  avgMomentum: number;
  avgPhase: number;
  flowScore: number;

  // Detected episodes
  flowEpisodes: Array<{ start: Date; end: Date }>;
  breakdownPeriods?: Array<{ start: Date; end: Date }>;

  // Context tagging
  activity?: string;
  projectIds?: string[];
  skillIds?: string[];
  notes?: string;
}

---

Indexes & Performance

Critical Indexes

prisma
// Already defined in models above:
@@index([userId, timestamp])  // LifeState, Session, Memory
@@index([userId, skillId, timestamp])  // SkillEvidence
@@index([userId, status])  // Project

Query Patterns

Most Common:
1. Get current state: `LifeState.findFirst(userId, orderBy: timestamp desc)`
2. Get skill evidence: `SkillEvidence.findMany(userId, skillId)`
3. Get active projects: `Project.findMany(userId, status: active)`

Optimization:
- Index covers all common queries
- No full table scans
- Pagination for large result sets

---

Migrations

Create Initial Schema

bash
cd services/trajectory-core
pnpm prisma migrate dev --name init

Add New Model

1. Edit `schema.prisma`
2. Run migration:

bash
pnpm prisma migrate dev --name add_new_model

Deploy to Production

bash
pnpm prisma migrate deploy

---

Data Lifecycle

User Onboarding

1. Create User record
2. Run initial interview
3. Create SkillEvidence from interview
4. Compute initial LifeState
5. Store in database

Ongoing Updates

Daily:
- Background analysis job
- Recompute LifeState
- Store new snapshot

Weekly:
- Prune old LifeState snapshots (keep daily aggregates)
- Cleanup completed sessions

User Deletion (GDPR)

1. Mark user as deleted
2. Cascade delete all related records
3. Anonymize memories (remove userId)
4. Export user data before deletion (if requested)

---

Next: See [API Reference](../api/README.md) for endpoint documentation.

Promotion Decision

Promote into a technical note or architecture paper with implementation anchors.

Source Anchor

Comp-Core/backend/cc-trajectory/docs/architecture/data-models.md

Detected Structure

Method · Evaluation · References · Code Anchors · Architecture