YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
Diagnosing the belief, not the bug
A deductive multi-agent system for automated cognitive misconception diagnosis and Socratic intervention in advanced computer science education
Contemporary AI tutors operate in a direct response paradigm: a student brings a problem, the model returns the solution. That is efficient and pedagogically inert. In cumulative disciplines a correct answer handed over does not repair the belief that produced the wrong one, so the same cognitive error reappears in the next, harder problem.
This system inverts the use of the model's reasoning. Instead of pointing it at the problem, it points it at the student: three agents collaborate to find the exact instant a learner's reasoning left the correct path, locate the prerequisite concept that made that misstep possible, and ask the question that exposes the contradiction β without ever revealing the answer.
./dmas session --file attempt.py
Runs immediately from a fresh checkout. No install, no API key, no network, no third-party packages.
The session
The tutor is interactive, because Socratic teaching is. It reveals one rung at a time β a ladder printed all at once is just a worked answer delivered slowly β and it remembers you between attempts, so after you edit the file it can answer the question that matters: was the belief repaired, or the symptom patched?
Session transcript Β· plain text
dmas βΈ load attempt.py
loaded attempt.py Β· 10 lines Β· task lower_bound
DIAGNOSIS Mixed interval conventions Β· 0.77 Β· L4
5/7 inputs pass
______________________________________________________________
dmas βΈ hint
hint 1/3 Β· orienting Β· Loop invariants
Take the input ([0], 1) and step through your own function by hand, writing
down the values at line 4 each time you reach it. Stop at the first moment a
value surprises you.
sit with that one first β `hint` again when you are stuck
______________________________________________________________
dmas βΈ hint
hint 2/3 Β· contradiction Β· Loop invariants
At that point your `hi` holds 0, but for the answer to be reachable it would
have to be 1. Which line last wrote `hi`, and what did you assume about the
range it was allowed to take?
β¦ the student edits the file in their editor β¦
______________________________________________________________
dmas βΈ retry
NO FINDING 87/87 inputs pass; no structural warning sign either
ββ Attempt 2 vs 1 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
resolved Mixed interval conventions
checks 5/7 inputs pass β 87/87 inputs pass
mastery Loop invariants 0.39 β 0.72
A partial fix that makes things worse is reported just as plainly β persists,
new, checks 5/7 β 0/7 β which is the honest thing and the useful thing.
Command reference Β· copyable text
| command | |
|---|---|
load <file> |
read a file; the task is detected from the function it defines, or falls back to structural findings for a file the tutor has no reference for |
hint |
the next rung, and only the next rung |
challenge |
a predict-then-run task built from the minimal failing input |
why Β· code Β· report |
the evidence, the marked source, the full report |
retry |
re-read the file after you edit it, and diff the two attempts |
mastery Β· progress |
what the session believes you have mastered; every attempt so far |
concept [<id>] Β· problems Β· problem <id> |
explore the curriculum; pin a task |
Tab completion and history work in a terminal; commands can also be piped in, which is how the tests drive it.
What it actually does
Given a flawed submission, the system produces this:
Report transcript Β· plain text
ββ Cognitive diagnosis ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
misconception name belief
bs.interval-convention-mismatch Mixed interval conventions ββββββββββββ 0.77 MAJOR L4
The flawed belief: "I think the upper bound is just 'the end of the array'
β which end does not matter."
why:
β’ [dynamic] execution first diverges at line 4, the same line this rule flags
β’ [static] the guard `lo < hi` treats `hi` as an exclusive bound, but it is
initialised to `len(a) - 1`, the last valid index
ββ Knowledge-graph alignment ββββββββββββββββββββββββββββββββββββββββββββββββ
root cause Loop invariants Β· loop-invariant, depth 4
the deepest implicated concept whose own prerequisites are already secure
learning path Loop invariants β Half-open intervals β Boundary conditions
ββ Cognitive intervention βββββββββββββββββββββββββββββββββββββββββββββββββββ
target Loop invariants Β· success probability 61% Β· IN ZPD
1 Β· orienting
Take the input ([0], 1) and step through your own function by hand,
writing down the values at line 4 each time you reach it.
2 Β· contradiction
At that point your `hi` holds 0, but for the answer to be reachable it
would have to be 1. Which line last wrote `hi`, and what did you assume
about the range it was allowed to take?
3 Β· conceptual
Write down the property you believe holds at the top of every iteration.
Does it still hold immediately after your update lines run?
answer leakage 0.00 Β· grounding 0.55
Note what is not there: the fix. hi = len(a) never appears, and the gate that
guarantees that is a mechanism, not an instruction β see below.
The three agents
Socratic Evaluator. Executes the submission and a reference implementation on the same minimised failing input, matches their variables by behaviour rather than by name, and reports the earliest checkpoint at which the two disagree. Symbolic rules, trace divergence, cost analysis and the reasoning model are fused with DempsterβShafer belief functions β so agreement between independent evidence types compounds, and disagreement is surfaced as contested rather than averaged away. A leading hypothesis below the settlement threshold is labelled provisional rather than presented as a verdict; on the development bank 16 of 23 diagnoses are settled and 7 are flagged provisional.
Knowledge-Graph Alignment. Propagates blame through a 65-concept prerequisite DAG by personalised PageRank, folds it into a Bayesian knowledge-tracing model as soft negative evidence, and extracts the deficiency frontier: the unmastered concepts whose own prerequisites are already secure. Those are the only places where teaching can succeed β Vygotsky's zone of proximal development, read off the graph.
Cognitive Intervention. Selects a target inside that zone by item response theory, grounds its language in retrieved evidence cards, and emits a three-rung Socratic ladder plus a counter-factual challenge β predict what your function returns, then run it.
The guarantee
No guidance reaches a student without passing the answer-leakage gate.
Enforced by replacement, not by warning. Three independent detection channels:
MOSS-style winnowing fingerprints catch a copied passage; AST structural matching
catches a statement of the reference the student has not written; edit-proximity
catches a modified version of a line the student has written. Prose repairs
("set hi to len(a)") are normalised into assignments first, because a model
told not to write code reaches for that phrasing immediately.
Quoting the student verbatim is explicitly allowed. Making someone look at what they actually wrote is the method.
The test suite includes a backend that deliberately emits the full reference solution; the assertion is that the student never sees it, and that the guidance they see instead is still three usable rungs.
Results
Every number below is regenerated by the commands in experiments/ and quoted in
the paper through generated macros, so the README, the JSON and the paper cannot
disagree. The reasoning backends for the "+ model" rows are openai/gpt-oss-120b
(the paper's primary model) and openai/gpt-oss-20b (a comparison), open-weight
reasoning models served through an OpenAI-compatible endpoint; the other rows use
the deterministic offline generator and run with no network.
RQ1 β diagnostic accuracy
Two labelled banks. The development bank (23 labelled + 6 correct) was built
alongside the rules and establishes internal validity only. The held-out bank
(25 labelled + 6 correct, six new tasks) was written after the rules were
frozen and labelled before the system ran; no rule or threshold was changed
afterwards (the protocol is stated in data/heldout.py).
| bank | system | top-1 | recall | micro-F1 | ΞΊ | FPR on clean code |
|---|---|---|---|---|---|---|
| development | deterministic | 1.00 | 1.00 | 0.81 | 1.00 | 0.00 |
| development | + gpt-oss-120b | 1.00 | 1.00 | 0.81 | 1.00 | 0.00 |
| development | + gpt-oss-20b | 0.96 | 1.00 | 0.79 | 0.95 | 0.00 |
| development | gpt-oss-120b only | 0.87 | 0.91 | 0.83 | 0.86 | 0.00 |
| held-out | deterministic | 0.76 | 0.76 | 0.71 | 0.74 | 0.00 |
| held-out | + gpt-oss-120b | 0.88 | 0.92 | 0.78 | 0.87 | 0.00 |
| held-out | + gpt-oss-20b | 0.96 | 1.00 | 0.82 | 0.96 | 0.17 |
| held-out | gpt-oss-120b only | 0.80 | 0.88 | 0.71 | 0.79 | 0.00 |
The six held-out misses are listed and explained in the paper's appendix: four
are symptom patterns the rules do not cover (the failing input is found and
localised but no rule names the belief), one is a wrong rather than missing base
case, one is recursion inside a nested helper. Fusing gpt-oss-120b closes three
of the six without adding a false positive; it proposed no belief on any of the
twelve clean programs. The smaller gpt-oss-20b names more (top-1 0.96 held-out)
but also accuses one correct program of an asymptotic gap, which the reliability
discount (0.62) and the clean run's opposing mass reduce to a provisional 0.37
without silencing β the case for leaving the verdict on clean code to the
executional sources.
External validation β 4,225 real student programs
The Refactory corpus (Hu et al., ASE 2019) provides programs written by 361 students for five introductory assignments, each marked correct or wrong by the course's tests. Those labels say nothing about why, so the corpus cannot score diagnostic accuracy; it can score false accusations and detection.
| measure | value |
|---|---|
| course-accepted programs on which a correctness belief was named | 4.5% |
| β¦ with only a cost or hygiene finding | 31.2% |
| course-rejected programs on which a failing input was found | 96.5% |
| β¦ localised to a line | 99.6% |
| β¦ on which a correctness belief was named | 50.3% |
| latency per file | 37 ms |
Of the rejected programs with no failing input, 59 use the built-in sort in an assignment that forbade it. Of the accepted programs accused of a correctness belief, 51 fail on an input inside the course's contract that the course's own tests did not cover.
The gate
On 274 manufactured leaks (a reference line verbatim or renamed, a prose repair around a code span, the whole solution) the gate rejects 99.3%; on 416 legitimate items (the student's own line quoted back, a question, a fallback rung) it rejects 0.0%. A repair stated in plain words with no code span is beyond the gate's design; the grounding channel happens to catch 50% of those, and the paper says so.
RQ2 β design analysis with simulated learners
These are simulated learners. The response model encodes the scaffolding
assumption under test, so any single run reproduces it. What the simulation
establishes is narrower: under a null response model in which the arms cannot
differ, the family-wise rejection rate over 200 cohorts is
1.0% (the statistics do not manufacture an effect); under the
default model the retention effect is Hedges g = 0.56
[0.28, 0.73] and the recurring-error effect g = -0.59
[-0.89, -0.34] over 30 cohorts; and the one quantity that does not depend
on the response model β the on-target rate, the share of interventions aimed
at a concept the learner actually lacks β is 93% for the full system and
39% without the knowledge graph. Power curves for sizing a human study are
in experiments/results/rq2_design_offline.json.
RQ3 β robustness
Semantics-preserving rewrites (rename every identifier, split tuple assignments, expand augmented assignments, invert conditionals, inject dead code, all five at once), each mutant verified behaviourally identical before scoring. Top-1 stability: 0.942 over 138 development mutants, 1.000 over 150 held-out mutants. Renaming costs nothing, because variables are matched by behaviour.
Install and use
git clone <repository> && cd deductive_multi_agent_system_\(MAS\)
./dmas doctor # verify the environment
./dmas session --file attempt.py # the interactive tutor
./dmas demo # a non-interactive guided tour
./dmas is a two-line launcher that puts src/ on the import path, so a fresh
checkout works with no install step. pip install -e . puts an equivalent dmas
command on your PATH; every example below works with either.
dmas session # interactive; `load` a file inside
dmas diagnose --submission lb_inclusive_bound # one-shot report, from the built-in bank
dmas diagnose --file attempt.py --problem lower_bound
dmas kg show binary-search # inspect the curriculum
dmas kg path binary-search sequence-indexing
dmas retrieve "why does my BFS revisit nodes" --full
dmas bench --json > rq1.json # the three studies
dmas experiment --students 180 --json > rq2.json
dmas robustness --json > rq3.json
Every command takes --json, and every command is deterministic given --seed.
With a reasoning model
The paper's live results use openai/gpt-oss-120b, an open-weight reasoning
model, through Groq's OpenAI-compatible endpoint. That is the default, so with
a key in the environment the flags below are optional:
export OPENAI_API_KEY=...
dmas diagnose --submission mc_greedy --backend openai \
--base-url https://api.groq.com/openai/v1 --model openai/gpt-oss-120b
A locally served model works the same way (--base-url http://localhost:11434/v1 --model <name>), and a Claude backend is available (--backend claude --model claude-opus-5, reads ANTHROPIC_API_KEY). The backend is a swappable component behind a typed task
interface with a JSON schema per task, so running the offline generator and a
model and diffing the reports is the ablation that measures what the model
contributes. A model's chain of thought is captured for the audit trail and never
shown to a student β reasoning traces routinely contain the answer, which is
exactly what this system must not disclose. Every completion is cached by
content hash (keyed by backend and model), so a study can be resumed and
re-derived without network access.
As a library
# PYTHONPATH=src, or after `pip install -e .`
from deductive_mas import DeductiveOrchestrator, problem, submission
result = DeductiveOrchestrator().tutor(
problem("lower_bound"), submission("lb_inclusive_bound")
)
print(result.diagnosis.primary.misconception_id) # bs.interval-convention-mismatch
print(result.alignment.root_cause) # loop-invariant
for hint in result.intervention.hints:
print(hint.level, hint.text)
assert result.intervention.leakage < 0.18 # the gate held
Why no dependencies
Every numerical, retrieval and statistical routine is implemented here from first principles: one-sided Jacobi SVD, randomised range finding, the Hungarian algorithm, dynamic time warping, Okapi BM25, reciprocal rank fusion, winnowing fingerprints, Dempster's rule, the regularised incomplete beta and gamma functions, BCa bootstrap intervals.
That is a deliberate scientific choice, not asceticism. Every p-value in the
results section traces to code in this repository, the statistics are validated
against published reference tables in tests/test_stats.py, and the whole system
runs identically on any machine with a Python 3.9 interpreter β which is the
deployment setting the proposal targets.
Documentation
docs/ARCHITECTURE.md |
layering, the blackboard, evidence flow, the compliance gate |
docs/ALGORITHMS.md |
every algorithm, why it was chosen, and the subtleties that bit |
docs/EXPERIMENT_PROTOCOL.md |
how each RQ is measured, and what the results do and do not establish |
docs/PROPOSAL_TRACEABILITY.md |
claim-by-claim mapping to the proposal, including the deviations |
Limitations
Stated plainly, because a system that diagnoses overconfidence should not exhibit it.
- Diagnostic accuracy is measured on a bank developed alongside the rules. Internal validity only.
- The RQ2 cohort is simulated. No claim is made about human learning.
- Grounding is support, not entailment. It catches invented vocabulary and off-corpus claims; a fluent, on-topic, subtly false sentence the corpus does not contradict can pass.
- The guarded interpreter is not a security sandbox. Three independent limits, appropriate for classroom submissions, unsuitable for adversarial code.
- Cost inference is an upper bound, deliberately over-approximating data-dependent loops; every complexity claim shown to a student is corroborated dynamically first.
- Cross-algorithm comparison is coarse. When a submission attacks the problem by a different method than the reference β a greedy scan against a dynamic-programming solution β the variable correspondence is weak by construction. Roles below a confidence bar are dropped and the divergence falls back to the output level, but the resulting contradiction is less pointed than it is for two implementations of the same algorithm.
- Python only. The analysis layer is AST-specific; the knowledge, retrieval, belief and statistics layers are not.
- Files with no reference get structural findings only. Differential testing, trace alignment and the complexity comparison all need an oracle; for an unknown task the session says so and reports what the rules, the dataflow facts and the cost analysis can still establish.
Layout
Repository layout Β· plain text
dmas run the CLI from a checkout, no install
src/deductive_mas/
domain.py config.py pipeline.py shared vocabulary, settings, composition
util/ determinism, tokenisation, linear algebra
analysis/ CFG, dataflow, cost, tracing, alignment, shrinking, leakage
knowledge/ ontology, misconception taxonomy, mastery, ZPD
retrieval/ BM25, LSA, fusion, corpus, MA-RAG
llm/ Claude, OpenAI-compatible endpoints, offline reasoner, caching
agents/ the three agents, the gate, the orchestrator
simulation/ RQ1 benchmark, RQ2 experiment + design analysis, RQ3 robustness,
gate benchmark and audit, external validation (Refactory)
stats/ special functions, tests, effect sizes, power, agreement
ui/ terminal user interface, the interactive UI
cli/ terminal presentation, the dmas command, the interactive session
tests/ the test suite
experiments/ result files, figure and number scripts, the live-run driver
docs/
Licence
MIT.