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: Only for real, unambiguous numeric dates no later than today.
XML validation suggests YYYY-MM-DD; workbook import uses the same calendar
rules to normalize birth-date text before validation.
| Input | Result |
|---|---|
2015/4/13 or 2015-4-13 |
2015-04-13 |
13/04/2015 or 04-13-2015 |
2015-04-13 |
04/04/2015 |
2015-04-04 (both orders agree) |
03/04/2015 |
Review required; day/month order is ambiguous |
2015-02-29 or 31/04/2015 |
Review required; impossible calendar date |
Use a four-digit year and consistent slash or hyphen separators. Month names,
two-digit years, numeric serial text, and timestamps require source confirmation;
PanoReady does not use locale guessing or timezone conversion. Workbook dates
are evaluated as formatted cell text, so export them as YYYY-MM-DD to avoid
ambiguous displays. Invalid or ambiguous values are preserved for review.
Future birth dates still fail validation and receive no automatic suggestion.
Metadata CreateDate continues to require a real YYYY-MM-DD date no later
than today; it is not automatically rewritten. Age reports and filters consume
only confirmed, valid ISO birth dates. Unresolved dates have unknown age and
do not contribute to age-group counts.
OEN identity findings¶
OEN_DUPLICATE blocks same-school duplicates; OEN_DUAL_ENROLLMENT warns
about cross-school occurrences. Neither finding offers a replacement OEN input.
Review the records in the source system and upload a corrected file if needed.
A cross-school occurrence does not hide later same-school duplicates. Correction
of a malformed OEN (OEN_FORMAT) remains available. A separate duplicate
resolution workflow is outside the current scope.
Rule: postal-code¶
Severity: info, warning, or error
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 four 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 |
| U.S. ZIP / ZIP+4 shape | error | No | 12345 or 12345-6789 |
A five-digit numeric value or a five-digit value followed by a hyphen and four
digits matches the standard U.S. ZIP / ZIP+4 shape. These values produce a
blocking POSTAL_CODE_US_ZIP error and must be replaced with a Canadian postal
code. PanoReady does not convert U.S. ZIP codes automatically.
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 and PoBoxNumber are handled by their dedicated format rules rather
than this generic length rule. Invalid postal codes and box numbers 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: ALTERNATE_DELIVERY_IN_STREET_FIELD¶
Severity: warning
Fields: StreetName, StreetNumber
Detects complete numeric PO Box references entered in a street field, including
PO Box 42, P.O. Box #42, Post Office Box 42, and Box 42. Detection runs
before the generic character policy.
Auto-fix: Yes when PoBoxNumber is empty or identifies the same number and
the proposed values meet their field rules. The fix stores only the digits in
PoBoxNumber. Leading zeroes are preserved. A complete box reference clears
the source field. A leading reference followed by whitespace or a hyphen and
a civic-address fragment (street number followed by street text) preserves
that fragment in the source field. For example, PO BOX 57 918 Example Grove
becomes box number 57 with 918 Example Grove retained in StreetName, and
P.O Box 68-427 Sample Way becomes box number 68 with 427 Sample Way retained.
The retained fragment can then be reviewed as part of the street address.
Conflicting destinations, references in both street fields, letters in the box
number, additional delivery references, station information, and unrecognized
trailing text remain manual review. A numeric range without street text, such
as PO Box 57-918, is not automatically split.
Rule: PO_BOX_NUMBER_FORMAT¶
Severity: warning; error when the configured length limit is exceeded
Field: PoBoxNumber
A populated field must contain only the box number in digits, such as 42 or
0042. Do not include PO Box, a #, spaces, letters, or other address text.
The optional field may be empty. Manual field editing uses the same validation
and marks an invalid draft Check value. The formatted address preview adds
PO Box for readability; the field and exported value contain only the number.
Auto-fix: Yes for a complete recognizable numeric value: PO Box 0042,
P.O. Box #0042, Post Office Box 0042, Box 0042, and #0042 become 0042.
Numbers are never truncated or converted to integers. Values containing other
text or numbers exceeding the configured limit remain manual review. This rule
owns the field, so generic character cleanup cannot remove punctuation to turn
an ambiguous value into a different box number.
Rule: RURAL_ROUTE_IN_STREET_FIELD¶
Severity: warning
Fields: StreetName, StreetNumber
Detects rural-route delivery text entered in a street field. Detection runs
before the generic character policy so punctuation can contribute to
recognition. For example, R.R. #01 is accepted as input even though that
punctuation is not retained in the canonical rural-route value.
Auto-fix: Yes for an unambiguous route number when RuralRoute is empty or
already identifies the same route. The fix writes the normalized value, such as
RR 1, to RuralRoute. If the route is the complete source value, that source
field is cleared. If it is a leading token followed by a hyphen or whitespace,
the token and separator are removed while the remaining street text is
preserved. A conflicting existing RuralRoute, or another rural-route marker
in the remaining text, remains manual review.
Rule: RURAL_ROUTE_FORMAT¶
Severity: warning
Field: RuralRoute
A populated rural-route field must contain the uppercase identifier RR, one
space, and a route number containing one to four digits—for example, RR 4. A
#, periods, expanded wording, station information, additional spaces, five or
more route-number digits, and other text are not accepted in this canonical
field. An empty value remains valid because the field is optional. This is a
data-quality finding and does not block submission.
The same rule is applied while editing an address during manual review, so an invalid draft is marked Check value before it is applied.
Auto-fix: Yes when a one-to-four digit route number can be parsed
unambiguously, including a bare number in the RuralRoute field (for example,
2 becomes RR 2 and R.R. #01 becomes RR 1). Longer route numbers and
values containing other text remain manual review.
Rule source: Canada Post — Addressing guidelines: Civic address
Rules: free-text characters¶
Severity: info
Fields: configured independently in freeTextCharacterChecks
Four separate rules identify characters that are accepted in STIX but may make downstream reporting or matching less reliable:
| Rule ID | Characters | Suggested fix |
|---|---|---|
FREE_TEXT_APOSTROPHE |
Straight and curly apostrophes | Remove |
FREE_TEXT_QUOTATION |
Straight and curly quotation marks | Remove |
FREE_TEXT_ACCENT |
Accented Latin letters, including é è à ù ä ö ü |
Replace with the unaccented letter |
FREE_TEXT_SPECIAL_CHARACTER |
Anything outside ASCII letters, numbers, whitespace, -, round brackets, or the field's configured exceptions |
Remove |
Each category has its own field list. The built-in profile permits apostrophes,
periods, and ampersands in SchoolName, while the other enabled checks still
apply there.
Periods and slashes are also preserved in the street-address fields Unit,
StreetNumber, StreetNumberSuffix, and StreetName.
Periods, slashes, and ampersands are preserved in City as well.
Profiles can enable or disable every category for every supported free-text
field. When one field contains multiple categories, the findings remain
separate but share the same composed suggestion so applying any or all of them
produces the complete safe value.
Balanced parenthetical spans are excluded entirely: the brackets and their contents are preserved for possible future handling as aliases or former names. An unmatched round bracket is allowed but does not shield the remaining text.
Character checks run last and act only as a fallback. If another validator, including rural-route detection, already reports the same record field, its specialized correction owns that field and no character finding is added.
Auto-fix: Yes. These findings never change the validation gate.
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 |
|---|---|---|
ALTERNATE_DELIVERY_IN_STREET_FIELD |
Yes when unambiguous | Move the numeric PO Box reference to PoBoxNumber, without a prefix |
PO_BOX_NUMBER_FORMAT |
Yes when the complete number is unambiguous | Remove a recognized prefix or number marker; preserve leading zeroes |
RURAL_ROUTE_IN_STREET_FIELD |
Yes when unambiguous | Move to RuralRoute and normalize to RR n |
RURAL_ROUTE_FORMAT |
Yes when a 1–4 digit number is unambiguous | Normalize to RR n; other values need manual review |
FREE_TEXT_APOSTROPHE |
Yes | Apostrophe removed |
FREE_TEXT_QUOTATION |
Yes | Quotation mark removed |
FREE_TEXT_ACCENT |
Yes | Unaccented Latin letter |
FREE_TEXT_SPECIAL_CHARACTER |
Yes | Other special character removed |
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 | — |
XML structure acceptance¶
STIX XML is checked before values enter the working model. Every element must use the http://ontario.ca namespace and the supported STIX hierarchy. Unknown elements or attributes, duplicate singleton elements, more than two guardians, mixed container text, multiple roots, and DTD/entity declarations are rejected. Namespace aliases, comments, standard XML entities, phone type attributes and root xsi:schemaLocation are supported. Missing values in known fields remain validation findings. These are local structure checks, not certified XSD validation.
Workbook birth-date interpretation¶
Intake shows evidence across all imported student birth dates, with the first five populated values as a preview. Choose day/month/year or month/day/year to resolve ambiguous text; each file in Compare Files has its own choice. Opposing unambiguous day-first and month-first values block conversion even if an order is selected. Choices reset when the file changes and are not stored with workbook metadata.
Typed Excel date cells use their stored numeric value, date format and workbook 1900/1904 date system, not their displayed text. Excel serial 60 in the 1900 system, fractional days, numeric cells without a date format, formulas and invalid calendar dates are rejected. Year-first and uniquely interpretable text dates can normalize without a choice. Output uses YYYY-MM-DD. Unresolved ambiguous, invalid or conflicting dates block intake; correct the source or choose a consistent interpretation before continuing. Other workbook mapping behavior is unchanged.