Marketplace Tables — Clustering, Contribution, Scoring

← Back to Platform Architecture

Marketplace Tables — Clustering, Contribution, Scoring

Overview

The marketplace system enables precedent discovery and sharing through a network effect: groups of related precedents (clusters) become more valuable as multiple tenants contribute. Three tables work together:
  • marketplace_clusters — Derived intelligence from grouped precedents
  • contribution_scores — Per-tenant contribution metrics to each cluster
  • marketplace_queries — Audit log of marketplace access (credit tracking)
  • Core Concept

    Cluster: A deterministic grouping of precedents by cluster_id = "Payer LOC". Example clusters: IOP" — All frequency limit denials for Cigna IOP
  • "UHC
  • PHP" — Medical necessity denials for UHC PHP
  • "Anthem
  • " — All LOC denials for Anthem (LOC = NULL) Network Effect Gate: Cluster only appears in marketplace after 2+ distinct tenants contribute to it. Prevents single-tenant seed data from appearing. Credit Economy: Tenants earn credits for contributing precedents, spend credits to query clusters.

    Schema Definition

    marketplace_clusters

    CREATE TABLE marketplace_clusters (
      id UUID PRIMARY KEY,
      
      -- Cluster Identity (deterministic grouping)
      cluster_id TEXT NOT NULL UNIQUE,  -- "Payer 
    " payer TEXT NOT NULL, denial_type TEXT NOT NULL, loc TEXT, -- NULL if non-LOC denial -- Maturity Tier (network effect indicator) maturity_tier TEXT, -- Embryonic (1 contributor) -- Emerging (2-3 contributors, <10 precedents) -- Mature (4+ contributors, 10+ precedents, stable outcomes) -- Canonical (20+ precedents, 70%+ win rate, <7 days avg resolution) -- Aggregate Metrics ipo_count INTEGER DEFAULT 0, -- Total precedents in cluster contributor_count INTEGER DEFAULT 0, -- Distinct tenants who contributed -- Outcome Analytics win_rate DECIMAL(5, 2), -- % of precedents with outcome="Won" avg_resolution_days DECIMAL(8, 2), -- Average days to resolution -- Evidence Synthesis (JSONB) top_evidence_types JSONB, -- Shape: { "clinical_notes": 85, "psychiatric_evaluation": 78, "gaf_score": 92 } narrative_patterns JSONB, -- Shape: { "functional_impact": 0.85, "evidence_combination": 0.72, "escalation_path": 0.40 } -- Composite Evidence Kit (merged from all precedents) evidence_kit_composite JSONB, -- Shape: { "required": [...], "recommended": [...], "optional": [...] } -- Drift Detection drift_signals JSONB, -- Shape: { "outcome_trending_down": false, "resolution_time_increasing": false } -- Metadata last_refreshed TIMESTAMPTZ DEFAULT NOW(), tenant_id UUID NOT NULL REFERENCES tenants(id), -- Indexes INDEX idx_cluster_payer (payer, denial_type, loc), INDEX idx_cluster_maturity (maturity_tier), INDEX idx_cluster_refresh (last_refreshed DESC), INDEX idx_cluster_tenant (tenant_id) );

    contribution_scores

    CREATE TABLE contribution_scores (
      id UUID PRIMARY KEY,
      
      -- Who & Where
      tenant_id UUID NOT NULL REFERENCES tenants(id),
      cluster_id TEXT NOT NULL REFERENCES marketplace_clusters(cluster_id),
      
      -- Contribution Metrics
      ipo_count INTEGER DEFAULT 0,           -- How many precedents this tenant added
      gap_score DECIMAL(8, 2) DEFAULT 0,     -- Gap coverage in cluster (0–100)
      outcome_bonus DECIMAL(8, 2) DEFAULT 0, -- +X for high-quality outcomes
      
      -- Total Score (for ranking contributors)
      total_score DECIMAL(10, 2) GENERATED ALWAYS AS (ipo_count  10 + gap_score + outcome_bonus) STORED,
      
      -- Metadata
      updated_at TIMESTAMPTZ DEFAULT NOW(),
      
      UNIQUE(tenant_id, cluster_id),
      INDEX idx_contribution_tenant (tenant_id, total_score DESC),
      INDEX idx_contribution_cluster (cluster_id, total_score DESC)
    );

    marketplace_queries

    CREATE TABLE marketplace_queries (
      id UUID PRIMARY KEY,
      
      -- Access Log
      tenant_id UUID NOT NULL REFERENCES tenants(id),
      cluster_id TEXT NOT NULL,              -- cluster_id queried
      query_type TEXT,                       -- "view_cluster", "export", "search"
      
      -- Credit Ledger Integration
      credits_spent DECIMAL(10, 2),
      receipt_hash TEXT,                     -- Hash of credit_ledger entry
      
      -- Metadata
      queried_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
      
      INDEX idx_query_tenant_cluster (tenant_id, cluster_id, queried_at DESC),
      INDEX idx_query_cluster (cluster_id, queried_at DESC)
    );

    Cluster Lifecycle

    1. Initial Contribution (Embryonic)

    When tenant A adds first precedent to cluster:
  • If marketplace_clusters row doesn't exist: CREATE (maturity_tier = "Embryonic")
  • Add to contribution_scores with ipo_count=1
  • Row NOT visible in marketplace yet (gate: <2 contributors)
  • INSERT INTO marketplace_clusters (cluster_id, payer, denial_type, loc, contributor_count, ipo_count)
    VALUES ('Cigna 
    IOP', 'Cigna', 'Frequency Limit', 'IOP', 1, 1); INSERT INTO contribution_scores (tenant_id, cluster_id, ipo_count) VALUES ('tenant-a-uuid', 'Cigna IOP', 1);

    2. Network Effect Gate (Emerging)

    When tenant B adds second precedent:
  • Increment contributor_count to 2
  • Update maturity_tier to "Emerging"
  • Cluster now appears in marketplace
  • UPDATE marketplace_clusters
    SET contributor_count = 2, maturity_tier = 'Emerging'
    WHERE cluster_id = 'Cigna 
    IOP'; INSERT INTO contribution_scores (tenant_id, cluster_id, ipo_count) VALUES ('tenant-b-uuid', 'Cigna
    Denial Type
    Frequency Limit
    Medical Necessity
    Level of Care
    Denial TypeLOC" or "PayerDenial Type
    Frequency Limit
    Frequency Limit
    Frequency Limit
    Frequency Limit
    IOP', 1);

    3. Maturity Progression (Mature/Canonical)

    As cluster grows:
  • Embryonic → Emerging (2+ contributors)
  • Emerging → Mature (4+ contributors, 10+ precedents, stable win rate > 50%)
  • Mature → Canonical (20+ precedents, win rate > 70%, avg resolution < 7 days)
  • Tiers refresh nightly or on new precedent creation.

    Contribution Scoring

    gap_score (0–100)

    Measures what this tenant uniquely contributed:
  • If cluster has 5 precedents total, all from tenant A: gap_score = 100 (full coverage)
  • If cluster has 5 precedents, 3 from A + 2 from B: A's gap_score = 60%, B's = 40%
  • Formula: ipo_count / total_cluster_ipo_count 100
  • outcome_bonus

    Added for high-quality contributions:
  • +5 points for outcome = "Won"
  • +3 points for outcome = "Partial"
  • +10 points for evidence_score = "Strong" + outcome = "Won"
  • total_score

    Ranks contributors per cluster:
    total_score = (ipo_count  10) + gap_score + outcome_bonus
    Example:
  • Tenant A: 3 precedents in cluster (ipo_count=3), 2 Won (bonus=10), gap_score=75
  • total_score = (3 10) + 75 + 10 = 115
  • Tenant B: 1 precedent in cluster (ipo_count=1), 1 Won (bonus=5), gap_score=25
  • total_score = (1 10) + 25 + 5 = 40
  • Tenant A is ranked #1 contributor to this cluster.

    Query Patterns

    Get Marketplace Clusters (Browse)

    SELECT cluster_id, payer, denial_type, loc, maturity_tier, ipo_count, win_rate
    FROM marketplace_clusters
    WHERE tenant_id = $1 AND maturity_tier IN ('Emerging', 'Mature', 'Canonical')
    ORDER BY ipo_count DESC
    LIMIT 50;

    View Cluster Profile

    SELECT 
      c.cluster_id, c.payer, c.denial_type, c.loc,
      c.maturity_tier, c.ipo_count, c.win_rate, c.avg_resolution_days,
      c.top_evidence_types, c.narrative_patterns,
      COUNT(DISTINCT s.tenant_id) AS contributor_count
    FROM marketplace_clusters c
    LEFT JOIN contribution_scores s ON s.cluster_id = c.cluster_id
    WHERE c.cluster_id = $1
    GROUP BY c.id;

    Get Top Contributors to Cluster

    SELECT tenant_id, ipo_count, gap_score, total_score
    FROM contribution_scores
    WHERE cluster_id = $1
    ORDER BY total_score DESC
    LIMIT 10;

    Find Clusters I Can Access (Credit Check)

    -- Step 1: Get tenant's credit balance
    SELECT SUM(amount) AS balance
    FROM credit_ledger
    WHERE tenant_id = $1
    GROUP BY tenant_id;
    
    -- Step 2: Get queryable clusters (2+ contributors)
    SELECT c.cluster_id, c.ipo_count, c.maturity_tier
    FROM marketplace_clusters c
    WHERE c.contributor_count >= 2
    ORDER BY c.ipo_count DESC
    LIMIT 25;

    Maturity Tier Calculation

    Refresh nightly or on new precedent:
    UPDATE marketplace_clusters
    SET maturity_tier = CASE
      WHEN contributor_count = 1 THEN 'Embryonic'
      WHEN contributor_count <= 3 AND ipo_count < 10 THEN 'Emerging'
      WHEN contributor_count >= 4 AND ipo_count >= 10 AND win_rate > 50 THEN 'Mature'
      WHEN ipo_count >= 20 AND win_rate > 70 AND avg_resolution_days < 7 THEN 'Canonical'
      ELSE 'Emerging'
    END
    WHERE last_refreshed < NOW() - INTERVAL '1 day';

    Credit Ledger Integration

    When a tenant queries a cluster:
  • Check credit balance:
  • SELECT SUM(amount) FROM credit_ledger WHERE tenant_id = $1;
  • Calculate query cost:
  • Base cost: 1 credit per cluster view
  • Scaling: +0.5 credit per 10 precedents (e.g., 20-precedent cluster = 2 credits)
  • Formula: cost = 1 + (ipo_count / 10 0.5)
  • If balance >= cost:
  • Deduct from ledger: INSERT INTO credit_ledger (event_type='query_burn', amount=-cost, reference_type='marketplace_cluster')
  • Return cluster data
  • Log query: INSERT INTO marketplace_queries (cluster_id, credits_spent, receipt_hash)
  • If balance < cost: Return 402 Payment Required
  • Drift Detection

    drift_signals flags clusters where metrics are trending negatively:
    {
      "outcome_trending_down": false,     // Win rate decreasing month-over-month
      "resolution_time_increasing": false, // Avg resolution time > 2x baseline
      "contributor_churn": false,         // Contributors leaving (contributor_count decreasing)
      "evidence_effectiveness_declining": false  // New precedents have lower win rate
    }
    Recalculate on precedent update:
    -- Example: Check if win rate is declining
    SELECT 
      AVG(CASE WHEN outcome='Won' THEN 1 ELSE 0 END) AS current_win_rate,
      LAG(AVG(CASE WHEN outcome='Won' THEN 1 ELSE 0 END)) 
        OVER (ORDER BY DATE(created_at)) AS prior_month_rate
    FROM precedent_objects
    WHERE cluster_id = $1
      AND created_at > NOW() - INTERVAL '60 days'
    GROUP BY DATE(created_at);

    Compliance Notes

    Multi-Tenancy:
  • Each row in marketplace_clusters has tenant_id (but represents aggregate across all tenants in that tenant's network)
  • Queries filter by tenant_id to show only clusters visible to that tenant
  • SUD data contributions: mark cluster with has_sud_content = true if any precedent in cluster has data_origin_type='SUD'
  • HIPAA Audit:
  • Every marketplace query logged to marketplace_queries with timestamp and tenant
  • Query access is a compliance event (logged to audit trail)
  • See also

  • Credit Economy — Mint/burn mechanics
  • Precedent Objects — Source of cluster data
  • Data Models Overview — All relationships
  • Marketplace System — Business logic
  • Code reference

  • src/models/marketplace.ts — Query helpers (clustering, maturity tiers, scoring)
  • src/services/marketplace.ts — Cluster refresh logic, drift detection, tier calculation
  • src/routes/marketplace.ts — API endpoints (browse, profile, query)
  • src/db/marketplace-schema.sql — Table definitions