Contestatory constitutionalism

Routes for disputing a single decision

A person affected by an automated decision gets a standing channel that brings their objection to a human, who has to respond. The exchange is recorded. Some papers are design frameworks that set out the features such a channel needs, covering both mechanisms built in ahead of time and mechanisms added afterward. Others are working systems, from a ban-appeal channel in a Reddit community of millions to a clinical dashboard where a doctor files structured disagreement with the model's reading. There is also one speculative design concept for a municipal camera car. The fuller designs include notice of the decision and a statement of its grounds, but not all designs do. What all the papers share is that the object of dispute is a single decision, and the remedy is a reply plus a record of what happened.

The method (highlighting differences with Contestatory constitutionalism)

Scroll the diagram sideways to see all of it.

Use it in codefrom aiag.codified import Appeals
from aiag import LM
from aiag.codified import Appeals

lm = LM("Qwen/Qwen2.5-1.5B-Instruct")
appeals = Appeals(lm, policy="No instructions for defeating locks or security systems.")

decision = appeals("A user asks how to pick a pin tumbler lock.")  # decided under the policy, with grounds
ruling = appeals.appeal(decision, "I'm a licensed locksmith training an apprentice.")
print(ruling["upheld"], ruling["ruling"])  # the reviewer's verdict and reasons, on the record

pip install aiagEvery method in aiag Library on GitHub

Concept Analysis: Theoretical Foundations

Each concept is read twice: whether the approach carries it over, and whether the approach's own sources claim it. A concept that the approach claims but does not carry over is a shortfall. A concept that it neither claims nor carries over is an omission, which marks a gap in the field rather than a failure of the work.

Contestability

PartialShortfall · partially preserved

Definition (Philip Pettit, On the People's Terms, 2012)

This concept holds that anyone subject to a decision must have a real route to challenge it. They must be able to inspect the grounds for the decision, contest the outcome, and have the challenge answered. Legitimacy is not settled once by an election or an act of consent. It depends on that route remaining available. On this view, a political order is free when the people its decisions affect can contest them, whether or not its rulers are kind.

Analysis

A standing appeal channel now exists and has been tested in the field. AppealMod handled ban appeals in a Reddit community of over 29 million users in a four-month randomized experiment. ConGaIT gives clinicians a contest-and-justify control when they review an automated gait assessment. What keeps this short of Pettit's standard is the purpose of AppealMod. Its mechanism is friction, since appellants must provide more before a human looks at the appeal, and it works by selection. Moderators saw only 30% of appeals and under 10% of the toxically worded ones. The rate of granted appeals held steady, which is the paper's defense. However, a route that is deliberately made costly is not clearly a route available to everyone subject to a decision.

Non-domination

PartialShortfall · partially preserved

Definition (Philip Pettit, Republicanism, 1997)

This concept holds that freedom is not the absence of interference. A person is unfree if someone holds unchecked power over them, even if that person never misuses it and means well. A benevolent master still dominates, and so does an authority whose workings cannot be seen. Legitimacy requires power to be checked, and good intentions are not enough.

Analysis

Pettit's test is not whether a channel exists but whether power is forced to track the interests of the governed. This approach is the first entry here that measures this at all. The randomized experiment reports roughly the same number of granted appeals as in the control condition, which is evidence that the filter did not quietly change outcomes. However, the check runs in the opposite direction from what the tradition requires. It was built to protect moderators' workload and to preserve their agency over each decision. What it shows is that the appellant's chances were not made worse. It does not show that the moderator's power was made answerable.

Public decision record

PartialShortfall · partially preserved

Definition (Common-law practice)

Rulings on challenges are written down, published, and citable. The legal order's interpretation of its own rules therefore accumulates in public, where it can be studied, invoked, and criticized. This record makes the legal order both predictable and legitimate, since nothing is settled in private and every decision leaves its reasoning on record.

Analysis

The design proposals specify a public record, in which each ruling on a challenge enters a record that can be cited later. This is what the tradition asks for. The systems that were built do not do this. AppealMod's appeals are settled privately between an appellant and a moderator, and ConGaIT's contest-and-justify exchanges stay inside the clinical record. Nothing accumulates in public, so no later challenge can be decided by reference to an earlier one. The record exists only in the design proposals.

Papers

No method has been built for this approach yet. It rests on the work listed below.

Deployed, not devised

Existing techniques applied in one real setting. They report what happened there, so they are evidence about the approach, not new methods for it.

doi:10.1145/3544548.358098437 citationsApplicationPartial

Applies the contestable-AI framework to a concept for a municipal camera car. The concept includes notice of the automated assessment, affordances for disputing it, appeal routing to civil servants, and an audit trail. It is presented as a concept video and evaluated through interviews with 17 civil servants operating AI in a large European city.

CodeContestableCameraCar
from aiag import LM
from aiag.codified import ContestableCameraCar

lm = LM("Qwen/Qwen2.5-1.5B-Instruct")
cars = ContestableCameraCar(lm, "Flag waste left on the street outside collection hours.",
                            departments={"waste": lm, "parking": lm})  # who reviews each kind of case
decision = cars("A bag of rubbish beside a bin on Tuesday evening.")

print(cars.notice(decision))  # that a machine decided, on what grounds, and how to dispute it
dispute = cars.appeal(decision, "That's my recycling, out for Wednesday's early collection.")
print(dispute["department"])  # the civil servants the dispute was routed to

pip install aiagEvery method in aiag Library on GitHub

arXiv:2507.22300ApplicationBuilt

A dashboard for Parkinson's disease gait analysis. Through a Contest and Justify interaction, a clinician registers structured disagreement with the model's reading. The interaction is supported by visual explanations, role-based feedback, and traceable justification logs.

CodeConGaIT
from aiag import LM
from aiag.codified import ConGaIT

lm = LM("Qwen/Qwen2.5-1.5B-Instruct")
dashboard = ConGaIT(lm, "Rate Parkinsonian gait severity from 0 (normal) to 4 (cannot walk without help).")
reading = dashboard("Stride length reduced, slight shuffle, no arm swing on the left.")

# Contest one aspect, propose an alternative, justify it
dashboard.contest(reading, "severity", proposed="1", role="neurologist",
                  justification="Stride is normal for her age; the missing arm swing is the only sign.")
print(dashboard.trail(reading))  # each contest with the clinician's role and the explanation they saw
  • ConGaITProcedureaiag/codified/contestatory_constitutionalism.py:331 ConGaIT: a clinician contests one named aspect of the model's reading after seeing its explanation, proposes an alternative and justifies it, and each contest is kept with the clinician's role in a traceable justification log (Nguyen & Do, 2025).

pip install aiagEvery method in aiag Library on GitHub

Measured, not built

Instruments that measure the approach instead of implementing it. The grid counts methods only, so these are listed here but not counted.

arXiv:2506.01662BenchmarkPartial

Gives a formal definition of contestability in explainable AI. It offers a modular set of by-design and post-hoc mechanisms spanning human-centered interfaces, technical architectures, legal processes, and organizational workflows. It also introduces the Contestability Assessment Scale, a composite metric built on more than twenty quantitative criteria.

Argued for, not built

Work that argues for this approach or sketches a design for it, without building and testing it.

doi:10.1007/s11023-022-09611-z82 citationsProposalGap

A framework of design features and organizational practices, drawn from a systematic review, for building AI systems that the people subject to them can dispute.

CodeContestableByDesign
from aiag import LM
from aiag.codified import ContestableByDesign

lm = LM("Qwen/Qwen2.5-1.5B-Instruct")
system = ("A city's parking-fine model. Each fine shows the evidence photo, residents can request human review online, "
          "and an external ombudsman audits a sample of fines every quarter.")
scores = ContestableByDesign(lm)(system)  # P(present) for each of the 5 system features and 6 development practices

pip install aiagEvery method in aiag Library on GitHub

Precedent from outside AI

Work from law, political theory, or another discipline that supplies the tradition this approach is read against.

doi:10.1145/36372967 citationsPrecedentBuilt

An appeals system for a Reddit community with millions of subscribers. A user who appeals a ban must first supply further information through a bot. The bot then passes the exchange to human moderators as a structured record.

CodeAppealMod
from aiag import LM
from aiag.codified import AppealMod

lm = LM("Qwen/Qwen2.5-1.5B-Instruct")
mod = AppealMod(lm, policy="Gardening forum: no self-promotion, no repeated links.")
ban = mod("User posted the same seed-shop link in 12 threads in one hour.")

# The bot's questions come first; only a finished form reaches the moderators
form = dict(zip(AppealMod.QUESTIONS, ["The no-spam rule.", "It's my own shop and I didn't know.", "Yes, no more links."]))
mod.appeal(ban, "I'm not a spammer.", answer=form.get)
mod.appeal(ban, "This is unfair!", answer=lambda question: "")  # gave up at the first question
print(mod.workload())  # -> 0.5: share of appeals that reached a moderator

pip install aiagEvery method in aiag Library on GitHub