Validation Rules Reference¶
This page documents every rule checked during the Validate & Fix workflow. Rules are loaded from config/rules.stix.default.json at runtime.
Severity Levels¶
| Level | Meaning |
|---|---|
error |
Blocks the gate. The file should not be submitted until all errors are resolved. |
warning |
Does not block the gate, but indicates data quality issues worth reviewing. |
info |
Informational notice only — no action required. |
Rule Catalogue¶
Rule: xml-wellformed¶
Severity: error Field: (structural)
Checks that the uploaded file is valid XML. This is the first check — if it fails, no other rules run.
Pass condition: fast-xml-parser can parse the file without throwing.
Auto-fix: No. A malformed XML file must be corrected externally.
Rule: root-element¶
Severity: error Field: (structural)
Checks that the root element is ns1:SchoolUpload.
Pass condition: The parsed document has a root key of ns1:SchoolUpload.
Auto-fix: No.
Rule: school-structure¶
Severity: error
Field: SchoolNumber
Each ns1:School element must have a SchoolNumber attribute or child element.
Pass condition: SchoolNumber is present and non-empty on the school element.
Auto-fix: No.
Rule: required-fields¶
Severity: error
Fields: FirstName, LastName, BirthDate, Grade, SchoolNumber
Each student record must have all required fields present and non-empty.
Required fields (from rules.stix.default.json):
FirstName, LastName, BirthDate, Grade, SchoolNumber
Pass condition: Each required field exists and contains at least one non-whitespace character. Auto-fix: No. Missing required fields must be supplied manually.
Rule: grade-value¶
Severity: error
Field: Grade
The Grade field must be one of the allowed values.
Allowed values:
JK, SK, GR1, GR2, GR3, GR4, GR5, GR6, GR7, GR8, GR9, GR10, GR11, GR12
Grade aliases (auto-corrected):
| Input | Corrected to |
|---|---|
K |
JK |
GR01 |
GR1 |
1 |
GR1 |
2 |
GR2 |
3 |
GR3 |
4 |
GR4 |
5 |
GR5 |
6 |
GR6 |
7 |
GR7 |
8 |
GR8 |
9 |
GR9 |
10 |
GR10 |
11 |
GR11 |
12 |
GR12 |
Auto-fix: Yes, when the value matches a known alias. The suggested fix is the canonical form.
Rule: gender-value¶
Severity: error
Field: Gender
The Gender field must be one of the allowed values.
Allowed values:
M, F, X, U
Gender aliases (auto-corrected):
| Input | Corrected to |
|---|---|
MALE |
M |
FEMALE |
F |
NON-BINARY |
X |
UNKNOWN |
U |
Auto-fix: Yes, when the value matches a known alias.
Rule: province-value¶
Severity: warning
Field: Province
The Province field must be a valid Canadian province or territory code.
Allowed values:
AB, BC, MB, NB, NL, NS, NT, NU, ON, PE, QC, SK, YT
Auto-fix: No. Province codes must be corrected manually.
Rule: birthdate-format¶
Severity: error
Field: BirthDate
The BirthDate field must be in YYYY-MM-DD format and represent a parseable calendar date.
Pass condition: Value matches YYYY-MM-DD and the date is valid (e.g. month 1–12, day within month).
Auto-fix: Yes, for common alternate formats. The validator attempts to parse dates in formats such as DD/MM/YYYY, MM/DD/YYYY, and YYYY/MM/DD, and suggests the normalized YYYY-MM-DD form when it can resolve the date unambiguously.
Rule: postal-code¶
Severity: info or warning
Field: PostalCode
The built-in rule validates Canadian postal-code structure and produces the
canonical six-character STIX value A1A1A1 (uppercase, no separator). Canada
Post normally displays the same code as A1A 1A1; PanoReady accepts that form
as input and suggests the unspaced machine representation used in its output.
Allowed characters:
- Position 1:
A B C E G H J K L M N P R S T V X Y - Positions 3 and 5:
A B C E G H J K L M N P R S T V W X Y Z - Positions 2, 4, and 6: digits
0–9; zero in position 2 is valid and identifies a rural forward sortation area - Letters
D F I O Q Uare never valid;W Zare additionally excluded from position 1
Built-in canonical pattern:
^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ]\d[ABCEGHJKLMNPRSTVWXYZ]\d$
The following input connectors are accepted only between the first and last
three characters: one or more whitespace characters, -, en dash (–), em
dash (—), /, \, _, and .. Whitespace may surround a punctuation
connector. For example, N1G / 2W1 safely normalizes to N1G2W1. A connector
in any other position, repeated punctuation, or arbitrary punctuation remains
invalid; PanoReady does not globally strip punctuation.
The validator reports one of three issue outcomes:
| Outcome | Severity | Auto-fix | Example |
|---|---|---|---|
| Formatting/case normalization | info | Yes | n1g 2w1 → N1G2W1 |
| Numeric-position transcription repair | warning | Yes | NIG2W1 → N1G2W1 |
| Unresolved invalid structure | warning | No | N1/G2W1 |
Only O → 0, I → 1, and L → 1 are repaired, and only in positions that
must be numeric. PanoReady does not truncate, stitch, reverse a digit into a
letter, or make speculative substitutions such as S → 5.
These checks prove syntactic structure only. They do not prove that Canada Post currently assigns the postal code or that it belongs to the supplied address.
Rule sources:
- Canada Post — Addressing guidelines: Postal codes
- Canada Post — Addressing guidelines: Important information
- Statistics Canada — Postal Code Conversion File Reference Guide
Rules: PHONE_FORMAT, PHONE_EXTENSION_NORMALIZE, PHONE_EXTENSION_FORMAT, PHONE_NPA_STRUCTURE, PHONE_NXX_STRUCTURE, PHONE_PLACEHOLDER¶
Severity: error
Fields: metadata ContactPhone, student Phone, and each guardian Phone
The built-in phone rule expects the canonical North American Numbering Plan
(NANP) form NPA-NXX-XXXX, optionally followed immediately by a lowercase x
and an extension of 1–5 digits: NPA-NXX-XXXXx12345. Both the area code (NPA)
and central-office or exchange code (NXX) have the form NXX, where N is a
digit from 2 through 9 and each X is a digit from 0 through 9.
For example, 519-824-1234 is structurally valid. 019-824-1234 has an
invalid NPA, and 519-124-1234 has an invalid NXX. PanoReady never guesses a
replacement digit for either structural failure.
Common numeric presentation variants are interpreted deterministically. Ten
digits, parentheses and spaces, and an optional leading NANP country code 1
(including +1) can be normalized to XXX-XXX-XXXX. The resulting suggestion
uses the existing apply-and-revalidate workflow. Common unambiguous extension
markers—uppercase X, spaced x, ext, ext., extension, and #—are
similarly normalized. For example, 519-824-1234 ext. 12
becomes 519-824-1234x12.
An extension marker with no digits, more than five digits, non-numeric extension
text, too few or too many base-number digits, appended notes, and multiple
numbers require manual correction. PanoReady does not guess or truncate those
values. Numbers
listed in phoneConfig.placeholderNumbers are also errors; a placeholder may
receive both the applicable structural issue and the placeholder issue.
Auto-fix: Base-number formatting and unambiguous extension-marker normalization only. Missing, overlong, or non-numeric extensions, NPA/NXX structural failures, multiple numbers, appended notes, and placeholders are not auto-fixable.
Rule sources:
- Canadian Numbering Administrator — NPA Code (Area Code)
- NANPA — CO Codes/Thousands-Blocks
- NANPA — About the North American Numbering Plan
Rule: PHONE_CANADIAN_AREA_CODE¶
Severity: off, info, or warning
Fields: metadata ContactPhone, student Phone, and each guardian Phone
After a number passes NANP structural validation, this optional policy rule
checks whether its NPA is a currently active Canadian geographic area code.
It does not classify a structurally valid US or other NANP number as invalid.
The built-in STIX ruleset uses warning; custom rulesets can choose off,
info, or warning. The rule can never produce an error and therefore never
changes a READY gate to BLOCKED.
PanoReady bundles a static CNAC-derived set rather than making a runtime network
request. The set was verified on 2026-09-01 against CNAC's current CO Code
Status data and relief notices. It excludes future or reserved relief NPAs such
as 273 and 851, and Canadian non-geographic numbering resources such as
600. Because area codes change, that source date is part of the rule and the
set must be reviewed over time.
No Canadian policy issue is emitted unless the number first passes both the NPA and NXX structural checks. Policy findings have no suggested fix.
Passing the structural and Canadian-geographic checks proves neither that the subscriber number exists nor that it is active or belongs to the stated person.
Rule sources:
- Canadian Numbering Administrator — CO Code Status
- Canadian Numbering Administrator — Non-Geographic (6YY) Codes
- Canadian Numbering Administrator — 782/902 relief planning for future NPA 851
Rule: oen-format¶
Severity: error
Field: OEN
The Ontario Education Number (OEN) must be exactly 9 digits.
Pass condition: Value contains exactly 9 digit characters and no other characters.
Auto-fix: No.
Rule: field-length¶
Severity: warning Field: varies
Field values must not exceed the maximum length for that field.
Maximum field lengths:
| Field | Max characters |
|---|---|
FirstName |
50 |
MiddleName |
50 |
LastName |
50 |
AliasFirstName |
50 |
AliasMiddleName |
50 |
AliasLastName |
50 |
StreetName |
80 |
StreetNumber |
10 |
StreetNumberSuffix |
5 |
StreetType |
10 |
Unit |
10 |
City |
50 |
OEN |
9 |
Auto-fix: No. Values exceeding the limit must be shortened manually.
PostalCode is intentionally handled by its dedicated structural rule rather
than this generic length rule. Invalid postal codes are never auto-truncated.
Rule: whitespace¶
Severity: info Field: varies
Fields with leading or trailing whitespace are flagged.
PostalCode is intentionally excluded: its dedicated rule supplies the full
canonical value so the same input does not also receive a generic whitespace
issue.
Auto-fix: Yes. The suggested fix is the trimmed value (whitespace removed from both ends).
Rule: duplicate-oen¶
Severity: error
Field: OEN
Each OEN must appear only once in the file. A duplicate OEN indicates two records share the same student identifier.
Pass condition: No two student records have the same non-empty OEN value. Auto-fix: No. Duplicate OENs require manual investigation to determine which record is correct.
Rule: duplicate-name-dob-school¶
Severity: warning
Field: FirstName, LastName, BirthDate, SchoolNumber
Flags student records where the combination of FirstName + LastName + BirthDate + SchoolNumber appears more than once, indicating a possible duplicate enrollment.
Pass condition: No two records share the same name, date of birth, and school. Auto-fix: No.
Custom Rulesets¶
The allowed values, field lengths, patterns, and aliases that drive these rules are configurable. You can create board-specific rulesets without code changes by using the Validation ruleset control in Validate & Fix.
See docs/rulesets.md for a full field-by-field reference, including how each ruleset field maps to the rule IDs above.
Auto-Fix Summary¶
| Rule | Auto-fixable | Fix applied |
|---|---|---|
xml-wellformed |
No | — |
root-element |
No | — |
school-structure |
No | — |
required-fields |
No | — |
grade-value |
Yes (alias match) | Canonical grade code |
gender-value |
Yes (alias match) | Canonical gender code |
province-value |
No | — |
birthdate-format |
Yes (parseable alternate format) | YYYY-MM-DD |
postal-code |
Yes (safe normalization or O/I/L numeric-position repair) | Canonical six-character value |
PHONE_FORMAT |
Yes (deterministic formatting only) | XXX-XXX-XXXX |
PHONE_NPA_STRUCTURE |
No | — |
PHONE_NXX_STRUCTURE |
No | — |
PHONE_PLACEHOLDER |
No | — |
PHONE_CANADIAN_AREA_CODE |
No | — |
oen-format |
No | — |
field-length |
No | — |
whitespace |
Yes | Trimmed value |
duplicate-oen |
No | — |
duplicate-name-dob-school |
No | — |