A Python implementation of the TRACE model for analysing human reliance on AI in trial-level decision-making datasets.
Naiseh, M. (2026). Reliance as a Trajectory: The TRACE Model of Dynamic Human Reliance on AI. International Journal of Human-Computer Interaction. (Under revision.)
Most reliance studies report aggregate scores — mean RAIR, mean WOA — that discard all temporal information. TRACE treats those aggregates as time-averaged snapshots of an underlying dynamic trajectory and provides tools to recover the trajectory itself.
TRACE represents each person's reliance disposition as a point in a two-dimensional state space defined by:
- F(t) — following tendency (operationalised as RAIR)
- Res(t) — resistance tendency (operationalised as RSR) The model has four components:
| Component | What it does |
|---|---|
1. Prior [F₀, Res₀] |
Starting position, set by algorithm appreciation and domain expertise |
| 2. Update function | Moves the state after each trial, asymmetrically (γ_D > 1) |
| 3. Decision function | Maps the latent state to an observable follow/resist decision |
| 4. Transfer function | Carries the final state forward to the next context |
Components 2 and 3 together make TRACE generative: given only a prior and an AI accuracy sequence, the model produces a complete synthetic sequence of decisions.
git clone https://github.com/monaiseh/TRACE-RELIANCE.git
cd TRACE-RELIANCE
pip install -e .Dependencies: numpy, pandas, matplotlib, scipy
Your dataset needs three columns per trial:
import pandas as pd
import trace
# Your data — one row per trial per participant
df = pd.DataFrame({
"participant_id": ["P001", "P001", "P001", ...],
"trial": [1, 2, 3, ...],
"ai_recommendation": [1, 1, 0, ...], # what the AI advised
"human_decision": [1, 0, 0, ...], # what the participant decided
"ground_truth": [1, 1, 0, ...], # the correct answer
})
# Step 1: classify trials and compute trajectories
traj_df = trace.compute_trajectories_by_participant(df)
# Step 2: compute trajectory statistics
stats_df = trace.compute_stats_by_participant(traj_df)
print(stats_df[["participant_id", "rair_final", "rsr_final",
"final_quadrant", "asymmetry_ratio"]])
# Step 3: visualise
fig, ax = trace.plot_state_space(traj_df, participant_col="participant_id")
fig.savefig("state_space.png", dpi=150, bbox_inches="tight")TRACE classifies each trial into one of four types based on AI correctness and human following behaviour:
| Type | AI Correct? | Human Followed? | Label | Update |
|---|---|---|---|---|
| A | Yes | Yes | Appropriate reliance | F += ε·α_A |
| B | Yes | No | Under-reliance error | F -= ε·α_B, Res += ε·β_B |
| C | No | No | Appropriate self-reliance | Res += ε·α_C |
| D | No | Yes | Over-reliance error | F -= ε·γ_D·α_A, Res -= ε·δ_D·α_C |
Type D carries two distinctive features: the asymmetric loss-aversion weight γ_D > 1, and cross-dimensional contamination (δ_D > 0) — following wrong AI advice also degrades the capacity to resist.
ε is the expertise scale: ε = 1 for lay users, ε < 1 for domain experts,
who update more slowly.
Component 3 — Decision function. Maps the latent state to a follow probability, decomposed into two signal-detection parameters:
d'(t) = (F(t) + Res(t)) / 2 # discriminability — calibration quality
c(t) = -(F(t) - Res(t)) / 2 + ctx # response bias — directional tendency
p = Φ(d'(t) - c(t)) # Φ = standard normal CDF
High F and high Res gives high discriminability (well-calibrated); low F and
low Res gives low discriminability (disengaged). The criterion c(t) captures
which direction a person leans, and is modulated by decision confidence,
stakes, and presentation format.
Component 4 — Transfer function. Carries reliance across contexts:
R₀_next = λ · R_final + (1 - λ) · P_domain
where λ ∈ [0,1] is moderated by contextual similarity, temporal proximity,
and AI system continuity.
| Function | Description |
|---|---|
classify_trials(ai, human, gt) |
Classify trials into types A–D |
trace_update(F, Res, trial_type, params) |
Component 2 — one update step |
trace_decision(F, Res, context=None) |
Component 3 — returns (p_follow, d_prime, c) |
generate_decision(F, Res, context, rng) |
Sample a binary follow/resist decision |
trace_transfer(R_final, P_domain, lam) |
Component 4 — initialise the next context |
run_full_trace(...) |
Full generative model over a trial sequence |
| Function | Description |
|---|---|
compute_trajectories(trial_types) |
Running RAIR(t), RSR(t) for one participant |
compute_trajectories_by_participant(df) |
Apply to a full dataset |
compute_trajectory_stats(traj_df) |
Trajectory statistics for one participant |
compute_stats_by_participant(df) |
Apply to a full dataset |
get_quadrant(rair, rsr) |
Identify state space quadrant |
| Function | Description |
|---|---|
estimate_gamma_D(traj_df) |
Asymmetry ratio from a trajectory |
estimate_lambda(s1_final, s2_initial) |
Transfer weight from two-session data |
required_trials(p_D) |
Minimum session length for a given Type D rate |
| Statistic | Description |
|---|---|
rair_final / rsr_final |
Final trajectory position |
rair_slope / rsr_slope |
Linear trend across trials |
stabilisation_trial |
When the trajectory stopped changing |
final_quadrant |
appropriate_reliance / over_reliance / under_reliance / disengagement |
asymmetry_ratio |
Empirical γ_D estimate (expected > 1 for lay users) |
alpha_a_hat / alpha_c_hat |
Reinforcement rate estimates |
| Function | Description |
|---|---|
plot_state_space(traj_df) |
Trajectories in F–Res state space |
plot_trajectories(traj_df) |
RAIR(t) and RSR(t) as time series |
plot_trial_type_distribution(stats_df) |
Bar chart of A/B/C/D counts |
plot_asymmetry_ratio(stats_df) |
Distribution of γ_D estimates |
python trace_simulation.pyGenerates four figures corresponding to Section 4 of the paper:
| Output | Content |
|---|---|
sim1_anchoring_primacy |
P2 — early vs late errors, mean session F |
sim2_asymmetric_updating |
P1 — asymmetry across γ_D = 1.0 to 2.5 |
sim3_cross_context_transfer |
P4 — carry-over as a function of λ |
sim4_parameter_recovery |
Recovery at T = 40 plus minimum session length |
Note on P3. The selective intervention prediction is deliberately not simulated. Setting γ_D lower and observing that F degrades less restates the update equation rather than testing it; P3 acquires empirical content only when applied to a real intervention whose mechanism is not known in advance. See Section 4.1 of the paper.
TRACE generates five testable predictions. The two most directly testable from existing data are:
- P1 (Asymmetric degradation):
asymmetry_ratio > 1for lay users, approaching 1 for domain experts. - P2 (Sequence primacy): Early Type D errors produce a larger
cumulative RAIR deficit than identical errors occurring later, measured
as mean session RAIR (the average of RAIR(t) across all trials). Final RAIR
may partially converge as the trajectory recovers; the cumulative measure
captures time spent in a disrupted reliance state.
See
examples/trace_example.ipynbfor worked code testing both.
Ground truth on every trial is required — without it, Types C and D cannot be distinguished.
Minimum session length is design-dependent. Estimating γ_D requires at least 5 Type D events per participant. These occur at rate
p_D = P(AI incorrect) × P(follow)
so the required session length is approximately T ≈ 8 / p_D for 90%
participant coverage:
| AI accuracy | Follow rate | p_D | Minimum T |
|---|---|---|---|
| 70% | 70% | 0.21 | 36 (recommend 40) |
| 80% | 70% | 0.14 | ~57 (recommend 60) |
| 90% | 70% | 0.07 | ~110 |
Use required_trials(p_D) to compute this for your own design. Studies using
highly accurate AI cannot support individual-level γ_D estimation at realistic
session lengths, and must either pool across participants or deliberately
introduce errors.
Varying AI accuracy within-session is recommended so all four trial types occur. For λ estimation, at least two sessions or tasks per participant are needed.
pip install pytest
pytest tests/@article{naiseh2026trace,
title = {Reliance as a Trajectory: The {TRACE} Model of Dynamic
Human Reliance on {AI}},
author = {Naiseh, Mohammad},
journal = {International Journal of Human-Computer Interaction},
year = {2026},
note = {Under revision}
}MIT License — see LICENSE for details.