tidaldb/SEQUENCE.md
jordan 413b712c0a chore: initialize tidalDB repository with schema foundation and standards
- Schema phase 1 (tasks 01-02): EntityId, EntityKind, Timestamp, Score, SignalTypeDef, DecayModel, Window, WindowSet — all with property tests and benchmarks scaffolding
- Stub modules for storage, signals, query, ranking
- Full documentation suite: VISION, USE_CASES, SEQUENCE, API, CODING_GUIDELINES, ai-lookup, research docs, specs, roadmap, planning docs
- Marketing site (Next.js) with blog infrastructure
- .claude/ agents and skills for the tidalDB development workflow
- Foundation standards enforced: thiserror + tracing declared as dependencies, clippy::unwrap_used = deny added to lint config
- .gitignore hardened: .next/, node_modules/, .env, secrets, logs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 12:52:20 -07:00

439 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Sequence Diagrams
User-perspective flows for every major surface. Each diagram shows what the application sends, what tidalDB does internally, and what signals flow back to close the loop.
---
## Table of Contents
- [UC-01 · For You Feed](#uc-01--for-you-feed)
- [UC-02 · Search with Personalized Ranking](#uc-02--search-with-personalized-ranking)
- [UC-03 · Trending / Popular](#uc-03--trending--popular)
- [UC-04 · Following Feed](#uc-04--following-feed)
- [UC-05 · Related Content / Up Next](#uc-05--related-content--up-next)
- [UC-06 · Browse / Category Discovery](#uc-06--browse--category-discovery)
- [UC-07 · Notification Prioritization](#uc-07--notification-prioritization)
- [UC-15 · Cohort-Scoped Trending](#uc-15--cohort-scoped-trending)
- [Core · Engagement Feedback Loop](#core--engagement-feedback-loop)
- [Write · Content Ingest](#write--content-ingest)
---
## UC-01 · For You Feed
User opens the app. tidalDB retrieves candidates, scores them against the user's preference profile, enforces diversity, and returns a ready-to-render batch. Pagination continues with previously-returned IDs excluded.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Opens app / pulls to refresh
App->>TidalDB: RETRIEVE items\nFOR USER @u123\nCONTEXT feed\nUSING PROFILE for_you\nFILTER unseen, unblocked\nDIVERSITY max_per_creator:2\nLIMIT 50
Note over TidalDB: 1. Load user preference vector\n2. ANN retrieval over item embeddings\n3. Apply seen / blocked filters\n4. Score via for_you profile:\n preference_match\n × engagement_velocity(24h)\n × recency_decay\n × social_proof\n5. Enforce diversity constraints\n6. Return ranked batch
TidalDB-->>App: [{item_id, score, signals_snapshot} × 50]
App-->>User: Feed renders
User->>App: Scrolls to bottom
App->>TidalDB: RETRIEVE items\nFOR USER @u123\nCONTEXT feed\nUSING PROFILE for_you\nFILTER unseen, unblocked\nEXCLUDE [previously_returned_ids]\nLIMIT 50
TidalDB-->>App: Next batch of 50
App-->>User: Feed extends
```
**Signals powering this query:** user preference vector (built from history), item view velocity (24h window), item completion rate, user→creator interaction weight, social graph engagement, item age with decay curve, skip and hide signals.
---
## UC-02 · Search with Personalized Ranking
Text relevance is the floor — an irrelevant result never appears just because the user likes the creator. Personalization reorders within the relevant candidate set. A beginner and an expert searching the same query get different orderings.
```mermaid
sequenceDiagram
actor User
participant App
participant Embed as Embedding Service
participant TidalDB
User->>App: Types "rust tutorial beginner"
App->>Embed: embed("rust tutorial beginner")
Embed-->>App: query_vector[1536]
App->>TidalDB: SEARCH items\nQUERY "rust tutorial beginner"\nVECTOR query_vector\nFOR USER @u123\nUSING PROFILE search\nDIVERSITY max_per_creator:2\nLIMIT 20
Note over TidalDB: 1. BM25 text match → relevance scores\n2. ANN over item embeddings → semantic scores\n3. Merge: text(0.6) + semantic(0.4)\n4. Personalization layer:\n user topic engagement history\n item quality signals (completion, like ratio)\n recency curve (slow decay for tutorials)\n5. Diversity pass\n6. Return ranked results
TidalDB-->>App: [{item_id, relevance_score, rank} × 20]
App-->>User: Search results render
User->>App: Clicks result #3
App->>TidalDB: SIGNAL search_click\nitem: @item_id\nuser: @u123\nquery_context: "rust tutorial beginner"\nrank_at_click: 3
Note over TidalDB: Updates item relevance signal\nfor this query category.\nBoosts user→topic weight.
TidalDB-->>App: ok
User->>App: Watches 80% of video
App->>TidalDB: SIGNAL completion\nitem: @item_id\nuser: @u123\nratio: 0.80
Note over TidalDB: Strong positive on item quality.\nUpdates user preference vector\ntoward this topic and format.
TidalDB-->>App: ok
```
---
## UC-03 · Trending / Popular
Velocity, not volume. A video posted 4 hours ago with a high share rate outranks a video with 10× the total views but slow recent growth. The same profile applies to global, category-scoped, social-graph-scoped, and cohort-scoped trending — only the candidate set and signal scope change.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Taps "Trending" tab
App->>TidalDB: RETRIEVE items\nUSING PROFILE trending\nWINDOW 24h\nDIVERSITY max_per_creator:1\nLIMIT 25
Note over TidalDB: Profile: trending\nPrimary: share_velocity(6h)\nSecondary: view_velocity(6h)\nBoost: new_user_reach (virality)\nGate: engagement_ratio > 0.03\nNo personalization.\nNo total-count signals.
TidalDB-->>App: [{item_id, trending_score, velocity_snapshot} × 25]
App-->>User: Trending page renders
User->>App: Taps "Jazz" category filter
App->>TidalDB: RETRIEVE items\nUSING PROFILE trending\nFILTER category: jazz\nWINDOW 24h\nDIVERSITY max_per_creator:1\nLIMIT 25
Note over TidalDB: Same profile. Same velocity signals.\nHard filter on category metadata.\nScoped candidate set.
TidalDB-->>App: Trending in Jazz
App-->>User: "Trending in Jazz" renders
User->>App: Switches to "Among People I Follow"
App->>TidalDB: RETRIEVE items\nUSING PROFILE trending\nFILTER social_graph: @u123 depth:2\nWINDOW 24h\nLIMIT 25
Note over TidalDB: Same profile.\nCandidates constrained to items\nengaged by users @u123 follows.
TidalDB-->>App: Trending among follows
App-->>User: Social trending renders
User->>App: Switches to "Trending in My Demo"
App->>TidalDB: RETRIEVE items\nUSING PROFILE trending\nCOHORT locale:en-US, age:18-24\nWINDOW 24h\nLIMIT 25
Note over TidalDB: Same profile.\nSignal aggregation scoped to\nusers matching cohort predicate.
TidalDB-->>App: Cohort-scoped trending
App-->>User: Demographic trending renders
```
**One profile, four scopes.** Global, category, social, and cohort trending are the same ranking profile applied to different signal scopes. No code changes — just query parameters.
---
## UC-04 · Following Feed
The surface where users expect control. Recency-dominant, minimal algorithmic intervention. A creator's worst-performing video still appears here — because the user chose to follow them.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Taps "Following" tab
App->>TidalDB: RETRIEVE items\nFOR USER @u123\nFILTER relationship: follows\nUSING PROFILE following\nFILTER unseen\nLIMIT 50
Note over TidalDB: Profile: following\nPrimary sort: created_at DESC\nTiebreaker: completion_rate\nHard filter: creator in user's follows\nHard filter: unseen by this user\nNo exploration budget.\nNo aggressive personalization.
TidalDB-->>App: Chronological feed from follows
App-->>User: Subscription feed renders
User->>App: Scrolls — catching up from 3 days ago
App->>TidalDB: RETRIEVE items\nFOR USER @u123\nFILTER relationship: follows\nFILTER created_at < @cursor_timestamp\nUSING PROFILE following\nLIMIT 50
TidalDB-->>App: Older batch (cursor pagination)
App-->>User: Older content loads
User->>App: Follows a new creator
App->>TidalDB: WRITE relationship\ntype: follows\nfrom: @u123\nto: @creator_id\ntimestamp: now()
Note over TidalDB: Adds edge to relationship graph.\nUpdates user preference vector\nto include creator's topic signals.\nNew creator appears in next query.
TidalDB-->>App: ok
```
---
## UC-05 · Related Content / Up Next
Anchored to the item just consumed. Blends semantic similarity with collaborative filtering and user taste. The autoplay accept/skip signal strengthens or decays the item-to-item pairing for future recommendations.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Finishes watching @item_abc (Rust tutorial, beginner)
App->>TidalDB: SIGNAL completion\nitem: @item_abc\nuser: @u123\nratio: 0.94
Note over TidalDB: Appends to @item_abc signal ledger.\nUpdates user→item_abc relationship.\nUpdates user preference vector\ntoward rust/programming/tutorials.
TidalDB-->>App: ok
App->>TidalDB: RETRIEVE items\nSIMILAR TO @item_abc\nFOR USER @u123\nUSING PROFILE related\nFILTER unseen\nEXCLUDE creator: @item_abc.creator_id (top 3 only)\nLIMIT 10
Note over TidalDB: Profile: related\n1. ANN: items near @item_abc embedding\n2. Collaborative: items co-engaged with @item_abc\n3. Personalize: re-rank by user preference match\n4. Quality gate: completion_rate > 0.4\n5. Diversity: avoid same creator in top 3\n6. Return
TidalDB-->>App: [{item_id, similarity_score, collab_score} × 10]
App-->>User: Up Next queue renders
User->>App: Autoplay begins on result #1
App->>TidalDB: SIGNAL autoplay_accept\nsource_item: @item_abc\ntarget_item: @item_xyz\nuser: @u123
Note over TidalDB: Strong positive on item_abc → item_xyz pairing.\nStrengthens collaborative edge.
TidalDB-->>App: ok
User->>App: Skips after 8 seconds
App->>TidalDB: SIGNAL skip\nitem: @item_xyz\nuser: @u123\ndwell_ms: 8200\ncontext: autoplay_from @item_abc
Note over TidalDB: Negative on this pairing.\nDecays item_abc → item_xyz\ncollaborative edge slightly.
TidalDB-->>App: ok
```
---
## UC-06 · Browse / Category Discovery
Quality-dominant ranking within a filtered candidate set. Mix of established content and breakout newcomers. Sort mode switches (Top, New, All Time) are different profiles on the same candidate set — no application logic needed.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Taps "Jazz" category
App->>TidalDB: RETRIEVE items\nFILTER category: jazz\nUSING PROFILE browse\nDIVERSITY max_per_creator:2\nLIMIT 20
Note over TidalDB: Profile: browse\nPrimary: quality_score\n completion_rate(0.5)\n + like_ratio(0.3)\n + reach(0.2)\nRecency boost: 30d half-life\nBreakout bonus: age < 14d\n AND velocity_percentile > 0.9
TidalDB-->>App: [{item_id, quality_score} × 20]
App-->>User: Jazz browse page renders
User->>App: Switches sort to "New"
App->>TidalDB: RETRIEVE items\nFILTER category: jazz\nUSING PROFILE new\nLIMIT 20
Note over TidalDB: Profile: new\nSort: created_at DESC\nNo quality gate.
TidalDB-->>App: Latest jazz content
App-->>User: New jazz renders
User->>App: Switches sort to "Top All Time"
App->>TidalDB: RETRIEVE items\nFILTER category: jazz\nUSING PROFILE top_all_time\nDIVERSITY max_per_creator:3\nLIMIT 20
Note over TidalDB: Profile: top_all_time\nSort: total_completion_weighted_views DESC\nNo recency boost. No decay.\nPure historical quality.
TidalDB-->>App: All-time top jazz
App-->>User: Top jazz renders
```
---
## UC-07 · Notification Prioritization
Of all events since the user was last active, tidalDB decides which are worth a push and in what order they appear in the notification center. Open and dismiss signals feed back to adjust future notification priority per creator.
```mermaid
sequenceDiagram
participant Job as Background Job
participant TidalDB
participant Push as Push Service
actor User
Job->>TidalDB: RETRIEVE notifications\nFOR USER @u123\nSINCE @last_seen_timestamp\nUSING PROFILE notification\nLIMIT push:3, inbox:20
Note over TidalDB: Profile: notification\nCandidates: events from followed creators\n + social graph activity\nScore by:\n relationship_strength(user, creator)\n × item engagement_velocity at event time\n × user notification_open_rate\nHard filter: event_age > 48h → suppress\nHard filter: max 1 per creator per day
TidalDB-->>Job: push_candidates[3], inbox_candidates[20]
Job->>Push: Send push notifications (top 3)
Push->>User: Push notification arrives
User->>Push: Taps notification
Push->>Job: opened — item @item_id
Job->>TidalDB: SIGNAL notification_open\nuser: @u123\ncreator: @creator_id\nitem: @item_id
Note over TidalDB: Strong positive on user→creator\nrelationship for notification context.\nIncreases future notification priority\nfor this creator.
TidalDB-->>Job: ok
User->>Push: Swipes to dismiss
Push->>Job: dismissed
Job->>TidalDB: SIGNAL notification_dismiss\nuser: @u123\ncreator: @creator_id
Note over TidalDB: Mild negative on relationship\nfor notification context.\nReduces push frequency\nfrom this creator slightly.
TidalDB-->>Job: ok
```
---
## UC-15 · Cohort-Scoped Trending
User explores what's trending within their audience segment. tidalDB scopes signal aggregation to users matching the cohort predicate, ranks by velocity within that cohort, and supports search composition on top.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Opens "Trending For You"
Note over App: App resolves user's primary cohort<br/>from their attributes:<br/>locale:en-US, age:18-24, interest:music
App->>TidalDB: RETRIEVE items<br/>USING PROFILE trending<br/>COHORT locale:en-US, age:18-24, interest:music<br/>WINDOW 24h<br/>DIVERSITY max_per_creator:1<br/>LIMIT 25
Note over TidalDB: 1. Resolve cohort: users matching predicate<br/>2. Load cohort-scoped signal aggregates<br/> (view_velocity, share_velocity scoped<br/> to signals from cohort members)<br/>3. Rank by cohort-scoped velocity<br/>4. Gate: engagement_ratio > 0.03<br/>5. Enforce diversity<br/>6. Return ranked batch
TidalDB-->>App: [{item_id, cohort_trending_score, velocity_snapshot} × 25]
App-->>User: "Trending in your world" renders
User->>App: Searches "jazz piano" within trending
App->>TidalDB: SEARCH items<br/>QUERY "jazz piano"<br/>WITHIN TRENDING<br/>COHORT locale:en-US, age:18-24, interest:music<br/>WINDOW 24h<br/>LIMIT 20
Note over TidalDB: 1. Cohort-scoped trending candidates<br/>2. BM25 text match within candidates<br/>3. Merge: trending_score × text_relevance<br/>4. Return intersection
TidalDB-->>App: [{item_id, composite_score} × 20]
App-->>User: Search-within-trending results render
User->>App: Switches to "Trending Globally"
App->>TidalDB: RETRIEVE items<br/>USING PROFILE trending<br/>WINDOW 24h<br/>DIVERSITY max_per_creator:1<br/>LIMIT 25
Note over TidalDB: Same profile, no cohort scope.<br/>Global signal aggregates used.<br/>Different results than cohort view.
TidalDB-->>App: Global trending results
App-->>User: "Trending Globally" renders
```
**Three layers, one engine.** Global trending, cohort trending, and search-within-cohort-trending are the same ranking profile applied to different signal scopes. The profile doesn't change — the signal aggregation scope does.
---
## Core · Engagement Feedback Loop
Every interaction closes the loop in a single write transaction. There is no ETL, no Kafka consumer, no feature store sync. The next ranking query — even 100ms later — sees the updated state.
```mermaid
sequenceDiagram
actor User
participant App
participant TidalDB
User->>App: Likes a video
App->>TidalDB: SIGNAL like\nitem: @item_id\nuser: @u123\ntimestamp: now()
Note over TidalDB: Atomic write transaction:\n1. Append event to item signal ledger\n2. Update windowed aggregates:\n like_count_1h, _24h, _7d\n3. Recompute like_velocity\n4. Update user→item relationship weight\n5. Increment user→creator interaction_weight\n6. Update user preference vector\n toward item's topic embedding\n7. Attribute signal to user's cohorts\n (increment cohort-scoped counters)\n8. Commit
TidalDB-->>App: ok
Note over App: Next RETRIEVE for this user\nreflects updated signals immediately.
User->>App: Hides a video ("Not interested")
App->>TidalDB: SIGNAL hide\nitem: @item_id\nuser: @u123
Note over TidalDB: 1. Set permanent hard-negative flag\n on user→item relationship\n2. Decay user→creator interaction_weight\n3. Update user preference vector\n AWAY from item's topic embedding\n4. Item excluded from all future\n queries for this user
TidalDB-->>App: ok
User->>App: Blocks a creator
App->>TidalDB: SIGNAL block\nuser: @u123\ntarget_creator: @creator_id
Note over TidalDB: 1. Set permanent hard block\n on user→creator relationship\n2. All items by @creator_id excluded\n from every query for this user\n3. Existing relationship edges zeroed
TidalDB-->>App: ok
```
---
## Write · Content Ingest
How a new item enters the system and becomes immediately retrievable and rankable. Cold start is handled by the database via an exploration budget — the application does not manage this.
```mermaid
sequenceDiagram
actor Creator
participant App
participant Embed as Embedding Service
participant TidalDB
Creator->>App: Uploads video\n(title, description, tags, category, transcript)
App->>Embed: embed(title + description + transcript)
Embed-->>App: content_vector[1536]
App->>TidalDB: WRITE item\nid: @item_id\ncreator: @creator_id\nmetadata: {title, description, tags, category, duration}\nembedding: content_vector\ncreated_at: now()
Note over TidalDB: 1. Store metadata in entity store\n2. Index text fields into inverted index\n3. Insert vector into ANN index (HNSW)\n4. Initialize signal ledger (all zeros)\n5. Apply new-item exploration budget:\n appears in a small % of for_you feeds\n before signals accumulate\n6. Link to creator entity\n7. Commit — item is immediately queryable
TidalDB-->>App: ok, @item_id indexed
App-->>Creator: "Your content is live"
Note over TidalDB: Item is now retrievable in:\n• Search (text + semantic)\n• Following feeds of creator's followers\n• Browse / category pages\n• Trending (once signals accumulate)\n• For You (exploration budget active)
```
**Cold start is a first-class problem.** New content has no engagement signals. tidalDB handles this natively — new items receive a configurable exploration window proportional to the creator's relationship strength with their existing followers. The application does not manage this.
---
## Signal Reference
| Signal | Type | Decay | Primary Use |
|---|---|---|---|
| `view` | count | slow (7d half-life) | baseline engagement |
| `completion` | ratio 01 | very slow | quality signal |
| `like` | count | slow | positive sentiment |
| `share` | count | medium | virality |
| `comment` | count | medium | community |
| `skip` | count | fast (1d half-life) | negative quality |
| `hide` | bool | permanent | hard negative |
| `block` | bool | permanent | hard filter |
| `follow` | bool | permanent | relationship |
| `interaction_weight` | float | slow | relationship strength |
| `dwell_time` | duration | medium | true engagement |
| `autoplay_accept` | bool | medium | recommendation quality |
| `notification_open` | bool | slow | creator notification priority |
| `notification_dismiss` | bool | medium | reduce push frequency |
| `search_click` | count + rank | medium | query relevance signal |