# System index

_Generated by `kg.mjs system` — do not edit. Start with [README](README.md)._

Apps: abigail, ad, adam, arc, cf, cow, lp, mot, mre, navvy, oscar, psaes, xprt. 334 cross-app links, 633 nodes involved, 94 system nodes.

## System nodes (94)

| node | type | summary |
|---|---|---|
| [ad-authoring-web-components](nodes/ad-authoring-web-components.md) | interface | AD's embeddable authoring custom elements (ad-authoring.js and the QTI item components) that Abigail hosts for item, stimulus, resource and media editing; ADAM's legacy editors only use the item components. |
| [ad-data-api-oauth](nodes/ad-data-api-oauth.md) | interface | OAuth2 client-credentials token endpoint of AD; every host (Abigail, ADAM, ARC, Navvy) mints a bearer token from an AD credential and uses it for /api/data, /api/delivery and /api/scoring. |
| [ad-embedded-player](nodes/ad-embedded-player.md) | interface | The ad-test-player custom element that hosts load from the AD host and drive with a player launch JWT; ADAM, ARC, Navvy and Abigail all deliver or preview AD forms through it. |
| [ad-register-session](nodes/ad-register-session.md) | interface | POST /api/delivery/registerSession — how a host creates an AD delivery session for one student (form, host session id, PNP, callback_url, CAT settings) and gets the player launch token back. |
| [adam-psaes-lookup-api](nodes/adam-psaes-lookup-api.md) | interface | Planned PSAES → ADAM seam - ADAM serves POST /v1/api/orgs/lookup and /v1/api/barcodes/lookup (environment JWT with aud psaes, cross-tenant, rate-limited) so PSAES can resolve org codes and scanned Pre-ID barcodes, but PSAES has no client for it yet. |
| [arc-lockdown-extension](nodes/arc-lockdown-extension.md) | interface | ARC's Chrome lockdown extension and its page API window.ArcExtension (lock, unlock, launch, onbreach); ARC's learner UI and Navvy's test player both use it to lock the student's window. |
| [cow-elk-document-lookup](nodes/cow-elk-document-lookup.md) | interface | COW Doc Depot lookup ADAM calls to show per-session documents — POST /idToken for a tenant token, then GET /reporting/v1/elk/{externalLoginKey} returning a document with presigned URLs. |
| [cow-report-asset-manifest](nodes/cow-report-asset-manifest.md) | interface | The 13-column manifest CSV plus files COW drops into ADAM's internal S3 bucket under imported/<program>/<admin>/, which ADAM imports as downloadable report assets. |
| [lp-oidc-sso](nodes/lp-oidc-sso.md) | interface | LaunchPad's OpenID Connect provider (authorization code) that ADAM, Navvy and the COW forensics dashboard use for "Sign in with LaunchPad"; sub is the user's LPI and is matched to each app's sourced_id. |
| [lp-oneroster-api](nodes/lp-oneroster-api.md) | interface | LaunchPad's read-only OneRoster 1.2 external API with client-credentials auth per app config; ADAM and Navvy pull rosters from it and the COW forensics dashboard reads a signed-in user's roles and orgs. |
| [oscar-external-api](nodes/oscar-external-api.md) | interface | OSCAR's host ingest contract - POST /v1/auth/token (AD, X-Auth-Token) or HTTP Basic (ADAM), GET /v1/api/tenant/:t/manifest\|item\|rubric to map content, and PATCH /v1/api/response with an ExtResponse that names the callback_url the score comes back to. |
| [adam-cow-read-replica](nodes/adam-cow-read-replica.md) | datastore | COW-dedicated read-only replica of ADAM's Postgres (adam-*-cow-ro) that COW's ingest and extract jobs query directly to copy delivered results into the Redshift warehouse. |
| [ad-host-callback](nodes/ad-host-callback.md) | event | The JSON webhook AD POSTs to host apps when a session is scored or bank content changes; Abigail, ADAM, ARC and Navvy each consume it and pull the real data back over AD's APIs. |
| [lp-roster-change-webhook](nodes/lp-roster-change-webhook.md) | event | Per-row roster change notification LaunchPad POSTs to subscribed apps from Postgres WAL changes; ADAM is the only known consumer and re-fetches the referenced object over the OneRoster API. |
| [oscar-score-callback](nodes/oscar-score-callback.md) | event | The ExtScorePayload JSON POST OSCAR sends to a response's callback_url once it is scored - AD (/api/scoring/oscar/callback) and ADAM (/v1/api/score) both receive it with no authentication; non-200 is retried every 2 h up to 5 attempts. |
| [adam-class-assignment-on-ad](nodes/adam-class-assignment-on-ad.md) | flow | A teacher builds a Class Assignment from AD content (AD form plus a local ad_tests copy), students take it in AD's player, and ADAM fetches the responses from AD. |
| [ai-score-explanation-to-host](nodes/ai-score-explanation-to-host.md) | flow | The scoredResponseText chain - CF's IEA2 scoring copies the exact text it scored into the outcome tags, OSCAR stores it on the score and echoes it as meta.scoredResponseText in the score callback, and AD keeps it in the response state (AD-6322); Navvy, the intended reader, does not read it yet. |
| [author-ad-item-in-abigail](nodes/author-ad-item-in-abigail.md) | flow | An Abigail author edits an item in AD's embedded editor, Abigail gates and proxies the save to AD, and AD's content-changed callback reindexes it in Abigail's content agent. |
| [deliver-ad-test-from-adam](nodes/deliver-ad-test-from-adam.md) | flow | A district ADAM session with platform AD is registered on AD, played in AD's player, scored by AD save-off, and pulled back into ADAM by ADAM's own saveoff after AD's callback. |
| [deliver-cow-report-assets-to-adam](nodes/deliver-cow-report-assets-to-adam.md) | flow | A completed COW extract staged for ADAM is copied with a manifest CSV into ADAM's internal S3 bucket, an out-of-repo S3 trigger queues the import, and ADAM loads the files as report assets. |
| [forensics-dashboard-login](nodes/forensics-dashboard-login.md) | flow | Staff sign in to COW's forensics dashboard with LaunchPad OIDC (PKCE); COW gates on the LP tenant and reads the user's OneRoster roles and orgs to scope access to all, district or school data. |
| [human-score-in-adam](nodes/human-score-in-adam.md) | flow | A teacher scores rubric traits in ADAM, ADAM pushes the trait scores to AD, AD re-runs save-off and calls back, and ADAM re-pulls the final scores. |
| [import-export-qti-via-abigail](nodes/import-export-qti-via-abigail.md) | flow | Abigail starts AD's async QTI package import or export jobs for a bank and polls their progress. |
| [ingest-adam-to-warehouse](nodes/ingest-adam-to-warehouse.md) | flow | COW copies ADAM client data from ADAM's COW read replica into a per-administration Redshift Data Vault, via ECS-to-S3 or direct Glue JDBC paths, then refreshes materialized views. |
| [launchpad-sso-into-adam](nodes/launchpad-sso-into-adam.md) | flow | ADAM staff sign in with LaunchPad over OIDC authorization code; ADAM matches the LP sub (LPI) to users.sourced_id and exchanges it for an ADAM session. |
| [launchpad-sso-into-navvy](nodes/launchpad-sso-into-navvy.md) | flow | Navvy users choose Sign in with Launchpad; Navvy runs OIDC against LaunchPad and matches the sub (LPI) and email to a rostered Navvy user. |
| [materials-ordering-from-adam](nodes/materials-ordering-from-adam.md) | flow | ADAM reads MOT program and distribution config, posts Initial/Additional orders (postOrder) and Pre-ID student rosters (postStudent) to MOT's Orders service, and polls MOT's order-status and tracking routes to show shipments; MOT batches, approves and exports the orders for fulfilment. |
| [preview-form-in-abigail](nodes/preview-form-in-abigail.md) | flow | Abigail gets a preview or practice launch token for a form from AD and runs the form in AD's embedded test player. |
| [print-form-via-xprt](nodes/print-form-via-xprt.md) | flow | Abigail (or ADAM's legacy UI) asks AD to print an item, passage or form; AD exports a QTI package and submits it to XPRT with a JWT and a presigned S3 PUT URL, XPRT composes it on Typefi and PUTs the PDF into AD's bucket, and AD serves it until the content changes. |
| [proctor-ad-session-from-arc](nodes/proctor-ad-session-from-arc.md) | flow | An ARC teacher watches live AD sessions and pauses, resumes or submits them by polling and setting AD session state, which the player picks up. |
| [push-adam-gradebook-to-launchpad](nodes/push-adam-gradebook-to-launchpad.md) | flow | ADAM's saveoff pushes OneRoster gradebook categories, line items and results to LaunchPad, but LP no longer has those routes, so every push fails. |
| [rescore-arc-attempts](nodes/rescore-arc-attempts.md) | flow | An ARC admin asks AD to rescore selected attempts, AD re-runs save-off and calls back, and ARC re-runs saveoff and always passes back. |
| [roster-launchpad-to-adam](nodes/roster-launchpad-to-adam.md) | flow | LaunchPad roster changes reach ADAM live through LP's change webhook and a per-object OneRoster re-fetch, with a scheduled delta or full pull over the same API as backstop. |
| [roster-launchpad-to-navvy](nodes/roster-launchpad-to-navvy.md) | flow | Nightly (or on demand) Navvy pulls each auto-sync client's roster from LaunchPad's OneRoster 1.2 API and upserts orgs, classes, users and enrollments by LPI. |
| [score-constructed-response-with-oscar](nodes/score-constructed-response-with-oscar.md) | flow | AD save-off sends a mapped constructed response to OSCAR, OSCAR routes it to CF/IEA AI scoring and/or human scorers, exports the final score to AD's unauthenticated callback, and AD stores it (with scoredResponseText), rescores the session and calls the host back. |
| [score-math-response-with-mre](nodes/score-math-response-with-mre.md) | flow | When AD scores a QTI item whose response processing has a pearson.mre custom operator - in delivery for any host (ADAM, ARC, Navvy) or in preview - it POSTs the inline item definition and the student's answer to MRE /ws/stateless and uses the returned score; any MRE error scores 0. |
| [sync-ad-banks-to-abigail](nodes/sync-ad-banks-to-abigail.md) | flow | Abigail lists an account's AD banks with the account's AD credentials and upserts one canonical bank row per AD bank id plus the account's membership. |
| [sync-ad-content-to-adam](nodes/sync-ad-content-to-adam.md) | flow | An AD bank, form or item save triggers AD's content-changed callback, and ADAM pulls the entity into its QTI tables for every client that owns the AD bank. |
| [sync-ad-items-to-navvy](nodes/sync-ad-items-to-navvy.md) | flow | Twice a day Navvy pages AD banks, items and stimuli and upserts its item mirror by AD item id, then recomputes assessment item counts. |
| [take-ad-test-from-arc](nodes/take-ad-test-from-arc.md) | flow | A student launches an ARC assignment, ARC registers the attempt as an AD session with its own callback_url, AD's player runs and scores it, and ARC pulls the result back and passes the grade to the LMS. |
| [take-navvy-check-in-ad](nodes/take-navvy-check-in-ad.md) | flow | A Navvy student launches a check, Navvy selects items and has AD build a dynamic form, registers the AD session with a callback_url, AD's player runs and scores it, and Navvy pulls results back on callback. |
| [upload-item-statistics](nodes/upload-item-statistics.md) | flow | An Abigail user uploads a psychometric statistics CSV into an AD historical stat set, which AD parses into historical-stat rows. |
| [view-cow-documents-in-adam](nodes/view-cow-documents-in-adam.md) | flow | ADAM's ISR modal looks up per-session documents in COW Doc Depot by external login key, using a COW idToken, and shows presigned download links. |
| [adam-term](nodes/adam-term.md) | concept | The name ADAM (or adam) covers two different products — the ADAM test-administration app, and (in Abigail, Navvy and AD's own code) the AD authoring and delivery platform. |
| [admin-term](nodes/admin-term.md) | concept | "Admin" / test administration means a testing window or delivery of a test in ADAM, MOT and PSAES (joined by admin_code), a CF test administration (= an OSCAR project), and a role or route prefix in OSCAR - never a person in ADAM. |
| [attempt-term](nodes/attempt-term.md) | concept | In ARC an attempt is one sitting and its id is the AD session id; in Navvy an attempt is a numbered try at a check; in COW a test attempt is an ADAM session. |
| [bank-term](nodes/bank-term.md) | concept | A bank is AD's content container and permission scope; Abigail wraps each AD bank in its own row, and ADAM has both a legacy Learnosity bank and a QTI mirror of AD banks. |
| [battery-term](nodes/battery-term.md) | concept | A battery is a group of unit tests scored and reported as one; AD scores it via a battery STM, ADAM enrols students in it, Abigail authors its scoring map, and COW reports it. |
| [client-term](nodes/client-term.md) | concept | Client or tenant means an LP tenant, an ADAM tenant (clients.id, COW's datasource_id; customer_code = PSAES account_code), a Navvy customer, an AD host account, an OSCAR tenant or a CF client depending on the app. |
| [cow-term](nodes/cow-term.md) | concept | COW is "Core Warehouse", Pearson's reporting/ETL platform; ADAM treats it as an opaque external document and report-asset service. |
| [eligibility-term](nodes/eligibility-term.md) | concept | Eligibility in ADAM is whether a student may take an administration (rule trees, proctor approval, Pre-ID eligible sessions); in PSAES it is which forms of a scan program a test administration covers. |
| [external-login-key-term](nodes/external-login-key-term.md) | concept | ELK is ADAM's sessions.external_login_key — the session's login id on its delivery engine (the AD session id, or a TestNav StudentTestUUID) — and COW's join key for documents and scores. |
| [form-term](nodes/form-term.md) | concept | A form is AD's deliverable test version; ADAM also has legacy Learnosity forms and QTI copies, and Navvy distinguishes dynamic item sets from fixed forms. |
| [iea-term](nodes/iea-term.md) | concept | IEA, CF and KT all name the same Pearson AI scoring service (ktcf-continuous-flow, ktscoringservices.com) - OSCAR's code says IEA or cf_config, CF calls itself Continuous Flow and IEA/IEA2 its engine; MRE (ktmath-scoring) is a different KT service for math. |
| [item-term](nodes/item-term.md) | concept | An item is an authored, versioned question in AD (mirrored by Abigail, ADAM, Navvy and COW), a scoring queue for one question's responses in OSCAR, a prompt in CF, and a scoring definition in MRE - matched across apps by reference/identifier strings, not by AD's id. |
| [lti-tool-term](nodes/lti-tool-term.md) | concept | ARC, ADAM and Navvy are each an LTI 1.3 tool that external LMS platforms launch (OIDC login + RS256 id_token); none of them is a platform for another app in this graph, so there is no LTI link between them. |
| [outcome-term](nodes/outcome-term.md) | concept | An outcome is the score AD computes for one STM objective on a session; ADAM, ARC and Navvy copy those rows, and ADAM also computes program outcomes itself. |
| [pnp-term](nodes/pnp-term.md) | concept | PNP (personal needs and preferences) is the accommodations block a host sends to AD at session registration; each host builds it from its own accommodation data. |
| [record-type-term](nodes/record-type-term.md) | concept | Record type means a level of a distribution's shipping hierarchy in MOT (which ADAM reads per distribution code when ordering) but the scanner record type of a form (01, 17, 99) in PSAES - unrelated codes. |
| [resource-term](nodes/resource-term.md) | concept | In AD and Abigail a resource is section-intro or exhibit content attached to forms; in ARC a resource is an assignable test wrapping AD forms. |
| [role-term](nodes/role-term.md) | concept | A LaunchPad role is a OneRoster user-at-org role row; an ADAM role is an unrelated permission set; Navvy turns OneRoster roles into user-org rows and a user role. |
| [rollover-term](nodes/rollover-term.md) | concept | Rollover means copying last cycle's setup into a new one - in MOT either a test administration (MATERIALS_ROLLOVER, optionally with its TAIL) or an orders distribution (ORDERS_ROLLOVER), and in ADAM a whole tenant for the next school year (TENANT_ROLLOVER); none of them triggers another app. |
| [saveoff-term](nodes/saveoff-term.md) | concept | Save-off is AD's async scoring pass on a submitted session; ADAM and ARC reuse the word for pulling the scored AD session back into their own tables after the callback. |
| [session-term](nodes/session-term.md) | concept | Session means an AD delivery attempt, a host's record of a student's test attempt, a login cookie, or a OneRoster school term depending on the app. |
| [sourced-id-term](nodes/sourced-id-term.md) | concept | sourcedId is the OneRoster id of a roster record; LaunchPad stores the source system's id but emits its own LPI in that field, so ADAM, Navvy and COW sourced_id columns actually hold LPIs for LaunchPad tenants. |
| [standard-id-term](nodes/standard-id-term.md) | concept | Standard ids in AD, ADAM, Navvy and Abigail are the same Academic Benchmarks GUIDs — a shared key space, not a sync — so ids are interchangeable across apps. |
| [stimulus-term](nodes/stimulus-term.md) | concept | Stimulus, shared stimulus and passage all mean AD's shared stimulus — content several items refer to; an exhibit is that stimulus seen from inside an item. |
| [stm-term](nodes/stm-term.md) | concept | STM (scoring test map) is AD's per-form scoring definition (objectives to outcomes) authored in Abigail; in COW it is a TestNav-era per-form test description, unrelated to AD STMs. |
| [test-term](nodes/test-term.md) | concept | AD has no test entity (the form is delivered); ADAM's test is a definition with forms or a class-assignment test, Navvy says check or assessment, ARC says resource. |
| [workflow-state-term](nodes/workflow-state-term.md) | concept | Workflow state/status is a bank-defined authoring position of an item or form; it is separate from pub_state (Draft/Published/Retired) and from a delivery session's state. |
| [ad-content-in-host-apps](nodes/ad-content-in-host-apps.md) | capability | AD banks, forms, items and stimuli show up inside ADAM, Navvy and Abigail so those apps can set up tests and report on them, kept fresh by sync jobs and AD's change callbacks. |
| [adaptive-testing-carry-over](nodes/adaptive-testing-carry-over.md) | capability | ARC tells AD's adaptive engine which items a student already saw and where their ability estimate ended, so the next adaptive attempt starts from there. |
| [ai-content-indexing](nodes/ai-content-indexing.md) | capability | Every save of an item, passage, form or media in AD triggers a callback that makes Abigail reindex it in its AI content agent, so AI search and chat see current content. |
| [assessment-delivery-on-ad](nodes/assessment-delivery-on-ad.md) | capability | ADAM schedules, proctors and reports district tests while AD plays and scores them. |
| [assessment-reporting-warehouse](nodes/assessment-reporting-warehouse.md) | capability | Delivered test results are copied out of ADAM into a per-administration Redshift warehouse in COW so customers get data extracts. |
| [class-assignments-on-ad](nodes/class-assignments-on-ad.md) | capability | Teachers build quick classroom tests in ADAM from AD content, students take them in AD's player and scores land back in ADAM. |
| [constructed-response-scoring](nodes/constructed-response-scoring.md) | capability | Open-ended answers in AD- or ADAM-delivered tests are scored by people and/or AI in OSCAR (with CF/IEA as the AI engine) and the scores flow back into the test result automatically. |
| [content-review](nodes/content-review.md) | capability | Abigail runs reviews of AD items and forms with internal reviewers or external reviewers who join by code; content is read from AD and forms are shown in AD's player. |
| [embedded-item-authoring](nodes/embedded-item-authoring.md) | capability | Abigail users write items, passages, resources and media in AD's own editors embedded in Abigail, with Abigail enforcing roles, workflow and locks; AD stores everything. |
| [extracts-in-adam-report-assets](nodes/extracts-in-adam-report-assets.md) | capability | Completed COW extracts and report PDFs show up as downloadable report assets in ADAM. |
| [forensics-dashboard-sign-in](nodes/forensics-dashboard-sign-in.md) | capability | State, district and school staff sign in to COW's test-security dashboard with LaunchPad and see forensics only for their own organisations. |
| [form-assembly-and-preview](nodes/form-assembly-and-preview.md) | capability | Authors build forms, setting profiles, scoring maps and batteries in Abigail, saved to AD, and preview, practice or print them through AD's player and print service. |
| [hand-scoring-and-rescoring](nodes/hand-scoring-and-rescoring.md) | capability | Teachers and admins score open responses or trigger rescoring in their host app; AD stores the scores, rescores the session and notifies the host to pull final results. |
| [item-statistics](nodes/item-statistics.md) | capability | Psychometricians upload and query historical and scoring item statistics in Abigail, stored in AD, and use them for gold sets, test profiles and extracts. |
| [launchpad-rostering](nodes/launchpad-rostering.md) | capability | District rosters maintained in LaunchPad appear automatically in ADAM (scheduled plus live webhooks) and Navvy (nightly). |
| [launchpad-single-sign-on](nodes/launchpad-single-sign-on.md) | capability | Users sign in to ADAM, Navvy and the COW forensics dashboard with their LaunchPad account. |
| [live-proctoring](nodes/live-proctoring.md) | capability | Teachers watch students' test progress live and pause, resume or submit their AD sessions from the host app. |
| [lms-gradebook-score-sync](nodes/lms-gradebook-score-sync.md) | capability | AD scores a finished ARC attempt, ARC pulls the scores and posts the grade to the LMS gradebook automatically; ADAM's similar push to LaunchPad is dead. |
| [locked-down-testing](nodes/locked-down-testing.md) | capability | ARC's Chrome lockdown extension locks the student's window during AD tests in ARC and, optionally, in Navvy. |
| [math-auto-scoring](nodes/math-auto-scoring.md) | capability | Math answers (expressions, numbers with units, equations) in AD-delivered tests are scored automatically by the Math Response Engine using scoring rules the item author embeds in the item. |
| [online-check-delivery](nodes/online-check-delivery.md) | capability | Navvy students take their checks in AD's test player and AD scores them back into Navvy's reports. |
| [paper-materials-ordering](nodes/paper-materials-ordering.md) | capability | District users order paper test books and answer documents, including Pre-ID labelled documents, from ADAM; MOT fulfils the orders and ADAM shows their shipping status and tracking. |
| [print-composition](nodes/print-composition.md) | capability | Authors get a print-ready PDF of an item, passage or form, laid out in the program's house style by XPRT, from Abigail (through AD) or ADAM's legacy screens. |
| [secure-classroom-test-delivery](nodes/secure-classroom-test-delivery.md) | capability | Students launch AD tests from their LMS through ARC, optionally in a locked-down browser window; ARC tracks the attempt and AD plays and scores it. |

## abigail → ad (77)

| from | rel | to | note |
|---|---|---|---|
| [abigail:ad-client](../abigail/nodes/ad-client.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | Authenticate POST /api/oauth/token; 401 invalidates token and re-mints once |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | GetBank/SaveBank/bank_states proxies for /api/ad/banks/:bankID |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | ItemService List/Get/Save/Lock/pub_state/test_cases + metadata/standards/bulk routes |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | StimulusService shared_stims + resource handlers |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | FormService forms + SettingProfileService setting_profiles + test maps, form_scoring |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | MediaService media v2/upload/files, cached-media re-upload |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:standards-api](../ad/nodes/standards-api.md) | /api/ad/standards/* proxies |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:stats-api](../ad/nodes/stats-api.md) | historical/scoring stat set proxies, statistics/items |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:test-maps-api](../ad/nodes/test-maps-api.md) | battery_stms + battery_scoring proxies |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:oscar-api](../ad/nodes/oscar-api.md) | oscar-manifest, oscar-tenants, metametrics-test proxies |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:qti-packaging-api](../ad/nodes/qti-packaging-api.md) | StartQtiExport / StartQtiImport relay (4-min client) |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:xprt-api](../ad/nodes/xprt-api.md) | XPRT print handlers under /api/data/xprt |
| [abigail:ad-content](../abigail/nodes/ad-content.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | preview_token / practice_token → /api/delivery/launch_token |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | POST /api/oauth/token client_credentials scope=* — bearer cached 10 min per client id |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | /api/data/banks, bank_states, bank_initial_state, next_identifier_by_type |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | /api/data/banks/:id/items (+ v2, lock, test_cases, new_version, pub_state, item_clone, metadata/standards CSV, bulk ops, qti/generic_score) |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | shared_stims (+ v2, lock, clone, metadata, bulk) and resources (+ resource_clone) |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | forms (+ v2, new_version, pub_state, form_clone, history, scoring-validation, form_scoring, form_test_map), setting_profiles, print_item/form/stim |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | media (+ v2, upload) and files/upload |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:standards-api](../ad/nodes/standards-api.md) | /api/data/standards tree, authorities, by_number, displays, children/below |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:stats-api](../ad/nodes/stats-api.md) | historical_stat_sets, scoring_stat_sets, statistics/items, analytics/overview |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:test-maps-api](../ad/nodes/test-maps-api.md) | battery_stms (+ search), battery_scoring, form_sid_test_map |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:oscar-api](../ad/nodes/oscar-api.md) | oscar-manifest, oscar-tenants items/rubrics, metametrics-test |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:qti-packaging-api](../ad/nodes/qti-packaging-api.md) | qti export_start / job_progress / import_upload / import_start |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:xprt-api](../ad/nodes/xprt-api.md) | /api/data/xprt print_eligibility, print_start, print_job, entity_pdf |
| [abigail:ad-data-api](../abigail/nodes/ad-data-api.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /api/delivery/launch_token — preview and practice player JWTs |
| [abigail:ad-web-components](../abigail/nodes/ad-web-components.md) | embeds | [ad:ad-authoring](../ad/nodes/ad-authoring.md) | ${adHost}/public/ad-authoring.js (ad-item-editor, ad-stimulus-editor, ad-media-picker, ad-standards-picker) |
| [abigail:ad-web-components](../abigail/nodes/ad-web-components.md) | embeds | [ad:item-components](../ad/nodes/item-components.md) | ${adHost}/public/qti-item-components-v1.0.0.js |
| [abigail:ad-web-components](../abigail/nodes/ad-web-components.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | ${adHost}/public/ad-test-player.js on demand |
| [abigail:administration-service](../abigail/nodes/administration-service.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | batch item queries scoped to one AD form |
| [abigail:bank-admin](../abigail/nodes/bank-admin.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | ListBanks (sync), GetBank/SaveBank/SaveBankStates (copy config) |
| [abigail:bank-admin](../abigail/nodes/bank-admin.md) | calls | [ad:stats-api](../ad/nodes/stats-api.md) | GetBankDashboard → analytics/overview; GetHistoricalStatSet (gold set check) |
| [abigail:bank-secret](../abigail/nodes/bank-secret.md) | mirrors | [ad:bank-secret](../ad/nodes/bank-secret.md) | ad.BankSecret; secrets/:service (secret masked) |
| [abigail:bank](../abigail/nodes/bank.md) | mirrors | [ad:bank](../ad/nodes/bank.md) | banks.ad_banks_id — one Abigail row per AD bank; AD record edited via PUT /api/ad/banks/:bankID |
| [abigail:battery](../abigail/nodes/battery.md) | mirrors | [ad:battery-stm](../ad/nodes/battery-stm.md) | Go struct BatterySTM; battery_stms endpoints |
| [abigail:battery](../abigail/nodes/battery.md) | mirrors | [ad:battery-unit](../ad/nodes/battery-unit.md) | units[] |
| [abigail:battery](../abigail/nodes/battery.md) | mirrors | [ad:battery-objective](../ad/nodes/battery-objective.md) | objectives[] |
| [abigail:battery](../abigail/nodes/battery.md) | mirrors | [ad:battery-outcome](../ad/nodes/battery-outcome.md) | BatteryScoringInput → BatteryOutcome[] preview (not persisted) |
| [abigail:bulk-request-service](../abigail/nodes/bulk-request-service.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | ItemMetadataUploadService legacy UploadItemMetadata |
| [abigail:content-agent-proxy](../abigail/nodes/content-agent-proxy.md) | consumes | [ad:content-changed-callback](../ad/nodes/content-changed-callback.md) | POST /agent/ai/index-entity (X-Internal-Route-Token via AD callback-credential) — reindex item/form/stimulus/media |
| [abigail:extracts](../abigail/nodes/extracts.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | FormHydrator loads forms + adaptive section items |
| [abigail:extracts](../abigail/nodes/extracts.md) | calls | [ad:stats-api](../ad/nodes/stats-api.md) | HistoricalStatsClient for stats columns |
| [abigail:extracts](../abigail/nodes/extracts.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | bank custom fields for metadata columns |
| [abigail:form](../abigail/nodes/form.md) | mirrors | [ad:form](../ad/nodes/form.md) | Go struct ad.Form; PUT /api/data/banks/:id/forms |
| [abigail:form](../abigail/nodes/form.md) | mirrors | [ad:stm](../ad/nodes/stm.md) | form.stm nested scoring test map |
| [abigail:form](../abigail/nodes/form.md) | mirrors | [ad:section](../ad/nodes/section.md) | sections[] with form_items |
| [abigail:form](../abigail/nodes/form.md) | mirrors | [ad:form-oscar-mapping](../ad/nodes/form-oscar-mapping.md) | oscar_mappings saved with the form |
| [abigail:forms-ui](../abigail/nodes/forms-ui.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | ad-test-player preview/practice (FormPreviewLauncher, FormPracticeLauncher) |
| [abigail:historical-stat-set](../abigail/nodes/historical-stat-set.md) | mirrors | [ad:historical-stat-set](../ad/nodes/historical-stat-set.md) | HistoricalStatSet |
| [abigail:historical-stat-set](../abigail/nodes/historical-stat-set.md) | mirrors | [ad:historical-stat](../ad/nodes/historical-stat.md) | per-item HistoricalStat rows |
| [abigail:historical-stat-set](../abigail/nodes/historical-stat-set.md) | mirrors | [ad:stat-upload](../ad/nodes/stat-upload.md) | StatUpload |
| [abigail:item-test-case](../abigail/nodes/item-test-case.md) | mirrors | [ad:item-test-case](../ad/nodes/item-test-case.md) | ad.ItemTestCase; items/:id/test_cases |
| [abigail:item](../abigail/nodes/item.md) | mirrors | [ad:item](../ad/nodes/item.md) | Go struct ad.Item; read/written via /api/data/banks/:id/items |
| [abigail:item](../abigail/nodes/item.md) | mirrors | [ad:trait](../ad/nodes/trait.md) | traits[] nested on the item |
| [abigail:item](../abigail/nodes/item.md) | mirrors | [ad:item-history](../ad/nodes/item-history.md) | GetItemHistory rows |
| [abigail:items-ui](../abigail/nodes/items-ui.md) | embeds | [ad:ad-authoring](../ad/nodes/ad-authoring.md) | ad-item-editor, ad-media-picker, ad-standards-picker |
| [abigail:job-queue](../abigail/nodes/job-queue.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | TranslationService.SaveTranslatedItem, item metadata upload, test-case runs |
| [abigail:job-queue](../abigail/nodes/job-queue.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | TranslationService.SaveTranslatedPassageStandalone |
| [abigail:media-ui](../abigail/nodes/media-ui.md) | embeds | [ad:ad-authoring](../ad/nodes/ad-authoring.md) | ad-media-picker |
| [abigail:media](../abigail/nodes/media.md) | mirrors | [ad:media](../ad/nodes/media.md) | Go struct ad.Media |
| [abigail:resource](../abigail/nodes/resource.md) | mirrors | [ad:resource](../ad/nodes/resource.md) | Go struct ad.Resource |
| [abigail:review-service](../abigail/nodes/review-service.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | GetItem hydrates review item snapshots |
| [abigail:review-service](../abigail/nodes/review-service.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | GetSharedStimulus hydrates stimulus snapshots |
| [abigail:review-service](../abigail/nodes/review-service.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GetForm hydrates form snapshots |
| [abigail:review-service](../abigail/nodes/review-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | GetFormPreviewToken → POST /api/delivery/launch_token for reviewer form preview |
| [abigail:review-service](../abigail/nodes/review-service.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | GetMedia hydrates media snapshots |
| [abigail:reviews-ui](../abigail/nodes/reviews-ui.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | reviewer form preview (FormPreviewLauncher) |
| [abigail:scoring-stat-set](../abigail/nodes/scoring-stat-set.md) | mirrors | [ad:scoring-stat-set](../ad/nodes/scoring-stat-set.md) | ScoringStatSet |
| [abigail:scoring-stat-set](../abigail/nodes/scoring-stat-set.md) | mirrors | [ad:scoring-stat](../ad/nodes/scoring-stat.md) | per-item ScoringStat keyed by identifier |
| [abigail:setting-profile](../abigail/nodes/setting-profile.md) | mirrors | [ad:form-setting-profile](../ad/nodes/form-setting-profile.md) | Go struct FormSettingProfile; setting_profiles endpoints |
| [abigail:standard](../abigail/nodes/standard.md) | mirrors | [ad:standard](../ad/nodes/standard.md) | Go struct ad.Standard (read-only) |
| [abigail:stimuli-ui](../abigail/nodes/stimuli-ui.md) | embeds | [ad:ad-authoring](../ad/nodes/ad-authoring.md) | ad-stimulus-editor, ad-media-picker |
| [abigail:stimulus](../abigail/nodes/stimulus.md) | mirrors | [ad:shared-stimulus](../ad/nodes/shared-stimulus.md) | Go struct ad.SharedStimulus; shared_stims endpoints |
| [abigail:stimulus](../abigail/nodes/stimulus.md) | mirrors | [ad:shared-stimulus-history](../ad/nodes/shared-stimulus-history.md) | SharedStimulusHistory rows |
| [abigail:test-profile-service](../abigail/nodes/test-profile-service.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | batched item-count queries for feasibility validation |
| [abigail:test-profile-service](../abigail/nodes/test-profile-service.md) | calls | [ad:stats-api](../ad/nodes/stats-api.md) | historical stat uploads for statistics conditions |
| [abigail:workflow-state](../abigail/nodes/workflow-state.md) | mirrors | [ad:bank-state](../ad/nodes/bank-state.md) | Go struct ad.State; bank_states endpoints |

## ad → mre (1)

| from | rel | to | note |
|---|---|---|---|
| [ad:qti-engine](../ad/nodes/qti-engine.md) | calls | [mre:scoring-api](../mre/nodes/scoring-api.md) | MREScorer POST {MRE_HOST}/ws/stateless {clientUUID, clientSECRET, itemUUID, itemDefinition, candidateResponse, requestUUID, testUUID, admin (AD-5990)}; retries on status 2 / 5xx |

## ad → oscar (3)

| from | rel | to | note |
|---|---|---|---|
| [ad:oscar-api](../ad/nodes/oscar-api.md) | calls | [oscar:external-api](../oscar/nodes/external-api.md) | GET /v1/api/tenant/:t/manifest, item/:i, rubric/:r with X-Auth-Token (bank-secret service=oscar) |
| [ad:oscar-score](../ad/nodes/oscar-score.md) | mirrors | [oscar:response](../oscar/nodes/response.md) | one row per ExtScore in the callback ExtScorePayload.scores[] (score_id, score_type, trait_scores) for the AD response |
| [ad:oscar-scoring](../ad/nodes/oscar-scoring.md) | calls | [oscar:external-api](../oscar/nodes/external-api.md) | POST /v1/auth/token {clientId, clientSecret} → X-Auth-Token, then PATCH /v1/api/response (ExtResponse, callback_url = AD /api/scoring/oscar/callback) at save-off |

## ad → xprt (1)

| from | rel | to | note |
|---|---|---|---|
| [ad:xprt-orchestration](../ad/nodes/xprt-orchestration.md) | calls | [xprt:xprt-api](../xprt/nodes/xprt-api.md) | POST /xprt/api/item/v1/AD/submit/{jobId} (multipart zip + presigned S3 PUT URL, HS256 JWT with XPRT_KEY) then /item/v1/AD/polling/{jobId}; XPRT PUTs the PDF into AD_S3_INTERNAL |

## adam → abigail (1)

| from | rel | to | note |
|---|---|---|---|
| [adam:frontend-app](../adam/nodes/frontend-app.md) | calls | [abigail:web-client](../abigail/nodes/web-client.md) | sidebar ABIGAIL link opens ABIGAIL_URL in a new tab (AD enabled + role ad_banks >= 1, ADAM-706) |

## adam → ad (87)

| from | rel | to | note |
|---|---|---|---|
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | AdamADService token cached in Redis ad_oauth_token_<host>_<client_id>; ADClient fetches a fresh token per call |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | ListBanks/GetBank/SaveBank proxy and SyncADBank |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GetADForm/SyncADForms, form_clone for CloneTest, PrintForm |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | ListADItems, SyncItem/EnsureItem, saveTestItemTraits |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | ListADSharedStimuli |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:standards-api](../ad/nodes/standards-api.md) | authorities, standards/tree, standards/id (class-assignment standards) |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | RegisterStudentSession, LaunchPracticeTest, force submit/reseat state, FetchSessionResponses |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | ScoreClassAssignmentResponse PUT /api/scoring/responses/{id}/score |
| [adam:ad-delivery](../adam/nodes/ad-delivery.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | adPostStream POST /api/data/fetch_response_from_s3 (teacher plays student recording) |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | POST /api/oauth/token — client_credentials, scope *, per-tenant credentials.adam_ad_client_id/secret |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | POST /api/data/banks, GET/PUT /api/data/banks/{bank}, PUT bank_states (ad_migrate) |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | POST/GET /api/data/banks/{bank}/forms[/{form}], PUT forms (ad_migrate), PUT form_clone |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | POST/GET /api/data/banks/{bank}/items[/{item}], PUT items (ad_migrate) |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | POST/PUT /api/data/banks/{bank}/shared_stims, PUT resources (ad_migrate) |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | POST /api/data/banks/{bank}/media (ad_migrate), POST /api/data/fetch_response_from_s3 (recordings) |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:standards-api](../ad/nodes/standards-api.md) | GET /api/data/standards/authorities, id/{id}, children/{id}; POST /standards/tree, POST /standards |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /api/delivery/registerSession, launch_token; PUT sessions/{id}/state, section_change; POST sessions/current_info; GET sessions/{id}, responses/{id} |
| [adam:ad-platform](../adam/nodes/ad-platform.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | PUT /api/scoring/responses/{id}/score, POST /api/scoring/rescore |
| [adam:ad-section-sync-job](../adam/nodes/ad-section-sync-job.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /api/delivery/sessions/current_info (25 ids per call, against adam_ad_host) |
| [adam:ad-test-session](../adam/nodes/ad-test-session.md) | mirrors | [ad:session](../ad/nodes/session.md) | external_session_id / external_session_token from registerSession |
| [adam:ad-test-session](../adam/nodes/ad-test-session.md) | mirrors | [ad:response](../ad/nodes/response.md) | ad_test_session_item_results id = AD response id |
| [adam:ad-test-session](../adam/nodes/ad-test-session.md) | mirrors | [ad:response-trait-score](../ad/nodes/response-trait-score.md) | ad_test_session_item_trait_scores id = AD trait-score id |
| [adam:ad-test](../adam/nodes/ad-test.md) | mirrors | [ad:form](../ad/nodes/form.md) | ad_tests.form_id (AD form delivered to the class) |
| [adam:ad-test](../adam/nodes/ad-test.md) | mirrors | [ad:item](../ad/nodes/item.md) | ad_test_items local copy keyed by external_item_id |
| [adam:ad-test](../adam/nodes/ad-test.md) | mirrors | [ad:trait](../ad/nodes/trait.md) | ad_test_item_traits keyed by AD trait id |
| [adam:ad-test](../adam/nodes/ad-test.md) | mirrors | [ad:standard](../ad/nodes/standard.md) | ad_test_standards keyed by external_standard_id |
| [adam:adam-ad-api](../adam/nodes/adam-ad-api.md) | consumes | [ad:host-callback](../ad/nodes/host-callback.md) | POST /adam_ad/event — {entity_type, entity_id, session_id, bank_id}; unauthenticated |
| [adam:adam-ad-api](../adam/nodes/adam-ad-api.md) | consumes | [ad:content-changed-callback](../ad/nodes/content-changed-callback.md) | BANK/FORM/ITEM → AD_QTI_*_SYNC per client owning the AD bank; STIMULUS/MEDIA ignored |
| [adam:adam-ad-api](../adam/nodes/adam-ad-api.md) | consumes | [ad:session-scored-callback](../ad/nodes/session-scored-callback.md) | SESSION → QueueSessionForSaveoff on ADAM_SCORING_SQS_URL |
| [adam:adam-ad-api](../adam/nodes/adam-ad-api.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | GET /adam_ad/oauth/token hands the tenant AD token + host to the browser |
| [adam:admin-service](../adam/nodes/admin-service.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | RescoreAdmin POST /api/scoring/rescore |
| [adam:admin-service](../adam/nodes/admin-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | admin submit — PUT /api/delivery/sessions/{id}/state |
| [adam:fe-api-client](../adam/nodes/fe-api-client.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | adam_ad/bank_service, bank_state_service direct to AD host |
| [adam:fe-api-client](../adam/nodes/fe-api-client.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | adam_ad/form_service direct |
| [adam:fe-api-client](../adam/nodes/fe-api-client.md) | calls | [ad:standards-api](../ad/nodes/standards-api.md) | adam_ad/standard_service direct |
| [adam:fe-api-client](../adam/nodes/fe-api-client.md) | calls | [ad:labels-api](../ad/nodes/labels-api.md) | adam_ad/label_bundle_service direct |
| [adam:fe-class-assignments-ui](../adam/nodes/fe-class-assignments-ui.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | ClassAssignmentEdit PUT/GET /api/data/banks/:b/forms (browser, AD token) |
| [adam:fe-class-assignments-ui](../adam/nodes/fe-class-assignments-ui.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | ClassAssignmentSelectItems POST /api/data/banks/:b/items |
| [adam:fe-class-assignments-ui](../adam/nodes/fe-class-assignments-ui.md) | calls | [ad:standards-api](../ad/nodes/standards-api.md) | authorities, standards/below/bank/:b/standard/:id |
| [adam:fe-item-analysis-ui](../adam/nodes/fe-item-analysis-ui.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | PrintModal ADService.getItem direct |
| [adam:fe-test-management-ui](../adam/nodes/fe-test-management-ui.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | TestEditGeneralSettings POST /api/data/banks/:b/forms direct |
| [adam:legacy-classroom-ui](../adam/nodes/legacy-classroom-ui.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | ADService.getForm/createForm direct |
| [adam:legacy-classroom-ui](../adam/nodes/legacy-classroom-ui.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | getItems POST /api/data/banks/:b/items |
| [adam:legacy-my-classes-ui](../adam/nodes/legacy-my-classes-ui.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | ADService.postScore PUT /api/scoring/responses/:id/score from the browser |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | direct <adam-ad-host>/api/data/banks with adam-ad-token |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | ADFormEdit — forms, form_clone, form_history, form_reviewer, form_scoring, print_form |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | ADSharedStimEdit / ADResourceEdit |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | ADMediaEdit media, media/upload |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:stats-api](../ad/nodes/stats-api.md) | ADStatsList / ADStatsItem statistics/* |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:xprt-api](../ad/nodes/xprt-api.md) | xprt/upload, pdf, auth |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:ai-api](../ad/nodes/ai-api.md) | translate_stimulus |
| [adam:legacy-qti-ad-authoring-ui](../adam/nodes/legacy-qti-ad-authoring-ui.md) | calls | [ad:test-maps-api](../ad/nodes/test-maps-api.md) | form_sid_test_map export |
| [adam:legacy-qti-item-editor-ui](../adam/nodes/legacy-qti-item-editor-ui.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | ADItemEdit — items, items/:id/lock, qti/generic_score |
| [adam:legacy-qti-item-editor-ui](../adam/nodes/legacy-qti-item-editor-ui.md) | calls | [ad:ai-api](../ad/nodes/ai-api.md) | translate |
| [adam:legacy-qti-item-editor-ui](../adam/nodes/legacy-qti-item-editor-ui.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | print_item |
| [adam:legacy-qti-item-editor-ui](../adam/nodes/legacy-qti-item-editor-ui.md) | embeds | [ad:item-components](../ad/nodes/item-components.md) | loadQTILibraries.js loads qti-item-components-v1.0.0.js for preview |
| [adam:legacy-shell-ui](../adam/nodes/legacy-shell-ui.md) | embeds | [ad:player-ui](../ad/nodes/player-ui.md) | ADTestPlayer.vue — register token → <ad-test-player>.init, progress on updateTestState |
| [adam:legacy-tester-ui](../adam/nodes/legacy-tester-ui.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | /tester/ad_launch.html staff preview with ad-player-token |
| [adam:proctor-service](../adam/nodes/proctor-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | ProcessADStatus POST /api/delivery/sessions/current_info |
| [adam:program-outcome](../adam/nodes/program-outcome.md) | mirrors | [ad:session-outcome](../ad/nodes/session-outcome.md) | session_outcomes upserted on (session_id, objective_key) from AD session_outcomes |
| [adam:qti-api](../adam/nodes/qti-api.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | PreviewForm use_new_player → POST /api/delivery/launch_token (PlayerPreview JWT) |
| [adam:qti-bank](../adam/nodes/qti-bank.md) | mirrors | [ad:bank](../ad/nodes/bank.md) | AD-synced banks (external_bank_id); EnsureBank, name "<AD name> (AD)", custom_fields split by content_type |
| [adam:qti-form](../adam/nodes/qti-form.md) | mirrors | [ad:form](../ad/nodes/form.md) | form_type=ad rows keyed by ad_external_form_id; EnsureForm from GET /api/data/banks/{bank}/forms/{form} |
| [adam:qti-item-result](../adam/nodes/qti-item-result.md) | mirrors | [ad:response](../ad/nodes/response.md) | AD rows via doSyncAD; external_response_id = AD response id (used for human-score push) |
| [adam:qti-item-result](../adam/nodes/qti-item-result.md) | mirrors | [ad:response-trait-score](../ad/nodes/response-trait-score.md) | qti_trait_scores from AD response_trait_scores (trait matched on ad_external_id) |
| [adam:qti-item](../adam/nodes/qti-item.md) | mirrors | [ad:item](../ad/nodes/item.md) | AD-synced rows keyed by (client_id, ad_external_item_id); EnsureItem, item_status OP |
| [adam:results-service](../adam/nodes/results-service.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | PostScoreQTI → PUT /api/scoring/responses/{external_response_id}/score |
| [adam:role-service](../adam/nodes/role-service.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | FetchADRoleBanks via AdamADService.ListBanks |
| [adam:saveoff-service](../adam/nodes/saveoff-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | doSyncAD GET /api/delivery/sessions/{external_login_key}?cow=true |
| [adam:saveoff-service](../adam/nodes/saveoff-service.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | syncOscarItemsToAD / SubmitHumanScore PUT /api/scoring/responses/{id}/score |
| [adam:scripts-content-migration](../adam/nodes/scripts-content-migration.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | ad_migrate SaveBankState |
| [adam:scripts-content-migration](../adam/nodes/scripts-content-migration.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | ad_migrate SaveItem |
| [adam:scripts-content-migration](../adam/nodes/scripts-content-migration.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | ad_migrate SaveForm |
| [adam:scripts-content-migration](../adam/nodes/scripts-content-migration.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | ad_migrate SaveSharedStim/SaveResource |
| [adam:scripts-content-migration](../adam/nodes/scripts-content-migration.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | ad_migrate SaveMedia |
| [adam:scripts-session-repairs](../adam/nodes/scripts-session-repairs.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | backfillUnattemptedItemScores PUT /api/scoring/responses/{id}/score |
| [adam:session-service](../adam/nodes/session-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | registerADSession, PUT state in UpdateStates, PUT section_change in MoveSectionForSession |
| [adam:session](../adam/nodes/session.md) | mirrors | [ad:session](../ad/nodes/session.md) | platform=AD sessions; external_login_key = AD session id |
| [adam:session](../adam/nodes/session.md) | mirrors | [ad:session-section](../ad/nodes/session-section.md) | session_sections from current_info (section_code = AD section identifier) |
| [adam:standard](../adam/nodes/standard.md) | mirrors | [ad:standard](../ad/nodes/standard.md) | same Academic Benchmarks GUID ids; SyncStandard inserts AD standards ON CONFLICT (id) |
| [adam:tester-api](../adam/nodes/tester-api.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | adLaunch — registerSession, PUT state, section_change |
| [adam:tester-api](../adam/nodes/tester-api.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | src/template/ad_delivery.html, ad_practice.html, ad_readaloud.html host <ad-test-player> |
| [adam:tester-service](../adam/nodes/tester-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | RegisterSession + SetState in adLaunch (CAT retest settings, admin-code suffix) |
| [adam:tester-test-player-ui](../adam/nodes/tester-test-player-ui.md) | embeds | [ad:player-ui](../ad/nodes/player-ui.md) | ClassTestPlayerView/AdPreviewView — <ad-test-player>.init(token), updateTestState events |
| [adam:tester-ui-components](../adam/nodes/tester-ui-components.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | useADPlayerScripts loads <host>/public/ad-test-player.js |
| [adam:tester-ui-components](../adam/nodes/tester-ui-components.md) | embeds | [ad:item-components](../ad/nodes/item-components.md) | loads qti-item-components-v1.0.0.js before the player |
| [adam:trait](../adam/nodes/trait.md) | mirrors | [ad:trait](../ad/nodes/trait.md) | qti_traits.ad_external_id; synced from AD item traits, removed when gone from AD |

## adam → cow (5)

| from | rel | to | note |
|---|---|---|---|
| [adam:cow-service](../adam/nodes/cow-service.md) | calls | [cow:reporting-api](../cow/nodes/reporting-api.md) | GET {COW_URL}/reporting/v1/elk/{sessionID} — Authorization raw idToken, 10 workers |
| [adam:cow-service](../adam/nodes/cow-service.md) | calls | [cow:platform-tenant-management-api](../cow/nodes/platform-tenant-management-api.md) | POST {COW_AUTH_URL}/idToken client_credentials |
| [adam:cow](../adam/nodes/cow.md) | calls | [cow:reporting-api](../cow/nodes/reporting-api.md) | GET /reporting/v1/elk/{externalLoginKey} with ADAM session ids |
| [adam:cow](../adam/nodes/cow.md) | calls | [cow:platform-tenant-management-api](../cow/nodes/platform-tenant-management-api.md) | POST /idToken (COW_CLIENT_ID / COW_CLIENT_SECRET) |
| [adam:report-asset](../adam/nodes/report-asset.md) | mirrors | [cow:adam-manifest-row](../cow/nodes/adam-manifest-row.md) | report_assets rows imported from COW manifest CSV (imported/<program>/<admin>/…_manifest.csv) via COW_REPORT_ASSETS_IMPORT → REPORT_ASSETS_IMPORT; same 13 columns |

## adam → lp (16)

| from | rel | to | note |
|---|---|---|---|
| [adam:academic-session](../adam/nodes/academic-session.md) | mirrors | [lp:academic-session](../lp/nodes/academic-session.md) | upserted by ConvertAcademicSessionLaunchpadToAdam; sourced_id = LPI |
| [adam:class](../adam/nodes/class.md) | mirrors | [lp:class](../lp/nodes/class.md) | upserted by ConvertClassLaunchpadToAdam; sourced_id = LPI |
| [adam:class](../adam/nodes/class.md) | mirrors | [lp:enrollment](../lp/nodes/enrollment.md) | user_classes rows written by SyncEnrollments; user_classes.sourced_id = enrollment LPI |
| [adam:course](../adam/nodes/course.md) | mirrors | [lp:course](../lp/nodes/course.md) | upserted by ConvertCourseLaunchpadToAdam; sourced_id = LPI |
| [adam:demographics](../adam/nodes/demographics.md) | mirrors | [lp:demographic](../lp/nodes/demographic.md) | upserted by ConvertDemographicsLaunchpadToAdam keyed by user_sourced_id (LP demographic sourcedId = user LPI) |
| [adam:launchpad-auth-api](../adam/nodes/launchpad-auth-api.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | /lp/login redirects to /auth/oidc/authorize; /lp/callback exchanges the code at /auth/oidc/oauth/token and reads /auth/oidc/userinfo sub (LPI) matched to users.sourced_id |
| [adam:launchpad](../adam/nodes/launchpad.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | roster pull — POST /api/external/oauth2/token (client_credentials) then GET /api/external/{orgs.launchpad_client_id}/ims/oneroster/rostering/v1p2/ orgs, academicSessions, courses, classes, users, enrollments, demographics (+ /stats, single object by sourcedId) |
| [adam:launchpad](../adam/nodes/launchpad.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | gradebook push POST .../categories, .../lineitems, .../results — LP serves no such routes (GET-only API, gradebook tables dropped 2025-04) |
| [adam:launchpad](../adam/nodes/launchpad.md) | consumes | [lp:roster-change-notification](../lp/nodes/roster-change-notification.md) | NotificationMessage POSTed to ADAM /ims/oneroster/rostering/v1p2/sync |
| [adam:launchpad](../adam/nodes/launchpad.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | Launchpad SSO — /auth/oidc/authorize, /auth/oidc/oauth/token, /auth/oidc/userinfo (sub = LPI) |
| [adam:oneroster-data-api](../adam/nodes/oneroster-data-api.md) | consumes | [lp:roster-change-notification](../lp/nodes/roster-change-notification.md) | POST /ims/oneroster/rostering/v1p2/sync — LP notifier gets its bearer from this API /oauth/token (app_subscriptions.notification_info.oauthUrl) with ADAM oauth_credentials |
| [adam:org](../adam/nodes/org.md) | mirrors | [lp:org](../lp/nodes/org.md) | orgs with sync_type launchpad upserted by ConvertOrgLaunchpadToAdam; sourced_id = LP sourcedId (LPI) |
| [adam:roster-sync](../adam/nodes/roster-sync.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | LaunchpadSyncService full/delta pull (filter dateLastModified>watermark) + /stats counts + GetObject for real-time sync |
| [adam:roster-sync](../adam/nodes/roster-sync.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | LaunchpadCategoriesService POST categories / lineitems / results — routes absent in LP |
| [adam:user](../adam/nodes/user.md) | mirrors | [lp:user](../lp/nodes/user.md) | upserted by ConvertUserLaunchpadToAdam; sourced_id = LPI (also username for students) |
| [adam:user](../adam/nodes/user.md) | mirrors | [lp:role](../lp/nodes/role.md) | user_orgs rows (non-manual) rebuilt from LP roles; role_sourced_id = role LPI |

## adam → mot (6)

| from | rel | to | note |
|---|---|---|---|
| [adam:mot-order](../adam/nodes/mot-order.md) | mirrors | [mot:order](../mot/nodes/order.md) | mot_orders.order_number sent to MOT as customerOrderId (postOrder); status synced back by customer order id |
| [adam:mot-order](../adam/nodes/mot-order.md) | mirrors | [mot:distribution](../mot/nodes/distribution.md) | mot_distributions rows synced from /api/motOrder/getDistributions* (distribution_id, distribution_code, name, orders_type) |
| [adam:mot](../adam/nodes/mot.md) | calls | [mot:mot-orders-api](../mot/nodes/mot-orders-api.md) | /api/motOrder/* (distributions, material items AO, enrollment buckets, customer attributes, record types, postOrder, getOrderStatusByCustomerOrderId, orderdetails) and /api/student/postStudent; OAuth2 client credentials |
| [adam:mot](../adam/nodes/mot.md) | calls | [mot:mot-tracking-api](../mot/nodes/mot-tracking-api.md) | /api/getCarrierCodes, trackdetailshistorybynum, tracknumsbyprogram, tracknumsbycdspage |
| [adam:mot](../adam/nodes/mot.md) | calls | [mot:test-admin-api](../mot/nodes/test-admin-api.md) | CONFIG /api/testAdmin/getProgramNumber (GetProgramByNumber) |
| [adam:mot](../adam/nodes/mot.md) | calls | [mot:program-api](../mot/nodes/program-api.md) | CONFIG /api/progConfig/getProgram (ListPrograms, no auth) |

## adam → oscar (1)

| from | rel | to | note |
|---|---|---|---|
| [adam:oscar](../adam/nodes/oscar.md) | calls | [oscar:external-api](../oscar/nodes/external-api.md) | PATCH {OSCAR_URL} (= /v1/api/response) with HTTP Basic OSCAR_USERNAME/PASSWORD, callback_url {APP_URL}/v1/api/score; GET {OSCAR_HOST}/v1/api/tenant/{t}/manifest for the test picker |

## arc → ad (25)

| from | rel | to | note |
|---|---|---|---|
| [arc:ad-api](../arc/nodes/ad-api.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | POST /api/oauth/token client_credentials, scope=* |
| [arc:ad-api](../arc/nodes/ad-api.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | POST /api/data/banks/ (ListBanks) |
| [arc:ad-api](../arc/nodes/ad-api.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GET /api/data/banks/{bank}/forms_light and /forms/{form} |
| [arc:ad-api](../arc/nodes/ad-api.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /registerSession, PUT /sessions/{id}/state, GET /sessions/{id}, POST /sessions/current_info |
| [arc:ad-api](../arc/nodes/ad-api.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | POST /api/scoring/rescore {session_ids} |
| [arc:ad-api](../arc/nodes/ad-api.md) | consumes | [ad:host-callback](../ad/nodes/host-callback.md) | session callback to $APP_URL/api/ad/event |
| [arc:ad-client](../arc/nodes/ad-client.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | POST /api/oauth/token — token cached per connection ≤5 min |
| [arc:ad-event-webhook](../arc/nodes/ad-event-webhook.md) | consumes | [ad:host-callback](../ad/nodes/host-callback.md) | POST /api/ad/event — per-session callback_url set at registerSession; only session_id read |
| [arc:admin](../arc/nodes/admin.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | POST /api/data/banks/ via ADConfigService |
| [arc:admin](../arc/nodes/admin.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GET forms_light and full form (STM for primary-outcome picker) |
| [arc:app-backend](../arc/nodes/app-backend.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | POST /api/scoring/rescore via ScoreService.RescoreAttempts |
| [arc:app-backend](../arc/nodes/app-backend.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | PUT /sessions/{id}/state via AttemptService.ResetAttempt |
| [arc:async-workers](../arc/nodes/async-workers.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | GET /sessions/{attempt id} on saveoff |
| [arc:attempt-outcome](../arc/nodes/attempt-outcome.md) | mirrors | [ad:session-outcome](../ad/nodes/session-outcome.md) | copied from GET /sessions/{id} session_outcomes at saveoff |
| [arc:attempt-response](../arc/nodes/attempt-response.md) | mirrors | [ad:response](../ad/nodes/response.md) | copied from GET /sessions/{id} responses at saveoff |
| [arc:attempt](../arc/nodes/attempt.md) | mirrors | [ad:session](../ad/nodes/session.md) | attempt.id = AD session id; form_id, player_status, scoring_status copied from AD |
| [arc:connection](../arc/nodes/connection.md) | mirrors | [ad:credential](../ad/nodes/credential.md) | settings.client_id / client_secret — one AD account credential per connection |
| [arc:delivery](../arc/nodes/delivery.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /registerSession (session_id = attempt id, callback_url, pnp, cat_settings) and PUT /sessions/{id}/state IN_PROGRESS |
| [arc:delivery](../arc/nodes/delivery.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GET /banks/{bank}/forms/{form} for CAT section settings |
| [arc:learner-ui](../arc/nodes/learner-ui.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | {connection host}/public/ad-test-player.js — <ad-test-player> |
| [arc:learner-ui](../arc/nodes/learner-ui.md) | embeds | [ad:player-ui](../ad/nodes/player-ui.md) | exposed.init(launch_token); listens updateSessionState / updateTestState |
| [arc:learner-ui](../arc/nodes/learner-ui.md) | embeds | [ad:item-components](../ad/nodes/item-components.md) | {connection host}/public/qti-item-components-v1.0.0.js |
| [arc:legacy-session-outcome](../arc/nodes/legacy-session-outcome.md) | mirrors | [ad:session-outcome](../ad/nodes/session-outcome.md) | dead table — same shape as session_outcomes |
| [arc:proctoring](../arc/nodes/proctoring.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /sessions/current_info (≤25 ids) and PUT /sessions/{id}/state |
| [arc:resource](../arc/nodes/resource.md) | mirrors | [ad:form](../ad/nodes/form.md) | forms[] {bank, id, accom, primary_outcome} — 1..n AD forms (Default/Spanish) |

## cf → oscar (9)

| from | rel | to | note |
|---|---|---|---|
| [cf:cf-admin](../cf/nodes/cf-admin.md) | mirrors | [oscar:project](../oscar/nodes/project.md) | OSCAR project.iea_project.projectId sent as adminName (system_integration CreateProject) |
| [cf:cf-prompt](../cf/nodes/cf-prompt.md) | mirrors | [oscar:item](../oscar/nodes/item.md) | OSCAR item.cf_config.item_id sent as itemId, matched via aliases (system_integration CreateItem) |
| [cf:cf-response](../cf/nodes/cf-response.md) | mirrors | [oscar:response](../oscar/nodes/response.md) | OSCAR RequestScore POST /v1/response; testId = OSCAR responseId "<ref_id>#<_id>" |
| [cf:external-client-driver](../cf/nodes/external-client-driver.md) | calls | [oscar:iea-callback-api](../oscar/nodes/iea-callback-api.md) | SendScore POST /iea/v1/outcome, SendLidScore /iea/v1/outcome/lid, RequestAdditionalHumanScores /iea/v1/score/request (via tags.outcomeEndpoint); oscardriver POST /iea/v1/workflow/state |
| [cf:external-client-driver](../cf/nodes/external-client-driver.md) | calls | [oscar:external-api](../oscar/nodes/external-api.md) | AuthStandard / oscardriver.Auth POST /iea/v1/auth {clientToken, clientSecret} for X-Auth-Token |
| [cf:iea](../cf/nodes/iea.md) | mirrors | [oscar:cf](../oscar/nodes/cf.md) | same engine naming (IEA / CF / KT) as OSCAR uses it |
| [cf:lid](../cf/nodes/lid.md) | mirrors | [oscar:lid](../oscar/nodes/lid.md) | LID alert CF raises and OSCAR receives on /iea/v1/outcome/lid |
| [cf:oscar](../cf/nodes/oscar.md) | calls | [oscar:iea-callback-api](../oscar/nodes/iea-callback-api.md) | /iea/v1/outcome, /outcome/lid, /score/request, /workflow/state (sent by external-client-driver) |
| [cf:qc-score](../cf/nodes/qc-score.md) | mirrors | [oscar:qc-score](../oscar/nodes/qc-score.md) | OSCAR QC scores reported via POST /v1/outcome (responseId "<oid>#<ref>") |

## cow → adam (30)

| from | rel | to | note |
|---|---|---|---|
| [cow:adam-manifest-row](../cow/nodes/adam-manifest-row.md) | mirrors | [adam:report-asset](../adam/nodes/report-asset.md) | one manifest row = one report_assets row imported by COW_REPORT_ASSETS_IMPORT → REPORT_ASSETS_IMPORT |
| [cow:adam](../cow/nodes/adam.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | read-only COW reader endpoints adam-*-cow-ro (JDBC from Glue jobs and the ECS worker) |
| [cow:adam](../cow/nodes/adam.md) | calls | [adam:oneroster-data-api](../adam/nodes/oneroster-data-api.md) | legacy DataIngestApp — OAuth client_credentials token then GET .../orgs, students, teachers, sessions, battery_scores |
| [cow:adam](../cow/nodes/adam.md) | shares | [adam:s3](../adam/nodes/s3.md) | COW delivers extracts + _manifest.csv into adam-*-internal buckets under imported/<program>/<admin>/ |
| [cow:admin-client](../cow/nodes/admin-client.md) | mirrors | [adam:client](../adam/nodes/client.md) | CLIENTS_TABLE keyed by ADAM clients.id (datasource_id) |
| [cow:battery-attempt](../cow/nodes/battery-attempt.md) | mirrors | [adam:student-battery](../adam/nodes/student-battery.md) | battery_uuid = student_batteries.id (battery_scores query) |
| [cow:class](../cow/nodes/class.md) | mirrors | [adam:class](../adam/nodes/class.md) | hub_class.class_id = classes.sourced_id; enrollments from user_classes |
| [cow:data-oneroster-payload](../cow/nodes/data-oneroster-payload.md) | mirrors | [adam:session](../adam/nodes/session.md) | sessions page of GET .../sessions (plus user / org / class pages of the same API) |
| [cow:etl-adam-db-connection](../cow/nodes/etl-adam-db-connection.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | ADAMDBEnv → Secrets Manager ARN + *-cow-ro reader host |
| [cow:etl-datasource-id](../cow/nodes/etl-datasource-id.md) | mirrors | [adam:client](../adam/nodes/client.md) | datasource_id = ADAM clients.id |
| [cow:etl-ecs-worker](../cow/nodes/etl-ecs-worker.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | Worker.java streams the same entity SQL from the ADAM read replica to S3 CSV |
| [cow:etl-external-login-key](../cow/nodes/etl-external-login-key.md) | mirrors | [adam:external-login-key](../adam/nodes/external-login-key.md) | same term — sessions.external_login_key |
| [cow:etl-ingest-orchestrator](../cow/nodes/etl-ingest-orchestrator.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | PostgresWarmupLambda pings the ADAM DB secrets before an ingest |
| [cow:etl-validation-framework](../cow/nodes/etl-validation-framework.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | AdamValidator runs every sql_queries entity SELECT against ADAM |
| [cow:external-score](../cow/nodes/external-score.md) | mirrors | [adam:qti-item-result](../adam/nodes/qti-item-result.md) | qti_external_scores rows (ref_id, rater_id, trait_scores) |
| [cow:glue-adam-extract-jobs](../cow/nodes/glue-adam-extract-jobs.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | ADAM-direct extracts via pws.adam_utils.get_adam_db_info (prd-account secrets) |
| [cow:glue-ingest-jobs](../cow/nodes/glue-ingest-jobs.md) | shares | [adam:postgres](../adam/nodes/postgres.md) | JDBC per-entity SELECTs from pws/sql_queries.py (sessions, users, orgs, classes, qti_item_results, session_outcomes ...) |
| [cow:item-outcome](../cow/nodes/item-outcome.md) | mirrors | [adam:trait](../adam/nodes/trait.md) | item_outcome_id = qti_traits.external_id (item_outcomes query) |
| [cow:item](../cow/nodes/item.md) | mirrors | [adam:qti-item](../adam/nodes/qti-item.md) | item_id = qti_item_results.qti_item_reference (item identifier) per qti_forms.identifier |
| [cow:oneroster-ingest-app](../cow/nodes/oneroster-ingest-app.md) | calls | [adam:oneroster-data-api](../adam/nodes/oneroster-data-api.md) | POST {api_base}/oauth/token client_credentials; GET {api_base}/<entity>?limit&offset&modifiedAfter |
| [cow:organization](../cow/nodes/organization.md) | mirrors | [adam:org](../adam/nodes/org.md) | hub_organization.organization_id = orgs.sourced_id |
| [cow:person](../cow/nodes/person.md) | mirrors | [adam:user](../adam/nodes/user.md) | hub_person from users (students/teachers) — person_id = sourced_id, adam_student_uuid = users.id |
| [cow:person](../cow/nodes/person.md) | mirrors | [adam:demographics](../adam/nodes/demographics.md) | sat_student_demographic from demographics by user_sourced_id |
| [cow:proctor-group](../cow/nodes/proctor-group.md) | mirrors | [adam:proctor-group](../adam/nodes/proctor-group.md) | proctor_group_id = proctor_groups.id (sessions query) |
| [cow:reporting-delivery-lambdas](../cow/nodes/reporting-delivery-lambdas.md) | shares | [adam:s3](../adam/nodes/s3.md) | deliverAdamToS3 cross-account copy + createAdamManifest CSV into adam_bucket (adam-*-internal) imported/ prefix |
| [cow:result-category](../cow/nodes/result-category.md) | mirrors | [adam:program-outcome](../adam/nodes/program-outcome.md) | resultcategory_category = session_outcomes / program_outcomes objective_key; sat_link_testattempt_result lower_bound / upper_bound / level from session_outcomes (AD SEM bounds, COW-4552) |
| [cow:test-attempt](../cow/nodes/test-attempt.md) | mirrors | [adam:session](../adam/nodes/session.md) | hub_testattempt.testattempt_id = sessions.id (sql_queries sessions) |
| [cow:test-attempt](../cow/nodes/test-attempt.md) | mirrors | [adam:accommodation](../adam/nodes/accommodation.md) | sat_testattempt_accommodation flattens sessions.accommodations (PNP) |
| [cow:tools-analytics](../cow/nodes/tools-analytics.md) | mirrors | [adam:qti-item-result](../adam/nodes/qti-item-result.md) | tools_analytics_id = qti_item_results.id; blob = qti_item_results.source |
| [cow:warehouse-reference-table](../cow/nodes/warehouse-reference-table.md) | mirrors | [adam:client](../adam/nodes/client.md) | ref_accountability_codes from clients.acc_codes |

## cow → lp (5)

| from | rel | to | note |
|---|---|---|---|
| [cow:forensics-api](../cow/nodes/forensics-api.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | /auth/login → authorize, /auth/logout → end_session_endpoint |
| [cow:forensics-auth](../cow/nodes/forensics-auth.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | authlib PKCE S256 login; tenant = clientId claim |
| [cow:forensics-auth](../cow/nodes/forensics-auth.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | lookup_scope GET users/{sub} roles → orgs/{sourcedId} (type, identifier) |
| [cow:forensics-launchpad](../cow/nodes/forensics-launchpad.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | issuer {APP_URL}/auth/oidc — discovery, authorize, token, userinfo, logout (claims sub = LPI, clientId = LP client) |
| [cow:forensics-launchpad](../cow/nodes/forensics-launchpad.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | POST /api/external/oauth2/token client_credentials; GET /api/external/{clientId}/ims/oneroster/rostering/v1p2/users/{sub}, /orgs/{sourcedId} |

## cow → navvy (1)

| from | rel | to | note |
|---|---|---|---|
| [cow:navvy-db-connection](../cow/nodes/navvy-db-connection.md) | shares | [navvy:postgres](../navvy/nodes/postgres.md) | read-only reader endpoint navvy-cow-ro (us-east-2, navvy-prd account); connectivity check only so far |

## navvy → ad (36)

| from | rel | to | note |
|---|---|---|---|
| [navvy:ad-callback-api](../navvy/nodes/ad-callback-api.md) | consumes | [ad:session-scored-callback](../ad/nodes/session-scored-callback.md) | POST /api/callbacks/ad/score_complete — entity_type SESSION / entity_status SCORE_COMPLETE |
| [navvy:ad-callback-api](../navvy/nodes/ad-callback-api.md) | consumes | [ad:host-callback](../ad/nodes/host-callback.md) | callbackUrl registered per session in registerSession |
| [navvy:ad-score-complete](../navvy/nodes/ad-score-complete.md) | mirrors | [ad:session-scored-callback](../ad/nodes/session-scored-callback.md) | ADCallbackPayload {entity_type, entity_id, entity_status, event_time, bank_id, session_id} |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:auth-api](../ad/nodes/auth-api.md) | POST /api/oauth/token — client-credentials bearer (backend host) |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | POST /api/data/banks — Banks |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | POST /api/data/banks/:bank/items and GET /api/data/banks/:bank/items/:item — Items, Item |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | POST /api/data/banks/:bank/shared_stims — Stimulus |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | POST/GET /api/data/banks/:bank/forms[/:form] and PUT /api/data/banks/:bank/form_by_item_ids — Forms, Form, GenerateForm |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | POST /api/data/fetch_response_from_s3 — ORF miscue audio |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | /api/delivery registerSession, launch_token, sessions[/:id], sessions/:id/state, responses/:session, delete_file |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | POST /api/scoring/rescore — Rescore |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /api/delivery/player/response and GET /api/delivery/player/form/:id with the student's player token — PostPlayerResponse, PlayerForm (writing practice draft prefill) |
| [navvy:adam-ad](../navvy/nodes/adam-ad.md) | calls | [ad:adam-ad](../ad/nodes/adam-ad.md) | AD Go server, backend + delivery hosts (ADAM_AD_BACKEND_API_URL / ADAM_AD_DELIVERY_API_URL) |
| [navvy:adam-item-sync](../navvy/nodes/adam-item-sync.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | POST /api/data/banks |
| [navvy:adam-item-sync](../navvy/nodes/adam-item-sync.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | POST /api/data/banks/:bank/items (paged) |
| [navvy:adam-item-sync](../navvy/nodes/adam-item-sync.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | POST /api/data/banks/:bank/shared_stims (stimulus metadata) |
| [navvy:assessment-form](../navvy/nodes/assessment-form.md) | mirrors | [ad:form](../ad/nodes/form.md) | ad_form_id / ad_form_identifier; fixed form in assessment ad_bank_id |
| [navvy:assessment-tts](../navvy/nodes/assessment-tts.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GET /api/data/banks/:bank/forms/:form — form_settings tts flags (authored in Abigail) |
| [navvy:assessments-api](../navvy/nodes/assessments-api.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GET /api/data/banks/:bank/forms/:form — enrich ad_form_identifier |
| [navvy:assessments-service](../navvy/nodes/assessments-service.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | GET /api/data/banks/:bank/forms/:form and forms-by-identifier — fixed forms |
| [navvy:assessments-service](../navvy/nodes/assessments-service.md) | calls | [ad:banks-api](../ad/nodes/banks-api.md) | POST /api/data/banks — resolve subject bank by name |
| [navvy:assessments-service](../navvy/nodes/assessments-service.md) | calls | [ad:stimuli-api](../ad/nodes/stimuli-api.md) | POST /api/data/banks/:bank/shared_stims |
| [navvy:assessments-service](../navvy/nodes/assessments-service.md) | calls | [ad:items-api](../ad/nodes/items-api.md) | GET /api/data/banks/:bank/items/:item — SyncItemFromADAM for unknown items |
| [navvy:assessments-service](../navvy/nodes/assessments-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /api/delivery/registerSession (RegisterExistingSession) and POST /api/delivery/launch_token |
| [navvy:external-integrations](../navvy/nodes/external-integrations.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | GET /api/delivery/sessions/:id — SCALE_SCORE + SEM outcomes for MetaMetrics |
| [navvy:form](../navvy/nodes/form.md) | mirrors | [ad:form](../ad/nodes/form.md) | ad_form_id; AD dynamic form generated by PUT form_by_item_ids |
| [navvy:item](../navvy/nodes/item.md) | mirrors | [ad:item](../ad/nodes/item.md) | adam_item_id; upserted from POST /api/data/banks/:bank/items by adam-item-sync |
| [navvy:student-testing-ui](../navvy/nodes/student-testing-ui.md) | embeds | [ad:adam-player](../ad/nodes/adam-player.md) | ad-test-player.js from https://ad.adamexam.com/public/ (prod) or coread-stg-dev |
| [navvy:student-testing-ui](../navvy/nodes/student-testing-ui.md) | embeds | [ad:player-ui](../ad/nodes/player-ui.md) | <ad-test-player> custom element, init(launch token) / host DOM events |
| [navvy:testing-session-response](../navvy/nodes/testing-session-response.md) | mirrors | [ad:response](../ad/nodes/response.md) | rebuilt from GET /api/delivery/responses/:session; no AD response id kept |
| [navvy:testing-session](../navvy/nodes/testing-session.md) | mirrors | [ad:session](../ad/nodes/session.md) | adam_session_uuid; registered via POST /api/delivery/registerSession, synced from GET /api/delivery/sessions/:id |
| [navvy:testing-sessions-service](../navvy/nodes/testing-sessions-service.md) | calls | [ad:delivery-api](../ad/nodes/delivery-api.md) | POST /api/delivery/registerSession (with TTS form_settings + pnp for Progress Checks), POST /api/delivery/player/response + GET /api/delivery/player/form/:id (writing practice prefill), GET /api/delivery/sessions/:id, GET /api/delivery/responses/:session, PUT /api/delivery/sessions/:id/state (force submit), POST /api/delivery/delete_file |
| [navvy:testing-sessions-service](../navvy/nodes/testing-sessions-service.md) | calls | [ad:forms-api](../ad/nodes/forms-api.md) | PUT /api/data/banks/:bank/form_by_item_ids — dynamic form per launch |
| [navvy:testing-sessions-service](../navvy/nodes/testing-sessions-service.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | POST /api/scoring/rescore |
| [navvy:testing-sessions-service](../navvy/nodes/testing-sessions-service.md) | calls | [ad:media-api](../ad/nodes/media-api.md) | POST /api/data/fetch_response_from_s3 — recording proxy |
| [navvy:testing-sessions-service](../navvy/nodes/testing-sessions-service.md) | consumes | [ad:session-scored-callback](../ad/nodes/session-scored-callback.md) | via ad-callback-api, then re-pulls session + responses |

## navvy → arc (3)

| from | rel | to | note |
|---|---|---|---|
| [navvy:student-testing-ui](../navvy/nodes/student-testing-ui.md) | calls | [arc:lockdown-extension-api](../arc/nodes/lockdown-extension-api.md) | new window.ArcExtension(lejnbofknclafimlnbgnaaamehkchifm) — lock() on load, unlock() on unmount, when client.lock_student_browser |
| [navvy:student-testing-ui](../navvy/nodes/student-testing-ui.md) | consumes | [arc:lockdown-breach](../arc/nodes/lockdown-breach.md) | ldb.onbreach — shows breach dialog only (no server record) |
| [navvy:student-testing-ui](../navvy/nodes/student-testing-ui.md) | calls | [arc:lockdown-extension](../arc/nodes/lockdown-extension.md) | ARC Chrome lockdown extension; content script matches https://*.navvyeducation.com/* |

## navvy → lp (13)

| from | rel | to | note |
|---|---|---|---|
| [navvy:academic-session](../navvy/nodes/academic-session.md) | mirrors | [lp:academic-session](../lp/nodes/academic-session.md) | sourced_id holds the LP lpi; from OneRoster academicSessions |
| [navvy:auth-api](../navvy/nodes/auth-api.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | GET /api/launchpad_login redirects to /auth/oidc/authorize; /api/launchpad_callback exchanges code at /auth/oidc/oauth/token |
| [navvy:auth-service](../navvy/nodes/auth-service.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | authorization-code login (go-oidc); OIDC sub (= LP user lpi) matched to users.sourced_id + email |
| [navvy:class](../navvy/nodes/class.md) | mirrors | [lp:class](../lp/nodes/class.md) | sourced_id holds the LP lpi; from OneRoster classes |
| [navvy:client](../navvy/nodes/client.md) | mirrors | [lp:client](../lp/nodes/client.md) | oneroster_client_id = LP client uuid in /api/external/:clientID path |
| [navvy:course](../navvy/nodes/course.md) | mirrors | [lp:course](../lp/nodes/course.md) | sourced_id holds the LP lpi; from OneRoster courses |
| [navvy:enrollment](../navvy/nodes/enrollment.md) | mirrors | [lp:enrollment](../lp/nodes/enrollment.md) | sourced_id holds the LP lpi; from OneRoster enrollments |
| [navvy:launchpad](../navvy/nodes/launchpad.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | GET {oneroster_base_url}/{client}/ims/oneroster/rostering/v1p2/{orgs,academicSessions,courses,classes,users,roles,demographics,enrollments}; POST oauth2/token |
| [navvy:launchpad](../navvy/nodes/launchpad.md) | calls | [lp:sso-oidc-provider](../lp/nodes/sso-oidc-provider.md) | OIDC discovery / authorize / token / userinfo at LAUNCHPAD_AUTH_DOMAIN, scopes openid profile email |
| [navvy:org](../navvy/nodes/org.md) | mirrors | [lp:org](../lp/nodes/org.md) | sourced_id holds the LP lpi; from OneRoster orgs |
| [navvy:roster-sync-service](../navvy/nodes/roster-sync-service.md) | calls | [lp:oneroster-external-api](../lp/nodes/oneroster-external-api.md) | /ims/oneroster/rostering/v1p2 list routes, filter dateLastModified>since, limit=1000, follows next |
| [navvy:user-demographic](../navvy/nodes/user-demographic.md) | mirrors | [lp:demographic](../lp/nodes/demographic.md) | from OneRoster demographics (metadata ell / section504 / iep / gt); keyed by user, no sourced_id |
| [navvy:user](../navvy/nodes/user.md) | mirrors | [lp:user](../lp/nodes/user.md) | sourced_id holds the LP lpi; from OneRoster users (+ roles to user_orgs) |

## oscar → ad (6)

| from | rel | to | note |
|---|---|---|---|
| [oscar:export-scores](../oscar/nodes/export-scores.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | POST /api/scoring/oscar/callback (no auth on AD side) |
| [oscar:export-scores](../oscar/nodes/export-scores.md) | consumes | [ad:score-with-oscar](../ad/nodes/score-with-oscar.md) |  |
| [oscar:external-response-import](../oscar/nodes/external-response-import.md) | consumes | [ad:score-with-oscar](../ad/nodes/score-with-oscar.md) |  |
| [oscar:response](../oscar/nodes/response.md) | mirrors | [ad:response](../ad/nodes/response.md) | ref_id = AD responses.id, set by AD SendOscarResponses on PATCH /v1/api/response |
| [oscar:score-callback-endpoint](../oscar/nodes/score-callback-endpoint.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | DefaultOutboundDriver POST callback_url = AD /api/scoring/oscar/callback (ExtScorePayload, NOAUTH) |
| [oscar:score-export](../oscar/nodes/score-export.md) | calls | [ad:human-scoring-api](../ad/nodes/human-scoring-api.md) | DefaultOutboundDriver POST callback_url = AD /api/scoring/oscar/callback (ExtScorePayload, NOAUTH) |

## oscar → adam (3)

| from | rel | to | note |
|---|---|---|---|
| [oscar:export-scores](../oscar/nodes/export-scores.md) | calls | [adam:external-score-api](../adam/nodes/external-score-api.md) | POST /v1/api/score |
| [oscar:score-callback-endpoint](../oscar/nodes/score-callback-endpoint.md) | calls | [adam:external-score-api](../adam/nodes/external-score-api.md) | DefaultOutboundDriver POST callback_url = adam /v1/api/score (ExtScorePayload, NOAUTH) |
| [oscar:score-export](../oscar/nodes/score-export.md) | calls | [adam:external-score-api](../adam/nodes/external-score-api.md) | DefaultOutboundDriver POST callback_url = adam /v1/api/score (ExtScorePayload, NOAUTH) |

## oscar → cf (2)

| from | rel | to | note |
|---|---|---|---|
| [oscar:iea-integration](../oscar/nodes/iea-integration.md) | calls | [cf:client-api](../cf/nodes/client-api.md) | IeaService POST /v1/auth (X-Auth-Token), POST /v1/response (RequestScore), POST /v1/outcome (ReportHumanScore, SmartSortCodeReviewed), PATCH /v1/outcome (NotifyScoreInvalidated), POST /v1/outcome/lid (LidReviewed), POST /v1/response/release (NotifyResponseExported) |
| [oscar:iea-integration](../oscar/nodes/iea-integration.md) | calls | [cf:system-integration](../cf/nodes/system-integration.md) | /v1/system_integration/* tenant, project, item, TOD, smart-sort, field-test and modeling provisioning (CreateTenant, UpsertProject, CreateItem, CreateTodItem...) |

## xprt → ad (3)

| from | rel | to | note |
|---|---|---|---|
| [xprt:ad-print-pdf](../xprt/nodes/ad-print-pdf.md) | mirrors | [ad:print-with-xprt](../ad/nodes/print-with-xprt.md) |  |
| [xprt:ad](../xprt/nodes/ad.md) | mirrors | [ad:xprt-orchestration](../ad/nodes/xprt-orchestration.md) | the AD module that drives this contract (services/xprt_service.go) |
| [xprt:s3-buckets](../xprt/nodes/s3-buckets.md) | shares | [ad:s3-buckets](../ad/nodes/s3-buckets.md) | AD_S3_INTERNAL receives the PDF via presigned PUT |
