Appearance
Touli Points Architecture (DLD)
Purpose
Define the deterministic points engine contract, config snapshoting model, cap/decay ordering, and ledger invariants.
Core Principle
Points attribution is deterministic and reproducible:
- no model calls
- no hidden constants in code
- all thresholds and multipliers sourced from versioned config snapshots
Engine Contract
Function signature (logical)
calculatePoints(input, context, configSnapshot) -> pointsDecision
Inputs
submission_iduser_idhours_claimedverify_levelgroup_size_bucketbeneficiary_flagpillaractivity_typebeneficiary_id(nullable)activity_at
Context
trust_tierstreak_statechallenge_completion_statepillar_diversity_statedaily_hours_usedweekly_hours_usedrepeat_activity_countermarket_mode
Output
points_awardedpoints_ledger_entry_typecomputation_breakdown(json)applied_caps[]applied_decays[]config_snapshot_iddecision_reason_codes[]
Formula and Ordering
Base formula:
final = round(55 * hours_capped * verify * community * trust * (1 + streak + completion + diversity))
Deterministic ordering:
- Validate eligibility and launch-mode constraints.
- Apply hour bounds:
- max per submission
- max per day
- max per week
- Resolve multipliers from lookup tables (
verify,community,trust). - Compute additive bonuses (
streak,completion,diversity). - Apply structural multiplier cap.
- Apply repeat-decay rule.
- Apply beneficiary policy rules (
selfvsothers|community). - Round and return final points.
The ordering above is immutable per config_snapshot_id.
Config Snapshot Model
Config domains:
anchor_points_per_hour- multiplier tables
- cap thresholds
- decay policies
- market mode flags (
launch|steady) - generosity bonus policy
- redemption eligibility policies
Snapshot rules:
- Each points decision references one immutable
config_snapshot_id. - Historical entries are never recalculated in place.
- Recompute jobs must use the historical snapshot attached to each ledger row.
Ledger Model
Source of truth:
- append-only
points_ledgerevent rows
Projection:
points_wallet.balanceas derived current-state cache
Required ledger fields:
ledger_entry_iduser_idsubmission_id(nullable for non-deed events)entry_type(deed_reward,gift_debit,gift_credit,adjustment,expiry,escrow_hold,escrow_release)points_deltabalance_after(optional but recommended for fast audit)config_snapshot_idreason_codes[]created_at
Ledger Invariants
- Ledger is append-only; no update/delete on financial semantics.
points_deltamust be non-zero for economic events.- Wallet projection must equal sum of ledger deltas for the user.
- One deed can produce at most one final reward entry per decision version.
- Reversal entries must reference original ledger entry id.
- Idempotent processing must prevent duplicate credits.
Idempotency Strategy
Idempotency key:
submission_id + decision_version + ledger_entry_type
Enforcement:
- unique constraint on idempotency key
- workers retry safely using the same key
- duplicate message processing resolves to no-op
Repeat-Decay and Beneficiary Rules
Repeat decay:
- keyed by
(pillar, activity_type, beneficiary_id, week_window) - third and subsequent identical actions apply configured decay
Beneficiary policy:
beneficiary_flag=selfcan trigger restricted/non-redeemable pathways in launch modebeneficiary_flag=others|communityrequired for full redeemable points, based on policy config
Generosity Bonus Path
- Applied on send events only.
- Percent sourced from policy tables by gift route type.
- Monthly cap and count cap enforced before credit.
- Bonus posts as separate ledger entry for audit clarity.
Dispute and Reversal Flow
mermaid
flowchart LR
disputeRaised[DisputeRaised] --> adjudication[Adjudication]
adjudication --> noChange[NoChange]
adjudication --> reverseEntry[ReverseOriginalEntry]
reverseEntry --> correctedEntry[PostCorrectedEntry]
correctedEntry --> walletReproject[WalletReprojection]Rules:
- never mutate original event
- always post compensating entries
- preserve linkage between original and correction entries
Observability Metrics
points_calc_latency_mspoints_credit_success_rateduplicate_credit_prevented_countledger_projection_drift_countreversal_rateconfig_snapshot_usage_distribution