Who
The engineer maintaining AcmeTest, already using a Platform3 QTI player and OneRoster identities.
Use this reference to implement assign → launch → QTI state → Results write-back without guessing. It defines every shipped v1 request, response, query, header, persisted column, enum, validation rule, and endpoint error. Platform3-native identifiers remain opaque pass-throughs; learner, attempt, session, outcome, score, and mastery facts stay in their owning systems.
The AcmeTest maintainer can generate a typed client from these definitions without learning AlphaTest internals. Read the Administration resource, choose one target variant, then follow the create endpoint. Candidate delivery state is composed live from OneRoster and QTI; it is never a local copy.
The engineer maintaining AcmeTest, already using a Platform3 QTI player and OneRoster identities.
Wire assignment, window-gated delivery launch, polling, retakes, close, and verified Results write-back in one afternoon.
All Platform3 IDs are opaque UTF-8 strings. Store and compare them byte-for-byte; never parse prefixes or infer ownership.
Fields are non-null unless their row explicitly says nullable. An omitted optional field differs from a JSON null, which is rejected unless explicitly allowed.
POST /v1/bank-generations for same_blueprint_fixed_forms returns typed 424 dependency_contract_unavailable before admission and creates no operation until an owner-backed receipt proves all six assignability predicates below and a same-tenant Administration create accepts the returned native IDs. The future 202 Administration create schema remains normative, but a client must not treat a Bank ready/assignable flag as sufficient evidence. Retained same-tenant evidence explains the gate: Bank operation bop_37Q999HAPF1PRK8H2FGCWFZRHH reported ready/assignable for bank f937d471-d97f-4fca-83c8-8a2faf98bf0b, while authoritative Content returned status=draft, is_mastery_gate=false, membership_rule=null, and spec_id=null; Administration therefore rejected the native IDs before roster, persistence, or session effects. See the approved Bank dictionary and ITD-037.These outcomes occur at different ownership boundaries and are not interchangeable. Preserve each surface’s exact code; do not normalize Bank’s underscore-delimited code into an Administration code.
| Call and response | Machine meaning | Effect boundary | Typed-client action | Provenance |
|---|---|---|---|---|
Bank generation → 424 dependency_contract_unavailable | The fixed-form producer lacks the complete owner-backed certification receipt. This is the only expected fixed-generation outcome today. | No Bank operation is admitted; do not call Administration with locally inferred IDs. | Surface the dependency gap and retain the original generation request for a later retry. Do not poll an operation because none exists. | Bank ITD-016 · Administration ITD-037 |
Administration create → 422 test-not-assignable | Authoritative Content/QTI resources were reachable, but the first predicate in the deterministic validation order failed. | No Administration row, OneRoster lookup, or QTI session effect. | Treat the supplied native IDs as unusable; do not retry unchanged. Use detail for diagnosis and branch on code. | ITD-009 · ITD-037 |
Administration create → 424 content-unavailable or 424 qti-unavailable | The authoritative predicate could not be evaluated; this is not evidence that a predicate was false. | No Administration row, OneRoster lookup, or QTI session effect. | Retry the same logical create with the same Idempotency-Key after the dependency recovers. | ITD-006 · ITD-024 · ITD-037 |
Administration create → 202 + Location | All pre-effect validation passed and the administration plus its retry-safe provisioning intent is durable. | Provisioning may continue asynchronously; poll the returned resource. | Follow Location; never synthesize the administration ID or infer completion from acceptance. | ITD-014 · ITD-037 |
This map is an index over the normative schemas below, not a second contract. Each method name links to its exact HTTP row; each input and output links to the complete field dictionary. A client should decode every non-2xx response as ProblemDetails and branch on its stable code.
interface AdministrationClient {
create(input: CreateAdministration, idempotencyKey: string): Promise<Created<Administration>>;
provision(id: string, input: {}, idempotencyKey: string): Promise<Accepted<Administration>>;
list(query?: AdministrationListQuery): Promise<Page<Administration>>;
get(id: string, options?: { include?: "candidates" }): Promise<Entity<Administration>>;
patch(id: string, input: PatchAdministration, ifMatch: string): Promise<Entity<Administration>>;
candidates(id: string, query?: CandidateListQuery): Promise<Page<CandidateDelivery>>;
launch(id: string, candidateSourcedId: string, idempotencyKey: string): Promise<LaunchReceipt>;
advance(id: string, candidateSourcedId: string, input: {}, idempotencyKey: string): Promise<CandidateDelivery>;
retake(id: string, input: CreateRetake, idempotencyKey: string): Promise<Accepted<CandidateDelivery>>;
close(id: string, input: {}, idempotencyKey: string): Promise<Accepted<Administration>>;
}
type Created<T> = { status: 202; body: T; location: string; idempotentReplayed: boolean };
type Accepted<T> = { status: 202; body: T; idempotentReplayed: boolean };
type Entity<T> = { status: 200; body: T; etag: string };
type Page<T> = { data: T[]; nextCursor: string | null; hasMore: boolean; requestId: string };
Created.location is required for create; Accepted deliberately has no location member for provision, retake, or close. idempotentReplayed is true only when the response carries literal Idempotent-Replayed: true. The wire response body is the linked resource itself—these wrappers describe status and headers in a typed transport layer; they are not JSON envelope fields. Provenance: ITD-005, 006, 014, 030, 031./v1/… paths. At the product origin, authenticated API traffic lives below /api, so the complete wire URL is https://alphatest-administration.vercel.app/api/v1/…. For example, POST /v1/administrations below means POST https://alphatest-administration.vercel.app/api/v1/administrations. Documentation remains unauthenticated at /, /architecture, and this durable dictionary route, /reference. Provenance: ITD-023, ITD-027.| Concept | Wire type and range | Rules | Provenance |
|---|---|---|---|
| AlphaTest ID | string, 1–255 bytes | Opaque, case-sensitive, immutable. Returned by the service; clients must not synthesize it. Opacity is pinned by the approved HTTP contract; the 1–255-byte validation bound is this dictionary’s wire refinement. | Architecture HTTP contract |
| Platform3 reference | string, 1–255 bytes | Opaque byte-for-byte pass-through. No prefix, UUID, or URL assumption. Blank and surrounding whitespace are invalid. | ITD-001, 035 |
| Instant | string(date-time) | RFC 3339 UTC with terminal Z; fractional seconds accepted and normalized. Offsets other than Z, local times, and leap seconds are rejected. | ITD-031 |
| Duration seconds | integer, 60–86,400 | Whole seconds only. AlphaTest stores this as nominal scheduling/audit policy; QTI does not enforce it in v1. | ITD-031 |
| Time multiplier | number | The only accepted v1 value is the semantic no-op 1. Any other value requires an upstream QTI capability that is not currently available. | ITD-018 |
| Count | integer, ≥0 | Non-negative JSON integer. Counts are snapshots of the response composition, not locally durable learner facts. | ITD-016 |
| Request ID | string, 1–128 bytes | Opaque correlation value generated at the boundary and propagated upstream. Contains no learner identifiers. | ITD-025 |
| Header | Required | Meaning and validation | Failure | Provenance |
|---|---|---|---|---|
Authorization | Every endpoint | Bearer <JWT>; verified HS256 claims: sub, role, tenantId, iat, exp. The role grants a maximum permission set; optional scope, school, and class claims can only narrow it. A valid five-claim token does not need scope. | 401 authentication-required or 403 insufficient-scope | ITD-007 |
Content-Type | Requests with body | application/json; optional media-type parameters are ignored. Invalid JSON is not field validation. | 415 unsupported-media-type or 400 malformed-json | ITD-009 |
Idempotency-Key | Create, provision-resume, first launch, adaptive advance, retake, and close | String, 1–255 visible ASCII characters, no leading/trailing whitespace; scoped to verified tenant + method + concrete path for 24 hours. Always send it on launch. Provision and adaptive operations retain deterministic per-candidate child keys so partial fan-out can resume without duplicates. Launch authorization is evaluated before receipt lookup. | 400 missing-idempotency-key or 409 idempotency-key-reused | ITD-006, 031, 034 |
If-Match | PATCH | Exact strong ETag last returned by detail. Weak tags and * are rejected. | 428 precondition-required or 412 etag-mismatch | ITD-005 |
X-Timeback-Tenant | No | Diagnostic assertion only. If supplied, must exactly equal the verified JWT tenantId; it never selects a tenant. | 403 tenant-mismatch | ITD-010 |
| Header | Present on | Wire type / allowed values | Meaning | Provenance |
|---|---|---|---|---|
Location | Successful create | absolute-path reference, non-null | Canonical wire path /api/v1/administrations/{id} for the accepted resource. Endpoint templates elsewhere omit the product-origin /api mount as defined in Base URL and path notation. | ITD-014, 027 |
ETag | Successful detail and patch | Opaque strong entity-tag, non-null | Quote and send byte-for-byte as the next If-Match; never parse the version from it. | ITD-005 |
Idempotent-Replayed | Stored effectful-POST replay; stored launch replay only while launch-authorized | Literal true; otherwise absent | The status and body are the original response for the same scoped key and identical semantic request. This covers create, provision, advance, retake, and close. Launch is the exception: outside [opensAt, closesAt), window denial wins and the header is absent. | ITD-006, 031 |
Retry-After | 429 or retryable 503 when a retry time is known | HTTP-date or non-negative decimal delay-seconds; otherwise absent | Earliest safe retry boundary; clients must still check retryable and preserve idempotency. | ITD-024 |
Content-Type | Every response with a body | application/json on success; application/problem+json on non-2xx | Selects the success resource or ProblemDetails decoder. | ITD-009 |
Allow | 405 only | Comma-separated HTTP methods; non-null | Exact shipped methods for the matched path, including POST on provision, launch, advance, retake, and close actions. | ITD-002, 009 |
400 malformed-json. Provenance: ITD-006.Authorization: Bearer <JWT>. Reviewer/demo token bootstrap is deployment tooling, not a production API contract. This prevents a cold client from searching for an AlphaTest login or credential resource that does not exist. Provenance: ITD-007.| Claim | Type / range | Required / nullable | Meaning and validation | Provenance |
|---|---|---|---|---|
sub | string, 1–255 bytes | Required; never null | Opaque Platform principal identifier. | ITD-007 |
role | non-empty string, ≤120 bytes | Required; never null | Looks up the maximum administration permission set below. Unknown values authenticate but grant no administration permission. | ITD-007 |
tenantId | string, 1–255 bytes | Required; never null | Authoritative opaque tenant route. It is never overridden by a header or path. | ITD-007, 010 |
iat | integer NumericDate seconds | Required; never null | JWT issued-at instant; a token issued in the future beyond verifier clock tolerance is invalid. | ITD-007 |
exp | integer NumericDate seconds | Required; never null | Must be later than iat and later than verifier time. | ITD-007 |
scope | space-delimited string, 1–1,024 bytes | Optional; null rejected | Intersection-only permission narrowing. Each token is one of the five exact permission strings below; duplicates have no effect; unknown tokens grant nothing. | ITD-007 |
schoolSourcedIds | array of 1–1,000 unique Platform3 references | Optional; null rejected | Narrows target access to these OneRoster schools; empty arrays are rejected rather than interpreted as unrestricted. | ITD-007 |
classSourcedIds | array of 1–1,000 unique Platform3 references | Optional; null rejected | Narrows target access to these OneRoster classes; empty arrays are rejected rather than interpreted as unrestricted. | ITD-007 |
| JWT role | Maximum permissions | Optional scope behavior | Resource constraints | Provenance |
|---|---|---|---|---|
integrator | administrations:read, administrations:write, administrations:read_sensitive, administrations:deliver, administrations:close | If absent, the full role maximum applies. If present as a space-delimited string, the effective set is its intersection with the role maximum; unknown permissions grant nothing. | Optional schoolSourcedIds and classSourcedIds arrays, each 1–1,000 unique Platform3 references, narrow reads/writes. | ITD-007 |
reviewer | administrations:read, administrations:write, administrations:read_sensitive, administrations:deliver, administrations:close | Same narrowing rule; a standard five-claim reviewer token receives the role maximum. | Same optional narrowing arrays. | ITD-007 |
| Any other non-empty string | None in administration v1. | A scope claim cannot add permission. | Constraints cannot add permission. | ITD-007 |
The tenant-scoped orchestration resource. It contains policy and provisioning metadata, not roster members, responses, scores, or mastery.
| JSON field | Type | Nullable | Meaning / allowed values / validation | Owner + provenance |
|---|---|---|---|---|
id | AlphaTest ID | No | Immutable administration identifier. | AlphaTest glue · ITD-014 |
object | string enum | No | Always administration; this literal response discriminator is the dictionary refinement for the v1 resource exposed under the path-major contract. | AlphaTest glue · ITD-023 |
status | string enum | No | provisioning, provisioning_with_errors, scheduled, open, window_ended, closing, scored, or close_failed. This is orchestration lifecycle, not candidate state. scored requires fixed-form Results verification or, for adaptive diagnostics, completed mastery-engine runs with acknowledged Results KC components. | AlphaTest glue · ITD-014, 034, 036 |
test | TestRef | No | Immutable Content/QTI identity and required test-kind selector. A fixed mastery-gate identity is persisted only after authoritative Content and QTI validation succeeds. | Content/QTI pass-through · ITD-032, 035, 037 |
adaptiveConfig | AdaptiveConfigSummary | Conditional; never null | Present only for adaptive_diagnostic. Echoes immutable non-learner execution pins; resultsStudentBindings is never echoed. | AlphaTest glue · ITD-032, 033 |
target | TargetSummary | No | Immutable target kind. Explicit candidate IDs are never echoed or durably retained as a local membership list. | OneRoster/QTI pass-through · ITD-015, 026 |
window | Window | No | AlphaTest withholds the delivery session reference outside this window. QTI does not terminate an already revealed session. | AlphaTest glue · ITD-031 |
timing | Timing | Conditional; never null | Present for fixed-form kinds only and omitted for adaptive diagnostics. Fixed duration is nominal metadata, not QTI-enforced; adaptive stopping belongs to mastery_engine. | AlphaTest/mastery_engine boundary · ITD-031, 033 |
retakes | RetakePolicy | No | Attempt policy plus kind-specific fixed-form rotation or adaptive fresh-run semantics. | AlphaTest glue · ITD-017, 034 |
accommodations | Accommodations | No | Always the normalized semantic no-op in v1. It is not a claim that QTI applies accommodations. | AlphaTest glue · ITD-018 |
candidateCounts | CandidateCounts | No | Composed from per-binding QTI reads. Can lag while provisioning; asOf makes staleness explicit. | QTI pass-through · ITD-008, 016 |
provisioning | ProvisioningProgress | No | Bounded Content/OneRoster/QTI or mastery-engine provisioning progress. Partial success is retained and failed candidates are resumable. | AlphaTest glue + upstream refs · ITD-014, 024, 034 |
close | CloseProgress | Conditional; never null | Present only in closing, close_failed, or scored; omitted earlier. Counts describe reconciliation progress, never score values. | AlphaTest reconciliation glue · ITD-030 |
candidates | CandidateDelivery array, 0–100 | Conditional; never null | Present only when detail is requested with include=candidates; otherwise omitted. If more than 100 bindings exist, the request returns 422 candidates-page-required instead of truncating. | QTI/OneRoster composition · ITD-003, 007 |
version | integer ≥1 | No | Monotonic version of mutable AlphaTest-owned policy; basis of strong ETag. Upstream-only runtime changes do not increment it. | AlphaTest glue · ITD-005 |
createdAt | Instant | No | When the local resource became durable. | AlphaTest glue · ITD-014 |
modifiedAt | Instant | No | Latest local lifecycle, policy, or provisioning change; list ordering and modifiedSince compare this value. | AlphaTest glue · ITD-004 |
requestId | Request ID | No | Correlation for this read, not the create request. | AlphaTest glue · ITD-025 |
| Field | Type | Nullable | Meaning / validation | Owner + provenance |
|---|---|---|---|---|
qtiTestId | Platform3 reference, 1–255 bytes | Conditional; never null | Required for mastery_gate and formative; forbidden for adaptive_diagnostic, whose native QTI offers are created by mastery_engine. For a mastery gate this is the requested native fixed-form test-bank reference: Content must resolve it to the exact ordered member set, and every member’s immutable QTI artifact version must dereference before create has any effect. | Content/QTI pass-through · ITD-032, 033, 037 |
contentTestSpecId | Platform3 reference, 1–255 bytes | No | Requested Content test_spec reference. It must describe the supplied test kind. For mastery_gate, it must equal the authoritative bank’s non-null spec_id byte-for-byte. | Content pass-through · ITD-001, 037 |
testKind | string enum | No | Exactly mastery_gate, adaptive_diagnostic, or formative. Required and never inferred; all three use the same administration resource. | AlphaTest selector · ITD-032 |
contentTestSpecId and the Content bank identified by qtiTestId in the verified JWT tenant. Accept only when all six predicates hold: bank status=published; is_mastery_gate=true; membership_rule=same_blueprint_fixed_forms; bank spec_id exactly equals contentTestSpecId; the ordered member set is non-empty and exactly the set returned by Content; and every member’s immutable QTI artifact version dereferences. A Bank operation’s ready or assignable flag is correlation evidence only. A reachable authoritative resource that violates any predicate returns 422 test-not-assignable with no persistence, roster lookup, or QTI effect. Failure to obtain or validate an authoritative Content/QTI response returns the owning retryable 424 content-unavailable or 424 qti-unavailable, never a fabricated predicate result.ITD-037 · Content owns bank/spec/membership facts; QTI owns immutable artifact versions; AlphaTest stores only the accepted opaque references.
The response is deliberately smaller than the create input. Durable membership comes from QTI sessions; OneRoster remains identity authority.
| Variant / field | Type | Nullable | Meaning / validation | Owner + provenance |
|---|---|---|---|---|
type | string enum | No | class or candidate_list. | AlphaTest glue · ITD-026 |
oneRosterSourcedId | Platform3 reference | No* | Present and required only for class; absent for candidate_list. Live tenant authorization is required. | OneRoster pass-through · ITD-015 |
resolvedCandidateCount | integer ≥0 | No | Number of durable candidate-attempt bindings established by provisioning. It is neither an embedded roster nor a count of locally owned attempts. | AlphaTest binding count · ITD-015, 026 |
Required only when test.testKind=adaptive_diagnostic and forbidden for fixed-form kinds. All identifiers are opaque UTF-8 strings, 1–255 bytes, non-null. The input binding set is validated before persistence or any upstream effect; the response summary omits learner bindings.
| Field | Type | Input / output | Validation and meaning | Owner + provenance |
|---|---|---|---|---|
selectionPolicyId | Platform3 reference | Required / echoed | Exact immutable mastery-engine selection-policy version; aliases such as latest are invalid. | mastery_engine pass-through · ITD-032 |
scaleCalibrationId | Platform3 reference | Required / echoed | Exact immutable scale calibration valid for the referenced test spec and bank. | mastery_engine pass-through · ITD-032 |
testBankId | Platform3 Content reference | Required / echoed | Adaptive Content test_bank associated with test.contentTestSpecId. | Content/mastery_engine pass-through · ITD-032, 035 |
bankOperationId | AlphaTest Bank reference | Required / echoed | Exact terminal same-tenant bank operation whose manifest pins the native adaptive pool. | Bank/mastery_engine pass-through · ITD-032, 035 |
runMode | string literal | Required / echoed | Exactly production_learner. Administration does not expose owner-conformance runs. | mastery_engine pass-through · ITD-032 |
resultsStudentBindings | ResultsStudentBinding array, 1–1,000 | Required / omitted | Must contain exactly one entry for every resolved OneRoster candidate and no others. Missing, extra, duplicate, unknown, or cross-tenant entries return 422 adaptive-capability-required before persistence or effects. | Caller input validated through OneRoster + Results · ITD-032, 033 |
| Field | Type | Nullable | Meaning / validation | Owner + provenance |
|---|---|---|---|---|
candidateSourcedId | OneRoster reference, 1–255 bytes | No | Must match one resolved target candidate exactly; unique within the array. | OneRoster pass-through · ITD-032 |
resultsStudentId | Results reference, 1–255 bytes | No | Existing same-tenant Results learner reference. Administration validates but never infers it from OneRoster. | Results pass-through · ITD-032, 033 |
| Field | Type | Rule |
|---|---|---|
opensAt | Instant | Non-null; must be earlier than closesAt. Before this instant, launch returns 403 launch-not-open without revealing a session reference, including an otherwise-identical replay of a previously stored launch receipt. |
closesAt | Instant | Non-null; must be after opensAt. At or after this instant, launch returns 410 launch-window-ended without Idempotent-Replayed or a stored receipt, including an otherwise-identical replay. QTI does not terminate an already revealed session. |
Launch replay precedence: ITD-031 authorization is evaluated before ITD-006 idempotency receipt lookup. Only an authorized request inside [opensAt, closesAt) may replay the original LaunchReceipt; outside the window, the 403/410 denial wins and no deliverySessionRef is revealed. A denied replay does not delete or extend the stored 24-hour receipt.
| Field | Type | Rule |
|---|---|---|
timeLimitSeconds | integer 60–86,400 | Non-null nominal duration metadata. Returned in LaunchReceipt with runtimeEnforced:false; QTI does not enforce or terminate delivery from this value in v1. |
AlphaTest nominal policy · ITD-031
| Field | Type | Rule |
|---|---|---|
maxAttempts | integer 1–10 | Non-null total attempts including first. 1 disables retakes. |
parallelFormRotation | string enum | different_form_required for mastery gates, not_required for formative, or not_applicable for adaptive diagnostics. Adaptive retakes start a new mastery run and continuation; they never reuse the expired run. |
V1 has exactly one representable value: {"default":{"timeMultiplier":1},"candidateOverrides":[]}. The create field may be omitted, in which case that value is returned. Any non-default multiplier, any candidate override, null, extra field, or alternate shape returns 422 qti-accommodation-capability-required. This object is policy-shape compatibility only; QTI does not apply an accommodation.
| Path | Type | Nullable | Only allowed v1 value | Owner + provenance |
|---|---|---|---|---|
default | object | No | Exactly {"timeMultiplier":1}. | AlphaTest no-op policy · ITD-018 |
default.timeMultiplier | number | No | Literal numeric value 1. | AlphaTest no-op policy · ITD-018 |
candidateOverrides | array | No | Exactly an empty array. | AlphaTest no-op policy · ITD-018 |
| Field | Type | Nullable | Meaning | Owner |
|---|---|---|---|---|
notStarted | integer ≥0 | No | Fixed QTI sessions or adaptive offers not yet launched. | QTI/mastery_engine composed |
inProgress | integer ≥0 | No | Started fixed attempt or adaptive run in progress. | QTI/mastery_engine composed |
submitted | integer ≥0 | No | Fixed submission awaiting score, or adaptive finalizing with no offer. | QTI/mastery_engine composed |
scored | integer ≥0 | No | Fixed QTI score or adaptive completed output with acknowledged Results KC components. | QTI/mastery_engine/Results composed |
total | integer ≥0 | No | Sum of the four states. | QTI derived |
asOf | Instant | No | Completion time of the QTI read used for these counts. | AlphaTest composition |
ITD-016; never persisted as durable evidence.
| Field | Type | Nullable | Meaning / allowed values | Owner + provenance |
|---|---|---|---|---|
status | string enum | No | running, complete, or with_errors. This covers target resolution and per-candidate fixed QTI-session or adaptive mastery-run provisioning. | AlphaTest glue · ITD-014, 034 |
requested | integer ≥0 | No | Eligible candidate count resolved live from OneRoster for this provisioning run; count only, never a roster snapshot. | OneRoster-derived operational metadata · ITD-015 |
pending | integer ≥0 | No | Resolved candidates whose fixed QTI binding or adaptive mastery-run binding is not yet durable. | AlphaTest orchestration metadata · ITD-024, 034 |
failed | integer ≥0 | No | Resolved candidates whose latest provisioning attempt failed; retained for targeted resume and never folded into pending. | AlphaTest orchestration metadata · ITD-024, 034 |
succeeded | integer ≥0 | No | Immutable candidate-attempt bindings created and verified. Invariant: pending + failed + succeeded = requested. | AlphaTest binding count · ITD-015 |
errors | ProvisioningError array, 0–100 | No | Current diagnostics: {dependency,code,retryable,occurredAt}. Dependency is exactly content, oneroster, qti, results, or mastery_engine; code is 1–120 bytes; retryable is boolean; occurredAt is an Instant. No upstream body, continuation, or learner identifier is returned. | Privacy-safe local metadata · ITD-009, 025, 034 |
lastAttemptAt | Instant | Yes | null before the first upstream attempt; otherwise the latest bounded provisioning attempt. | AlphaTest glue · ITD-024 |
Operational reconciliation counts only. The API never returns or stores the QTI score body here.
| Field | Type | Nullable | Meaning / invariant | Owner + provenance |
|---|---|---|---|---|
submittedAttempts | integer ≥0 | No | Latest launched attempts eligible for close: fixed QTI submitted/scored attempts or adaptive attempts already composed as scored. | QTI/mastery_engine-derived count · ITD-030, 036 |
verifiedResults | integer ≥0 | No | Fixed attempts with exact Results read-back plus adaptive attempts whose completed inspect reports acknowledged Results KC components and a dereferenceable result reference. | Results/mastery_engine-derived count · ITD-030, 036 |
failed | integer ≥0 | No | Attempts whose latest QTI read, Results create, or exact verification failed. Invariant: verifiedResults + failed ≤ submittedAttempts. | AlphaTest reconciliation metadata · ITD-024, 030 |
lastAttemptAt | Instant | Yes | null only before asynchronous reconciliation begins; otherwise latest close worker attempt. | AlphaTest glue · ITD-024 |
Returned only from the candidates subcollection or include=candidates. The caller’s effective permissions must include administrations:read_sensitive. Every row is composed from the immutable binding, current QTI runtime data, and a live OneRoster identity reference. The raw delivery session is intentionally absent; only the launch action may reveal it.
| Field | Type | Nullable | Meaning / validation | Owner + provenance |
|---|---|---|---|---|
oneRosterSourcedId | Platform3 reference | No | Candidate identity reference; no name, email, or demographics. | OneRoster pass-through · ITD-015 |
state | string enum | No | not_started, in_progress, submitted, or scored. Fixed forms derive it from QTI. Adaptive composition maps pre-launch offer→not_started, mastery-engine in_progress→in_progress, finalizing without offer→submitted, and completed with reportable output plus acknowledged Results KC components→scored. | QTI/mastery_engine composition · ITD-016, 036 |
attemptNumber | integer 1–10 | No | QTI attempt ordinal for this candidate and administration. | QTI pass-through · ITD-017 |
qtiFormId | Platform3 reference | Conditional; never null | Present for fixed-form attempts only; omitted for adaptive diagnostics because each current native QTI offer is revealed only as deliverySessionRef by launch. | QTI pass-through · ITD-017, 033 |
adaptiveRunRef | mastery_engine reference | Conditional; never null | Present only for adaptive diagnostics. Opaque run reference used for support and inspect correlation; continuation token and ETag are never returned. | mastery_engine pass-through · ITD-033 |
launchEligibility | string enum | No | eligible, not_open, window_ended, or administration_closed. A hint computed at response time; the launch endpoint reauthorizes. | AlphaTest glue · ITD-031, 030 |
resultRecordRef | Platform3 reference | Conditional; never null | Present after fixed-form exact Results read-back or adaptive completion reports acknowledged Results KC components. It is a reference, never a score, scale value, KC map, or result body. | Results pass-through · ITD-030, 036 |
Returned only by the candidate launch action after current authorization succeeds.
| Field | Type | Nullable | Meaning | Owner + provenance |
|---|---|---|---|---|
administrationId | AlphaTest ID | No | Administration being launched. | AlphaTest glue · ITD-014 |
oneRosterSourcedId | Platform3 reference | No | Candidate path identity, repeated for correlation. | OneRoster pass-through · ITD-015 |
deliverySessionRef | Platform3 reference | No | Opaque QTI player session reference; revealed only while the window is open and the administration accepts launches. | QTI pass-through · ITD-011, 031 |
timeLimitSeconds | integer 60–86,400 | Conditional; never null | Present for fixed-form kinds only; omitted for adaptive diagnostics. | AlphaTest glue · ITD-031 |
runtimeEnforced | boolean literal | Conditional; never null | Present with timeLimitSeconds and always false; omitted for adaptive diagnostics. | Capability declaration · ITD-031 |
requestId | Request ID | No | Boundary correlation for this authorization. | AlphaTest glue · ITD-025 |
| Field | Type | Nullable | Meaning |
|---|---|---|---|
data | array | No | Administration or CandidateDelivery resources. Empty array is valid. |
nextCursor | string 1–1,024 | Yes | Opaque, request-shape-bound continuation; null when no next page. Do not parse or reuse with different filters/order. |
hasMore | boolean | No | Whether nextCursor can continue. |
requestId | Request ID | No | Boundary correlation for this page. |
Unknown fields and JSON null are rejected. Required and forbidden fields are selected solely by test.testKind. Pre-effect validation is atomic: any invalid test predicate, unauthorized target, or invalid adaptive Results binding rejects the whole request. For a fixed mastery gate, test assignability is checked before persistence, OneRoster resolution, or QTI effects.
| Field | Type | Required | Validation | Trace |
|---|---|---|---|---|
test | TestRef | Yes | contentTestSpecId and testKind are always required. qtiTestId is required for fixed kinds and forbidden for adaptive. Immutable after create. A mastery gate must satisfy the complete authoritative assignability predicate; no Bank workflow flag substitutes for Content/QTI read-back. | ITD-032, 033, 037 |
target | TargetInput | Yes | Exactly one discriminated variant. | ITD-026 |
adaptiveConfig | AdaptiveConfigInput | Conditional | Required exactly for adaptive_diagnostic; forbidden for fixed kinds. The Results binding set must equal the live resolved candidate set before effects. | ITD-032 |
window | Window | Yes | opensAt < closesAt; AlphaTest enforces it when revealing a QTI session reference. | ITD-031 |
timing | Timing | Required for fixed kinds; forbidden for adaptive | Fixed-form nominal metadata only; adaptive stopping policy belongs to mastery_engine and is never restated as a local duration. | ITD-031, 033 |
retakes | RetakePolicy | Yes | Must be compatible with test kind and available bank/form policy. | ITD-017 |
accommodations | Accommodations | No | If absent, normalizes to the documented no-op. If present, must equal it exactly; every non-default request returns 422 qti-accommodation-capability-required. | ITD-018 |
POST /v1/administrations/{id}/provision has an exact empty JSON object body {}, no query parameters, and requires Idempotency-Key. It retries only candidate attempts whose current provisioning state is failed and reuses each original deterministic child key. It never restarts successful QTI sessions or mastery runs. Success is 202 Administration; no failed candidates is a safe 202 no-op. Unknown fields or null return 400 validation-failed.
POST /v1/administrations/{id}/candidates/{candidateSourcedId}/advance is valid only for an adaptive candidate attempt after QTI has scored the current offer. Its strict request body is {}; candidate identity, opaque continuation, and current strong mastery-engine ETag come from the tenant-scoped binding, never from the caller. Idempotency-Key is required. Administration calls mastery_engine :advance, then atomically replaces the stored continuation token, ETag, expiry, and current offered QTI session. Success is 200 CandidateDelivery. A dependency failure returns 424 mastery-engine-unavailable without changing the binding; expiry returns 409 adaptive-continuation-expired and requires a policy-permitted retake. Fixed-form use returns 409 administration-state-conflict.
| Variant | Required fields | Forbidden fields | Validation |
|---|---|---|---|
type: "class" | oneRosterSourcedId: Platform3 reference | oneRosterCandidateSourcedIds | Class must exist, be active, belong to tenant and caller constraints, and resolve to at least one eligible active candidate. |
type: "candidate_list" | oneRosterCandidateSourcedIds: array of 1–1,000 Platform3 references | oneRosterSourcedId | Every ID unique, active, tenant-authorized, and allowed by caller constraints. No partial acceptance; list is not retained after the idempotency body expires. |
Merge-patch semantics are not used. The body is a strict JSON object containing one or more of the fields below; nested objects replace that policy section in full. JSON null and unknown fields are rejected. test, target, status, identifiers, counts, provisioning, and close progress are immutable. PATCH changes AlphaTest policy only and never claims to mutate QTI policy. Every PATCH field is guarded by the same authoritative-state rule: if any bound candidate has left QTI not_started, the whole request returns 409 administration-state-conflict and changes nothing.
| Field | Type | Required | Validation |
|---|---|---|---|
window | Window | No | Full object; subject to the all-candidates-not_started guard. A window_ended, closing, close_failed, or scored administration cannot be reopened. |
timing | Timing | No | Full nominal-metadata object; subject to the all-candidates-not_started guard. |
retakes | RetakePolicy | No | Full object; subject to the all-candidates-not_started guard and cannot reduce maxAttempts below an existing QTI attempt count. |
accommodations | Accommodations | No | Only the exact no-op object is accepted; any non-default value returns 422 qti-accommodation-capability-required. |
| Field | Type | Required | Validation |
|---|---|---|---|
oneRosterSourcedId | Platform3 reference, 1–255 bytes | Yes | Must identify a same-tenant bound candidate. No other fields are allowed. The administration must be open. For a fixed-form attempt, the latest authoritative QTI state must be submitted or scored. For an adaptive attempt, the latest composed state must be submitted, scored, or its advance must have returned the typed 409 adaptive-continuation-expired. Every other combination returns 409 administration-state-conflict. |
Composed guard — documented ITD-034 extension to ITD-017: ITD-017 supplies the submitted/scored base guard and fixed-form semantics; ITD-034 expressly adds the expired-continuation disjunct for adaptive diagnostics. Fixed forms: after the state guard, maxAttempts or eligible mastery-gate inventory exhaustion returns 409 parallel-forms-exhausted; success creates the deterministic next fixed attempt. Adaptive: policy exhaustion returns 409 retake-policy-exhausted; success—including after typed continuation expiry—starts attemptNumber+1 through mastery_engine with the original immutable pins, validated Results identity, a new child key, and a fresh continuation. The expired continuation is never reused. Success for either kind is 202 CandidateDelivery.
The launch action has no request body and therefore no request Content-Type. Candidate identity comes only from the path. Send Idempotency-Key on every call; the first successful reveal records the receipt. An identical replay returns the same LaunchReceipt only while the request is currently inside [opensAt, closesAt).
ITD-006 × ITD-031 precedence: launch authorization runs before idempotency receipt lookup. Before opensAt, an identical replay returns 403 launch-not-open; at or after closesAt, it returns 410 launch-window-ended. Both denials omit Idempotent-Replayed and never reveal the stored deliverySessionRef. Query parameters and JSON bodies are rejected as 400 validation-failed.
ITD-006 × ITD-031; see launch replay precedence.
The strict JSON request body is exactly {}; unknown fields and null are rejected. Close first stops new launch and retake authorization. Any launched fixed attempt lacking submission, or any launched adaptive attempt not yet scored under the four-state composition, returns 409 close-not-ready with no receipt. Otherwise success is 202 Administration in closing.
Fixed forms: for each eligible attempt, AlphaTest reads QTI outcomeState.SCORE, reads subject from Content, writes one Results record through POST /alpha/results/v1/result-records, and exact-reads it back through GET /alpha/results/v1/result-records?qtiAttemptId={qtiAttemptId}. The write and the settled read-back must agree byte-for-byte on administration_id, qti_attempt_id, qti_session_id, qti_test_id, qti_artifact_version_id, content_test_spec_id, test_kind, and subject. Exactly one settled record may resolve. Adaptive: AlphaTest inspect-verifies that mastery_engine reports completed with reportable scale output and acknowledged Results KC components, then retains only the upstream result reference; it never copies score, KC map, mastery, continuation content, or Results body.
Credential boundary: QTI, Content, and Results calls use only server-side provisioned PLATFORM3_TENANT and PLATFORM3_JWT. Neither credential is accepted in this request body, returned to the client, or persisted in reconciliation rows. Deterministic child keys and the original client idempotency key make partial close resumable. scored requires every fixed Results write or adaptive Results acknowledgement to verify and failed=0.
| Query | Endpoints | Type / default | Validation and semantics | Trace |
|---|---|---|---|---|
status | Administrations | enum; absent | Exact one-value match from Administration status enum. | ITD-004 |
testKind | Administrations | enum; absent | Exact one-value match. | ITD-004 |
qtiTestId | Administrations | string; absent | Exact opaque byte match; URL-encoded once. | ITD-004 |
targetSourcedId | Administrations | Platform3 reference; absent | Exact, case-sensitive sourcedId match by target type: for class, compare only administrations.class_sourced_id; for candidate_list, match when at least one immutable binding has candidate_sourced_id equal to the supplied value. It never searches names, emails, QTI candidate refs, or session refs. Results are administrations, de-duplicated even when multiple attempts exist for that candidate. | ITD-004, 026 |
modifiedSince | Administrations only | Instant; absent | Inclusive lower bound. Presence selects sync order modifiedAt,id ascending; absence selects browse order descending. Candidate modifiedSince is deferred until QTI exposes a monotonic runtime cursor. | ITD-004 |
state | Candidates | candidate state; absent | Exact QTI-derived state match. Paging still advances over every examined immutable binding, including rows removed by this live-state filter. | ITD-004, 016 |
cursor | Both lists | opaque string; absent | 1–1,024 bytes; mutually exclusive with changing any filter from the request that issued it. Administration cursors carry the pinned modified_at,id position. Candidate cursors carry the last examined binding position created_at,candidate_sourced_id,attempt_number ascending; this is the concrete storage key behind ITD-004’s logical createdAt,id ordering. Advancement uses examined bindings even when state filters a row out. | ITD-004 |
limit | Both lists | integer 1–100; 25 | Decimal integer; no leading sign or fraction. | ITD-004 |
include | Detail only | enum; absent | Only candidates. Requires the sensitive-read permission and is rejected when resolved candidate count exceeds 100; use subcollection paging instead. | ITD-003, 007 |
Every non-2xx response uses Content-Type: application/problem+json. Upstream bodies and credentials are never passed through.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
type | HTTPS URI | No | Stable documentation URI: https://alphatest-administration.vercel.app/problems/{code}. This is a data-dictionary refinement of ITD-009’s typed RFC 9457 contract and a required durable public route for every later bundle at this module origin; see route durability. |
title | string 1–120 | No | Stable human summary; clients branch on code, not title. |
status | integer 400–599 | No | Matches HTTP status. |
detail | string 1–2,000 | No | Request-specific explanation with no secrets or upstream body. For test-not-assignable, it MUST truthfully name the first failed predicate in the deterministic order documented in assignability failure detail; it must not describe a different predicate merely because several failed. |
instance | string URI-reference | No | Request path plus opaque occurrence reference. |
code | kebab-case string | No | Stable machine code from catalog below. |
requestId | Request ID | No | Support/upstream correlation. |
retryable | boolean | No | Whether the same logical operation may succeed later. It does not waive idempotency/precondition rules. |
errors | FieldError array, 0–100 | No | Request field/query failures; empty for non-field errors. |
dependency | string enum | Conditional; never null | Present on shipped v1 424 responses only, as exactly one of content, oneroster, qti, results, or mastery_engine; omitted on every non-424 response. Caliper and report materialization are not close dependencies. |
| Field | Type | Nullable | Meaning / allowed values | Provenance |
|---|---|---|---|---|
pointer | JSON Pointer string, 1–1,024 bytes | No | Request body location (for example /target/type) or query location prefixed /query/. | ITD-009 |
code | string enum | No | required, unknown-field, invalid-type, invalid-format, invalid-enum, out-of-range, duplicate, or conflict. | ITD-009 |
message | string, 1–500 bytes | No | Safe human explanation; clients branch on code. | ITD-009, 025 |
| HTTP / code | Applies to | When | Retryable |
|---|---|---|---|
400 malformed-json | Body endpoints | Body is not valid JSON. | No |
400 validation-failed | Create, provision, patch, launch, advance, retake, close, lists | One or more typed field/query/path rules fail; see errors. | No |
400 missing-idempotency-key | Create, provision, first launch, adaptive advance, retake, close | Required header absent or invalid; clients should always send it on launch. | No |
401 authentication-required | All shipped endpoints | Bearer JWT absent, invalid, expired, or missing required claims. | No |
403 insufficient-scope | All shipped endpoints | Valid principal’s role-derived, optionally narrowed permission set lacks the endpoint permission. | No |
403 tenant-mismatch | All shipped endpoints | Optional tenant header differs from JWT tenant. | No |
403 target-not-authorized | Create | Class or candidate falls outside tenant or resource constraints. | No |
403 launch-not-open | Launch | Current time is before opensAt; launch authorization precedes replay lookup, so even an identical stored replay omits Idempotent-Replayed and reveals no delivery session reference. | Yes, at opensAt |
404 route-not-found | Unknown paths outside the published endpoint matrix | No shipped v1 route matches. | No |
405 method-not-allowed | Known path with unsupported method | Path exists but method is outside its endpoint contract; response includes Allow. | No |
404 administration-not-found | Detail, patch, candidates, provision, launch, advance, retake, close | Documented divergence/mapping from ITD-034: this endpoint-specific code is the Administration API rendering of the pinned generic resource-not-found. It means no tenant-scoped administration exists; the same status, code, title, and detail are returned for another tenant’s ID. See ITD-034. | No |
404 candidate-not-found | Launch, advance, retake | Documented divergence/mapping from ITD-034: this endpoint-specific code is the candidate-binding rendering of the pinned generic resource-not-found. It means the candidate is not bound to this administration; another tenant’s binding yields the same status, code, title, and detail. See ITD-034. | No |
409 idempotency-key-reused | Create, provision, launch, advance, retake, close | Same scoped key, different canonical request semantics. | No |
409 administration-state-conflict | Patch, launch, advance, retake | PATCH cannot mutate current state; launch is closed by closing/close_failed/scored; or retake is outside open. A fixed-form retake also conflicts unless the latest authoritative QTI state is submitted or scored. An adaptive retake conflicts unless the latest composed state is submitted or scored, or advance returned typed adaptive-continuation-expired. No new effect occurs. See ITD-017 and the adaptive extension in ITD-034. | No |
409 close-not-ready | Close | A launched fixed attempt is incomplete, or a launched adaptive attempt has not reached owner-verified scored state. The request is not accepted. | Yes, after submission |
409 parallel-forms-exhausted | Fixed-form retake | After the state guard, fixed-form maxAttempts or eligible mastery-gate form inventory is exhausted. Adaptive policy exhaustion uses retake-policy-exhausted. | No |
410 launch-window-ended | Launch | Current time is at or after closesAt; launch authorization precedes replay lookup, so even an identical stored replay omits Idempotent-Replayed and reveals no delivery session reference. | No |
412 etag-mismatch | Patch | Strong tag is stale. | Yes, after GET and review |
415 unsupported-media-type | Body endpoints | Content-Type is not JSON. | No |
422 test-not-assignable | Create | An authoritative, reachable fixed-test resource fails its declared relationship. For a mastery gate this means any ITD-037 predicate fails: bank is not published, is not marked mastery-gate, has a membership rule other than same_blueprint_fixed_forms, has a null/different spec_id, has an empty or mismatched ordered member set, or contains a member whose immutable QTI version does not exist. Returned before persistence, OneRoster, or QTI effects. Upstream transport/invalid-response failures use 424 instead. | No |
422 target-empty | Create | Class resolves to zero eligible candidates. | No |
422 target-invalid | Create | One or more candidates missing, inactive, duplicate, or invalid; whole request rejected. | No |
422 qti-accommodation-capability-required | Create, patch | Request differs from the v1 semantic no-op. | No |
422 candidates-page-required | Detail with include=candidates | More than 100 bindings; use candidates subcollection. | No |
422 adaptive-capability-required | Create | Adaptive configuration or exact candidate-to-Results binding set is missing, duplicate, extra, cross-tenant, or invalid; rejected before persistence or upstream effects. | No |
409 adaptive-continuation-expired | Advance | The bound opaque mastery-engine continuation expired. While the administration remains open and maxAttempts permits another attempt, this typed result satisfies the adaptive CreateRetake state guard; the retake starts a fresh run and continuation and never reuses the expired token. See the base guard in ITD-017 and adaptive expiry rule in ITD-034. | No |
409 retake-policy-exhausted | Adaptive retake | The declared maxAttempts policy permits no new adaptive run. | No |
409 candidate-not-provisioned | Launch, advance | The candidate binding has not completed provisioning; retry failed provisioning first. | Yes, after provision |
424 content-unavailable | Create/read/close | Content cannot return a valid authoritative test-spec, bank, membership, or required close-subject response. This is dependency unavailability, not a reachable bank’s predicate mismatch. | Yes |
424 roster-unavailable | Create/candidate reads | OneRoster cannot resolve target or live identity. | Yes |
424 qti-unavailable | Create/read/patch/launch/retake/close | QTI cannot dereference a required immutable bank-member version or create/read the required session, state, attempt history, or score outcome. | Yes |
424 mastery-engine-unavailable | Provision, advance, adaptive retake, adaptive close | A real mastery-engine call was attempted but transport, 5xx, or owner response validation failed; the prior binding remains retryable. | Yes |
424 results-unavailable | Close before acceptance | Results cannot safely accept or verify writes. Failures after 202 appear as close_failed, not a second HTTP response. | Yes |
428 precondition-required | Patch | If-Match missing or weak. | No |
429 rate-limited | All shipped endpoints | Boundary pressure limit; honor Retry-After. ITD-024 | Yes |
503 service-unavailable | All shipped endpoints | AlphaTest itself cannot safely accept or read, distinct from an upstream 424. | Yes |
test-not-assignable detail selectionThe stable machine branch remains code=test-not-assignable; detail is diagnostic and reports exactly one observed predicate. Evaluate in this order and stop at the first mismatch: status=published, is_mastery_gate=true, membership_rule=same_blueprint_fixed_forms, spec_id=contentTestSpecId, non-empty exact ordered membership, then dereferenceability of every immutable QTI version. For example, a bank with status=draft and is_mastery_gate=false reports that its status is draft and published is required; it must not claim the mastery-gate flag was the selected failure. Safe observed enum/boolean/null values may appear; upstream bodies, titles, and learner data may not. If an authoritative response cannot be validated, return the owning 424 instead of inventing a failed predicate.
tenant_id derived from the verified JWT. Anonymous requests are rejected before database access.Migrations are idempotent. Names below define ownership and constraints for the later implementation; SQL types use PostgreSQL. AlphaTest owns only these glue tables. It does not create roster, QTI session/attempt/response, Results, mastery, or score tables.
| Migration ID | Owned objects | Re-run contract | Provenance |
|---|---|---|---|
administration_001_core | administrations and its tenant-first indexes/checks | CREATE TABLE/INDEX IF NOT EXISTS; columns added with ADD COLUMN IF NOT EXISTS; constraint definitions verified before serving. | ITD-001, 010, 014 |
administration_002_bindings | administration_candidate_bindings | Idempotent create; tenant-scoped FK/unique definitions verified; never backfilled from copied roster/session bodies. | ITD-015 |
administration_003_operations | administration_idempotency_receipts, administration_provisioning_errors | Idempotent create; 24-hour receipt purge index; no migration stores upstream bodies beyond the receipt replay window. No accommodation table exists while v1 accepts only the semantic no-op. | ITD-006, 012, 018, 024 |
administration_004_close_reconciliation | administration_close_reconciliations | Idempotent create; tenant-scoped FK/unique definitions verified. Adds only attempt/result correlation and retry metadata; never outcome, score, Results body, or Caliper event. | ITD-001, 006, 030 |
administration_005_adaptive | Adaptive columns on administrations/administration_candidate_bindings; administration_adaptive_close_reconciliations | Idempotent column/table/index creation. CHECK constraints enforce fixed/adaptive disjointness; migration never derives continuations, learner bindings, or mastery facts from local data. | ITD-015, 032–036 |
administrations — owner: administration module| Column | Postgres type | Null | Constraint / meaning | API trace |
|---|---|---|---|---|
tenant_id | text | No | Verified JWT tenant; first member of PK/uniques/indexes. | Never returned; tenant routing |
id | text | No | PK (tenant_id,id); opaque 1–255 bytes. | id |
status | text | No | CHECK Administration status enum. | status |
qti_test_id | text | Yes | Opaque 1–255-byte requested fixed-test/bank reference; required for fixed-form kinds and null for adaptive. A mastery-gate value is inserted only after ITD-037 Content bank/member and QTI immutable-version validation succeeds. Member metadata is not copied locally. | qtiTestId · ITD-037 |
content_test_spec_id | text | No | Opaque Content reference, 1–255 bytes. For mastery gates the accepted bank’s spec_id must have matched before insert; the Content object is not copied. | contentTestSpecId · ITD-037 |
test_kind | text | No | CHECK mastery_gate|formative|adaptive_diagnostic. | testKind |
target_type | text | No | CHECK class|candidate_list. | target.type |
class_sourced_id | text | Yes | Required only for class; CHECK discriminant. No candidate-list request array is retained; membership is represented only by immutable bindings below. | oneRosterSourcedId |
opens_at | timestamptz | No | CHECK opens_at < closes_at; authoritative lower bound for AlphaTest launch authorization. Before it, no QTI session reference is revealed. | opensAt |
closes_at | timestamptz | No | Authoritative upper bound for AlphaTest launch authorization. At or after it, no QTI session reference is revealed; it does not terminate a session already disclosed. | closesAt |
time_limit_seconds | integer | Yes | CHECK 60–86,400 when non-null; required for fixed kinds and null for adaptive. | timeLimitSeconds |
max_attempts | smallint | No | CHECK 1–10. | maxAttempts |
parallel_form_rotation | text | No | CHECK policy enum and kind compatibility. | parallelFormRotation |
version | bigint | No | DEFAULT 1; increments on successful policy mutation. | version/ETag |
provisioning_status | text | No | CHECK running|complete|with_errors. | provisioning.status |
provisioning_requested | integer | No | CHECK ≥0; OneRoster-derived count only. | requested |
provisioning_pending | integer | No | CHECK ≥0 and requested = pending + failed + succeeded. | pending |
provisioning_failed | integer | No | CHECK ≥0. | failed |
provisioning_succeeded | integer | No | CHECK ≥0. | succeeded |
provisioning_last_attempt_at | timestamptz | Yes | Null before first upstream attempt. | lastAttemptAt |
created_at | timestamptz | No | Database clock at insert. | createdAt |
modified_at | timestamptz | No | Updated on local lifecycle, policy, or provisioning mutation. | modifiedAt |
| Column | Postgres type | Null | Constraint / meaning | API trace |
|---|---|---|---|---|
selection_policy_id | text | Yes | Required for adaptive; null for fixed. Opaque immutable execution pin. | selectionPolicyId |
scale_calibration_id | text | Yes | Required for adaptive; null for fixed. | scaleCalibrationId |
test_bank_id | text | Yes | Required for adaptive; null for fixed. Content bank reference only. | testBankId |
bank_operation_id | text | Yes | Required for adaptive; null for fixed. Terminal Bank operation reference only. | bankOperationId |
adaptive_run_mode | text | Yes | Adaptive CHECK literal production_learner; null for fixed. | runMode |
Kind constraint: adaptive rows require all five adaptive columns and null qti_test_id/time_limit_seconds; fixed rows require those two fixed columns and null all five adaptive columns. Indexes: (tenant_id, modified_at DESC, id DESC); (tenant_id, modified_at ASC, id ASC); (tenant_id,status,modified_at DESC,id DESC); (tenant_id,test_kind,modified_at DESC,id DESC); partial (tenant_id,qti_test_id,modified_at DESC,id DESC); (tenant_id,class_sourced_id,modified_at DESC,id DESC). No global unscoped index is used for API reads. Provenance: ITD-032, 033.
administration_candidate_bindings — owner: administration moduleImmutable correlation glue only; it makes an administration enumerable without copying an upstream roster or QTI session body.
| Column | Postgres type | Null | Constraint / meaning | API trace |
|---|---|---|---|---|
tenant_id | text | No | Verified JWT tenant; first member of every key and lookup. | Never returned; tenant routing |
administration_id | text | No | Tenant-scoped FK to administrations. | Administration.id |
candidate_sourced_id | text | No | Opaque OneRoster reference, 1–255 bytes; no identity body. Unique with tenant, administration, and attempt number. | oneRosterSourcedId |
attempt_number | smallint | No | QTI ordinal, CHECK 1–10; not a locally advanced attempt history. | attemptNumber |
qti_candidate_ref | text | Yes | Opaque QTI candidate correlation, 1–255 bytes; never exposed as identity. | QTI pass-through · ITD-015 |
qti_session_ref | text | Yes | Current opaque QTI session reference; fixed for static attempts, atomically replaced after adaptive advance, and null while adaptive finalizes. | deliverySessionRef |
selected_form_ref | text | Yes | Opaque fixed-form QTI reference; required for fixed attempts and null for adaptive. | qtiFormId |
results_student_id | text | Yes | Adaptive-only same-tenant opaque Results learner reference; null for fixed attempts. No learner profile. | resultsStudentId |
adaptive_run_ref | text | Yes | Adaptive-only opaque mastery-engine run reference; null for fixed attempts. | adaptiveRunRef |
continuation_token | text | Yes | Adaptive-only opaque compact JWE. Server-only; never parsed, logged, or returned. Replaced atomically with the ETag, expiry, and current offer. | ITD-033 |
continuation_etag | text | Yes | Adaptive-only strong mastery-engine ETag; null for fixed attempts. | ITD-033 |
continuation_expires_at | timestamptz | Yes | Adaptive-only owner-declared token expiry; null for fixed attempts and non-null for an active adaptive binding. At or after this instant, advance returns typed 409 adaptive-continuation-expired; while the administration remains open and policy permits another attempt, that typed expiry satisfies the adaptive retake state guard and starts a fresh run. The expired token is never reused. | ITD-034 |
creation_receipt_ref | text | No | Opaque fixed QTI-session or adaptive mastery-run creation receipt, 1–255 bytes, used to verify—not reconstruct—the upstream write. | QTI/mastery_engine pass-through · ITD-015, 033 |
created_at | timestamptz | No | Binding durability instant; immutable after insert. Candidate enumeration orders this first. | ITD-004, 015 |
Primary key / logical binding id: (tenant_id, administration_id, candidate_sourced_id, attempt_number). Candidate pages order by created_at, candidate_sourced_id, attempt_number ascending. Required paging index: (tenant_id, administration_id, created_at ASC, candidate_sourced_id ASC, attempt_number ASC). Partial uniques: non-null (tenant_id,qti_session_ref) and non-null (tenant_id,adaptive_run_ref). Fixed attempts require QTI candidate/session/form refs and null adaptive fields; adaptive attempts require Results student, run, continuation, ETag, and expiry while active, and null selected form. No identity profile, session body, response, posterior, score, KC map, mastery state, attempt body, or Results body is stored. Provenance: ITD-001, 015, 033, 034.
administration_idempotency_receipts — owner: administration module| Column | Type | Null | Constraint / meaning |
|---|---|---|---|
tenant_id | text | No | First key member. |
method | text | No | CHECK POST. |
path | text | No | Canonical route template plus resource ID where applicable. |
key_hash | bytea | No | SHA-256 of key; raw key not retained. Unique (tenant_id,method,path,key_hash). |
request_hash | bytea | No | SHA-256 of canonical request semantics. |
response_status | smallint | No | Original HTTP status. |
response_body | jsonb | No | Original response needed for exact replay; access limited to server. |
created_at | timestamptz | No | Receipt creation. |
expires_at | timestamptz | No | Exactly 24 hours after creation; purge index on expires_at. Candidate-list request bodies disappear with this row. |
administration_provisioning_errors — owner: administration module| Column | Type | Null | Constraint / meaning |
|---|---|---|---|
tenant_id | text | No | Verified tenant; first key member. |
administration_id | text | No | Tenant-scoped FK to administrations. |
candidate_sourced_id | text | No | Opaque OneRoster reference identifying the failed candidate for targeted resume; no identity profile. |
attempt_number | smallint | No | CHECK 1–10; identifies the failed child effect. |
dependency | text | No | CHECK content|oneroster|qti|results|mastery_engine. |
code | text | No | Stable catalog code, 1–120 bytes; no upstream body. |
retryable | boolean | No | Whether bounded provisioning may safely retry with the original child key. |
occurred_at | timestamptz | No | Latest occurrence instant. |
Primary key (tenant_id,administration_id,candidate_sourced_id,attempt_number,dependency,code). This is minimum retry metadata, not a roster or attempt body. The public progress array redacts candidate ID; the provision worker uses it only to resume failed bindings. Provenance: ITD-014, 024, 034.
administration_close_reconciliations — owner: administration moduleOne row per launched latest QTI attempt. This is retry correlation, not an attempt, outcome, or result store.
| Column | Postgres type | Null | Constraint / meaning | API trace |
|---|---|---|---|---|
tenant_id | text | No | Verified JWT tenant; first member of every key. | Never returned · tenant routing |
administration_id | text | No | Tenant-scoped FK to administrations. | Administration.id |
qti_attempt_id | text | No | Opaque QTI attempt reference, 1–255 bytes; not an attempt body. Primary key with tenant and administration. | QTI pass-through · ITD-030 |
result_record_ref | text | Yes | Null until exact Results read-back verifies one record; then immutable opaque reference. No result components or score. | resultRecordRef |
child_key_hash | bytea | No | SHA-256 of deterministic tenant + administration + QTI attempt child key; raw key is not retained. Unique per tenant and attempt. | ITD-006, 030 |
status | text | No | CHECK pending|written|verified|failed. written is not completion until exact read-back. | CloseProgress |
failure_dependency | text | Yes | Null unless status is failed; then CHECK content|qti|results. | ProblemDetails.dependency |
failure_code | text | Yes | Null unless failed; stable catalog code, 1–120 bytes. No upstream body. | error catalog |
last_attempt_at | timestamptz | Yes | Null before worker attempt; otherwise latest reconciliation attempt. | lastAttemptAt |
verified_at | timestamptz | Yes | Set only with status=verified after exact read-back; otherwise null. | resultRecordRef presence |
Primary key: (tenant_id, administration_id, qti_attempt_id). Unique: (tenant_id, qti_attempt_id), (tenant_id, child_key_hash). Every query/join is tenant-first. No QTI outcome, response, score, mastery, Results body, component, or Caliper payload is stored. Provenance: ITD-001, 006, 030.
administration_adaptive_close_reconciliations — owner: administration moduleOne row per launched latest adaptive attempt. It records inspect/reference verification only; it never stores the scale output or KC components.
| Column | Postgres type | Null | Constraint / meaning | API trace |
|---|---|---|---|---|
tenant_id | text | No | Verified tenant; first member of every key. | tenant routing |
administration_id | text | No | Tenant-scoped FK to administrations. | Administration.id |
candidate_sourced_id | text | No | Opaque OneRoster reference; no profile. | oneRosterSourcedId |
attempt_number | smallint | No | CHECK 1–10; matches the bound adaptive attempt. | attemptNumber |
adaptive_run_ref | text | No | Opaque mastery-engine run reference. | adaptiveRunRef |
result_record_ref | text | Yes | Null until inspect confirms completed reportable output and acknowledged Results KC components; then immutable. No Results body. | resultRecordRef |
status | text | No | CHECK pending|verified|failed. | CloseProgress |
failure_code | text | Yes | Required only when failed; stable catalog code, 1–120 bytes, with no owner body. | error catalog |
last_attempt_at | timestamptz | Yes | Null before inspect; otherwise latest reconciliation attempt. | lastAttemptAt |
verified_at | timestamptz | Yes | Set only with status verified. | resultRecordRef presence |
Primary key: (tenant_id,administration_id,candidate_sourced_id,attempt_number). Unique: (tenant_id,adaptive_run_ref). Every query is tenant-first. No continuation content, QTI response, scale score, posterior, KC map, mastery classification, Results body, or Caliper payload is stored. Provenance: ITD-036.
| Parameter | Endpoints | Type / nullability | Validation and meaning | Provenance |
|---|---|---|---|---|
{id} | Detail, patch, candidates, provision, launch, advance, retake, close | AlphaTest ID, 1–255 decoded bytes; non-null | Exactly one percent-encoded path segment. Compared as an opaque, case-sensitive ID inside the verified tenant. A well-formed ID absent from this tenant—including another tenant’s ID—returns the same 404 administration-not-found. | ITD-010, 023 |
{candidateSourcedId} | Launch and advance | Platform3 reference, 1–255 decoded bytes; non-null | Exactly one percent-encoded path segment. Must match an immutable binding in this tenant and administration; missing and cross-tenant bindings both return 404 candidate-not-found. | ITD-010, 015, 034 |
| Endpoint | Input | Success contract | Effective permission | Endpoint-specific errors |
|---|---|---|---|---|
POST /v1/administrations | CreateAdministration; JSON; idempotency required. For mastery gates, Content bank/spec/member and immutable QTI-version checks run before persistence or roster/session effects. | 202 Administration, Location: /api/v1/administrations/{id}; replay adds Idempotent-Replayed: true | administrations:write | test-not-assignable for a reachable predicate mismatch; content-unavailable/qti-unavailable for dependency failure; target errors, qti-accommodation-capability-required, adaptive-capability-required, and other owning dependency 424s |
POST /v1/administrations/{id}/provision | Strict {}; JSON; idempotency required | 202 Administration; retries failed candidate attempts only with original child keys | administrations:write | administration-not-found, idempotency-key-reused, QTI or mastery-engine 424 |
GET /v1/administrations | collection queries | 200 Administration page; no candidate/session refs | administrations:read | validation-failed, rate-limited |
GET /v1/administrations/{id} | Optional include=candidates | 200 Administration with conditional candidates member; strong ETag; included candidates require sensitive permission and ≤100 rows | administrations:read; plus administrations:read_sensitive for include | administration-not-found, insufficient-scope, candidates-page-required, dependency 424 if requested composition cannot be completed |
PATCH /v1/administrations/{id} | PatchAdministration; JSON; strong If-Match | 200 Administration + new strong ETag | administrations:write | precondition-required, etag-mismatch, administration-state-conflict, qti-accommodation-capability-required, qti-unavailable (dependency 424) |
GET /v1/administrations/{id}/candidates | state, cursor, limit; no modifiedSince in v1 | 200 CandidateDelivery page composed live, ordered by immutable binding created_at,candidate_sourced_id,attempt_number ascending (the concrete createdAt,id key) | administrations:read_sensitive | administration-not-found, insufficient-scope, QTI/OneRoster 424s |
POST /v1/administrations/{id}/candidates/{candidateSourcedId}/launch | No body or query; LaunchCandidate; send idempotency key. Window authorization runs before replay lookup. | 200 LaunchReceipt only inside [opensAt, closesAt); outside-window replays return 403/410 without a session reference | administrations:deliver | launch-not-open, launch-window-ended, administration-state-conflict, candidate-not-found, candidate-not-provisioned, qti-unavailable |
POST /v1/administrations/{id}/candidates/{candidateSourcedId}/advance | Adaptive only; strict {}; JSON; idempotency required | 200 CandidateDelivery after atomic continuation/ETag/offer replacement | administrations:deliver | candidate-not-provisioned, adaptive-continuation-expired, administration-state-conflict, mastery-engine-unavailable |
POST /v1/administrations/{id}/retakes | CreateRetake; JSON; idempotency required | 202 CandidateDelivery for a fixed rotated form or fresh adaptive mastery run | administrations:write | administration-state-conflict, fixed parallel-forms-exhausted, adaptive retake-policy-exhausted, QTI/mastery-engine 424s |
POST /v1/administrations/{id}/close | Strict {} body; JSON; idempotency required | 202 Administration with status=closing and CloseProgress; poll detail until scored or retryable close_failed | administrations:close | administration-not-found, close-not-ready, and Content/QTI/Results/mastery-engine dependency 424s |
Retry-After on 429/503 and retry only when retryable=true. Reuse the same idempotency key for uncertainty about one request; use a new key only for a new logical operation. For PATCH, refetch and intentionally reapply after 412. Provenance: ITD-024 (pressure/backoff), ITD-006 (idempotent replay), ITD-005 (ETag recovery).| Promise | Dictionary evidence | Authoritative owner | Invalid/misaligned value is detectable when… |
|---|---|---|---|
| Class or explicit candidate list | TargetInput, TargetSummary | OneRoster identities; QTI delivery membership | Discriminant, size, uniqueness, active status, tenant/scoped authorization, or atomicity fails. |
| Every test-kind selector is explicit | testKind, AdaptiveConfig, RetakePolicy | Content/QTI/mastery_engine + AlphaTest policy | Unknown kinds fail validation; fixed mismatches fail assignment; adaptive missing or misbound inputs fail pre-effect with adaptive-capability-required; a successful adaptive implementation additionally requires ITD-035 owner-backed release evidence. |
| Only an authoritative fixed mastery gate is assignable | current Bank 424 posture, six-part assignability predicate, typed mismatch, pre-effect create order | Content bank/spec/membership + QTI immutable artifact versions; AlphaTest validates, never copies | Today, fixed Bank generation is closed before admission with typed 424. After certification opens it, any returned bank that is draft, not a mastery gate, has the wrong membership rule/spec/member set, or contains an undereferenceable immutable member still fails Administration create with pre-effect 422. Bank workflow flags cannot make the check pass. |
| Window-authorized launchable sessions | LaunchReceipt, launch endpoint | AlphaTest launch authorization + QTI runtime | Reference is revealed outside the window, appears in a list/detail response, or does not dereference in live QTI. |
| Four runtime states across every test kind | state, CandidateCounts | QTI for fixed; mastery_engine + QTI + Results for adaptive | Value falls outside the enum, fixed state cannot trace to QTI, or adaptive state violates ITD-036’s explicit mapping. |
| Close verifies one authoritative result per attempt | CloseAdministration, CloseProgress, resultRecordRef, fixed and adaptive reconciliation tables | QTI/Results for fixed; mastery_engine/Results for adaptive; AlphaTest retry glue only | scored appears before every owner verification, retry can duplicate a fact, a reference is absent, or AlphaTest stores score, KC, mastery, or outcome bodies. |
| No shadow platform | Persistence dictionary | AlphaTest glue only | A local schema stores candidates, sessions, attempts, responses, scores, mastery, or copied upstream bodies. |
| Tenant isolation | JWT, tenant-first keys | Verified platform identity | Any query/join omits tenant, anonymous access reaches storage, or another tenant’s ID is distinguishable from missing. |
| Stable public provenance | This dictionary at the durable /reference route (also rendered at root in this bundle) plus the byte-identical approved architecture snapshot | One public module origin | Root, /architecture, or /reference is auth-walled, displaced, or any cited ITD fragment fails to resolve. ITD-027 |
| Stable problem documentation | Every ProblemDetails type dereferences at /problems/{code} to the matching stable error-catalog row | Administration data-dictionary contract, refining typed RFC 9457 from ITD-009 | Any emitted problem type is auth-walled, returns non-2xx, resolves to a different code, or a later customer-website/implementation bundle omits the /problems/:code rewrite and catalog-link behavior. Unlike root, /architecture, and /reference, this durability requirement is a dictionary refinement rather than a route named by ITD-027. |
modifiedSince; reopen when QTI and mastery_engine expose a common monotonic runtime cursor (ITD-004).This dictionary uses the same cold-integrator virtues as Stripe’s API reference—predictable resources, explicit objects, standard HTTP behavior, authentication, and per-operation clarity—while adding field-level nullability, upstream ownership, persistence mapping, and Architecture-ITD provenance required by AlphaTest. The only normative source is the approved administration architecture; no vendor bundle exists in this repository.