Trust, built in seven layers
A narrative introduction that builds the framework from first principles — no mathematics prerequisites. Each layer is explained with intuition first, formalism second, and code third. Seven hands-on walkthroughs apply the framework to concrete scenarios.
Foundations
Why trust needs layers, what each layer answers, and where the dyadic baseline sits in the framework.
1.1Why Trust Needs Layers
The Problem with "Just Give Me a Number"
Suppose you are building an autonomous purchasing agent. It must decide whether to buy a refurbished camera from an unknown seller on Amazon. The naive approach is to compute a single trust score — say, "the seller is 87% trustworthy" — and act if the score exceeds some threshold.
This fails for three reasons.
The layered framework addresses all three problems by decomposing trust into seven independent-but-coupled components, each answering a distinct question.
1.2The Seven Questions
Each layer of the framework answers one question:
| Layer | Question it answers |
|---|---|
| L1 — Perceived Trustworthiness | What do I believe about this trustee's competence, goodwill, and honesty? |
| L2 — Behavioral Threshold | Given what I believe, is acting on that belief worth the risk? |
| L3 — Bayesian Learning | How do I update my belief as I observe new evidence? |
| L4 — Temporal Dynamics | How does trust evolve between observations — and how does it break? |
| L5 — Strategic Layer | Does the trustee have an incentive to betray me? |
| L6 — Network Propagation | What can I infer from others' experiences? |
| L7 — Group Trust Extension | How do I trust a team, committee, or multi-signature wallet? |
You do not need all seven. A simple transaction might use only L1–L3. An ongoing relationship might add L4 and L5. A coalition decision might add L6 and L7. The framework is composable: layers can be switched on and off without breaking the others.
1.3The Dyadic Baseline
The framework's starting point is the classical dyadic
relationship: one trustor i evaluating one trustee
j at time t, producing a trust score
T_{i,j}(t) ∈ [0,1].
This is the form most computational trust models take (Mayer–Davis–Schoorman, Beta reputation, TrustWalker). The framework's contribution is to show that this dyadic model is a special case of a more general collective model, and that the seven layers compose cleanly into both.
The Seven Layers
Each layer in turn: the question it answers, the intuition behind it, the formalism, and code that exercises it.
L1Perceived Trustworthiness
What do I actually believe about this trustee?
The Idea
The Mayer–Davis–Schoorman cognitive trust model, which has been validated across decades of organizational psychology, holds that trustworthiness has three components:
- Ability (
A) — can the trustee do the job? - Benevolence (
B) — does the trustee want to help me? - Integrity (
I) — will the trustee keep their word?
A surgeon may be highly able but have poor bedside manner (low benevolence). A friend may be benevolent but not competent to perform surgery (low ability). Both matter, and they matter differently depending on the context.
The Formalism
P_{i,j}(t) = α · A_{i,j}(t) + β · B_{i,j}(t) + γ · I_{i,j}(t), α + β + γ = 1
The weights α, β, γ encode what matters in this domain.
For a surgical team, ability might dominate (α = 0.7). For a
customer service interaction, benevolence might matter more.
The trustor's propensity τ_i ∈ [0,1]
modulates the baseline willingness:
T^{static}_{i,j}(t) = τ_i · P_{i,j}(t)
In Code
from trustlib_mas import Trustee, Trustor
ceo = Trustee("ceo", A=0.90, B=0.30, I=0.80)
veteran = Trustor("veteran", trust_propensity=0.30)
newbie = Trustor("newbie", trust_propensity=0.80)
P = ceo.perceived_trustworthiness(alpha=0.7, beta=0.2, gamma=0.1)
print(f"P = {P:.3f}") # P = 0.770
print(veteran.trust_propensity * P) # 0.231
print(newbie.trust_propensity * P) # 0.616
L2The Behavioral Threshold
Trustworthiness is not the same as action. When should I actually act?
The Idea
Trust is only actionable under risk. If the trustee always does the right thing, there is nothing to decide. The decision to rely on someone is an expected-utility calculation.
The Formalism
E[U_{i,j}(t)] = P_{i,j}(t) · U_win + (1 − P_{i,j}(t)) · U_loss
The trustor acts if E[U] ≥ θ_i(t), where
θ_i(t) = ρ_i · S(t) combines the trustor's
risk aversion ρ_i and the situational
stakes S(t).
In Code
from trustlib_mas import Trustee, Trustor, TrustScenario
buyer = Trustor("buyer", trust_propensity=0.6, risk_aversion=0.20)
seller = Trustee("seller", a=130, b=20, discount_factor=0.80)
sc = TrustScenario("Amazon", buyer, seller,
U_win=100, U_loss=-800, stakes=800)
decision, trust, eu = sc.run()
print(f"Trust: {trust:.3f}") # 0.372
print(f"EU: {eu:.2f}") # -465.29
print(f"Threshold: {sc.threshold():.2f}") # 160.00
print(f"Decision: {'BUY' if decision else 'DO NOT BUY'}") # DO NOT BUY
+$100 vs. −$800) makes the bet unattractive to
a moderately risk-averse buyer.
L3Bayesian Learning
How do I update my belief when I observe new evidence?
The Idea
Trust is not fixed. Each interaction — success or failure — should update the trustee's reliability estimate. The natural framework for this is Bayesian inference with a Beta-Binomial conjugate prior.
The Formalism
P_{i,j}(t) ~ Beta(a_{i,j}(t), b_{i,j}(t))
E[P_{i,j}(t)] = a_{i,j}(t) / (a_{i,j}(t) + b_{i,j}(t))
a_{i,j}(t+1) = λ · a_{i,j}(t) + s
b_{i,j}(t+1) = λ · b_{i,j}(t) + (1 − s)
The recency parameter λ ∈ (0, 1] controls
how much old evidence is discounted.
In Code
from trustlib_mas import Trustee
seller = Trustee("seller", a=1, b=1)
print(seller.bayes_mean()) # 0.500
for _ in range(3):
seller.update_bayes(success=True)
print(f"a={seller.a}, b={seller.b}, mean={seller.bayes_mean():.3f}")
# a=4.0, b=1.0, mean=0.800
seller.update_bayes(success=False, lam=0.9)
print(f"a={seller.a:.2f}, b={seller.b:.2f}, mean={seller.bayes_mean():.3f}")
# a=3.60, b=1.90, mean=0.654
L4Temporal Dynamics
What happens between observations? And why does trust break so much faster than it builds?
The Idea
Trust is not just a running average of evidence. It decays autonomously when no evidence arrives, and it responds asymmetrically to successes and failures. This asymmetry — the negativity bias — is one of the most robust findings in human-automation trust research.
The Formalism
dP_{i,j}/dt = −δ · (P_{i,j}(t) − P_baseline)
dT_{i,j}/dt = k_build (1 − T_{i,j}) · 1_success
− k_destroy · T_{i,j} · 1_failure
Recovery time: t = (1/k_build) · ln( (1 − T_0) / (1 − T*) )
In Code
from trustlib_mas import Trustee
car = Trustee("robotaxi", k_build=0.1, k_destroy=0.8)
car.trust = 0.65
car.asymmetric_dynamics(success=False)
print(f"After failure: {car.trust:.3f}") # 0.130
t = car.recovery_time(target=0.80)
print(f"Recovery time: {t:.2f} rides") # 14.70 rides
k_destroy / k_build = 8 captures the severe
collapse observed in real human-robot interaction studies.
L5The Strategic Layer
Cognitive trustworthiness is not enough. Does the trustee have an incentive to betray me?
The Idea
A trustee may be perfectly able, benevolent, and honest, yet still defect
if the incentives are wrong. In an infinitely repeated Prisoner's Dilemma,
the trustee cooperates if and only if their discount factor
δ exceeds a critical threshold.
The Formalism
δ* = (T − R) / (T − P)
Φ(δ_j) = σ( β_s (δ_j − δ*) ), σ(x) = 1 / (1 + e^{−x})
In Code
from trustlib_mas import Trustee, Trustor, TrustScenario, strategic_factor
for delta in [0.50, 0.60, 0.708, 0.80, 0.90]:
phi = strategic_factor(delta, delta_star=0.708, beta_s=10.0)
print(f"delta={delta:.3f} Phi={phi:.4f}")
lender = Trustor("lender", trust_propensity=0.5, risk_aversion=0.25)
borrower = Trustee("borrower", a=68, b=2, discount_factor=0.60)
sc = TrustScenario("P2P", lender, borrower,
U_win=750, U_loss=-5000, stakes=5000)
print(sc.report())
L6Network Propagation
I have never interacted with this trustee. Can I learn from others?
The Idea
If agent A trusts agent B, and B trusts agent C, then A has indirect evidence about C. Layer 6 aggregates these indirect paths.
The Formalism
T^{indirect}_{i,j}(t) = ( Σ_{k ≠ i,j} T_{i,k} · T_{k,j} · φ_{i,k} )
/ ( Σ_{k ≠ i,j} T_{i,k} · φ_{i,k} + ε )
T(t+1) = μ · T_direct(t+1) + (1 − μ) · T_indirect(t)
In Code
from trustlib_mas import TrustNetwork
net = TrustNetwork(n_agents=4)
net.set_direct(0, 1, 0.90)
net.set_direct(0, 2, 0.40)
net.set_direct(1, 2, 0.95)
net.set_direct(1, 3, 0.70)
net.set_direct(2, 3, 0.85)
net.iterate(steps=5, mu=0.5)
for row in net.direct:
print([round(x, 3) for x in row])
print(f"Agent 0's trust in agent 3: {net.direct[0][3]:.4f}")
L7The Group Trust Extension
Layer 7 is the paper's central contribution and deserves its own part. See Part III below.
The Group Trust Extension
How the framework generalizes from one trustee to a structured group, and why the dyadic model is a special case.
3.1The Problem with "Sum of Parts"
Suppose you are deciding whether to trust a five-truck autonomous platoon. Four trucks are reliable (trust = 0.92); one has a sensor glitch (trust = 0.40). What is your trust in the platoon?
The naive answer is the average: 0.816. But this is wrong for a platoon, because the platoon requires all trucks to function. If any one fails, the formation fails. The platoon's reliability is closer to the weakest link — 0.40.
The Group Trust Extension formalizes this intuition. It says: trust in a group depends on the group's decision architecture.
3.2Four Aggregation Architectures
Series (weakest-link)
T^{series}_{i,G} = min_{j ∈ G} (T_{i,j}) · κ
Used for: platoons, surgical teams, sequential pipelines.
Parallel (redundancy)
T^{parallel}_{i,G} = ( 1 − Π_{j ∈ G} (1 − T_{i,j}) ) · κ
Used for: sensor arrays, backup systems, ensembles.
Quorum (k-of-m)
T^{quorum}_{i,G} = P(X ≥ k) · κ, X ~ BetaBin(m, α, β)
Used for: DAO multi-signature wallets, juries, boards.
Custom
T^{custom}_{i,G} = f(T_{i,j}, …) · κ
Used for: harmonic mean (surgical teams), weighted averages.
3.3The Cohesion–Diversity Factor κ
κ = min{ 1, exp( −ν_pen · max(0, σ² − τ) + ν_rew · H ) }
σ²— variance of individual trust scoresH— Shannon entropy of the trust distributionν_pen— penalizes excess varianceν_rew— rewards entropyτ— variance tolerance
3.4The Correlated Quorum
The quorum formula above assumes members fail independently.
This is often wrong. In a DAO, signers may collude. In a sensor array,
sensors may share a firmware bug. The framework accounts for this with a
correlation parameter ρ ∈ [0, 1).
α = T̄ · (1 − ρ) / ρ, β = (1 − T̄) · (1 − ρ) / ρ
k > m·T̄), positive correlation reduces the
survival probability, because members fail together. Most realistic
multi-signature scenarios fall in this regime, so the framework's
correlated quorum is deliberately conservative.
3.5The Collective Strategic Factor
Φ_G = σ( β_s (Δ_G − δ*) )
T^{eff}_{i,G} = T^{agg}_{i,G} · Φ_G
3.6The Unification Theorem
For m = 1, the entire Group Trust Extension reduces
exactly to the dyadic model. This means the framework
is a strict generalization — you can use the group machinery everywhere,
and it will never disagree with the dyadic case when there is only one
member.
from trustlib_mas import verify_unification
print(verify_unification())
# {'specialisation': True, 'bayesian_consistency': True,
# 'strategic_consistency': True, 'bounds': True}
Using the Library
The four core classes, the decision pipeline, and the evaluation toolkit you will use to inspect and validate your model.
4.1The Four Core Classes
| Class | Represents | Key attributes |
|---|---|---|
Trustee |
The agent being evaluated | a, b, A, B,
I, discount_factor, k_build,
k_destroy |
Trustor |
The agent making the decision | trust_propensity, risk_aversion,
delta_star, beta_s |
TrustGroup |
A collective trustee | members, aggregation, quorum_k,
correlation_rho, cohesion_* |
TrustScenario |
The decision pipeline | trustor, target, U_win,
U_loss, stakes |
4.2The Decision Pipeline
1. Compute T_eff:
- Dyadic: τ × P × Φ(δ)
- Group: F(T_ij) × κ × Φ_G
2. Compute EU = T_eff × U_win + (1 - T_eff) × U_loss
3. Compute θ = ρ × stakes
4. Decision = (EU ≥ θ)
You invoke this with scenario.run(), which returns
(decision, trust, eu).
4.3Inspecting Intermediate Values
report = sc.report()
# {'name': ..., 'effective_trust': ..., 'expected_utility': ...,
# 'threshold': ..., 'decision': ...}
group.individual_trusts() # the trust vector
group.aggregate_raw() # F applied, before κ
group.cohesion_factor() # κ
group.aggregate_trust() # aggregate_raw × κ
4.4The Evaluation Toolkit
| Function | Purpose |
|---|---|
simulate_comparison() | Compare the unified model against baselines |
run_repeated_sim() | Same, with 95% confidence intervals |
run_ablation_study() | Remove each component one at a time |
run_robustness_check() | Test against model misspecification |
roc_auc(), precision_recall() | Classification metrics |
from trustlib_mas import run_ablation_study
for name, r in run_ablation_study(n_scenarios=2000).items():
print(f"{name:<24} acc={r['accuracy']:.3f} brier={r['brier']:.3f}")
# full acc=0.902 brier=0.073
# no_cohesion acc=0.856 brier=0.095
# no_correlated_quorum acc=0.871 brier=0.088
# no_strategic acc=0.847 brier=0.101
# no_temporal acc=0.864 brier=0.092
Seven Application Walkthroughs
Each walkthrough applies the framework to a concrete scenario, with the code, the result, and what the result teaches.
W1Autonomous Vehicle After a Failure
Scenario. A passenger trusts a Level-4 robotaxi. After ten flawless rides, a single "phantom brake" event occurs.
from trustlib_mas import Trustee, Trustor, TrustScenario
passenger = Trustor("passenger", trust_propensity=0.70, risk_aversion=0.15)
car = Trustee("car", a=10, b=1, discount_factor=0.90)
car.trust = 0.65
car.asymmetric_dynamics(success=False, k_build=0.1, k_destroy=0.8)
sc = TrustScenario("Robo-taxi", passenger, car,
U_win=50, U_loss=-200, stakes=100)
print(sc.report())
Result. Trust after failure: 0.13. Recovery time to 0.80: 14.7 rides. Expected utility: −$180.25 vs. threshold $15. Do Not Trust.
W2P2P Lending
Scenario. A lender evaluates a borrower with an excellent credit score but unstable income.
lender = Trustor("lender", trust_propensity=0.5, risk_aversion=0.25)
borrower = Trustee("borrower", a=68, b=2, discount_factor=0.60)
sc = TrustScenario("P2P Loan", lender, borrower,
U_win=750, U_loss=-5000, stakes=5000)
print(sc.report())
Result. Effective trust 0.123. EU = −$4,292.75 vs. threshold $1,250. Do Not Trust.
W3Blockchain Validator
Scenario. A token holder considers delegating $100k to a validator with 95% reliability, but with an unfavorable payoff structure.
delegator = Trustor("delegator", trust_propensity=0.80, risk_aversion=0.10)
validator = Trustee("validator", a=95, b=5, discount_factor=0.90)
sc = TrustScenario("Validator", delegator, validator,
U_win=5000, U_loss=-10000, stakes=10000)
print(sc.report())
Result. Effective trust 0.664. EU = −$56.94 vs. threshold $1,000. Do Not Delegate.
W4Autonomous Truck Platoon
Scenario. A manager considers activating a platoon of five trucks. Truck #4 has a sensor glitch.
from trustlib_mas import Trustee, TrustGroup, AggregationType
trucks = [Trustee(f"T{i}", a=92, b=8) for i in range(4)]
trucks.append(Trustee("T4", a=40, b=60))
platoon = TrustGroup(trucks,
aggregation=AggregationType.SERIES,
cohesion_pen=10.0, cohesion_tau=0.02)
print(f"Raw aggregate: {platoon.aggregate_raw():.4f}")
print(f"Cohesion factor: {platoon.cohesion_factor():.4f}")
print(f"Effective trust: {platoon.aggregate_trust():.4f}")
Result. Raw aggregate = 0.40 (the weakest link). Cohesion factor ≈ 0.79. Effective trust ≈ 0.317.
W5DAO Multi-Signature Treasury
Scenario. A DAO member considers delegating to a 5-of-9 multi-signature wallet. Signers may influence each other.
signers = [Trustee(f"S{i}", a=90, b=10) for i in range(6)]
signers.append(Trustee("M", a=60, b=40))
signers.extend([Trustee(f"U{i}", a=40, b=60) for i in range(2)])
for rho in [0.0, 0.2, 0.5]:
dao = TrustGroup(signers, aggregation=AggregationType.QUORUM,
quorum_k=5, correlation_rho=rho,
cohesion_pen=2.0, cohesion_tau=0.02)
print(f"rho={rho:.1f} T_agg={dao.aggregate_trust():.4f}")
Result. ρ = 0.0 → 0.917; ρ = 0.2 → 0.867; ρ = 0.5 → 0.760.
W6Hybrid Fact-Checking Panel
Scenario. A user evaluates a fact-checking panel: three AI models and two human experts, with mixed verdicts.
from trustlib_mas import Trustee, TrustGroup, AggregationType
members = [
Trustee("AI1", a=80, b=20),
Trustee("AI2", a=80, b=20),
Trustee("AI3", a=70, b=30),
Trustee("Hum1", a=90, b=10),
Trustee("Hum2", a=85, b=15),
]
panel = TrustGroup(members, aggregation=AggregationType.QUORUM,
quorum_k=3,
cohesion_pen=20.0, cohesion_tau=0.1,
cohesion_rew=5.0,
entropy_override=0.673)
print(f"T_agg = {panel.aggregate_trust():.4f}")
Result. T_agg ≈ 0.950. The entropy reward (ν_rew = 5) offsets the variance penalty, so κ = 1.0.
W7Surgical Team
Scenario. A patient evaluates a five-member surgical team that has never rehearsed together.
from trustlib_mas import Trustee, TrustGroup, AggregationType, harmonic_mean
team_members = [
Trustee("Surgeon", a=95, b=5),
Trustee("Anes", a=90, b=10),
Trustee("Nurse1", a=98, b=2),
Trustee("Nurse2", a=70, b=30),
Trustee("Perf", a=85, b=15),
]
pre = TrustGroup(team_members, aggregation=AggregationType.CUSTOM,
custom_aggregator=harmonic_mean,
cohesion_pen=50.0, cohesion_tau=0.0)
post = TrustGroup(team_members, aggregation=AggregationType.CUSTOM,
custom_aggregator=harmonic_mean,
cohesion_pen=5.0, cohesion_tau=0.0)
print(f"Pre-rehearsal: T_agg = {pre.aggregate_trust():.4f}")
print(f"Post-rehearsal: T_agg = {post.aggregate_trust():.4f}")
Result. Pre-rehearsal: 0.532. Post-rehearsal: 0.823.
Advanced Topics and Pitfalls
Aggregation choices, the heuristic nature of κ, calibration, validation, and the mistakes that trip people up.
6.1Choosing an Aggregation
| Decision structure | Use |
|---|---|
| All must succeed | SERIES |
| Any one suffices | PARALLEL |
| At least k must agree | QUORUM |
| Average / harmonic / weighted | CUSTOM |
PARALLEL would appear highly trustworthy (at least one
member will succeed), but this is not what you want — you want the
whole team to succeed.
6.2The Heuristic Nature of κ
The cohesion-diversity function is not derived from first principles. It is a plausible functional form that captures two qualitative intuitions: excessive heterogeneity is bad in safety-critical systems; useful diversity is good in advisory contexts.
from trustlib_mas import HEURISTIC_NOTE
print(HEURISTIC_NOTE)
cohesion_pen over a plausible range.
6.3The Monotonicity Caveat
A naive reading of the framework suggests that raising one member's trust
should raise the group's trust. This is not always true.
Consider a group with trust vector [0.9, 0.1, 0.1]. If you
raise one of the 0.1 members to 0.9, the variance may increase further,
reducing κ.
aggregate_raw() and
cohesion_factor() separately.
6.4Calibration
| Parameter | Class | How to calibrate |
|---|---|---|
a, b | Trustee | Count successes/failures |
A, B, I | Trustee | Survey instruments |
discount_factor | Trustee | Estimate from repeated interactions |
k_build, k_destroy | Trustee | Fit to observed recovery curves |
trust_propensity | Trustor | Survey of disposition |
risk_aversion | Trustor | Elicit from lottery choices |
correlation_rho | TrustGroup | Method of moments on joint outcomes |
cohesion_* | TrustGroup | MLE on team performance data |
6.5Validating Your Model
- Split your data: 70% train, 30% test.
- Fit on train, evaluate on test.
- Report Brier score, ROC-AUC, and calibration.
- Ablate: remove one component at a time.
- Robustness: test on data that violates your assumptions.
from trustlib_mas import (
run_repeated_sim,
run_ablation_study,
run_robustness_check,
)
summary = run_repeated_sim(n_scenarios=2000, n_repeats=50)
ablation = run_ablation_study(n_scenarios=2000)
robustness = run_robustness_check(n_scenarios=2000)
6.6Common Mistakes
Mistake 1 — Treating "Do Not Trust" as a verdict on the trustee.
The decision is a joint function of trust, payoff, and stakes. A declined
trustee may still be trustworthy. Check scenario.report().
Mistake 2 — Applying propensity twice.
In dyadic scenarios, the library applies τ automatically. If
you also wrap the result in a group and apply a group-level propensity,
you double-count.
Mistake 3 — Using SERIES for everything.
Series is appropriate when all must succeed. If your group has
redundancy, use PARALLEL or QUORUM.
Mistake 4 — Assuming independence in a quorum.
Real quorums correlate. If your signers share information, set
correlation_rho > 0.
Mistake 5 — Ignoring cohesion.
A group of individually excellent agents can still have low effective
trust if their coordination is poor. If your model always yields
κ = 1, you probably haven't set cohesion_pen.
6.7Performance
| Workload | Time |
|---|---|
| Single decision | < 1 ms |
| 1,000 decisions | < 1 s |
| 10,000 decisions | ~2 s |
| Simulation (2,000 scenarios, 50 repeats) | ~30 s |
For heavy workloads, parallelize with multiprocessing.
Where to Go Next
If you have read this far, you know:
- Why trust needs seven layers, not one number
- How each layer works and what problem it solves
- How the Group Trust Extension generalizes the dyadic model
- How to use the
trustlib-maslibrary in code - How to apply the framework to seven concrete scenarios
- What the framework's limitations are and how to address them
Next steps
- Read the manuscript for the full mathematical
derivations and the simulation study. The paper version is
v3(seetrustlib_mas.__paper_version__). - Run the examples. The repository's
examples.pyreproduces every case study in the paper. - Run the tests.
python -m unittest test_trustlib_mas -vverifies the library's behavior. - Build something. The framework is extensible — you can supply custom aggregators, custom entropy measures, and custom dynamics by subclassing.
trustlib-mas give you the vocabulary
and the tools to model all three.