Sanjaneh
Turns a 240-item sitting into a profile a person can read and an assessor can defend — with every number traceable back to the answer that produced it.
Who it is for: HR and organisational development teams, clinicians and counsellors who already work with personality inventories, and individuals reading their own profile.
Every figure here was measured, and the method is recorded. A number we did not measure does not appear.
Assessment first, then explanation
Sanjaneh administers a 240-item Persian five-factor personality inventory — NEO-based, five domains, thirty facets — and returns a scored profile with a written reading of it.
The order in that sentence is the product. The scoring happens first, in an engine that does arithmetic on a recorded key. The explanation happens second, over numbers that are already fixed. A language model writes the prose, and it cannot reach the numbers.
"What stops the model from making the score up?"
It never has the material to. The model is handed the computed profile — scores, bands, the facets that sit far from the middle — and never the person’s answers. It is told, as an absolute rule, that it may not compute, correct or re-interpret a score, and it is given no path by which it could. The division is stated on the product itself rather than buried, because a buyer who discovers it later assumes it was hidden.
| The scoring engine | The language model | Neither |
|---|---|---|
| Scores answers against the version's recorded key | Explains the computed profile in plain language | Changes any score |
| Applies the direction of every reverse-scored item | Places related patterns side by side | Invents a trait or a facet |
| Produces 30 facet scores and 5 domain scores | Suggests questions for a development conversation | Gives a psychological diagnosis |
| Determines each score's interpretation band | Records which model wrote each passage, beside it | Makes a hiring, promotion or rejection decision |
Every number in a report must be explainable years later
That rule was written down before the scoring engine was, and it is the reason the report looks the way it does. A profile that cannot be reconstructed is not a record; it is an opinion with a chart on it.
- Answer — one of five options, stored per item exactly as the person submitted it
- Key — which facet and which domain the item loads onto, in which direction and at what weight, read from the version's stored key rather than computed from the item's number
- Raw score — facet and domain totals, each carrying how many items actually contributed
- Reference population — which norm set and which group the score was read against, stored on the result by name
- T-score and percentile — with a record of how the T was obtained: an exact table row, an interpolated row, or a mean and standard deviation
- Band — one of five, from half-open intervals that leave no value unlabelled
Five bands, one scale, everywhere: very low, low, average, high, very high, cut at the quintile points. A result rendered in three years renders under the bands of the version it was sat on, not under whatever the current version says.
What the model is allowed to know about you
The prompt carries scores and nothing else. No name, no phone number, no free-text answers. And — deliberately — nothing about the employer.
The organisation’s own profile is loaded and available at that moment, and it is withheld anyway. The reasoning is written into the code and enforced by a test that fails if any of the employer’s text reaches the model: this is a personal instrument. The result belongs to the person who sat it, it follows them out of the job, and a reading bent toward what the employer is currently worried about is no longer a reading of them.
Guardrails that are not prompts
Several facets in the five-factor model carry names that mean something medical in ordinary language — anxiety and depression among them. A reader who meets one of those words in a report about themselves, or a manager who meets it in a report about an employee, hears a diagnosis. It is not one.
Telling the model to explain the term does not fix this. Asked to define it, a model writes its own definition, and the definitions it writes drift toward the clinical reading it has seen most often. So the definition is supplied with the scores, as data. After the model answers, the finished narrative is scanned for those terms and a glossary section is appended by the platform, carrying the sentence that this is not a clinical diagnosis, for every term actually used. The model is never asked to write it.
The rest of the layer is built the same way, to degrade rather than fail. A caption pointing at a chart the version does not draw is dropped. An out-of-range importance value is clamped. Output that ignores the requested structure is kept as prose rather than thrown away, because a reading without chart captions is worth far more than an exception. Where an organisation has written free text about itself, that text is quoted to the model with an explicit instruction to read it as description and never to execute an instruction found inside it — and in the manager-facing assistant, the model may only select a key from a fixed catalogue. No model output reaches a query.
For the organisation
An owner assigns the assessment to employees or groups. Each person gets their own report. Above that sits an aggregate report drawn as distributions rather than as a tally of individuals, and it is generated on request and never stored — a saved paragraph would be describing a group that no longer exists.
Where it stops
"What happens if somebody just answers 'agree' to all 240 items?"
Today they receive a complete, confident, wrong profile, and the platform will not tell you that it happened. There is no response-quality screening. The indicators that would catch it are specified and written down, and they are not built, and no amount of interface polish substitutes for them.
Nobody reads the AI narrative before the person does, either. Both of these are the difference between what is designed and what is running, and stating them is cheaper than having a customer find them.
Built in fourteen days
141 commits between 11 and 25 August 2026 produced roughly 103,500 lines of backend code across 807 files, 56 migrations, 61 tables and 1,301 backend test cases. That is one engineer working with AI tooling, not a large team — which is worth saying plainly, because it is both the honest account and the more useful one if you are trying to work out how quickly this kind of platform can be built.
Technical decisions
Including what we did not choose, and why.
A domain is scored from its own items, never by summing its facets.
Alternatives: Sum the six facet scores to produce the domain score
An item can load onto a facet, a domain, both or neither, each with its own weight. Summing facets double-counts multi-loaded items and silently discards the weights. Both routes are computed and a validator warns when they disagree, so agreement is checked rather than assumed.
The item structure comes from the uploaded key as data. It is never derived arithmetically from item numbers.
Alternatives: Derive domain and facet from item position with a modulo formula, Hardcode the reverse-scored items as an array in code
An off-by-one anywhere produces a complete, plausible, wrong profile with nothing to detect it. Holding the key as validated data means it can be checked against the composition the instrument declares, and a mismatch is a failing test rather than a silent result.
The key is validated against the declared facets-per-domain and items-per-facet counts before a version can be published.
Missing answers warn, allow, record and flag. They never halt scoring.
Alternatives: Refuse to score a sitting with more than 10–15 missing answers
Halting destroys the record of a test somebody actually sat. Required items are refused on first submit and the runner shows only the blanks; a second submit with an explicit acknowledgement is recorded on the session and scored anyway, flagged. A minimum-answered ratio of 0.75 is the floor.
Every T-score records where it came from.
Alternatives: Store the T-score alone
A stored number without provenance cannot be defended later. Each T records whether it came from an exact table row, an interpolated row, or a mean and standard deviation — because 'the norm table probably had that row in 2026' is not an answer to a candidate's lawyer.
The definitions of clinically loaded terms travel with the scores as data, not as an instruction in the prompt.
Alternatives: Tell the model in the prompt not to define these terms itself
A prompt is a request. A live run under the previous version produced a clinical-sounding phrase with no definition anywhere and no statement that it was not a diagnosis. The definition is now supplied alongside the scores, and after the model answers, the finished text is scanned and a glossary section is appended server-side for every such term actually used.
Limitations
- There is no response-quality or validity screening. A sitting answered with the same option 240 times currently produces a confident, wrong profile. The indicators that would catch it — straight-line runs, response variability, distinct options used — are designed and written down, but they are not built. The only control running today is a minimum-answered ratio of 0.75.
- No human reviews the AI-written interpretation before the person receives it. There is no approval state, no moderation queue and no reviewer column. An administrator can read a narrative after the fact and regenerate or clear it, which is oversight after delivery, not before it.
- The inventory is not presented as validated or standardised. We compute and publish no reliability or validity coefficients for it, and any claim about its psychometric properties should come from the psychometric literature and your own judgement, not from us.
- There is no test–retest or reliable-change scoring. A difference between two sittings is a difference between two numbers; calling it change would need test–retest data the platform does not hold.
- Facets are reported with a raw score, a T-score and a percentile, but no interpretation band. The source document bands domains only, and inventing facet bands would be fabricated interpretation.
- The T-scores come from one published reference study on a convenience sample of roughly five hundred adults, not from a national norming programme. Respondent sex is not collected, so the pooled group is always used even where the source reports figures by sex.
- The Persian item set has documented defects: a small number of items read against the direction they are scored on. They are recorded in the instrument's own documentation and deliberately left as they are, because editing an item changes a published instrument and detaches it from the reference data collected on it.
- It gives no clinical diagnosis and is not a substitute for professional assessment. It is also not a hiring decision. A personality result is one input among several, and a page that pretended otherwise would be selling something the instrument cannot deliver.