Process-based supervision certification for streaming Human-in-the-Loop active learning
PoD attaches a credibility signal to every human-generated label using observable interaction traces, deliberation time and its coupling with task difficulty, rather than the label content itself, and gates model updates accordingly.
This repository is the official, reproducible companion to the paper. It packages the protocol as an installable Python library (pod), exposes console-script entry points, and ships frozen configurations, unit tests, and per-dataset reproduction recipes.
- β‘ Quickstart
- ποΈ Repository layout
- π¬ The PoD protocol at a glance
- π Reproducing the paper
βοΈ Hick-Hyman validation on ATC logs- π₯ Real-user labeling study
- π οΈ Development
- π³ Docker
- π§Ύ Artifact evaluation
- π‘ Real-time PoD dashboard
- π Citation
- π License
Step 1 β Clone and install
git clone https://github.com/jorge-martinez-gil/proof-of-deliberation.git
cd proof-of-deliberation
pip install -e .Step 2 β Reproduce the F1 trajectory figures from Section 6
pod-experiments --datasets synth,elec2,gasStep 3 (optional) β Hick-Hyman validation (Section 6.5)
pip install -e ".[validation]"
pod-validate --out hick_hyman_pod_validation_v2.pngFor developers (tests, lint, type-check):
pip install -e ".[dev]"
pytest
ruff check src tests
mypy src/podproof-of-deliberation/
β
βββ src/pod/ # Installable package
β βββ config.py # Frozen dataclasses (Section 4 notation)
β βββ core.py # Gate, coupling, vigilance checks
β βββ operator.py # Stochastic operator simulator
β βββ learner.py # SGD wrapper + decision-function softmax
β βββ baselines.py # AL, StaticGating, AdaptiveGating
β βββ experiment.py # Closed-loop runner and aggregator
β βββ viz.py # Publication-grade plotting
β βββ presets.py # Frozen per-dataset hyperparameters
β βββ streams/ # Synth-Boundary, OpenML, UCI 224 loaders
β βββ validation/ # Hick-Hyman pipeline on ATC corpora
β βββ cli/ # `pod-experiments`, `pod-validate`
β
βββ configs/ # JSON snapshots matching presets.py
βββ experiments/ # Extended-regime, ablation, and robustness runners
βββ scripts/ # Stats-report and claim-checking utilities
βββ tests/ # pytest suite (unit + integration)
βββ docs/ # Notation, reproducibility, architecture
βββ PoD_code/ # Browser-based MQTT dashboard + labeling app
βββ archive/ # Pre-refactor scripts (do NOT use)
β
βββ Makefile # Reproducibility entry points (`make paper`)
βββ pyproject.toml # PEP 621 packaging + tooling config
βββ requirements*.txt # Pinned dependency manifests
βββ CITATION.cff # Software citation metadata
βββ CHANGELOG.md # Project changelog
Generated experiment outputs (
out_*/) and downloaded datasets (data_cache_uci224/, etc.) are produced on demand and intentionally not tracked.
PoD checks three independent signals for each queried label. A label is incorporated into the learner only when all three checks agree:
V(Ο_t) = (V_t = 1) AND (Ο_cog > Ξ΅) AND (S_vig = 1)
flowchart LR
A([Human Label]) --> B{Deliberation Gate\nV_t}
B -->|pass| C{Cognitive Coupling\nΟ_cog}
B -->|fail| R1([β Rejected])
C -->|pass| D{Multi-scale Vigilance\nS_vig}
C -->|fail| R2([β Rejected])
D -->|pass| E([β
Accepted β Model Update])
D -->|fail| R3([β Rejected])
| Layer | Symbol | Implementation |
|---|---|---|
| Deliberation gate | V_t |
pod.core.gate_check |
| Cognitive coupling | Ο_cog |
pod.core.coupling_check |
| Multi-scale vigilance | S_vig |
pod.core.gaming_detector, pod.core.fatigue_detector |
See docs/NOTATION.md for the complete symbol-to-code mapping.
The reference experiments compare PoD against 4 baselines and 3 ablation variants on 5 data streams under 3 operator regimes (Baseline, Gaming, Fatigue):
| Family | Method | Decision rule |
|---|---|---|
| Baselines | AL |
Accept every queried label |
StaticGating |
Accept iff delib_ms >= 510 |
|
AdaptiveGating |
Difficulty-scaled deliberation window only | |
WorkerQuality |
Online Dawid-Skene single-annotator posterior | |
| PoD | PoD |
Composite verification (gate + coupling + S_vig) |
| Ablations | PoD-NoGate |
Drop V_t; keep coupling and vigilance |
PoD-NoCoupling |
Drop Ο_cog; keep V_t and vigilance | |
PoD-NoVigilance |
Drop gaming + fatigue detectors; keep V_t, Ο |
pod-experiments --datasets synth,elec2,gas,covertype,airlinesπ Output structure
out_pod_unified/
βββ synth_boundary/
β βββ figs/Synth-Boundary_methods_f1.{pdf,png} # Figure in Sec. 6
β βββ runs/Synth-Boundary_<method>_run<N>.csv # Per-run F1 trace
β βββ diagnostics.csv # Query/accept rates
β βββ config.json # Frozen config snapshot
βββ elec2/
βββ uci224_gas_drift/
pod-experiments --datasets synth --runs 3 --baseline 500 --gaming 500 \
--fatigue 500 --synth_pool 5000 --holdout 1000All randomness is centralised through numpy.random.default_rng(seed). The per-run seed is derived as 1000 * run_idx + 7 (see pod.experiment.run_suite_generic). Identical hardware + Python + NumPy versions + pinned dependencies reproduce F1 trajectories exactly.
Every run writes a config.json next to the figures. Verify against the paper's frozen configs:
diff -u configs/synth.json out_pod_unified/synth_boundary/config.jsonSee docs/REPRODUCIBILITY.md for the full recipe.
pod-stats --in out_pod_unified --reference PoDThis writes the following artefacts under out_pod_unified/stats/:
| Artefact | Contents |
|---|---|
per_run_scores.csv |
One row per (dataset, method, run) with scalar score |
average_ranks.csv |
Mean rank of each method across datasets (lower is better) |
friedman.json |
Friedman chi-square and Iman-Davenport F omnibus test |
nemenyi_cd.json |
Critical-difference value CD at chosen alpha |
cd_diagram.pdf/.png |
Demsar-style critical-difference diagram with NSD cliques |
wilcoxon_holm.csv |
Pairwise Wilcoxon signed-rank vs. reference, Holm-corrected |
bootstrap_ci.csv |
Percentile bootstrap CI (default 10K resamples) of mean F1 |
per_regime_anova.csv |
One-way ANOVA over regimes from per-phase accept rates |
summary.json |
Aggregated summary of the full suite |
Section 6.5 of the paper validates that PoD's coupling signal reflects real deliberation rather than a simulator artefact. The validation uses two HuggingFace corpora: atco2_corpus_1h and uwb_atcc.
pip install -e ".[validation]"
pod-validate --out hick_hyman_pod_validation_v2.pngThe pipeline:
- Loads ~3,400 pilot-controller pairs
- Computes out-of-fold predictive entropies with a TF-IDF + isotonic-calibrated logistic regression (averaged over 3 seeds)
- Applies post-hoc temperature scaling
- Runs Spearman tests against controller response delay with linguistic-proxy contrasts
- Renders the summary figure used in the paper
Participants label elec2 trials in a browser-based app across three induced regimes (baseline, speed-bonus, long-block) while millisecond-precision response times are recorded. Collected CSVs are analysed offline through the same PoD verification primitives.
# 1) Build the frozen task pool (once per study)
python -m pod.realdata.build_pool --out PoD_code/labeling/tasks.json
# 2) Deploy the labeling app
cd PoD_code/labeling && python -m http.server 8000
# 3) Collect participant CSVs, then analyse
pod-realdata --in data_real/ --out out_real/The labeling app at
PoD_code/labeling/app.htmlis a single-file, offline page β no analytics, no telemetry, no network calls.
The full protocol (consent text, exclusion criteria, statistical tests, and limitations) is documented in docs/REAL_DATA_PROTOCOL.md.
pip install -e ".[dev]"
pytest # Unit + integration smoke tests (~10 s)
pytest --cov=pod --cov-report=term-missing # With coverage
ruff check src tests # Lint and format checks
mypy src/pod # Static type checkingThe tests/ directory covers PoD primitives, the operator simulator, stream generation, the comparison baselines, and a tiny end-to-end run for every method.
A locked-environment image reproduces the exact toolchain recorded in
requirements-lock.txt (Python 3.10, numpy 2.2.6, scikit-learn 1.7.2, ...):
docker build -t pod .
docker run --rm pod # test suite
docker run --rm -v "$PWD/out_pod_unified:/work/out_pod_unified" pod \
pod-experiments --datasets synth,elec2,gas,covertype,airlinesReviewers can follow docs/ARTIFACT_EVALUATION.md,
which maps every experimental section of the paper to the exact command that
regenerates it, states expected runtimes, and documents the claim-consistency
gate (scripts/check_claims.py) that fails CI when a reported number drifts
from the regenerated statistics.
The PoD_code/ directory contains a single-page, browser-based MQTT dashboard that monitors the PoD gate live on a deployed sensor stream.
- Configure your broker in
PoD_code/config.json - Open
PoD_code/app.htmldirectly in a browser
The default broker (
broker.emqx.io) is a public test broker β replace it with your own for production deployments.
If you use this software, please cite the paper and the software artefact:
@software{MartinezGil2026PoDSoftware,
author = {Jorge Martinez-Gil},
title = {Proof-of-Deliberation (PoD): reference implementation},
year = {2026},
version = {1.3.0},
url = {https://github.com/jorge-martinez-gil/proof-of-deliberation}
}The full citation metadata in
CITATION.cffis GitHub-renderable β click "Cite this repository" on the project page to copy a BibTeX or APA entry.
This project is released under the MIT License.
| Source | Contribution |
|---|---|
| OpenML | Electricity (elec2, id 44156), Forest CoverType (id 1596), and Airlines (id 1169) benchmarks |
| UCI ML Repository | Gas Sensor Array Drift dataset (#224) |
| HuggingFace / Zuluaga-Gomez et al. | atco2_corpus_1h and uwb_atcc ATC corpora |
| scikit-learn, NumPy, pandas, Matplotlib, SciPy | Scientific computing stack |