OneRoster milestone — starting brief (v1)
Status: implemented (2026-06-12/13) — the design and build live in
oneroster-consumer-v1.md (CSV + REST-delta consumer) and
oneroster-provider-v1.md (REST rostering provider, CSV export, gradebook +
resource services, round-trip CI gate, deferred-items campaign). This file is
the original starting brief, retained for provenance.
Decisions this builds on: ADR-0012 (OneRoster is a projection, not the roster
core), ADR-0013 (person-rooted identity), ADR-0014 (erasure is anonymization)
Design groundwork: person-auth-decoupling-v1.md (implemented — the FK blocker
named in ADR-0012’s consequences is resolved; persons can exist without auth)
This brief is the handoff into the design session. It records what is already in place, what the milestone must decide, and the commitments the ADRs have already made so the session starts from alignment rather than archaeology.
Already in place
Section titled “Already in place”personis the identity root;identity_binding(provider / issuer / subject, effective window) is the only resolution path. OneRostersourcedIds are bindings, never identities (ADR-0013).- Trigger v2 resolve-or-mint with claim stamping; no-fallback deny posture.
identity_merge_review— the receiving structure for correlation review (pending/merged/dismissed, cascade from either side, erasure-classified). It has no producers yet.- Issuer strings are environment-owned via
public.identity_issuer()(docs/runbooks/identity-issuer.md). - Erasure registry CI gate: any new person-linked table fails CI until it
declares its erasure class (
packages/db/src/erasure-registry.ts). - The NRPS consumer pattern to mirror:
lti_tool_platform/lti_tool_context_mapping/lti_tool_nrps_*_snapshot— retained source snapshots, explicit mapping tables, identity resolution through bindings.
Prerequisites inside this milestone (ordered)
Section titled “Prerequisites inside this milestone (ordered)”Designed 2026-06-12: all three prerequisites are specified in
identity-linking-v1.md — decisions settled there: person_contact_point as
the evidence home, a pristine-guard rebind primitive shared by both linking
paths, authenticated claim-token redemption, the evidence-class principle, and
NRPS email-match alignment pulled into this milestone. Revised the same day:
review structures split in two (merge review for signup paths, correlation
review for consumer paths) — the SIS consumer inherits hold-and-correlate
on ambiguity, not mint-and-merge. Implemented 2026-06-12 (validation and
integration gates green); dev-database replay pending.
- Pre-provisioned linking paths (rows 3–4 of the decoupling doc’s linking
table): claim-token resolve and verified-email-match resolve. Note the
email-match path needs an
email_confirmed_atUPDATE trigger — confirmation happens after the auth-user INSERT that trigger v2 sees. Hard rules carry over verbatim: never link on an unverified email; binding rows only from service-role paths; post-session linking requires token refresh. - Person-side contact/roster evidence. Persons deliberately carry no email today; the consumer must decide where correlation evidence lives (roster snapshot tables vs. person profile fields) — this decision gates both the email-match path and merge-review producers.
- Merge-review producers: the email-match fall-through and SIS correlation
review enqueue into
identity_merge_review. The admin-console panel follows real queue traffic.
The milestone proper (ADR-0012 commitments)
Section titled “The milestone proper (ADR-0012 commitments)”Consumer designed 2026-06-12: oneroster-consumer-v1.md — CSV-first shared
ingest core, Course → Learning Container, academic sessions enter the core as
Learning Period (junction to offerings), identity rules inherited from
identity-linking-v1, demographics boundary-only, guardian links deferred.
Provider + round-trip gate remain outlined there, designed after the consumer.
- Consumer (SIS sync): NRPS-style retained snapshots + mapping tables;
membership lifecycle mapping per
docs/integration/roster-and-grade-exchange.md. - Provider (REST/CSV): projection over the neutral core, emitted only for
school-shaped contexts; deterministic Course synthesized per Offering;
conformance = service behavior (filtering, paging,
dateLastModifieddeltas, stable sourcedIds). - Round-trip CI gate: school-context core data must survive emergent → OneRoster → emergent losslessly (mirrors the QTI gate, ADR-0001). This is the invariant ADR-0012 names; nothing exists yet.
Vocabulary checklist items (enter the core as need arrives, never as wire shapes)
Section titled “Vocabulary checklist items (enter the core as need arrives, never as wire shapes)”Academic sessions (naming still open), guardian links (guardians are Persons — ADR-0013), course templates, org hierarchy, grade/subject vocabularies.
Constraints to keep honoring
Section titled “Constraints to keep honoring”- One-vocabulary rule: OneRoster terms (User, Org, Course, Class, Enrollment)
appear only at the
@conform-ed/contractsboundary — never in code, schema, or UI. status: tobedeletedsemantics stay at the boundary; they must not leak into pgxsinkit-synced tables’ lifecycle.- Zod contracts for OneRoster 1.2 already exist in
@conform-ed/contracts.