Generated by bun run conformance:render — do not edit by hand.
Denominator: pinned Coverage Map docs/conformance/maps/lti-v1.3.json (generated 2026-06-25). See conform-ed ADR-0013 (map) and emergent ADR-0028 (overlay).
| Profile |
Requirements |
Done |
Partial |
Other |
Progress |
| ags |
8 |
8 |
0 |
0 |
████████████████ 100% |
| core |
5 |
5 |
0 |
0 |
████████████████ 100% |
| deep-linking |
4 |
4 |
0 |
0 |
████████████████ 100% |
| nrps |
4 |
4 |
0 |
0 |
████████████████ 100% |
| platform-ags |
8 |
8 |
0 |
0 |
████████████████ 100% |
| platform-core |
5 |
5 |
0 |
0 |
████████████████ 100% |
| platform-deep-linking |
4 |
4 |
0 |
0 |
████████████████ 100% |
| platform-dynamic-registration |
2 |
2 |
0 |
0 |
████████████████ 100% |
| platform-nrps |
4 |
4 |
0 |
0 |
████████████████ 100% |
| platform-proctoring |
2 |
2 |
0 |
0 |
████████████████ 100% |
| platform-security |
4 |
3 |
0 |
1 |
████████████░░░░ 75% |
| proctoring |
2 |
2 |
0 |
0 |
████████████████ 100% |
| security |
4 |
3 |
0 |
1 |
████████████░░░░ 75% |
| Req |
Level |
Status |
Evidence |
Statement |
| LTI-AGS-1 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-1 |
A tool reads the AGS endpoint claim — the lineitems URL and the scopes it was granted (lineitem, lineitem.readonly, result.readonly, score) — and restricts itself to those scopes. (The claim is an LTI launch claim, not part of the AGS OpenAPI, so it has no schema anchor here.) |
| LTI-AGS-2 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-2 |
A line item MUST carry a label (the gradebook-column title) and a scoreMaximum. |
| LTI-AGS-3 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-3 |
A line item is identified by an id URL present on all responses, and MAY bind to a resource link (resourceLinkId) and a tool resource (resourceId). |
| LTI-AGS-4 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-4 |
The line item container (GET /lineitems) returns a paged array of line items, filterable by resource_link_id, resource_id and tag and paged by limit/page. |
| LTI-AGS-5 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-5 |
A tool publishes a score by POSTing to the scores endpoint; the Score MUST carry userId, activityProgress, gradingProgress and timestamp. |
| LTI-AGS-6 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-6 |
When scoreGiven is present it MUST be accompanied by scoreMaximum (the scale it is given in). |
| LTI-AGS-7 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-7 |
The result container (GET …/results, filterable by user_id) returns results; a Result references its line item (scoreOf), the user (userId) and the achieved and maximum scores (resultScore / resultMaximum). |
| LTI-AGS-8 |
MUST |
✅ done |
lti:1.3:conf:ags/LTI-AGS-8 |
A tool manages line items over the full REST surface: create (POST /lineitems) and read/update/delete the single line item (GET/PUT/DELETE …/lineitems/{lineItemId}). |
| Req |
Level |
Status |
Evidence |
Statement |
| LTI-CORE-1 |
MUST |
✅ done |
lti:1.3:conf:core/LTI-CORE-1 |
A tool MUST implement the OpenID Connect third-party-initiated login: on the login initiation it returns an authentication request to the platform’s authorization endpoint. Every launch follows OIDC — there are no exceptions. |
| LTI-CORE-2 |
MUST |
✅ done |
lti:1.3:conf:core/LTI-CORE-2 |
A tool MUST validate the id_token: a JWT signed (RS256) with the platform key resolved via its JWKS, with valid iss, aud, exp and iat, and the nonce the tool issued — rejecting any that fail. |
| LTI-CORE-3 |
MUST |
✅ done |
lti:1.3:conf:core/LTI-CORE-3 |
A resource-link launch MUST carry the required claims: message_type=LtiResourceLinkRequest, version=1.3.0, the deployment_id, the target_link_uri, and the resource_link claim with an id. |
| LTI-CORE-4 |
MUST |
✅ done |
lti:1.3:conf:core/LTI-CORE-4 |
The launch MUST carry the roles claim (an array of role URIs) binding the user to the context; the tool authorizes from it. |
| LTI-CORE-5 |
MUST |
✅ done |
lti:1.3:conf:core/LTI-CORE-5 |
A tool MUST reject a launch missing a required claim, carrying the wrong LTI version, with an invalid iat/exp, or whose JWT signature or kid does not verify. |
| Req |
Level |
Status |
Evidence |
Statement |
| LTI-DL-1 |
MUST |
✅ done |
lti:1.3:conf:deep-linking/LTI-DL-1 |
A LtiDeepLinkingRequest carries the deep_linking_settings claim with deep_link_return_url, accept_types and accept_presentation_document_targets. |
| LTI-DL-2 |
MUST |
✅ done |
lti:1.3:conf:deep-linking/LTI-DL-2 |
The request lti_message_type MUST be LtiDeepLinkingRequest and the tool’s reply LtiDeepLinkingResponse. |
| LTI-DL-3 |
MUST |
✅ done |
lti:1.3:conf:deep-linking/LTI-DL-3 |
The tool returns the selection as a signed JWT carrying the content_items claim (a JSON array of the selected content items: ltiResourceLink, link, file, html or image). |
| LTI-DL-4 |
MUST |
✅ done |
lti:1.3:conf:deep-linking/LTI-DL-4 |
After encoding the response JWT the tool MUST redirect the workflow to the deep_link_return_url via an auto-submitted form. |
| Req |
Level |
Status |
Evidence |
Statement |
| LTI-NRPS-1 |
MUST |
✅ done |
lti:1.3:conf:nrps/LTI-NRPS-1 |
A tool consumes the NRPS claim (context_memberships_url + service_versions) from the launch to locate the membership service. |
| LTI-NRPS-2 |
MUST |
✅ done |
lti:1.3:conf:nrps/LTI-NRPS-2 |
A tool retrieves the membership container (media type application/vnd.ims.lti-nrps.v2.membershipcontainer+json) via GET on the context membership URL, following Link-header paging. |
| LTI-NRPS-3 |
MUST |
✅ done |
lti:1.3:conf:nrps/LTI-NRPS-3 |
Each member carries a user_id (the launch sub) and a roles array; a member with status Inactive/Deleted MUST be honoured (not treated as active). |
| LTI-NRPS-4 |
MUST |
✅ done |
lti:1.3:conf:nrps/LTI-NRPS-4 |
The membership request MUST be authorized by an OAuth 2.0 access token bearing the scope https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly. |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-AGS-1 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-1 |
A platform MUST include the AGS endpoint claim (the lineitems URL and the granted scopes) in launches, and MUST enforce that a tool’s service calls stay within the scopes it was granted. |
| PLAT-AGS-2 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-2 |
A platform MUST accept line item creation (POST /lineitems), requiring a label (the gradebook-column title) and a scoreMaximum. |
| PLAT-AGS-3 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-3 |
A platform MUST assign each line item an id URL returned on every response, and MUST honour a binding to a resource link (resourceLinkId) and a tool resource (resourceId). |
| PLAT-AGS-4 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-4 |
A platform MUST serve the line item container (GET /lineitems) as a paged array, filterable by resource_link_id, resource_id and tag and paged by limit/page. |
| PLAT-AGS-5 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-5 |
A platform MUST accept a score POSTed to the scores endpoint, requiring userId, activityProgress, gradingProgress and timestamp. |
| PLAT-AGS-6 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-6 |
When an accepted score carries scoreGiven the platform MUST require scoreMaximum (the scale it is given in) alongside it. |
| PLAT-AGS-7 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-7 |
A platform MUST serve the result container (GET …/results, filterable by user_id); each Result references its line item (scoreOf), the user (userId) and the achieved and maximum scores (resultScore / resultMaximum). |
| PLAT-AGS-8 |
MUST |
✅ done |
lti:1.3:conf:platform-ags/PLAT-AGS-8 |
A platform MUST serve the full single-line-item REST surface: read, update and delete the line item (GET/PUT/DELETE …/lineitems/{lineItemId}). |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-CORE-1 |
MUST |
✅ done |
lti:1.3:conf:platform-core/PLAT-CORE-1 |
A platform MUST implement the OpenID Connect third-party-initiated login flow: it exposes a login-initiation endpoint and, on the tool’s authentication request, returns the signed id_token launch to the tool’s registered redirect_uri. |
| PLAT-CORE-2 |
MUST |
✅ done |
lti:1.3:conf:platform-core/PLAT-CORE-2 |
A platform MUST mint the id_token as a JWT signed RS256 with the platform key (resolvable via the platform’s JWKS), carrying iss (the platform issuer), aud (the tool’s client_id), sub (the user), exp and iat, and the nonce from the authentication request. |
| PLAT-CORE-3 |
MUST |
✅ done |
lti:1.3:conf:platform-core/PLAT-CORE-3 |
A resource-link launch the platform issues MUST carry the required claims: message_type=LtiResourceLinkRequest, version=1.3.0, the deployment_id, the target_link_uri, and the resource_link claim with an id. |
| PLAT-CORE-4 |
MUST |
✅ done |
lti:1.3:conf:platform-core/PLAT-CORE-4 |
The launch the platform issues MUST carry the roles claim (an array of role URIs from the LTI vocabulary) binding the user to the context. |
| PLAT-CORE-5 |
MUST |
✅ done |
lti:1.3:conf:platform-core/PLAT-CORE-5 |
A platform MUST issue only well-formed launches — never one missing a required claim, carrying the wrong LTI version, or with an invalid iat/exp — and MUST sign every launch with its private key. |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-DL-1 |
MUST |
✅ done |
lti:1.3:conf:platform-deep-linking/PLAT-DL-1 |
A platform MUST issue a LtiDeepLinkingRequest carrying the deep_linking_settings claim with deep_link_return_url, accept_types and accept_presentation_document_targets. |
| PLAT-DL-2 |
MUST |
✅ done |
lti:1.3:conf:platform-deep-linking/PLAT-DL-2 |
The platform’s request lti_message_type MUST be LtiDeepLinkingRequest and it MUST accept the tool’s reply as LtiDeepLinkingResponse. |
| PLAT-DL-3 |
MUST |
✅ done |
lti:1.3:conf:platform-deep-linking/PLAT-DL-3 |
A platform MUST accept the tool’s signed response JWT, validating the content_items claim and each selected content item (ltiResourceLink, link, file, html or image) before placing it. |
| PLAT-DL-4 |
MUST |
✅ done |
lti:1.3:conf:platform-deep-linking/PLAT-DL-4 |
A platform MUST receive the tool’s deep-linking response at the deep_link_return_url it advertised and persist the selected content items as placements in the originating context. |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-DR-1 |
MUST |
✅ done |
lti:1.3:conf:platform-dynamic-registration/PLAT-DR-1 |
A platform supporting Dynamic Registration MUST expose an OpenID Connect openid-configuration document advertising its issuer, the authorization/token/JWKS endpoints, the registration endpoint and the LTI platform capabilities it offers. |
| PLAT-DR-2 |
MUST |
✅ done |
lti:1.3:conf:platform-dynamic-registration/PLAT-DR-2 |
A platform MUST accept a tool’s registration request at the registration endpoint (bearer registration access token) and return the registered client configuration — the assigned client_id and the negotiated LTI tool configuration. |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-NRPS-1 |
MUST |
✅ done |
lti:1.3:conf:platform-nrps/PLAT-NRPS-1 |
A platform MUST include the NRPS claim (context_memberships_url + service_versions) in launches for contexts where the membership service is available. |
| PLAT-NRPS-2 |
MUST |
✅ done |
lti:1.3:conf:platform-nrps/PLAT-NRPS-2 |
A platform MUST serve the membership container (media type application/vnd.ims.lti-nrps.v2.membershipcontainer+json) on GET of the context membership URL, paging with the Link header when the roster spans pages. |
| PLAT-NRPS-3 |
MUST |
✅ done |
lti:1.3:conf:platform-nrps/PLAT-NRPS-3 |
Each member the platform serves MUST carry a user_id (the same value as the launch sub) and a roles array, and an inactive/withdrawn member MUST be marked with the appropriate status rather than omitted silently. |
| PLAT-NRPS-4 |
MUST |
✅ done |
lti:1.3:conf:platform-nrps/PLAT-NRPS-4 |
A platform MUST require the membership request to bear an OAuth 2.0 access token with the scope https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly, rejecting an unscoped or unauthorized read. |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-PROC-1 |
MUST |
✅ done |
lti:1.3:conf:platform-proctoring/PLAT-PROC-1 |
A platform MUST send the LtiStartProctoring message (with the proctoring settings and the start_assessment_url) to the proctoring tool, and accept the tool’s launch of the assessment via that start_assessment_url. |
| PLAT-PROC-2 |
MUST |
✅ done |
lti:1.3:conf:platform-proctoring/PLAT-PROC-2 |
A platform MUST accept the LtiEndAssessment message returning control at the end of the attempt (and MAY honour an Assessment Control Service verdict during it). |
| Req |
Level |
Status |
Evidence |
Statement |
| PLAT-SEC-1 |
MUST |
✅ done |
lti:1.3:conf:platform-security/PLAT-SEC-1 |
All JWT signing MUST use asymmetric RSA-256; the platform signs the id_token only with its private key (symmetric cryptosystems are forbidden). |
| PLAT-SEC-2 |
MUST |
➖ not-applicable |
— |
All communication endpoints MUST be secured with TLS (SSL alone is forbidden). |
| PLAT-SEC-3 |
MUST |
✅ done |
lti:1.3:conf:platform-security/PLAT-SEC-3 |
A platform MUST expose its public keys for tools to verify the id_token signature — a JWKS URL resolving the kid of every issued launch. |
| PLAT-SEC-4 |
MUST |
✅ done |
lti:1.3:conf:platform-security/PLAT-SEC-4 |
A platform MUST operate an OAuth 2.0 token endpoint accepting the client-credentials grant with private_key_jwt client authentication: it verifies the tool’s signed client-assertion against the tool’s registered JWKS, checks the requested scopes, and issues a scoped access token. |
| Req |
Level |
Status |
Evidence |
Statement |
| LTI-PROC-1 |
MUST |
✅ done |
lti:1.3:conf:proctoring/LTI-PROC-1 |
A proctoring tool receives the LtiStartProctoring message (with the proctoring_settings and the start_assessment_url) and only launches the assessment via the start_assessment_url once proctoring setup completes. |
| LTI-PROC-2 |
MUST |
✅ done |
lti:1.3:conf:proctoring/LTI-PROC-2 |
The tool returns control to the platform with an LtiEndAssessment message at the end of the attempt (and MAY surface an Assessment Control Service verdict during it). |
| Req |
Level |
Status |
Evidence |
Statement |
| LTI-SEC-1 |
MUST |
✅ done |
lti:1.3:conf:security/LTI-SEC-1 |
All JWT signing and verification MUST use asymmetric RSA-256; symmetric cryptosystems are forbidden and a JWT MUST be signed only with the holder’s private key. |
| LTI-SEC-2 |
MUST |
➖ not-applicable |
— |
All communication endpoints MUST be secured with TLS (SSL alone is forbidden). |
| LTI-SEC-3 |
MUST |
✅ done |
lti:1.3:conf:security/LTI-SEC-3 |
A tool MUST expose its public keys for the platform to verify the tool’s JWTs — a JWKS URL (recommended) or a registered public key. |
| LTI-SEC-4 |
MUST |
✅ done |
lti:1.3:conf:security/LTI-SEC-4 |
To call a service (NRPS / AGS) a tool MUST obtain an OAuth 2.0 access token via the client-credentials grant, presenting a signed client-assertion JWT and requesting the service scope. |
- 270 literal items — 189 modelled ✅, 0 partial 🟡, 0 gaps ❌
- Silent gaps (in spec, not modelled): none
- conform-ed extensions (modelled, not in spec): 7
- Transport surface (REST binding, separate axis): 7 operations, 6 query parameters, 0 security scheme(s) — see the transport requirements above
lti:1.3:conf:ags/LTI-AGS-1
- emergent records an AGS launch-context snapshot from the endpoint claim (the lineitems URL + scopes) when AGS services are present on the launch.
lti:1.3:conf:ags/LTI-AGS-2
- AGS line-item mappings carry the label and scoreMaximum of the gradebook column the tool publishes to.
lti:1.3:conf:ags/LTI-AGS-3
- Interop-proven: createLineItem POSTs a line item carrying the launch resourceLinkId to the platform’s line-item container over an OAuth token, and the platform echoes the bound id back — the lane asserts the resourceLinkId on the recorded request.
lti:1.3:conf:ags/LTI-AGS-4
- Interop-proven: the adapter’s listLineItems reads the platform’s line-item container over an OAuth lineitem.readonly token, narrowed by resource_link_id / resource_id / tag — the lane asserts the filter round-trips on the recorded GET and the parsed gradebook columns come back. (Wired through @lti-tool/core’s LTITool.listLineItems; emergent maps the result to LtiToolAgsLineItem[].)
lti:1.3:conf:ags/LTI-AGS-5
- emergent publishes scores via the AGS publication flush; the Score carries userId, activityProgress, gradingProgress and timestamp.
lti:1.3:conf:ags/LTI-AGS-6
- Interop-proven: submitScore POSTs a Score with scoreGiven on its scoreMaximum scale to the line item’s /scores endpoint over an OAuth token — the lane asserts both values on the recorded request.
lti:1.3:conf:ags/LTI-AGS-7
- Interop-proven: the adapter’s readResults reads the line item’s AGS result container (GET …/results, application/vnd.ims.lis.v2.resultcontainer+json) over an OAuth token scoped result.readonly, and the lane asserts the returned result rows (userId, resultScore) and the authorized request.
lti:1.3:conf:ags/LTI-AGS-8
- Interop-proven: the adapter performs full line-item management — createLineItem (POST), updateLineItem (PUT) and deleteLineItem (DELETE) against the platform line item over an OAuth token; the lane asserts the PUT body and the authorized PUT/DELETE requests.
lti:1.3:conf:core/LTI-CORE-1
- The /lti/login route accepts the OIDC third-party login-init parameters and 302-redirects to the platform authorization endpoint via the adapter.
lti:1.3:conf:core/LTI-CORE-2
- The /lti/launch route accepts the id_token + state and drives the launch. Interop-proven: the lti-interop lane signs a launch with the mock platform’s key and emergent’s adapter verifies the signature (against the platform JWKS), nonce, iss and aud end-to-end, and rejects a launch whose signature does not verify.
lti:1.3:conf:core/LTI-CORE-3
- Interop-proven: a real signed launch resolves into a session carrying the resource link and context, and emergent maps the membership role claim into its internal role vocabulary.
lti:1.3:conf:core/LTI-CORE-4
- Interop-proven: for an offering-mapped launch context the launch roles drive the NRPS roster sync end-to-end — the lane provisions an organization/offering/context-mapping and asserts the persisted NRPS context snapshot (memberCount > 0) after a real launch.
lti:1.3:conf:core/LTI-CORE-5
- The login/launch routes reject missing required parameters and unsupported launch targets (boundary-enforced to the learner-web origin).
lti:1.3:conf:deep-linking/LTI-DL-1
- Interop-proven: a real LtiDeepLinkingRequest carrying deep_linking_settings resolves into a Deep Linking session (isDeepLinkingAvailable) and emergent builds the auto-submitted return form to the request’s deep_link_return_url; a non-Deep-Linking (resource link) session is rejected.
lti:1.3:conf:deep-linking/LTI-DL-2
- The DL response path is gated on the LtiDeepLinkingRequest message type — non-Deep-Linking sessions are rejected.
lti:1.3:conf:deep-linking/LTI-DL-3
- emergent assembles the content_items claim honouring the platform’s deep_linking_settings accept_types and accept_multiple: it offers the launchable ltiResourceLink plus the link, html and standalone image representations, and enriches every link-like item with the offering’s canonical image (ADR-0035) as both thumbnail and icon. Interop-proven: the lti-interop lane drives a real Deep Linking launch advertising accept_types [“link”,“html”,“image”], decodes the signed response JWT and asserts emergent emits exactly those three with the canonical-image thumbnail (and the offline builder suite proves the accept_types filtering + fallback). The one content type deliberately not emitted is
file: an offering’s only file is its Common Cartridge export, an authenticated org-admin workflow rather than a publicly fetchable URL, so emitting it would leave a broken link in the platform.
lti:1.3:conf:deep-linking/LTI-DL-4
- The Deep Linking response route returns the auto-submitted-form HTML that redirects back to the platform’s deep_link_return_url.
lti:1.3:conf:nrps/LTI-NRPS-1
- emergent consumes the NRPS claim from the launch and synchronizes the resolved roster into snapshots, memberships and grants.
lti:1.3:conf:nrps/LTI-NRPS-2
- Interop-proven: the platform splits the roster across two pages and emergent follows the membership container’s
Link: rel=next to read every page before syncing — the lane asserts emergent GETs page 2 over the OAuth bearer token and the persisted snapshot’s member_count spans both pages. Paging lives in the vendored @lti-tool/core (packages/lti-tool-core, NRPSService.getMembers walks rel=next; same fix proposed upstream on AntonOfTheWoods/lti-tool feat/nrps-rel-next-paging).
lti:1.3:conf:nrps/LTI-NRPS-3
- Members carry their user_id (the launch sub) and roles; a member no longer active in the roster has its imported memberships/grants expired (status honoured).
lti:1.3:conf:nrps/LTI-NRPS-4
- Interop-proven: the membership container read carries the bearer access token acquired for the contextmembership.readonly scope — the lane asserts the Authorization header on the recorded NRPS request.
lti:1.3:conf:platform-ags/PLAT-AGS-1
- The launch carries the AGS endpoint claim (the lineitems container URL + granted scopes) and every AGS operation is scoped to the calling tool’s deployment in the context — a tool never sees another tool’s columns. Interop-proven: the claim is asserted and an undeployed tool is refused.
lti:1.3:conf:platform-ags/PLAT-AGS-2
- createLineItemWithDb accepts line-item creation requiring a label (the gradebook-column title) and a scoreMaximum; the line item is a first-class gradebook column (not coerced into an Assessment).
lti:1.3:conf:platform-ags/PLAT-AGS-3
- Each line item is assigned an id URL returned on every response, and a resourceLinkId binding is honoured (it must resolve to a resource link in the offering). Validated against conform-ed’s LineItemSchema.
lti:1.3:conf:platform-ags/PLAT-AGS-4
- listLineItemsWithDb serves the line-item container as a paged array filterable by resource_link_id, resource_id and tag, media type application/vnd.ims.lis.v2.lineitemcontainer+json. Validated against conform-ed’s LineItemContainerSchema; the lane proves the resource_link_id filter round-trips.
lti:1.3:conf:platform-ags/PLAT-AGS-5
- submitScoreWithDb accepts a score POSTed to the scores endpoint requiring userId, activityProgress, gradingProgress and timestamp; userId (the pairwise sub) is resolved back to the person, and an out-of-order score is rejected (last-writer-wins by timestamp).
lti:1.3:conf:platform-ags/PLAT-AGS-6
- When an accepted score carries scoreGiven the platform requires scoreMaximum alongside it — the lane asserts a scoreGiven without scoreMaximum is rejected.
lti:1.3:conf:platform-ags/PLAT-AGS-7
- listResultsWithDb serves the result container (GET …/results, filterable by user_id), each Result referencing its line item (scoreOf). Validated against conform-ed’s ResultContainerSchema.
lti:1.3:conf:platform-ags/PLAT-AGS-8
- The full single-line-item REST surface is served — read/update/delete via GET/PUT/DELETE …/lineitems/{lineItemId}; the lane reads, PUT-replaces and deletes a line item end-to-end.
lti:1.3:conf:platform-core/PLAT-CORE-1
- initiateResourceLinkLaunchWithDb mints a single-use login_hint + returns the OIDC third-party login-initiation parameters (iss, login_hint, target_link_uri, client_id, lti_deployment_id); completeAuthorizationWithDb validates the login_hint/client_id/redirect_uri and form-posts the signed id_token to the tool’s registered redirect_uri. Interop-proven: the mock tool initiates login and receives the launch at its redirect_uri.
lti:1.3:conf:platform-core/PLAT-CORE-2
- signIdToken mints the id_token as an RS256 JWT with the platform key (env keypair, kid resolvable via the platform JWKS) carrying iss=platform issuer, aud=client_id, sub (the pairwise subject), nonce and iat/exp. Interop-proven: the mock tool verifies the signature against the platform JWKS plus iss/aud/nonce end-to-end.
lti:1.3:conf:platform-core/PLAT-CORE-3
- buildResourceLinkClaims emits the required resource-link launch claims (message_type= LtiResourceLinkRequest, version=1.3.0, deployment_id, target_link_uri, resource_link). The normalized launch validates against conform-ed’s CoreLaunchRequestSchema in the lane.
lti:1.3:conf:platform-core/PLAT-CORE-4
- The launch carries the roles claim — an array of LTI membership role URIs resolved from the person’s offering membership (mapMembershipRoleToLtiRoles) — binding the user to the context. Interop-proven: the lane asserts the learner role URI on the verified launch.
lti:1.3:conf:platform-core/PLAT-CORE-5
- The platform issues only well-formed launches: the login_hint is single-use (replay-protected via consumed_at) and an unregistered redirect_uri is rejected — both asserted in the lane.
lti:1.3:conf:platform-deep-linking/PLAT-DL-1
- initiateDeepLinkingLaunchWithDb + completeDeepLinkingAuthorization issue a LtiDeepLinkingRequest carrying the deep_linking_settings claim (deep_link_return_url, accept_types, accept_presentation_document_targets, accept_multiple, and a stateless HS256
data correlation token). The normalized request validates against conform-ed’s DeepLinkingRequestSchema.
lti:1.3:conf:platform-deep-linking/PLAT-DL-2
- The request lti_message_type is LtiDeepLinkingRequest and the platform accepts the tool’s reply as a LtiDeepLinkingResponse (acceptDeepLinkingResponseWithDb) — both asserted in the lane.
lti:1.3:conf:platform-deep-linking/PLAT-DL-3
- The platform verifies the tool’s signed response JWT against the tool’s JWKS (iss=client_id, aud=platform issuer) and validates content_items against conform-ed’s DeepLinkingResponseSchema; a wrong-key signature is rejected.
lti:1.3:conf:platform-deep-linking/PLAT-DL-4
- The platform receives the response at the advertised deep_link_return_url (POST /lti/platform/deep-linking/return), re-derives the originating context from the verified
data token, and persists each selected content item as a resource-link placement; a forged data token is rejected. The lane drives a three-item response and asserts three placements in the offering.
lti:1.3:conf:platform-dynamic-registration/PLAT-DR-1
- buildPlatformOpenIdConfiguration serves the OpenID Connect openid-configuration document (GET /lti/platform/.well-known/openid-configuration) advertising the issuer, the authorization / token / JWKS / registration endpoints, RS256 + private_key_jwt, the service scopes, and the lti-platform-configuration capabilities claim (product_family_code + messages_supported). Asserted in the lane.
lti:1.3:conf:platform-dynamic-registration/PLAT-DR-2
- registerToolViaDynamicRegistrationWithDb accepts a tool’s registration request at the registration endpoint bearing a registration access token, creates the catalog row with a platform-assigned client_id (registrationMode “dynamic”), and returns the registered client configuration + negotiated lti-tool-configuration. Interop-proven: a mock tool self-registers, is entitled to the initiating org with a minted deployment, and then obtains a private_key_jwt service token (a first-class client); a forged registration token is rejected.
lti:1.3:conf:platform-nrps/PLAT-NRPS-1
- buildServiceClaims advertises the NRPS claim (context_memberships_url + service_versions [“2.0”]) in launches for the offering context. Interop-proven: the lane asserts the claim’s URL + versions.
lti:1.3:conf:platform-nrps/PLAT-NRPS-2
- buildMembershipPageWithDb serves the membership container with media type application/vnd.ims.lti-nrps.v2.membershipcontainer+json and a Link: rel=next header when the roster pages. The normalized container validates against conform-ed’s MembershipContainerSchema.
lti:1.3:conf:platform-nrps/PLAT-NRPS-3
- Each served member carries a user_id equal to the launch sub (the same per-(person,tool) pairwise subject, via the identity_binding) plus a roles array, and an inactive/withdrawn membership is surfaced with the matching status. Interop-proven: the lane asserts member.user_id === the launch sub.
lti:1.3:conf:platform-nrps/PLAT-NRPS-4
- The membership route requires a Bearer access token bearing the contextmembership.readonly scope (and the tool must be deployed in the context); a token without it gets 403 and an undeployed tool is refused. The token is minted only via the private_key_jwt grant.
lti:1.3:conf:platform-proctoring/PLAT-PROC-1
- completeProctoringAuthorization issues a LtiStartProctoring launch carrying the proctoring settings + start_assessment_url + a stateless HS256 session_data token, and the platform accepts the tool’s launch of the assessment (acceptStartAssessmentWithDb verifies the tool-signed StartAssessment vs its JWKS, validates it against conform-ed’s StartAssessmentMessageSchema, and advances the proctoring session to assessment_launched). The normalized StartProctoring validates against StartProctoringMessageSchema.
lti:1.3:conf:platform-proctoring/PLAT-PROC-2
- acceptEndAssessmentWithDb accepts the tool’s LtiEndAssessment returning control at the end of the attempt (verified vs the tool JWKS, validated against conform-ed’s EndAssessmentMessageSchema), marking the session ended. Forged-session_data and wrong-key messages are rejected. The optional Assessment Control Service verdict is now ALSO honoured (ADR-0043): the platform advertises assessment_control_url in StartProctoring and accepts control.all-scoped AssessmentControl requests at POST /lti/platform/proctoring/control, recording every incident to lti_platform_proctoring_control_event and acting on the action — flag, pause/resume, extra_time, and terminate (which voids the in-flight native attempt). Interop-proven (flag → terminate, audit, wrong-tool reject).
lti:1.3:conf:platform-security/PLAT-SEC-1
- The platform signs the id_token only with RS256 (asymmetric RSA) using its private key — the lane decodes the protected header and asserts alg=RS256 with the kid resolving in the JWKS.
lti:1.3:conf:platform-security/PLAT-SEC-3
- The GET /lti/platform/jwks route exposes the platform’s public RS256 key (the kid of every issued launch resolves there) so a tool can verify the id_token signature. Interop-proven: the mock tool resolves the JWKS and verifies a real launch.
lti:1.3:conf:platform-security/PLAT-SEC-4
- The platform operates a standalone OAuth 2.0 token endpoint (POST /lti/platform/token) accepting the client-credentials grant with private_key_jwt client authentication — issueServiceAccessTokenWithDb verifies the tool’s client_assertion against its registered JWKS and mints a scoped access token via the shared HS256 access-token codec. Interop-proven: a private_key_jwt grant yields a Bearer token, and an assertion signed by the wrong key is rejected.
lti:1.3:conf:proctoring/LTI-PROC-1
- Interop-proven: emergent is the proctoring tool. handleStartProctoring verifies the LtiStartProctoring launch (the vendored @lti-tool/core accepts the message type + passes the lti-ap proctoring claims through), persists the proctoring session (lti_tool_proctoring_session), and — once setup completes — launches the assessment by returning a tool-signed StartAssessment auto-submit form to the platform’s start_assessment_url (POST /lti/proctoring/start). The lane decodes the emitted StartAssessment and asserts message_type=LtiStartAssessment, the platform’s session_data, and aud=platform issuer. The StartAssessment payload is validated against conform-ed’s StartAssessmentMessageSchema before signing.
lti:1.3:conf:proctoring/LTI-PROC-2
- Interop-proven: at the end of the attempt endProctoredAttempt loads the proctoring session and returns control to the platform with a tool-signed EndAssessment auto-submit form posted to the session’s end_assessment_return_url (validated against conform-ed’s EndAssessmentMessageSchema, carrying the user’s roles). The lane decodes it and asserts message_type=LtiEndAssessment + deployment_id. The optional Assessment Control Service verdict is now ALSO honoured (ADR-0043): sendAssessmentControl obtains a control.all-scoped service token (client_credentials + private_key_jwt) and POSTs a conform-ed-validated AssessmentControlRequest to the platform’s advertised assessment_control_url, recording the outbound action + response in lti_tool_proctoring_control_event (authed POST /workflow/lti-tool/proctoring/sessions/:id/control).
lti:1.3:conf:security/LTI-SEC-1
- Interop-proven: the adapter exposes the tool’s RS256 verification key (kty RSA, kid) via JWKS, and RS256 verification of a real platform-signed launch is exercised end-to-end by the same lane.
lti:1.3:conf:security/LTI-SEC-3
- The /lti/jwks route serves the tool’s public JWKS (kid ‘main’) for the platform to verify the tool’s signed JWTs.
lti:1.3:conf:security/LTI-SEC-4
- Interop-proven: on launch, emergent acquires an OAuth 2.0 client-credentials access token from the platform token endpoint with a signed client_assertion, then makes the NRPS service call authorized by that bearer token — the lane asserts both on the recorded platform requests.