Most assessment programs don't fail because the psychometrics are bad. They fail because nobody can agree on what a "test" actually is in the database. One team calls it a form. Another calls it an exam version. The LMS calls it a course object. HRIS calls it a certification record. And when the CHRO asks a simple question — "how many people passed the safety cert last quarter, by region?" — three different reports come back with three different numbers, and everyone spends a week reconciling instead of deciding.
That's a data model problem. Not an analytics problem, not a reporting problem. The reports are downstream. If the underlying entities and relationships are muddy, every dashboard built on top inherits the mud.
This post is about the plumbing — the canonical entity-relationship model and taxonomy that lets an assessment program scale without turning into archaeology. We'll cover the core entities, the metadata that's actually mandatory versus the metadata people think is mandatory, naming conventions that survive contact with real users, how everything maps to HRIS/LMS/BI, and how to migrate a legacy item bank without destroying historical comparisons.
Why every growing program drifts into chaos
A program starts small. One person owns the item bank, one spreadsheet tracks who took what, and everyone in the room knows what "the Q3 form" means because they were all there when it was built.
Then it grows. New content authors join. A second business unit adopts the program. A vendor migration happens. Someone builds a Power BI dashboard off an export nobody documented. The shared context that held everything together disappears — but the words stay the same. "Form" now means five different things depending on who's talking.
-
An author duplicates an item to tweak wording, and now there are two item IDs that are "the same question" for reporting but different for versioning.
-
A proctoring vendor assigns its own candidate IDs, so the same person exists three times.
-
A form gets reused across two testing windows, and nobody recorded that the passing score changed between them.
None of these are dramatic. Each one is a Tuesday. But stacked over two or three years, they make the phrase "assessment canonical data model" sound aspirational rather than achievable — because by then, imposing one means untangling everything that came before.
The cost of not having a canonical model isn't paid up front. It's paid every single time someone runs a report, onboards a vendor, or tries to compare this year's cohort to last year's. It's a slow tax, which is exactly why it never gets prioritized until it's already expensive.
The six core entities (and the relationships that actually matter)
Strip an enterprise assessment program down and you get six entities. Everything else is an attribute, a join, or a view built on top.
Eliminate assessment bottlenecks.
Evaloly simplifies every step from test design to results analysis, making assessments faster and more reliable.
- Customizable test creation
- Automated grading and analytics
- Secure distribution and proctoring
No credit card required
| Entity | What it represents | What it is NOT |
|---|---|---|
| Item | A single reusable question or task, with a stable identity across edits | A specific placement on a form |
| Form | An ordered, fixed set of items assembled for delivery | The event of someone taking it |
| Administration | A specific delivery window/context (date range, location, policy, cut score in effect) | The form itself |
| Candidate | The person, with one canonical identity across all systems | A login, a proctoring record, or an HRIS row |
| Score | A result tied to one candidate + one administration + one form | A pass/fail flag floating on a spreadsheet |
| Tag | A classification applied to items or forms (competency, difficulty, blueprint area) | A folder or a naming hack |
The relationships are where programs live or die:
-
An Item can appear on many Forms. A Form contains many Items. Many-to-many, which means you need a join table that records item placement, including position and any form-specific point value.
-
A Form can be delivered across many Administrations. This is the relationship people flatten most often, and it's the one that quietly destroys cohort comparisons. The same form given in March under a 70% cut score and in September under a 75% cut score is not the same measurement event.
-
A Score references exactly one Candidate, one Administration, and one Form. If your score records don't carry all three, you can't answer basic questions later.
-
Tags attach to Items primarily, and roll up to Forms through the items on them.
If you get one thing from this post: Administration is a first-class entity, not a date column on a Form. The number of broken reports that trace back to teams treating "when it was given" as an afterthought is genuinely hard to overstate. The whole logic of keeping delivery context separate — and versioned — is worth digging into further in this piece on a branching and metadata model for assessment version control, especially if version drift is your current fire.
Mandatory metadata — and the fields people fake
There's a real difference between metadata that must exist for the system to function and metadata teams add because it feels responsible. Overloading the second kind kills adoption faster than anything else, because authors stop filling in any fields when the form has 40 of them.
Here's the minimal set that's genuinely mandatory, by entity:
Item
-
Stable item ID (never reused, never repurposed)
-
Item type (MC, constructed response, performance task, etc.)
-
Primary competency tag
-
Status (draft / in review / active / retired)
-
Version number and parent item ID (for edited derivatives)
-
Language / locale
Form
-
Form ID
-
Form version
-
Blueprint reference
-
Assembly date and assembler
-
List of item placements (ordered)
Administration
-
Administration ID
-
Associated form ID(s)
-
Delivery window (start/end)
-
Cut score in effect
-
Policy version (accommodation rules, proctoring mode, retake rules)
Candidate
-
Canonical candidate ID
-
Source-system ID mappings (HRIS ID, LMS ID, vendor ID)
Score
-
Score ID
-
Candidate ID + Administration ID + Form ID (all three, always)
-
Raw score, scaled score, and pass/fail plus the cut score used
That last detail — storing the cut score with the score, not just the pass/fail flag — seems redundant until the policy changes and you need to honestly re-answer an old question.
The fields people fake most often are the freeform ones. "Notes," "category," "owner" — these turn into inconsistent junk within months because there's no controlled vocabulary behind them. If a field matters, it should be a constrained list, not an open text box. If it doesn't matter enough to constrain, it probably doesn't need to be mandatory.
Naming conventions that survive real users
Naming feels trivial until you're staring at 4,000 items with names like FinalDraftv2REALupdatedJR. A convention only works if it's boring, positional, and impossible to improvise on.
A workable pattern for IDs:
``
ITEM-{domain}-{sequential} → ITEM-SAFE-004821
FORM-{program}-{year}-{seq} → FORM-FORKLIFT-2026-03
ADM-{formID}-{window} → ADM-FORKLIFT-2026-03-Q1EAST
``
-
IDs are opaque and permanent. Human-readable labels are separate and editable. Don't encode meaning into the ID that might change — a competency name might get reworded, but the item ID attached to it shouldn't have to.
-
Never reuse a retired ID. Ever. Retired means gone, not recycled.
-
Version lives in a field, not in the name.
_v2in the display name is fine for humans; the system should track version as structured data so you can query "all v3+ items" without regex gymnastics.
Naming conventions fail not because they're wrong but because they're not enforced at creation. If authors can type a name freely, they will, and no amount of documentation fixes it. The convention has to be baked into how items get created — the right ID gets generated automatically and the human never has to think about it.
Mapping to HRIS, LMS, and BI without a migration every quarter
This is where the canonical model earns its keep. The three downstream systems each want something different from your assessment data:
-
HRIS wants candidate-level outcomes
did this employee earn this certification, when, and does it expire.
-
LMS wants completion and enrollment linkage
did the assessment tied to this course get passed, so the course can be marked complete.
-
BI wants everything, disaggregated
pass rates by form, by administration, by region, by cohort, over time.
The mistake is mapping each of these point-to-point. Program → HRIS. Program → LMS. Program → BI. Three integrations, each with its own field assumptions, each breaking independently when something upstream changes. That's how you end up doing a "migration" every quarter that's really just repairing brittle connections.
A single canonical export layer that all three read from works considerably better. Your internal model stays clean; you define one mapping from canonical entities to each external system's expectations, and you version those mappings.
A minimal mapping contract for each system:
-
Identify the join key. For HRIS it's the canonical candidate ID ↔ HRIS employee ID. This is the single most important field to get clean, because everything person-related hangs off it.
-
Define the outcome object. HRIS gets a certification record (cert name, earned date, expiry, source administration ID). LMS gets a completion event (course ref, pass/fail, timestamp). BI gets the full score record with all dimensions attached.
-
Version the contract. When HRIS changes its cert schema, you update one mapping, not your entire item bank.
-
Log every push. So when a number is disputed, you can point to exactly what was sent, when, and from which administration.
Candidate ID hygiene matters more than most teams expect. If the same person exists as three IDs across your vendor, LMS, and HRIS, your BI pass rates are wrong and your HRIS certification records are incomplete — simultaneously — and nobody notices until an audit. Getting canonical candidate identity right isn't a nice-to-have; it's the load-bearing wall.
Migration recipes for legacy item banks
Nobody starts clean. You're almost always imposing a canonical model on a bank that grew organically for years. The temptation is to boil the ocean — reclassify everything, re-tag everything, fix every name — and that project dies around month four when enthusiasm runs out and daily work resumes.
-
Freeze and snapshot. Before touching anything, take a full read-only copy of the legacy bank. You will need it to validate that nothing got silently dropped.
-
Assign canonical IDs without changing content. Map every legacy item to a new opaque ID. Keep the old ID as a
legacy_idfield so you never lose the trail. This step alone unblocks a surprising amount. -
Backfill mandatory metadata only. Not everything — just the fields from the mandatory list. Where competency tags are missing, tag by best available signal and flag for human review rather than guessing silently.
-
Reconstruct administration history. This is the hard part. Go through historical delivery records and create Administration entities retroactively, attaching the cut score that was actually in effect at the time. If that's genuinely unrecoverable, record it as unknown explicitly — a documented gap beats a false assumption.
-
Deduplicate candidates. Resolve the multiple-identity problem before connecting anything downstream. Match on stable attributes, and keep a merge log.
-
Validate against the snapshot. Item counts, score counts, pass rates for a few known administrations. If the numbers don't reconcile with the frozen copy, something in the migration is lossy.
For the tagging portion specifically, the heuristics for prioritizing which items deserve careful classification first — rather than treating all 6,000 as equally urgent — connect to the approach described in competency-based question banks for role-based skill mapping. Migrate the high-traffic, decision-critical content first; the long tail can wait.
Keep the legacy_id field and a merge log to make validation and audits far simpler.
Migrate the high-traffic, decision-critical content first; the long tail can wait.
When this level of rigor makes sense — and when it doesn't
Not every program needs a full canonical model. Over-engineering a 200-item, single-team program is its own kind of waste.
This makes sense when:
-
You have multiple content authors or business units touching the same bank.
-
Assessment results feed HRIS certifications or compliance records.
-
You need year-over-year or cohort comparisons that must hold up under scrutiny.
-
You're anticipating a vendor migration and want to avoid being locked in again.
This is overkill when:
-
One person owns everything and shared context genuinely exists in their head.
-
Results are informal, formative, and never feed a downstream system.
-
The program is a short-lived pilot with no historical comparison need.
Who should NOT rush this: a team mid-crisis with a broken bank and no snapshot capability. If you can't freeze and snapshot first, don't start the migration — you'll lose the very history you're trying to protect. Stabilize, get a clean read-only copy, then proceed.
A real scenario
A regional healthcare network ran competency assessments across roughly 40 facilities. Each facility had adopted the program at a different time, and over about four years they'd accumulated close to 5,000 items with no shared model. "Form" meant a PDF at some sites and an LMS object at others. Candidate records were split across the proctoring tool, the LMS, and HRIS — the same nurse routinely existed as three different people in the data.
The breaking point was a compliance report. Leadership asked for pass rates on a mandatory safety certification by facility, year over year. It took the team nearly two weeks to produce, and the numbers still didn't fully reconcile because cut scores had changed twice and nobody had recorded when.
They ran a staged migration over roughly a quarter. Assigned canonical item IDs while preserving legacy IDs, reconstructed administration history with the cut scores actually in effect at the time, and deduplicated candidates down to a single canonical identity mapped to HRIS. Not glamorous work.
The change afterward wasn't a flashy metric. The same compliance report went from a two-week reconciliation project to something that ran in an afternoon — and the numbers actually matched across HRIS and BI. When the next audit came, the answer was defensible instead of apologetic. Fewer disputed numbers, faster answers, and history you can trust.
Where the model pays off long-term
The point of a canonical assessment data model isn't tidiness for its own sake. Once the entities and relationships are stable, everything downstream gets cheaper. Reports stop disagreeing. New systems plug into one mapping layer instead of a tangle of point-to-point connections. Vendor migrations become a data export, not a rebuild. And when someone asks a hard question about last year's cohort, you can answer it honestly.
Most of the downstream reporting work — the stakeholder-specific one-sheets and narrative packs covered in turning assessment data into decisions — only becomes trustworthy once this foundation is in place. You can't build reliable narratives on entities nobody agrees on.
If you take one action from this: make Administration a real entity, store the cut score with every score, and lock down a single canonical candidate identity. Those three moves prevent the majority of the reconciliation pain that quietly eats weeks out of every reporting cycle. The rest of the taxonomy is refinement — but those three are load-bearing, and they're worth getting right before the program grows past the point where anyone remembers what "the Q3 form" was supposed to mean.
Ready to revolutionize your evaluation process?
Join over 2,000 organizations using Evaloly to optimize assessments, improve learner outcomes, and make data-driven decisions.