Docs·a619bf7·Updated Jun 7, 2026·69 ADRs
Back
ADR-051implemented

ADR-051: Explore/Exploit Two-Tier Dibs Candidate Selection

ADR-051: Explore/Exploit Two-Tier Dibs Candidate Selection

Status: Implemented Date: 2026-05-04

Context

The dibs candidate selection system (filterEligibleCandidates in dibsScoringService.ts) previously required priorInteractions >= 1 as a hard gate. This is pure exploitation — it only considers people the requester has worked with before. A new user, or a requester whose trusted contacts have no prior interaction history, can never have a dibs candidate selected.

Additionally, getMutualAidCandidates hardcoded trustScore: 50 for every candidate. The reputation.trust_scores table exists and is populated — the query just never read it.

Decision

1. Real trust scores for mutual aid candidates

getMutualAidCandidates now reads reputation.trust_scores using a correlated subquery: MAX(score) across the requester's communities, defaulting to 50 if no score exists. The INNER JOIN on prior was changed to a LEFT JOIN, and all uses of prior.interaction_count are wrapped in COALESCE(..., 0).

2. Two-tier explore/exploit candidate selection

filterEligibleCandidates implements a fallback:

  • Tier 1 (exploit): Candidates with priorInteractions >= 1 && isAvailable. Preferred — these are known relationships.
  • Tier 2 (explore): Candidates with priorInteractions === 0 && trustGraphConnection === 'direct' && isAvailable. Fallback only when Tier 1 is empty.

A direct exchange connection (social_graph.connections.type = 'exchange') is required for explore candidates — community-only connections (type = 'community') do not qualify.

3. Trust context in DibsPrompt

The DibsCandidate interface gains trustGraphConnection. The hardcoded "Trusted provider" subtitle is replaced by a trustContextSummary() helper that outputs live context: e.g. "2 prior exchanges · direct connection" or "New connection".

Rationale

  • The explore tier enables first-contact dibs for requesters with no prior interaction history, using trust-graph position as the qualifying signal.
  • Requiring type = 'exchange' (not type = 'community') ensures the explore candidate has an actual completed transaction relationship with someone in the requester's trust graph — not just shared community membership.
  • The scoring formula already assigns 15 points for a direct connection and 10 for indirect, so explore candidates are naturally ranked lower than exploit candidates with equivalent trust scores. The tier system is a gate, not a score override.
  • This function applies to both provider and mutual aid candidate lists. A provider with 0 prior interactions but a direct trust connection also becomes an explore-tier candidate — this is intentional.

Consequences

  • Requesters with no prior interaction history can now receive dibs candidate suggestions.
  • The explore fallback is intentionally conservative: only one degree of trust-graph separation (direct exchange connection) qualifies.
  • Mutual aid dibs candidates now reflect real trust scores instead of a universal default.
  • Future work (Sprint 52+) may relax the explore criteria further if the explore tier proves useful in practice.