Inspiration

Every tool a clinician uses to track a child's autism progress plots one thing: the raw assessment score over time. A line goes up, everyone relaxes. A line goes down, the team intervenes.

But that line lies more often than anyone admits. The same child scores differently depending on who ran the assessment (a lenient BCBA versus a strict clinical psychologist) and where it happened (a calm clinic room versus a noisy school). So a "12-point gain" can be almost entirely a switch to an easier rater, and a "regression" can be one bad afternoon at home. Clinicians know this in their gut and have no tool that does anything about it. Decisions about a child's therapy get made on a number nobody has cleaned.

We had already built a model that separates a real fMRI signal from the scanner site it was collected on. The same shape of problem is sitting in plain sight in clinical progress data, and nobody has productized the fix.

What it does

Throughline deconfounds progress. For every assessment it estimates two offsets:

  • Rater offset: how far a clinician's scores sit from the consensus of all raters on the same instrument. Their leniency, measured.
  • Context offset: how much an instrument's scores shift by setting.

It subtracts both, places every score on a common scale, and plots the raw line and the deconfounded line together. The gap between them is the confound, made visible.

On top of that it raises one flag per child:

  • Artifact progress: raw scores climbing while the deconfounded line stays flat. Apparent gains that are really a more lenient rater or an easier context. This is the flag no raw-score tool can produce, and it is the whole pitch.
  • Real regression, Stall, On track, and Unreliable data for the rest.

A clinician opens the caseload, sees the children who need a second look floated to the top, opens one, and reads the verdict with the evidence underneath. They can log a new assessment under any rater and watch the lines recompute live.

How we built it

                 Browser (clinician)
                        |
    Next.js 15 App Router + React 19   (Vercel)
/                       |                      \
caseload page         child detail page       add-assessment
(server render)       (server render)         (client modal)
    \                       |                      /
                   Route handlers (/api/*)
                            |
            -----------------------------------
            |                                 |
     lib/queries.ts                    lib/recompute.ts
   (read series + flags)        (estimate offsets, write back)
            |             lib/deconfound.ts    |
            |         (pure deconfounding engine)
            -----------------------------------
                            |
                     Aurora Postgres
   assessments -> rater_calibration -> adjusted_scores -> flags
  • The engine (lib/deconfound.ts) is pure functions, no I/O, verified end to end with a standalonry flag from raw scores with no database required. It estimates per-rater and per-context offsetsagainst peer consensus, adjusts each score, and derives the flag from the recent raw-versus-adjusted trend. Keeping it pure let us verify the core math with zero database before any UI existed.
  • The data model is deliberate. assessments is the raw truth; rater_calibration, `adjusted_sco tables the engine writes, so the expensive estimation runs once on write and every read is a plainquery. Children carry an alias only, no PHI.
  • The API is three thin route handlers. The POST recomputes synchronously, so a new score moves thsame request.
  • The chart is a hand-built SVG component, not a chart library, because the one visual that matters, two diverging lines with the confound shaded between them, had to look exactly right.

Challenges we ran into

  • Making the demo honest. It is easy to rig seed data so the flag fires. We hand-traced the estimator and found that a first-pass mean-offset estimator under-corrects a strong rater, leaving residual that reads as fake progress. Rather than hide that, we set an explicit noise tolerance that absorbs the estimator's known slack, sortifact and not on estimator error.
  • Live recompute without a stale read. Re-deconfounding on every write, synchronously, then re-rendering the server component, so the new point is never a client-side guess.

Accomplishments that we're proud of

A complete, honest vertical slice: schema to engine to Postgres to API to a chart that tells the truth, with no mocked data anywhere in the path. And a clear, defensible claim about what is actually new.

What we learned

The hard part is not the statistics. Deconfounding rater and context effects is established psychometrics (measurement invariance, rater-mediated assessment). We did not invent the method and do not claim to. The hard part is the product: deciding which single number a clinician should distrust, and showing them why in a way they What does not exist yet is a shipping product that puts this in a clinician's hands as one actionableflag. Throughline is the first to productize confound-adjusted progress, not the first to describe it.

What's next for Throughline

  • Replace the first-pass mean-offset estimator with a hierarchical random-effects model (the point estimates are intentionally simple for v0).
  • Pull live data from assessment platforms instead of manual entry.
  • Pilot with one developmental clinic.

Built With

Share this project:

Updates