Credit Economy — Mint, Burn, Allocation, Scoring
Overview
The credit economy uses event-sourced ledger to incentivize contribution and control query load:- Mint: Earn credits for creating high-quality precedents
- Burn: Spend credits to query marketplace clusters
- Allocation: Monthly baseline credits (membership benefit)
- Bonus: Extra credits for exceptional contributions
- Incentive Alignment — Contribution rewards align with quality (evidence strength, outcomes)
- Scarcity & Fairness — Limited monthly credits prevent query hoarding
- No Double-Spend — Event-sourced ledger is immutable, prevents overdraft
- Audit Trail — Every transaction logged for 7-year retention
- Progressive Scaling — Query cost increases with cluster maturity (larger clusters cost more)
Design Principles
Mint Events (Earning Credits)
Contribution Mint (Create Precedent)
Trigger: Precedent created and passes validation Formula:credits = base_amount × evidence_quality_multiplier
base_amount = 10 credits
multiplier:
Minimal evidence_score → 1.0x (10 credits)
Moderate evidence_score → 1.5x (15 credits)
Strong evidence_score → 2.0x (20 credits)
Example:
{ event_type: 'contribution_mint', amount: 20, reference_id: 'precedent-uuid' }IF outcome = 'Won' THEN +5 bonus
IF outcome = 'Partial' THEN +2 bonus
IF outcome = 'Pending' THEN +0 (wait for resolution)
Example:
Bonus Mint (High-Quality Contribution)
Trigger: Precedent meets quality criteria after creation (can be awarded later) Criteria:Membership Allocation
Trigger: Monthly on the 1st Amount: 100 credits per tenant per month Purpose: Baseline access to marketplace (even new tenants get query ability) Implementation:INSERT INTO credit_ledger (
event_type='membership_allocation',
amount=100,
tenant_id=$1,
metadata={'allocation_period': '2024-04', 'monthly_baseline': 100}
)
ON CONFLICT DO NOTHING; -- Prevent duplicate if process runs twice
Burn Events (Spending Credits)
Query Burn (Access Cluster)
Trigger: Tenant queries marketplace cluster Formula:cost = 1 + (ipo_count / 10 × 0.5)
Examples:
10-precedent cluster → 1 + (10/10 × 0.5) = 1.5 credits
20-precedent cluster → 1 + (20/10 × 0.5) = 2 credits
50-precedent cluster → 1 + (50/10 × 0.5) = 3.5 credits
100-precedent cluster → 1 + (100/10 × 0.5) = 6 credits
Rationale: Larger clusters (more value) cost more. Incentivizes contribution to lower-cost clusters.
Implementation:
-- Step 1: Calculate cost
cost = 1 + (ipo_count / 10 0.5)
-- Step 2: Check balance
SELECT SUM(amount) AS balance FROM credit_ledger WHERE tenant_id = $1 AND status = 'posted'
IF balance < cost THEN RETURN 402 Payment Required
-- Step 3: Log burn
INSERT INTO credit_ledger (
event_type='query_burn',
amount=-cost,
reference_id=cluster_id,
metadata={'cluster_id': '...', 'ipo_count': ...}
)
-- Step 4: Return cluster data
Adjustment (Admin Only)
Use: Resolve disputes (e.g., refund erroneous query charge) Example:INSERT INTO credit_ledger (
event_type='adjustment',
amount=3.5, -- Refund amount
reference_id=original_ledger_entry_id,
metadata={'reason': 'disputed_charge_reversed', 'original_event_id': 'uuid'}
)
Credit Balance Query
Rule: Never use a "balance" column. Always compute from ledger.-- Tenant's current balance
SELECT COALESCE(SUM(amount), 0) AS balance
FROM credit_ledger
WHERE tenant_id = $1 AND status = 'posted';
-- Balance at specific date (for audits)
SELECT COALESCE(SUM(amount), 0) AS balance_as_of
FROM credit_ledger
WHERE tenant_id = $1 AND status = 'posted' AND posted_at <= $2;
Scoring Metrics
Contribution Score (Cluster-Level)
Per tenant, per cluster:SELECT
ipo_count, -- # of precedents contributed
gap_score, -- % of cluster contributed by this tenant
outcome_bonus, -- bonus points for quality
(ipo_count 10 + gap_score + outcome_bonus) AS total_score
FROM contribution_scores
WHERE tenant_id = $1 AND cluster_id = $2;
gap_score calculation:
gap_score = (this_tenant_ipo_count / total_cluster_ipo_count) 100
Example:
Cluster has 20 total precedents
Tenant A contributed 10
gap_score = (10 / 20) 100 = 50
Tenant B contributed 10
gap_score = (10 / 20) 100 = 50
Use: Rank contributors in cluster ("Top Contributors: Tenant A (110 pts), Tenant B (105 pts)")
Overall Contribution Leaderboard
SELECT
tenant_id,
SUM(total_score) AS overall_score,
COUNT(DISTINCT cluster_id) AS clusters_active_in,
SUM(ipo_count) AS total_precedents_contributed
FROM contribution_scores
GROUP BY tenant_id
ORDER BY overall_score DESC
LIMIT 20;
Economic Equilibrium
Supply (Contributions)
Tenants earn credits by contributing. Incentive structure:Strong evidence + Won outcome = 20 + 5 = 25 credits
Moderate evidence + Pending = 15 + 0 = 15 credits
Minimal evidence + Lost = 10 + 0 = 10 credits
Demand (Queries)
Tenants spend credits by querying. Scaling:Embryonic cluster (5 prec) → 1.25 credits (cheap to explore)
Mature cluster (15 prec) → 1.75 credits
Canonical cluster (30+ prec) → 2.5+ credits (premium for proven value)
Equilibrium Point
With 100 credits/month allocation:Exemptions & Edge Cases
Free Query (Admin)
Admins can query without spending credits:IF current_user.role = 'admin' THEN
// Skip credit check, return cluster data
ELSE
// Normal credit check
Waived Query (Partner Program)
Pilot partners get free access for N months:SELECT waived_until FROM partner_exemptions WHERE tenant_id = $1
IF waived_until > NOW() THEN
// Skip credit burn
Reversed Burn (Dispute)
If query returned error (404, 500), reverse charge:// Query returned error
INSERT INTO credit_ledger (
event_type='adjustment',
amount=original_cost,
reference_id=failed_query_id,
metadata={'reason': 'query_error_refund'}
)
Compliance & Audit
7-Year Retention
Credit ledger retained per HIPAA:-- Calculate retention deadline
retained_until = created_at + INTERVAL '7 years'
-- Monthly cleanup job (runs 1st of month)
SELECT COUNT() FROM credit_ledger WHERE retained_until < TODAY
// Archive to cold storage
// Delete from active DB
Monthly Reconciliation
Verify ledger integrity and balance:-- Reconcile query_burn with marketplace_queries
SELECT cl.id, mq.id
FROM credit_ledger cl
LEFT JOIN marketplace_queries mq ON mq.receipt_hash = cl.receipt_hash
WHERE cl.event_type = 'query_burn'
AND cl.posted_at > NOW() - INTERVAL '30 days'
AND mq.id IS NULL; // ORPHANED entries (should not exist)
-- Verify no negative balance at any point
SELECT tenant_id, posted_at, SUM(amount) OVER (PARTITION BY tenant_id ORDER BY posted_at) AS running_balance
FROM credit_ledger
WHERE running_balance < 0; // Should never happen
Monitoring & Alerts
Health Checks
Credit Balance Distribution:-- What % of tenants have < 10 credits (near zero)?
SELECT
COUNT() FILTER(WHERE balance < 10) 100.0 / COUNT() AS pct_low_balance
FROM (SELECT tenant_id, SUM(amount) AS balance FROM credit_ledger GROUP BY tenant_id);
Alert if >30% of tenants are below 10 credits (may indicate pricing too high).
Contribution Inequality:
-- GINI coefficient (contribution fairness)
// Calculate: does one tenant dominate contributions?
// Alert if one tenant > 50% of all mints
Query Velocity:
-- Avg queries per tenant per month
SELECT
DATE_TRUNC('month', posted_at) AS month,
COUNT() FILTER(WHERE event_type='query_burn') AS queries,
COUNT(DISTINCT tenant_id) AS active_tenants
FROM credit_ledger
GROUP BY month
ORDER BY month DESC;
See also
Code reference
src/services/credit-economy.ts — Mint/burn logic, balance calculationssrc/routes/marketplace.ts — Query endpoints that trigger burnssrc/routes/precedents.ts — Create endpoints that trigger mintssrc/models/credit-ledger.ts — Query helpers (balance, audit trail, reconciliation)src/db/marketplace-schema.sql — credit_ledger table definition