Clean Slate Eligibility Explorer — Vermont

A proof of concept for the Vermont Clean Slate effort. All records shown are synthetic.

1 · IDENTIFY eligible records→ 2 · Notify agencies→ 3 · Update (seal) records

This page lets you watch synthetic criminal records flow through a set of eligibility rules and see, record by record, which ones are eligible to be sealed and why. Every decision comes with its reason, so you can follow the logic at each step.

The work is done by a rules engine: software that takes a written set of yes-or-no rules and applies them to each record automatically and consistently, and can explain every decision it reaches. The questions it asks here are the familiar building blocks of Clean Slate eligibility — the grade of the offense, whether enough time has passed since the case was resolved, whether an offense is on a disqualified list, whether the record is a non-conviction, and, in the repository, whether a hanging arrest has aged past its deadline.

Vermont is a useful place to show one thing in particular: how much the "waiting period" choice matters. We model two technically feasible ways to count the wait, and you can flip between them. For some records the two choices reach the same answer; for others — watch the misdemeanor in Case 05 — one policy says "not yet" while the other says "eligible today." Seeing that difference on real-looking records is the point.

This is a proof of concept for the Identify step — the first of Clean Slate's three steps: Identify, Notify, and Update. It shows that eligible records can be found programmatically using data the agencies already hold, which speaks to technical feasibility. All records here are synthetic, and the rules are illustrative policy choices, not legal advice.

0
Eligible cases
0
Not eligible
0
Cannot determine
✓checking…

How eligibility is decided

Eligible Not eligible Cannot determine (missing data)

The assumptions behind these rules

Each rule here is a policy choice we made to demonstrate feasibility, not a recommendation for what Vermont's policy should be. We label them as assumptions on purpose.

Understanding eligibility criteria vs. data points

Clean Slate works by reading records that already exist in electronic form. In Vermont, two different agencies could be the one to start the process, and they keep slightly different kinds of records. A court record in the Judiciary's Odyssey case-management system is the court's own account of a case; because the court is the source of dispositions, its disposition information is complete. A repository record at the Vermont Crime Information Center (VCIC) is the rap-sheet view, built from fingerprint-based arrests and the dispositions reported back to it. One important difference: the repository also holds arrests that never became a court case, while the court does not.

Court record (Odyssey)Repository record (VCIC)
Offense severityCharge recordCharge segment
DispositionCharge record (complete; court is the source)Disposition segment (conviction-focused)
Disposition dateCharge recordDisposition segment
SentenceSentence orderPartial (not reliably held)
Arrest dateNot held (courts start at charge)Arrest / fingerprint record
Hanging arrests (arrest, no case filed)Not heldHeld

Each eligibility rule reads one of these fields. The offense-grade rule reads offense severity. Non-convictions are read straight from the disposition. The disqualified-offense check (convictions only) reads the offense together with the disposition. The waiting period reads the disposition date. The hanging-arrest rule reads the arrest date, which only the repository holds.

Two honest limits show up in this table. First, sentence completion is not reliably recorded in either system, so the sentence-based waiting-period model estimates it from the statutory maximum rather than reading a real end date. Second, hanging arrests exist only in the repository — the court never sees an arrest that was not charged — which is why the three hanging-arrest cases here appear only under VCIC. On the ten cases both agencies hold, they reach identical answers, which is the cross-check this POC verifies.

Showing that both a court system and a repository can run the same policy matters because either one could be the initiating agency. If the approach works whichever agency starts, the policy does not depend on a single system, and Vermont keeps flexibility in how it implements.

This is the core point: eligible records can only be identified by software when the eligibility criteria map to data points the agency actually holds in usable electronic form. A rule is only feasible if there is a field to read it from.

A look under the hood

The snippet below is the engine's actual decision logic, excerpted and lightly condensed from engine_template.py — the same engine that produced the cards above. Each charge passes through these checks in order, and the engine records a plain-language reason for whatever it decides.

def eval_charge(charge, scenario, cfg, today): disp = charge["disposition"].lower() grade = charge["severity"].lower() # (1) A non-conviction is eligible immediately — no waiting period. if disp in cfg["non_conviction_dispositions"]: return ELIGIBLE, "non-conviction, eligible on disposition date" # A repository arrest with no charges filed clears once the # statute of limitations has run (a "hanging arrest"). if disp == "" and charge["charges_filed"] != "yes": clear = add_years(arrest_date, sol_years[grade]) return (ELIGIBLE if today >= clear else NOT_ELIGIBLE), "hanging arrest" # This is a conviction — # (2) the offense grade must be on the eligible list. if grade not in cfg["eligible_grades"]: return NOT_ELIGIBLE, "offense grade not eligible" # (3) Optional: exclude disqualified offenses for this scenario. if scenario["disqualifiers"] and offense_code in disqualified_codes: return NOT_ELIGIBLE, "conviction for a disqualified offense" # (4) The waiting period must have passed: today vs. the clear date. clear = clear_date(charge, model_for(scenario)) if today >= clear: return ELIGIBLE, "waiting period met" return NOT_ELIGIBLE, "waiting period not met" def case_outcome(charge_results): # (5) A case is eligible only if ALL of its charges are eligible. if any(o == NOT_ELIGIBLE for o in charge_results): return NOT_ELIGIBLE return ELIGIBLE

Highlighted lines (1)–(5) are the key rules described above. Full source: engine_template.py.