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

19 KiB
Raw Permalink Blame History

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

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.

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.

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

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.

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.

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

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.

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.

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.

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

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.

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.

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.

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