Saltar al contenido principal

What Quick Scan extracts, and what a person must still check

Quick Scan turns a photograph of a completed paper application into a child's record. It is the only feature in PTRS that calls an outside AI model beyond the AI Assistant, and the only one anywhere in the product that reads a document.

This page states what it actually is: what is uploaded, where the file is stored, what reads it, what the confidence figure means, what a reviewer can change, and what is written when they press Confirm & Create Member.

It is a real model call, not a keyword matcher

Two earlier features in PTRS present themselves as AI and are not: the Incident Assistant and Incident Pattern Detection are both browser-side keyword matchers over fixed thresholds. Quick Scan is not one of those.

PTRS base64-encodes the uploaded file and sends it to an outside AI service over the internet, then reads back the model's structured reply. The request carries:

SettingValue
ModelA large vision-capable model, by default, overridable by configuration
Maximum reply length4,096 tokens
Temperature0.0, the most deterministic setting available
Content type sentAn image for JPEG/PNG/TIFF/WebP, a document block for PDF
System promptA fixed 17-line extraction brief
User promptA fixed structure naming 57 fields

The connection is set up with automatic retry behaviour: a timeout of 90 seconds by default, 2 retries with a backing-off delay starting at 2 seconds, and a circuit breaker that trips at a 0.5 failure rate over a 30-second window with a minimum of 5 attempts.

Whether it runs at all depends on one setting

The scan feature is only switched on when a credential for the outside AI service is present and not blank in name only, meaning even an empty value still counts as present. The credential is:

  • Blank in PTRS's own base settings file, the only file in the product that sets it directly
  • Supplied to the container by all three installation setups, each reading the credential from an environment variable that defaults to blank if unset

An empty value is not the same as an absent one, so the feature switches on either way and PTRS builds its connection with a blank credential. There is no second check.

How PTRS is startedThe credential's valueWhat a scan does
Run directly, without DockerBlank, from the base settings fileEvery extraction fails with the AI service refusing the blank credential. PTRS catches it and stores the scan as Failed with the service's own response as the reason
Docker with the development or cloud environment fileThe credential those files carryExtraction runs
Docker with the production templateBlank; the template ships with the variable emptyEvery extraction fails the same way
The production template ships with the credential blank

The production template is what an installed copy of PTRS starts from. With it, every upload is accepted, saved to disk, given a scan record, marked Processing, retried twice with a backing-off delay, and then stored Failed. The drawer shows a red toast carrying the service's own message; the queue shows a red Failed badge.

This is the same shape as the email switch documented across the product: a feature that is switched on regardless, with a credential that decides whether it actually does anything. Here the failure is at least loud.

The pipeline, step by step

  1. PTRS saves the file to disk. It is written to a scans folder under a generated name, keeping the original file ending. The folder is created if it does not exist. The file is never deleted; rejecting or confirming both leave it in place.
  2. PTRS creates the scan record, with a Pending status, the original file name, the stored location, the content type, the byte count and the signed-in account's organisation. Saved immediately.
  3. PTRS marks it Processing and saves again.
  4. PTRS calls the model.
  5. On success, PTRS sets the status to Extracted and stores the extracted values, the overall confidence, the extraction time, the model name, the input and output token counts, the estimated cost and how long it took.
  6. On any failure, PTRS sets the status to Failed and stores the failure message. The failure is logged; nothing else happens.

A scan can be in one of six states: Pending, Processing, Extracted, Confirmed, Failed, Rejected, and every one is actually reachable.

Batch

A batch runs up to 3 files at once, sharing a batch id and a position number. Both the check and the save cap a batch at 20 files.

The concurrency limit shares one connection to PTRS's data

Running up to three files at once means up to three tasks sharing the same connection to PTRS's stored data, which is not safe for that kind of concurrent use. Each file's processing performs three separate saves.

A batch of two or more files is therefore liable to fail with a message about two operations starting on the same connection at once, unpredictably, depending on which call reaches the data first. Single uploads are unaffected.

A setting for the concurrency limit exists and defaults to 3; the pipeline ignores it and uses its own fixed value of 3 instead, so changing the setting would do nothing anyway.

What is uploaded, and to where

The file limits are checked twice, once before the save and once again during it, with the same numbers both times.

RuleValue
Maximum file size10 MB
Accepted file typesJPG, JPEG, PNG, PDF, TIFF, TIF, WEBP
Content typeDecided from the file name ending, not from what the browser reports
Batch maximum20 files
The whole form leaves the organisation, and the AI pipeline's privacy protection does not apply

The uploaded bytes are the complete application form. A filled club form carries the child's full name, date of birth, home address, school, allergies, medications, physician, preferred hospital, insurance policy number, the family's pickup password, and the parent's employer and contact details.

All of it is sent, encoded, to an outside AI service on the internet.

PTRS's AI pipeline has a personal-information tokeniser and a leak detector, described as always switched on. Quick Scan does not use them. It lives in the Members module, holds its own connection to the outside service, and never touches the shared AI pipeline. There is no tokenisation, no redaction and no leak check on either the request or the reply.

Whether that is acceptable is a decision for the organisation and its data agreements. It is recorded here because an evaluator who has been told personal information never leaves the organisation will be told the wrong thing about this feature.

What is extracted

57 fields in three groups, defined identically by the prompt and by what PTRS reads back:

GroupFields
Child, 34 fieldsFirst, middle and last name, nickname, suffix, date of birth, gender, ethnicity, grade, school name, school district, home address, city, state, postal code, county, home phone, primary phone, email, allergies, medical alerts, medications, can swim, physician name and phone, preferred hospital and phone, insurance company and policy number, pickup password, previous member and years, referral source, language preference
Guardian, 16 fieldsFirst and last name, email, phone, cell, work phone and extension, employer, occupation, relationship, home address, city, state, postal code, lives with member, is emergency contact
Emergency contact, 7 fieldsFirst and last name, phone, extension, secondary phone, relationship, is authorised pickup

Each field arrives with a value and a confidence label, one of high, medium or low. PTRS treats a missing label as low.

The prompt tells the model what those three words mean, and it is worth quoting because it is the whole of the definition:

"high" means clearly readable, no ambiguity "medium" means somewhat readable, best guess applied "low" means barely legible or inferred from context

It also asks for normalisation: phone numbers in one fixed format, dates in another, US states as two-letter codes, named-choice fields spelled exactly as PTRS expects, and blank for anything unreadable.

The confidence figure is the model's own estimate, primed by one example

The review screens print a single overall confidence percentage in green above 80, amber from 60 to 79, and red below 60. The queue prints the same percentage per row on the same thresholds.

That number comes straight from the model's own reply and is stored on the scan record.

It is not worked out from anything. There is no arithmetic anywhere in PTRS that derives it, not an average of the 57 per-field labels, not a count of blanks, not a threshold table. The only place it is defined is the last line of the requested structure in the prompt, which shows one example value.

The prompt gives no instruction on how to work it out and no scale beyond that one example. So the figure is a number the model reports about its own work, in a field whose only specification is one sample value.

What this means in practice
  • It is not an accuracy measurement. Nothing has ever compared an extraction with the paper it came from, and PTRS holds no labelled set that could.
  • The colour thresholds are a display convention. 80 and 60 are fixed values written into two screens; they carry no meaning beyond that.
  • The per-field labels are more useful than the overall number. They are defined in the prompt, they vary field by field, and they are what the coloured dot beside each row shows.
  • Do not report it as a quality measurement. The scan dashboard's average confidence figure is the mean of these self-reported numbers across every scan in the organisation, which makes it a mean of estimates, not a measurement.

What a reviewer sees, and what they cannot change

There are two review surfaces.

The drawer, reached from the header's Quick Add → Quick Scan or from Quick Actions → Scan Application Form on the directory. A single-file upload goes straight into the compact review, which is read-only by design: 33 fields as label-and-value rows with a confidence dot, then Reject and Confirm & Create Member.

The detailed review, a split screen with the scanned image on the left and all 57 fields on the right, shown as editable-looking boxes when the scan is in the Extracted state.

Three things about that screen have to be said plainly.

The scanned image does not load

The image is rendered as a plain picture pointed at a link that requires you to be signed in. A plain picture request from a browser carries no sign-in with it, so PTRS refuses it and the element renders as a broken image.

The zoom, rotate and pan controls around it work; there is nothing under them. So the half of the screen designed for comparing an extraction against the paper form shows nothing, and the reviewer has only the values.

The same address is used for the drawer's compact preview, with the same result.

The editable fields cannot be edited

The review form is built to accept a function that reacts to a change, and every box calls it when its value changes.

The detailed review screen renders that form and does not actually pass it that reacting function.

Each box shows a fixed value that never updates, so typing into it produces no visible character. There is no error and no greyed-out styling; the box looks editable and quietly refuses input.

A correction would not be sent even if one could be made

Confirming a scan accepts an optional set of corrected values and prefers it over the original extraction when present. The scan record itself documents that field as holding the corrected data after a person's review, which may differ from the raw extraction if they made changes.

The detailed review screen's confirm action sends only the scan id and reviewer notes, and never actually sets that corrected-values field. The drawer does the same. Confirming a batch sends only the scan ids.

So that field is always blank on every confirmation in the product, and the child's record is always created from the raw model output.

The one field a reviewer can genuinely contribute is reviewer notes, behind the Add Notes toggle on the detailed review screen. It is stored on the scan record and appears nowhere else.

What is written when the reviewer presses Confirm

Confirming requires the scan to be in the Extracted state; anything else fails outright. It then maps the extraction to records and saves:

WrittenDetail
Child recordThe 34 child fields, plus status set to New, active flag set to yes, enrolment date set to today
Guardian recordThe 16 guardian fields, plus contact method set to email, language set to English, can-receive-communication set to yes
The child-guardian linkPrimary flag yes, authorised for pickup yes, relationship from the form or "Parent/Guardian"
Emergency contactOnly if a first or last name was extracted. Priority 1
The child's primary guardianSet to the new guardian
Scan recordStatus set to Confirmed, the created child recorded, who reviewed it, when, their notes, and the corrected-values field, always blank
Audit trailOne entry naming the child created

Everything is saved together, so a confirmation is atomic.

What is not written

  • No structured allergy record is created. The extracted allergies go into the child's own free-text list. The structured allergy record that CACFP and Health and Safety read is not touched.
  • No structured medical record is created. The physician, hospital and insurance values go onto the child's main record, not her separate structured medical record, so the enrolment gate's immunisation and physical checks, which read that separate record, cannot pass for a scanned child until somebody fills it in by hand.
  • No enrolment is created. Her enrolment history is untouched, so a confirmed scan produces a child with no enrolment record.
  • No document is created. The scanned form is not attached to the child as a document; it stays on disk, reachable only through the scan.
  • There is no duplicate check of any kind. Confirming the same scan twice is prevented by its status; scanning the same form twice is not. Two children are created, and neither can be deleted.

The eight silent defaults

PTRS substitutes a value wherever the model returned nothing. None of these produces a warning, and none is visible on the review screen; the reviewer sees a blank field and gets a filled one.

FieldSubstituted with
Child first name"Unknown"
Child last name"Unknown"
Child date of birth1 January 2000
GenderPrefer not to say
EthnicityDecline to state
Can swimNo
Language preferenceEnglish
Guardian first/last name"Unknown"
The date of birth default is permanent

A form whose date of birth could not be read produces a child born on 1 January 2000, a 26-year-old, in a system for children aged 5 to 18.

A child's date of birth is fixed at creation and no screen ever changes it, so that date can never be corrected. It drives the directory's Age column, the age-band filter, the printed badge, and every age calculation downstream.

The behaviour is deliberate; PTRS's own tests assert it happens on purpose. It is recorded here because it is invisible at the moment it happens and irreversible afterward.

Check the date of birth against the paper before confirming. It is the single most important thing on the screen.

Two smaller mapping notes. A guardian's email and phone default to an empty value rather than blank, so a guardian with no contact details is stored with empty contact details rather than being refused. And the emergency-contact rule tests for a first name and a last name, though its own comment says "at least name and phone", so a contact with a phone number and no readable name is dropped, and one with a name and no phone is created with an empty phone.

What a person must still check

Eleven fields where a wrong value is not merely untidy. Check each against the paper before pressing Confirm.

Before confirming a scanned application
  • Date of birth, a default of 1 January 2000 means the model could not read it, and it can never be corrected afterward
  • First and last name of the child, "Unknown" means the same thing
  • Allergies, these go into a free-text list, not the structured allergy record, and no other module will see them
  • Medications and medical alerts, same list, same limitation
  • Physician name and phone, and preferred hospital, the emergency card is only as good as these
  • Insurance company and policy number
  • Pickup password, the word an adult must say at the door
  • Guardian first and last name, "Unknown" here means the child has a primary guardian with no name
  • Guardian phone and email, an empty value is stored silently
  • Emergency contact name and phone, a contact with no name is dropped entirely
  • Grade, the model returns free text, and the directory filter matches it exactly

Because the image pane does not load and the fields cannot be typed into, the practical procedure is: read the values on screen against the paper form in your hand, and if any of the eleven is wrong, press Reject with a reason and enter the child through Quick Member Entry instead. Confirming and then correcting works for most fields but not for the date of birth.

Cost and usage tracking

Every extraction stores its input and output token counts and an estimated cost, and PTRS totals them per organisation for today, this week, this month and overall, plus an average per scan. The Scan Stats widget on the review queue shows them.

The cost is arithmetic over two settings, not a price quoted by the service itself:

cost equals the input tokens divided by a million, times the input price per million, plus the output tokens divided by a million, times the output price per million.

With the shipped defaults of $15.00 per million input tokens and $75.00 per million output tokens, a 5,000-input, 1,500-output extraction works out to about $0.19. That worked example is the one asserted by PTRS's own tests.

The two prices are settings, not a quote

The two per-million prices are settings with defaults, read from PTRS's base configuration. They are not fetched from the AI service and nothing checks them against a published price list. If the model or its pricing changes, every figure on the stats widget is wrong until somebody edits the setting.

The estimated cost is also visible to every role that can use the module, including a front-line staff member.

What the tests actually assert

Quick Scan has four test files and 64 tests, more than the rest of the product's business logic combined, and the only place in PTRS where a feature's behaviour is asserted rather than merely built. They are worth knowing about, and so are their limits.

FileTestsWhat it covers
The model-call tests13Cost arithmetic in five cases; the call itself against a stand-in for the outside service: a clean reply, a reply wrapped in fences, a reply in bare fences, a failure response, a server error, a reply with no text, and that a PDF sends a document block while an image sends an image block
The mapping tests20Every mapping rule on this page, including all eight defaults, case-insensitive matching of named choices, list handling, the child-guardian link, and the emergency-contact name rule
The "pipeline" tests10Not actually the pipeline. This file tests round-tripping of the extracted values through storage and back
The check tests21File size at and over 10 MB, all seven accepted formats, five rejected ones, batch size at and over 20, and the reviewer-note and rejection-reason length limits

The first, second and fourth are genuine and would catch a regression in the code they cover.

Nothing tests the pipeline, and the file that claims to says so itself

The file named for pipeline tests explains in its own comment that the orchestrator depends on PTRS's stored data and file access, and that those paths are covered elsewhere, by broader tests that exercise the whole product together.

There are no such broader tests. PTRS's test suite contains a handful of files covering audit, sign-in, the 2-minute search memory and the checks, and none of them mentions a scan. The web application's separate end-to-end tests cover thirteen flows and none touches the scan screens.

So nothing exercises the file write, the three status changes, the failure path, the batch concurrency, the confirm action, the organisation scoping or any of the nine scan actions. The two defects that stop a reviewer working, the image request with no sign-in and the discarded field edits, are both in that gap, and both are in the interface, which has no test coverage of any kind.

Where to go next

Checked against PTRS on 7 September 2026.