Most Indian schools still grade on paper and then type the results into software. The grading is the skilled work. The typing is not, and it is where the errors get introduced — a row skipped, a column misaligned, a fourteen entered as forty-one.
It is also where a lot of resistance to school software comes from. A teacher who has already written every mark in a register does not experience “now enter them in the system” as digitisation. They experience it as doing the job twice.
The gap between a marks register and a report card
The register is the source of truth for most staff rooms. It is quick, it works without a device, and it survives a power cut. Nothing about a school management system removes it, and any product that assumes it will is arguing with reality.
So the design question is not how to stop teachers using registers. It is how to get what is in the register into the system without a second manual pass. EdunodeX treats that as an extraction problem with a confirmation gate, and models it as a job with states rather than as a single upload action.
Photographing a register instead of typing it
The camera path takes an image of a marks page and passes it to a vision model along with the context the system already knows: which exam, which class, which subject.
The model returns structured data — a list of students with their marks — rather than free text. Getting that reliably is less trivial than it sounds. Models sometimes wrap the list in an object and sometimes return a bare array; sometimes they surround it in a code fence. The extractor normalises all of those into one shape before anything downstream sees it, which means a formatting quirk in one response does not surface to the teacher as a crash.
The call is routed through EdunodeX’s own AI proxy so the spend is attributed to the school, with a direct fallback path that exists only so the feature does not hard-fail in an unattributed context.
Pasting marks from a spreadsheet or message
The second path takes text. This covers the cases that are more common than anyone admits: a column copied out of Excel, a list a teacher typed into a chat, a scanned sheet whose text has already been pulled out elsewhere.
Text extraction runs the same normalisation and produces the same job record as the camera path. From the teacher’s point of view the two entry points converge immediately, and everything after extraction is identical.
This matters for adoption. The teacher who will photograph a register and the teacher who keeps marks in a spreadsheet are usually different people, and forcing either into the other’s workflow is how a feature goes unused.
Matching extracted names to enrolled students
Extraction produces names and numbers. Names are not identifiers.
A separate matching pass compares each extracted name against active students in the school’s own records and produces two counts: matched and unmatched. Both are stored on the job, along with the matched data itself, and the job’s state advances to matched.
Being explicit about the unmatched count is the important part. A matching step that quietly discarded rows it could not resolve would produce a job that looks complete and a class with three missing marks nobody notices until the report card is printed. Surfacing “thirty-seven matched, three unmatched” puts those three in front of the teacher while the register is still open on the desk.
Unmatched rows are usually mundane: a nickname, an initial where the record has a full middle name, a spelling variant, or a student who has left. Resolving them is quick when you are told which three they are.
The four states of an extraction job
An extraction job is a record with a lifecycle, and each state means something specific.
Pending — the job exists and the AI call has not returned. Useful because a photo of a full register is not instantaneous, and a teacher navigating away should be able to come back to it.
Extracted — the model returned parseable data and it has been stored. If extraction failed, the job lands in an error state carrying the reason instead.
Matched — extracted names have been reconciled against enrolled students, with matched and unmatched counts recorded.
Saved — a teacher confirmed, and marks are in the gradebook. The job stores who confirmed it and when.
The save step refuses to run on a job that is not in the extracted or matched state, so a job cannot be committed twice or committed before extraction finished. It writes only the confirmed list submitted with the request, upserting each student’s mark for that exam rather than inserting duplicates.
Handling the rows the model gets wrong
Three failure modes are worth planning for.
A misread digit is the common one, and it is why the confirmation screen shows the extracted values for review rather than a summary count. A teacher reading forty rows against the register they just photographed catches a transposed number quickly.
A misaligned row is rarer but worse, because the marks are all valid — they are simply attached to the wrong students. Reviewing names and marks together, in register order, is what catches this. A confirmation screen that showed only totals would not.
An unreadable page is the honest failure. Poor light, a folded page, a register photographed at an angle: the model may return partial data or the job may error. Re-photographing is faster than arguing with it.
None of these are unusual for document extraction, and none of them are dangerous here, because the model has no route to the gradebook that does not pass through a teacher pressing confirm. The value on offer is not “marks entry without humans”. It is a teacher checking forty rows instead of typing them, which is a different task with a different error profile — and, for most staff rooms, a considerably shorter one.