AlphaTest · Mastery Engine · v1 integrator contract

Run an adaptive QTI diagnostic. Return an actionable mastery map.

Give AlphaTest immutable Content, Bank, selection-policy, and scale-calibration IDs. Deliver the native Platform3 QTI sessions it returns. You receive a vertically comparable scale score and explicit mastered, gap, and not-yet knowledge components—without creating a second learner record.

One afternoon, four boundaries

You provide

Owner-issued IDs

Content test spec/bank IDs, the terminal Bank operation ID, immutable policy/calibration IDs, and—in production—the Results student ID.

Start request fields →

AlphaTest owns

Selection + calibration

Deterministic Bayesian KC updates, stopping rules, vertical-scale transform, encrypted continuation, and payload-free retry control.

Mastery contract →

Platform3 owns

Learner facts

Bank proves generation provenance. QTI owns delivery and scoring. CASE owns KC identity. Results owns durable mastery. Caliper owns audit events.

Ownership matrix →

You receive

Scale + explicit gaps

A scale only when reportable, uncertainty/provenance, and each KC classified mastered, gap, or not_yet.

AdaptiveRun →

Paste-and-check quickstart

Requirements: Bash, curl, jq, and uuidgen. Each block is valid shell. Use a verified JWT with mastery:run and mastery:read; AlphaTest derives tenant only from that JWT and selects a same-tenant, server-held provisioned Platform3 service profile. Never send an upstream host, tenant, or credential. Wire conventions · ITD-030

Set the immutable owner inputs

export ALPHATEST_BASE_URL="https://alphatest-mastery-engine.vercel.app"
export ALPHATEST_JWT="<platform-issued-jwt>"
export SELECTION_POLICY_ID="<immutable-selection-policy-id>"
export SCALE_CALIBRATION_ID="<immutable-scale-calibration-id>"
export TEST_SPEC_ID="<content-test-spec-id>"
export TEST_BANK_ID="<content-test-bank-id>"
export BANK_OPERATION_ID="<terminal-bank-operation-id>"
export RESULTS_STUDENT_ID="<same-tenant-results-student-id>"

The Bank operation—not a caller-supplied pool—binds the package root and ordered native member/CASE/KC projection. For synthetic conformance, omit resultsStudentId and use runMode=owner_conformance. All seven production fields →

Start once; retain the body and strong ETag

START_KEY="$(uuidgen)"
curl --fail-with-body -sS -D /tmp/mastery-start.headers \
  -X POST "$ALPHATEST_BASE_URL/v1/adaptive-runs" \
  -H "Authorization: Bearer $ALPHATEST_JWT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $START_KEY" \
  --data "$(jq -n \
    --arg policy "$SELECTION_POLICY_ID" \
    --arg calibration "$SCALE_CALIBRATION_ID" \
    --arg spec "$TEST_SPEC_ID" \
    --arg bank "$TEST_BANK_ID" \
    --arg operation "$BANK_OPERATION_ID" \
    --arg student "$RESULTS_STUDENT_ID" \
    '{selectionPolicyId:$policy,scaleCalibrationId:$calibration,
      testSpecId:$spec,testBankId:$bank,bankOperationId:$operation,
      runMode:"production_learner",resultsStudentId:$student}')" \
  | tee /tmp/mastery-run.json
ETAG="$(awk 'tolower($0) ~ /^etag:/{sub(/^[^:]+:[[:space:]]*/,"");sub(/[[:cntrl:]]$/,"");print;exit}' /tmp/mastery-start.headers)"
CONTINUATION="$(jq -er '.continuationToken' /tmp/mastery-run.json)"
QTI_SESSION="$(jq -er '.offeredItem.deliverySessionId' /tmp/mastery-run.json)"

Released success is 201 AdaptiveRun plus a strong ETag, receipt ID, and exactly one native QTI delivery session. Keep the ETag and continuation together; never parse, log, or put the continuation in a URL. Response contract →

Deliver and score in your existing QTI player

# Pass this native ID directly to the Platform3 QTI player.
printf 'Deliver this QTI session: %s\n' "$QTI_SESSION"
# Wait until QTI reports a durable scored attempt.
# Send no response, answer, score, or item body to AlphaTest.

Your player submits to Platform3 QTI. AlphaTest rereads the token-named scored outcome; it never returns item content or accepts candidate answers. OfferedItem → · ITD-018 →

Advance with a fresh semantic key

ADVANCE_KEY="$(uuidgen)"
curl --fail-with-body -sS -D /tmp/mastery-next.headers \
  -X POST "$ALPHATEST_BASE_URL/v1/adaptive-runs:advance" \
  -H "Authorization: Bearer $ALPHATEST_JWT" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $ADVANCE_KEY" \
  -H "If-Match: $ETAG" \
  --data "$(jq -n --arg token "$CONTINUATION" \
    '{continuationToken:$token}')" \
  | tee /tmp/mastery-run-next.json
ETAG="$(awk 'tolower($0) ~ /^etag:/{sub(/^[^:]+:[[:space:]]*/,"");sub(/[[:cntrl:]]$/,"");print;exit}' /tmp/mastery-next.headers)"
CONTINUATION="$(jq -er '.continuationToken' /tmp/mastery-run-next.json)"

If status=in_progress, deliver the next non-null offeredItem.deliverySessionId and repeat. If finalizing, call :inspect and deliver nothing. If completed, publish only when scaleReportability=reportable. All endpoint contracts →

Render the mastery map accurately

jq '{
  status, stopReason, scaleReportability,
  scale: (if .scaleReportability == "reportable" then .scale else null end),
  mastered: [.kcClassifications[] | select(.classification == "mastered")],
  gaps: [.kcClassifications[] | select(.classification == "gap")],
  notYet: [.kcClassifications[] | select(.classification == "not_yet")]
}' /tmp/mastery-run-next.json

not_yet means insufficient evidence, not failure. Treat unknown future reportability values as non-reportable. anchor_unavailable makes every KC classification provisional and forbids publishing a mastery result. KC fields → · Scale fields →

The loop you implement

StartPin policy, calibration, Content + Bank identity
DeliverOpen native QTI deliverySessionId
ScoreQTI persists attempt + outcome
AdvanceSend latest token, ETag, fresh semantic key
FinishRead reportable scale + KC map

Concurrency rule

Treat continuation and ETag as one compare-and-swap unit. A 412 stream-conflict means inspect, reconcile, then use currentEtag and a fresh key because the reconciled advance is new semantic work. ITD-006

Retry rule

Reuse a key only for the identical request after a transport or safe dependency retry. Changing a canonical body under the same tenant + method + path + key scope yields 409 idempotency-key-reused. ITD-007

Errors you must branch on

Every error is RFC 9457 application/problem+json. Branch on stable code, record requestId, obey retryable, and never parse title or detail. ProblemDetails fields · complete 14-row catalog · ITD-009

SignalMeaningCorrect action
409 idempotency-key-reusedSame scoped key, different canonical request.Restore the identical request for a retry, or use a new key for intentional work.
409 stream-conflictContent identity or QTI outcomes no longer form one coherent stream.Inspect once after start/advance. If inspect returns it, stop that continuation and preserve the request ID.
409 adaptive-pool-version-driftThe pinned Bank/QTI pool projection changed.Stop. Never swap in a newer or locally reconstructed pool; begin a new run only after certification.
412 stream-conflictYour If-Match is stale.Inspect, reconcile, then advance with currentEtag and a fresh key.
424 upstream-unavailableA required owner binding or same-tenant service profile is transiently unavailable.Retry only when retryable=true; reuse the key only for the identical request. Never supply credentials or a local substitute.
424 finalization-incompleteA required durable acknowledgement is pending or failed.Retry the identical advance with the same key only when instructed; otherwise inspect.
502 qti-adaptive-pool-invalidThe Bank manifest or independent QTI reconciliation failed integrity checks.Stop, preserve request/receipt ID, and report the owner-contract violation.

Release status and deliberate v1 limits

CapabilityStatusRequired proof
bank.read_adaptive_pool_manifestBLOCKS ARCHITECTURE RECEIPTA timestamped Bank 200 exposes immutable root identity plus a non-empty ordered native member/CASE/KC projection; repeat ETag/hash match and independent QTI-root reconciliation is exact.
Owner-backed adaptive journeyBLOCKS IMPLEMENTATION RELEASEDeployed start 201 → native QTI delivery and score → advance to a named stop → reportable scale and explicit mastered/gap/not_yet arrays, with replay and tenant-isolation evidence.
results.write_kc_componentsBLOCKS PRODUCTION COMPLETIONResults atomically or idempotently acknowledges one component per CASE GUID. Synthetic owner conformance never fakes this learner write.
Provisioned Platform3 authentication; Content/QTI root/runtime; CASE; anchor; base Results record; CaliperBOUND CONTRACTSServer-held profiles are tenant-matched before wire I/O; successful release still requires the receipts above.
No local bypasses. No caller member array, Content adaptive member row, generic artifact scan, copied pool, local KC store, caller credential, or forwarded client JWT satisfies a gate. Reviewed binding table · machine-readable manifest r7 · ITD-028

Also deliberately absent in v1

Every shipped and deferred API decision →

Reference map

Start here when coding

Six endpoints

Methods, scopes, headers, successes, and endpoint-specific failures.

Every failure

Error catalog

Status, stable code, trigger, retryability, and exact action.

Configuration + evidence

Upstream bindings

Policy/calibration reads, simulation, owner contracts, release consequences, and downloadable manifest.