{
  "module": "analytics",
  "surface": "alpha",
  "deliverable": "customer_website",
  "generatedAt": "2026-06-16T15:36:00.677Z",
  "benchmarkUrl": "https://docs.stripe.com/api",
  "architectureUrl": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture",
  "dataDictionaryUrl": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary",
  "demoBaseUrl": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/customer_website/api",
  "implementationUrl": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/implementation/api",
  "endpointCount": 20,
  "tableCount": 13,
  "endpoints": [
    {
      "id": "mint-demo-token",
      "method": "POST",
      "path": "/dev/mint?tenantId=demo",
      "title": "Mint a demo token",
      "summary": "Create a short-lived demo JWT. This utility is unauthenticated and only accepts tenantId=demo.",
      "auth": "No Authorization header.",
      "scopes": [
        "demo utility"
      ],
      "curl": "curl -sS -X POST \"$ANALYTICS_BASE_URL/dev/mint?tenantId=demo\"",
      "sampleResponse": {
        "token": "demo.analytics.jwt",
        "tenantId": "demo",
        "expiresIn": 3600
      },
      "sourceObject": {
        "name": "Endpoint catalog runtime utility",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#endpoint-catalog",
        "note": "No Analytics table is written. The demo token follows the approved endpoint catalog plus the auth and tenant-routing decisions."
      },
      "architecture": [
        {
          "id": "aitd-106-axis-auth-shape",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-106-axis-auth-shape"
        },
        {
          "id": "aitd-109-axis-tenant-routing",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-109-axis-tenant-routing"
        }
      ],
      "request": [
        {
          "name": "tenantId",
          "type": "TEXT enum",
          "requirement": "Required",
          "description": "Must be demo."
        }
      ],
      "response": [
        {
          "name": "token",
          "type": "JWT string",
          "requirement": "required",
          "meaning": "Bearer token scoped to the demo tenant.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture"
        },
        {
          "name": "tenantId",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Tenant claim inside the token.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture"
        },
        {
          "name": "expiresIn",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Seconds until the token expires.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture"
        }
      ]
    },
    {
      "id": "list-event-time-facts",
      "method": "GET",
      "path": "/alpha/analytics/v1/event-time-facts",
      "title": "List event time facts",
      "summary": "Read signed active, inactive, and waste-second contributions written when source Events close. Use this for audit and low-level time tracing.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/event-time-facts?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&factKind=active_seconds&startDate=2026-05-01&endDate=2026-06-01\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/event-time-facts",
        "data": [
          {
            "id": "8e9c0ef2-bc75-4f53-8124-df77df49f25f",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "source_event_id": "evt_alpha_000891",
            "fact_kind": "active_seconds",
            "seconds_delta": 420,
            "subject_id": "math",
            "application_ref": "app_math_academy",
            "policy_ref": "alpha.policy.analytics.time_classification.v2026-06-10",
            "quality_status": "ok",
            "modified_at": "2026-05-14T18:32:22Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/event-time-facts"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_event_time_fact",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact",
        "note": "Stores signed active, inactive, and waste second contributions for the DERIVED Events axis, so reports can audit time-on-task without classifying raw Caliper events themselves."
      },
      "architecture": [
        {
          "id": "aitd-005-time-facts-and-windows",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-005-time-facts-and-windows"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-012-corrections-and-reversals",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-012-corrections-and-reversals"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id. Omit only for authorized cohort reads."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical subject after server-side subject normalization."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive start date in the school/reporting timezone."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive end date. Must be later than startDate."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "UTC ISO-8601 polling checkpoint over modified_at."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor returned by the previous page."
        },
        {
          "name": "factKind",
          "type": "fact_kind enum",
          "requirement": "Optional",
          "description": "active_seconds, inactive_seconds, or waste_seconds."
        },
        {
          "name": "sourceEventId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Events Alpha event id that produced the fact."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-student-id"
        },
        {
          "name": "source_event_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Events Alpha event id this contribution derives from.",
          "constraints": "Must reference one closed Events row in the same tenant.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-source-event-id"
        },
        {
          "name": "fact_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Which time bucket this signed contribution belongs to.",
          "constraints": "Allowed values: fact_kind enum. Set by the versioned time-classification policy named in policy_ref, for example alpha.policy.analytics.time_classification.v2026-06-10.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-fact-kind"
        },
        {
          "name": "seconds_delta",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Signed seconds contributed by this source event to the fact_kind bucket.",
          "constraints": "May be negative for correction/reversal rows; ordinary display measures use rollup fields, not client-side clamping.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-seconds-delta"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "nullable where the row is all-subject or the source cannot validly resolve a subject",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-subject-id"
        },
        {
          "name": "application_ref",
          "type": "TEXT",
          "requirement": "nullable",
          "meaning": "Application/activity-source reference resolved from the source event when available.",
          "constraints": "Reference only; application identity/lifecycle belongs to Applications.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-application-ref"
        },
        {
          "name": "policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Named policy/config version used to compute the measure or rollup.",
          "constraints": "Must point at alpha.policy.analytics.* or an inherited Curriculum/Results policy active for the source effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-policy-ref"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-quality-status"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact-modified-at"
        }
      ]
    },
    {
      "id": "list-time-windows",
      "method": "GET",
      "path": "/alpha/analytics/v1/time-windows",
      "title": "List time windows",
      "summary": "Read active, inactive, waste, and display minutes by student, subject, and reporting window.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/time-windows?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&subjectId=math&windowKind=day&startDate=2026-05-01&endDate=2026-06-01\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/time-windows",
        "data": [
          {
            "id": "1b0d98de-8f58-4ec3-9f2b-5cfbfa3d0001",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "subject_id": "math",
            "window_kind": "day",
            "window_start": "2026-05-14",
            "window_end": "2026-05-15",
            "active_seconds_total": 3240,
            "inactive_seconds_total": 120,
            "waste_seconds_total": 0,
            "display_active_minutes": 54,
            "quality_status": "ok",
            "modified_at": "2026-05-14T23:59:59Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/time-windows"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_time_window",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window",
        "note": "Report-ready active, inactive, and waste time totals for the DERIVED Events axis. These complement the ingested Time Commitment tile and support audit/Waste views."
      },
      "architecture": [
        {
          "id": "aitd-005-time-facts-and-windows",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-005-time-facts-and-windows"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id. Omit only for authorized cohort reads."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical subject after server-side subject normalization."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive start date in the school/reporting timezone."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive end date. Must be later than startDate."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "UTC ISO-8601 polling checkpoint over modified_at."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor returned by the previous page."
        },
        {
          "name": "windowKind",
          "type": "window_kind enum",
          "requirement": "Optional",
          "description": "day, week, term, school_year, or custom."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-student-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "nullable where the row is all-subject or the source cannot validly resolve a subject",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-subject-id"
        },
        {
          "name": "window_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Named window family for this rollup.",
          "constraints": "Allowed values: window_kind enum; custom requires explicit policy/window metadata.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-window-kind"
        },
        {
          "name": "window_start",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Inclusive start date of the reporting window in the school timezone.",
          "constraints": "Must be before window_end; ISO date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-window-start"
        },
        {
          "name": "window_end",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Exclusive end date of the reporting window in the school timezone.",
          "constraints": "Must be after window_start; ISO date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-window-end"
        },
        {
          "name": "active_seconds_total",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Net active seconds from current event_time_fact rows in this window.",
          "constraints": "Can include signed corrections; display fields apply policy presentation.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-active-seconds-total"
        },
        {
          "name": "inactive_seconds_total",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Net inactive seconds from current event_time_fact rows in this window.",
          "constraints": "Can include signed corrections.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-inactive-seconds-total"
        },
        {
          "name": "waste_seconds_total",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Net waste/gaming seconds from current event_time_fact rows in this window.",
          "constraints": "Can be positive or negative after corrections.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-waste-seconds-total"
        },
        {
          "name": "display_active_minutes",
          "type": "NUMERIC(12,3)",
          "requirement": "required",
          "meaning": "Policy-defined active minutes shown in reports for this time window.",
          "constraints": "Computed by Analytics from active_seconds_total under policy_ref; consumers read it directly.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-display-active-minutes"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-quality-status"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window-modified-at"
        }
      ]
    },
    {
      "id": "list-school-day-minutes",
      "method": "GET",
      "path": "/alpha/analytics/v1/school-day-minutes",
      "title": "List minutes per enrolled school day",
      "summary": "Read active minutes, enrolled-school-day denominator, MAP-day exclusions, and null_reason when the calendar prerequisite is not yet materialized.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/school-day-minutes?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&subjectId=math&startDate=2026-05-01&endDate=2026-06-01&includeUnavailable=true\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/school-day-minutes",
        "data": [
          {
            "id": "2d4b32cd-c4d8-4e45-8a3a-9de8ce3b0002",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "school_id": "school_alpha_austin",
            "subject_id": "math",
            "window_start": "2026-05-01",
            "window_end": "2026-06-01",
            "active_minutes": 1080,
            "enrolled_school_day_count": 20,
            "excluded_school_day_count": 2,
            "minutes_per_enrolled_school_day": 54,
            "school_day_policy_ref": "alpha.policy.school_day.v2026-06-10",
            "null_reason": "none",
            "quality_status": "ok",
            "modified_at": "2026-06-01T01:00:00Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/school-day-minutes"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_school_day_minutes",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes",
        "note": "Minutes per enrolled school day for the Time Commitment tile. Numerator is ingested from reporting.processed_facts.active_seconds; denominator is alpha.school_calendar intersected with enrollment/subject assignment, with MAP-day exclusion."
      },
      "architecture": [
        {
          "id": "aitd-006-school-day-minutes",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-006-school-day-minutes"
        },
        {
          "id": "aitd-014-source-ownership-and-prerequisites",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-014-source-ownership-and-prerequisites"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id. Omit only for authorized cohort reads."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical subject after server-side subject normalization."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive start date in the school/reporting timezone."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive end date. Must be later than startDate."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "UTC ISO-8601 polling checkpoint over modified_at."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor returned by the previous page."
        },
        {
          "name": "schoolId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "People and Orgs school id used for the calendar denominator."
        },
        {
          "name": "includeUnavailable",
          "type": "BOOLEAN",
          "requirement": "Optional",
          "description": "When true, include current source_missing or policy_pending rows for UI explanation."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-student-id"
        },
        {
          "name": "school_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "People and Orgs school whose calendar/enrollment intersection defines the denominator.",
          "constraints": "Must resolve as the student school for the effective range; no current-only shortcut.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-school-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "nullable; null means all reportable subjects",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-subject-id"
        },
        {
          "name": "window_start",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Inclusive start date for the denominator/numerator window.",
          "constraints": "ISO date; half-open range with window_end.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-window-start"
        },
        {
          "name": "window_end",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Exclusive end date for the denominator/numerator window.",
          "constraints": "ISO date; must be after window_start.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-window-end"
        },
        {
          "name": "active_minutes",
          "type": "NUMERIC(12,3)",
          "requirement": "required",
          "meaning": "Policy-defined active minutes for the same window and subject grain.",
          "constraints": "Normalized by the timeback-xp-time-accuracy adapter from reporting.processed_facts.active_seconds, then stored as minutes under policy_ref.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-active-minutes"
        },
        {
          "name": "enrolled_school_day_count",
          "type": "INTEGER",
          "requirement": "required when null_reason=none; nullable only for source_missing repair rows",
          "meaning": "Denominator: school days intersecting the student effective-dated enrollment and subject assignment when subject_id is present.",
          "constraints": "Nonnegative; excludes weekends, holidays, teacher-workshop days, MAP-testing days, and non-time-locatable enrollments. Null only with a typed repair reason such as source_missing.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-enrolled-school-day-count"
        },
        {
          "name": "excluded_school_day_count",
          "type": "INTEGER",
          "requirement": "required when null_reason=none; nullable only for source_missing repair rows",
          "meaning": "Calendar dates inside the requested window that the school-day policy excluded from the denominator.",
          "constraints": "Nonnegative; includes weekend, holiday_break, teacher_workshop, nwea_map_testing, and governed other exclusions. Null only with a typed repair reason such as source_missing.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-excluded-school-day-count"
        },
        {
          "name": "minutes_per_enrolled_school_day",
          "type": "NUMERIC(12,3)",
          "requirement": "nullable when denominator is zero or policy/source is missing",
          "meaning": "Report-ready average active minutes per enrolled school day when the school-day denominator source is available.",
          "constraints": "Formula: round(active_minutes / enrolled_school_day_count, 3) when enrolled_school_day_count > 0 and null_reason=none. Null requires null_reason other than none; consumers never recompute the denominator or substitute active days.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-minutes-per-enrolled-school-day"
        },
        {
          "name": "school_day_policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Named policy/config version used to compute the measure or rollup.",
          "constraints": "Must point at alpha.policy.analytics.* or an inherited Curriculum/Results policy active for the source effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-school-day-policy-ref"
        },
        {
          "name": "null_reason",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Why minutes_per_enrolled_school_day and denominator counts are null or not reportable.",
          "constraints": "Allowed values: null_reason enum. none means the metric is populated; source_missing means the required calendar source does not exist or is unavailable and the row is not reportable.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-null-reason"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this school-day denominator row.",
          "constraints": "Allowed values: quality_status enum. Ordinary Learning Report rows are ok or corrected; source_missing is a readable repair state when the calendar source is unavailable.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-quality-status"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes-modified-at"
        }
      ]
    },
    {
      "id": "list-xp-rollups",
      "method": "GET",
      "path": "/alpha/analytics/v1/xp-rollups",
      "title": "List XP rollups",
      "summary": "Read report-ready XP totals, goals, remaining XP, and signed correction subtotals while Results remains the immutable XP ledger.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/xp-rollups?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&subjectId=math&windowKind=term&startDate=2026-01-01&endDate=2026-06-01\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/xp-rollups",
        "data": [
          {
            "id": "3f2b79e1-6182-4e21-a0b6-7d6cf7530003",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "subject_id": "math",
            "window_kind": "term",
            "window_start": "2026-01-01",
            "window_end": "2026-06-01",
            "positive_xp": 11850,
            "negative_xp": -50,
            "xp_total": 11800,
            "net_xp": 11800,
            "xp_goal": 9000,
            "daily_xp_goal": 100,
            "enrolled_school_day_count": 90,
            "xp_remaining": 0,
            "xp_goal_percent": 131.111,
            "xp_completion_percent": 131.111,
            "on_track": true,
            "award_count": 24,
            "reversal_count": 1,
            "source_import_id": "imp_01HT8XPTIME_2026_SPRING",
            "quality_status": "ok",
            "null_reason": "none",
            "modified_at": "2026-06-01T01:02:00Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/xp-rollups"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_xp_rollup",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup",
        "note": "Report-ready XP total plus goal progress fields. The goal fields use the same materialized school-day denominator as time commitment."
      },
      "architecture": [
        {
          "id": "aitd-007-xp-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id. Omit only for authorized cohort reads."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical subject after server-side subject normalization."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive start date in the school/reporting timezone."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive end date. Must be later than startDate."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "UTC ISO-8601 polling checkpoint over modified_at."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor returned by the previous page."
        },
        {
          "name": "windowKind",
          "type": "window_kind enum",
          "requirement": "Optional",
          "description": "day, week, term, school_year, or custom."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-student-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "nullable where the row is all-subject or the source cannot validly resolve a subject",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-subject-id"
        },
        {
          "name": "window_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Named window family for the XP rollup.",
          "constraints": "Allowed values: window_kind enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-window-kind"
        },
        {
          "name": "window_start",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Inclusive start date for included XP ledger effective dates.",
          "constraints": "ISO date; half-open with window_end.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-window-start"
        },
        {
          "name": "window_end",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Exclusive end date for included XP ledger effective dates.",
          "constraints": "ISO date; must be after window_start.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-window-end"
        },
        {
          "name": "positive_xp",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Positive XP contribution subtotal retained for audit/explanation.",
          "constraints": "Nonnegative; normalized by the adapter/materializer, with Results xp_ledger refs when available.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-positive-xp"
        },
        {
          "name": "negative_xp",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Sum of negative XP penalties/reversals in this rollup.",
          "constraints": "Zero or negative; gaming/cheating signals and reversals stay signed.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-negative-xp"
        },
        {
          "name": "xp_total",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Policy-defined report XP total after the report-source adapter applies subject folds, exclusions, corrections, and signed contributions.",
          "constraints": "Non-null values require source_import_id provenance; should equal the report value for this student/subject/window.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-xp-total"
        },
        {
          "name": "net_xp",
          "type": "NUMERIC(14,3)",
          "requirement": "required",
          "meaning": "Signed audit total after positive and negative XP contributions; equal to xp_total for ordinary report rows under the current policy.",
          "constraints": "positive_xp + negative_xp under policy_ref; retained for correction/reversal reconciliation.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-net-xp"
        },
        {
          "name": "xp_goal",
          "type": "NUMERIC(14,3)",
          "requirement": "required when null_reason=none; nullable only when enrolled_school_day_count or XP goal policy is missing",
          "meaning": "Window XP target for this student, subject, and window, used by the Learning Report XP Remaining and XP Goal Percent panels.",
          "constraints": "Nonnegative when populated; equals daily_xp_goal multiplied by enrolled_school_day_count when both are present. Null requires a typed repair reason such as source_missing or policy_pending.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-xp-goal"
        },
        {
          "name": "daily_xp_goal",
          "type": "NUMERIC(14,3)",
          "requirement": "nullable when daily XP policy is missing",
          "meaning": "Daily XP target used in the auditor-pinned XP goal percent denominator.",
          "constraints": "Nonnegative; read from alpha.policy.analytics.xp_goal_percent.v1 / Curriculum Policy, never from a consumer constant.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-daily-xp-goal"
        },
        {
          "name": "enrolled_school_day_count",
          "type": "INTEGER",
          "requirement": "required when null_reason=none; nullable only when school-day denominator source is missing",
          "meaning": "Number of days in the XP percent denominator: days the student was enrolled and school was in session.",
          "constraints": "Nonnegative integer when populated. Enrollment begin/end bound the count; the student's school calendar governs it; MAP testing days are excluded; per-subject rows count only days with a subject assignment. Null requires a typed repair reason such as source_missing.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-enrolled-school-day-count"
        },
        {
          "name": "xp_remaining",
          "type": "NUMERIC(14,3)",
          "requirement": "required when null_reason=none; nullable when xp_goal is null/source_missing",
          "meaning": "Report-ready remaining XP under policy_ref.",
          "constraints": "max(xp_goal - xp_total, 0) under policy_ref when xp_goal is present; stored by Analytics so reports do not subtract locally. Null requires a typed repair reason.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-xp-remaining"
        },
        {
          "name": "xp_goal_percent",
          "type": "NUMERIC(9,3)",
          "requirement": "nullable when daily_xp_goal or enrolled_school_day_count is null or zero",
          "meaning": "Uncapped percent of the XP goal reached in this window when the school-day denominator is available.",
          "constraints": "Formula under alpha.policy.analytics.xp_goal_percent.v1 when populated: xp_total / (daily_xp_goal x enrolled_school_day_count) x 100. Values above 100 are valid and must remain visible. Null requires a typed repair reason.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-xp-goal-percent"
        },
        {
          "name": "xp_completion_percent",
          "type": "NUMERIC(9,3)",
          "requirement": "deprecated compatibility alias; nullability matches xp_goal_percent",
          "meaning": "Deprecated compatibility alias for xp_goal_percent.",
          "constraints": "Must equal xp_goal_percent exactly and remains uncapped. It has no independent capped-completion meaning. Nullability matches xp_goal_percent.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-xp-completion-percent"
        },
        {
          "name": "on_track",
          "type": "BOOLEAN",
          "requirement": "nullable when xp_goal_percent is null",
          "meaning": "Whether the student is on track against the XP goal policy for this window.",
          "constraints": "Computed under policy_ref; null means the goal policy or denominator is missing.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-on-track"
        },
        {
          "name": "award_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of positive or neutral XP ledger rows contributing to this rollup.",
          "constraints": "Nonnegative; excludes superseded rows unless audit query requests them.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-award-count"
        },
        {
          "name": "reversal_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of reversal/correction XP ledger rows included.",
          "constraints": "Nonnegative.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-reversal-count"
        },
        {
          "name": "source_import_id",
          "type": "TEXT",
          "requirement": "required for report-tile rows; nullable for purely derived event-axis rows",
          "meaning": "Analytics source-import receipt that proves which named report-source adapter produced this report-grade fact.",
          "constraints": "Must reference alpha.analytics_source_import for non-null Learning Report tile values; no literal or fixture value may be reportable without this provenance.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-source-import-id"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-quality-status"
        },
        {
          "name": "null_reason",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Why XP goal fields are null or unavailable while xp_total itself may still be reportable.",
          "constraints": "Allowed values: null_reason enum. none means xp_goal, xp_remaining, xp_goal_percent, and on_track are populated; source_missing means the shared school-day denominator source is absent and the goal fields are not reportable.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-null-reason"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup-modified-at"
        }
      ]
    },
    {
      "id": "list-accuracy-rollups",
      "method": "GET",
      "path": "/alpha/analytics/v1/accuracy-rollups",
      "title": "List accuracy rollups",
      "summary": "Read report-ready correct questions, total questions, incorrect questions, and accuracy percent without client-side processed_facts math.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/accuracy-rollups?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&subjectId=math&windowKind=term&startDate=2026-01-01&endDate=2026-06-01\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/accuracy-rollups",
        "data": [
          {
            "id": "9c3f3e4f-1fd8-4c28-8a72-cbbf2e6d0006",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "subject_id": "math",
            "window_kind": "term",
            "window_start": "2026-01-01",
            "window_end": "2026-06-01",
            "correct_question_count": 480,
            "total_question_count": 600,
            "incorrect_question_count": 120,
            "accuracy_percent": 80,
            "source_import_id": "imp_01HT8XPTIME_2026_SPRING",
            "source_fact_refs": [
              "processed_facts_hash_01HT7Q"
            ],
            "quality_status": "ok",
            "null_reason": "none",
            "modified_at": "2026-06-01T01:02:30Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/accuracy-rollups"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_accuracy",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy",
        "note": "Report-ready Accuracy panel facts: correct questions, total questions, incorrect questions, and percent correct without client-side processed_facts math."
      },
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id. Omit only for authorized cohort reads."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical subject after server-side subject normalization."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive start date in the school/reporting timezone."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive end date. Must be later than startDate."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "UTC ISO-8601 polling checkpoint over modified_at."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor returned by the previous page."
        },
        {
          "name": "windowKind",
          "type": "window_kind enum",
          "requirement": "Optional",
          "description": "day, week, term, school_year, or custom."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-student-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "nullable where the row is all-subject or the source cannot validly resolve a subject",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-subject-id"
        },
        {
          "name": "window_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Named window family for the Accuracy rollup.",
          "constraints": "Allowed values: window_kind enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-window-kind"
        },
        {
          "name": "window_start",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Inclusive start date for source question rows included in this rollup.",
          "constraints": "ISO date; half-open with window_end.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-window-start"
        },
        {
          "name": "window_end",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Exclusive end date for source question rows included in this rollup.",
          "constraints": "ISO date; must be after window_start.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-window-end"
        },
        {
          "name": "correct_question_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Reportable correct-question numerator after the adapter applies subject, app/source, score_type, correction, and real-student rules.",
          "constraints": "Nonnegative integer; cannot exceed total_question_count when total_question_count is present. Normalized from source-shaped reporting.processed_facts.correct_questions, not read by reports from the source table.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-correct-question-count"
        },
        {
          "name": "total_question_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Reportable question-attempt denominator after the adapter applies the same policy filters as correct_question_count.",
          "constraints": "Nonnegative integer. Zero is allowed only with null_reason=no_questions and null accuracy_percent.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-total-question-count"
        },
        {
          "name": "incorrect_question_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Reportable incorrect-question count retained for explanations.",
          "constraints": "Nonnegative integer; equals total_question_count - correct_question_count under the policy version.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-incorrect-question-count"
        },
        {
          "name": "accuracy_percent",
          "type": "NUMERIC(9,3)",
          "requirement": "nullable when total_question_count is zero or source/policy is missing",
          "meaning": "Report-ready percent of reportable questions answered correctly.",
          "constraints": "0 through 100 when populated; null requires a typed null_reason. Formula and rounding are owned by Analytics under policy_ref.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-accuracy-percent"
        },
        {
          "name": "source_import_id",
          "type": "TEXT",
          "requirement": "required for report-tile rows; nullable for purely derived event-axis rows",
          "meaning": "Analytics source-import receipt that proves which named report-source adapter produced this report-grade fact.",
          "constraints": "Must reference alpha.analytics_source_import for non-null Learning Report tile values; no literal or fixture value may be reportable without this provenance.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-source-import-id"
        },
        {
          "name": "source_fact_refs",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Compact ids/hashes/cursor for source-shaped processed_facts rows accepted by the adapter.",
          "constraints": "Stores refs/hashes only; never copies raw processed_facts rows or student identifiers.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-source-fact-refs"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-quality-status"
        },
        {
          "name": "null_reason",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Why accuracy_percent is null or not reportable.",
          "constraints": "Allowed values: null_reason enum. no_questions means the source window had zero reportable question attempts; none means the metric is populated.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-null-reason"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy-modified-at"
        }
      ]
    },
    {
      "id": "list-mastery-deltas",
      "method": "GET",
      "path": "/alpha/analytics/v1/mastery-deltas",
      "title": "List mastery deltas",
      "summary": "Read dated changes in Results-owned KC mastery state. The current state remains in Results; Analytics reports what changed in the window.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/mastery-deltas?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&stateDimension=durable_mastery&startDate=2026-05-01&endDate=2026-06-01\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/mastery-deltas",
        "data": [
          {
            "id": "4e9268b7-e76a-46d9-9b6e-899aa2df0004",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "kc_id": "kc_math_fraction_addition_unlike_denominators",
            "grade_subject": "math",
            "grade_level": 5,
            "state_dimension": "durable_mastery",
            "effective_at": "2026-05-14T18:45:00Z",
            "previous_value": {
              "value": 0.82
            },
            "new_value": {
              "value": 0.91
            },
            "delta_value": 0.09,
            "transition_kind": "acquired",
            "source_result_refs": [
              "result_01HT7K8BR3",
              "result_kc_evidence_01HT7K8BR3_KC"
            ],
            "quality_status": "ok",
            "modified_at": "2026-05-14T18:45:04Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/mastery-deltas"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_mastery_delta",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta",
        "note": "Grade Levels Mastered facts for the Learning Report plus a typed change log of mastery state movements; Results remains the current mastery state of record."
      },
      "architecture": [
        {
          "id": "aitd-008-mastery-and-grade-levels",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-008-mastery-and-grade-levels"
        },
        {
          "id": "aitd-014-source-ownership-and-prerequisites",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-014-source-ownership-and-prerequisites"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id."
        },
        {
          "name": "kcId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Knowledge Component id."
        },
        {
          "name": "stateDimension",
          "type": "state_dimension enum",
          "requirement": "Optional",
          "description": "durable mastery, working grade, highest mastered grade, or another governed dimension."
        },
        {
          "name": "transitionKind",
          "type": "transition_kind enum",
          "requirement": "Optional",
          "description": "How the state changed."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive boundary for effective_at."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive boundary for effective_at."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "Poll for changed rows."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-student-id"
        },
        {
          "name": "kc_id",
          "type": "TEXT",
          "requirement": "nullable when the row is a grade-level mastered fact without a single KC",
          "meaning": "Knowledge Component whose student state changed.",
          "constraints": "Must reference a Curriculum KC; never a standard or lesson id.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-kc-id"
        },
        {
          "name": "grade_subject",
          "type": "TEXT enum",
          "requirement": "nullable except grade-level mastered rows",
          "meaning": "Subject for a Grade Levels Mastered row shown in the Learning Report.",
          "constraints": "Closed Alpha subject enum after write-time normalization; required when grade_level/completed_on are populated.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-grade-subject"
        },
        {
          "name": "grade_level",
          "type": "INTEGER",
          "requirement": "nullable except grade-level mastered rows",
          "meaning": "Grade level the student has mastered in the subject.",
          "constraints": "Positive integer; set by the grade-mastery adapter from passed gate/assessment evidence.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-grade-level"
        },
        {
          "name": "state_dimension",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Which Results mastery-state dimension changed.",
          "constraints": "Allowed values: state_dimension enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-state-dimension"
        },
        {
          "name": "effective_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "When the state transition is effective for as-of reporting.",
          "constraints": "UTC timestamp; comes from Results state transition, not Analytics computed_at.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-effective-at"
        },
        {
          "name": "previous_value",
          "type": "JSONB",
          "requirement": "nullable",
          "meaning": "Typed previous value for the changed state dimension.",
          "constraints": "JSON shape must match state_dimension; null allowed for first known state.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-previous-value"
        },
        {
          "name": "new_value",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Typed new value for the changed state dimension.",
          "constraints": "JSON shape must match state_dimension.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-new-value"
        },
        {
          "name": "delta_value",
          "type": "NUMERIC(12,6)",
          "requirement": "nullable",
          "meaning": "Numeric difference where the state dimension has a numeric value.",
          "constraints": "Null for non-numeric dimensions such as next_due_at or fluency_state.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-delta-value"
        },
        {
          "name": "transition_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Human-readable category of the state transition.",
          "constraints": "Allowed values: acquired, improved, decayed, review_due, fluency_changed, corrected, blocked. Set by Results/Analytics materializer policy; reports group by this value instead of classifying attempts.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-transition-kind"
        },
        {
          "name": "source_result_refs",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Result/evidence ids that caused or explain the state transition or grade-level mastery fact.",
          "constraints": "Stores ids/hashes only; no raw scored payload copies.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-source-result-refs"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-quality-status"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta-modified-at"
        }
      ]
    },
    {
      "id": "list-map-growth-rollups",
      "method": "GET",
      "path": "/alpha/analytics/v1/map-growth-rollups",
      "title": "List MAP growth rollups",
      "summary": "Read report-ready RIT, achievement percentile, growth percentile, Growth X, target, on-track state, sitting count, and retake count.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/map-growth-rollups?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&subjectId=math&termId=term_2026_winter&growthWindow=winter_to_winter&normsSet=2025\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/map-growth-rollups",
        "data": [
          {
            "id": "5a41fb2a-5d08-45fd-a62b-58a518060005",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "subject_id": "math",
            "canonical_term_id": "term_2026_winter",
            "growth_window": "winter_to_winter",
            "norms_set": "2025",
            "rit_score": 239,
            "achievement_percentile": 91,
            "growth_percentile": 43,
            "observed_growth": 6,
            "projected_growth": 7,
            "growth_x": 0.8571,
            "growth_x_target": 2,
            "on_track": false,
            "sitting_count": 2,
            "retake_count": 1,
            "source_import_id": "imp_01HT8MAP_2026_WINTER",
            "quality_status": "ok",
            "modified_at": "2026-05-14T19:00:00Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/map-growth-rollups"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_map_growth_rollup",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup",
        "note": "Report-ready RIT, achievement percentile, growth percentile, Growth X, MAP window, sitting-count, retake, and on-track facts without client-side norms tables, sitting selection, or term parsing."
      },
      "architecture": [
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical Alpha subject id."
        },
        {
          "name": "termId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Public API alias for canonical_term_id."
        },
        {
          "name": "growthWindow",
          "type": "growth_window enum",
          "requirement": "Optional",
          "description": "Use winter_to_winter for the Learning Report vs one-year panel."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Optional",
          "description": "2020 or 2025. This selects stored rollup rows; clients do not carry norm tables."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "Poll for changed rows."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-student-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "required for MAP rollups",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-subject-id"
        },
        {
          "name": "canonical_term_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Alpha canonical term id for the MAP observation/window.",
          "constraints": "Set by Results/NWEAMap term normalization; not parsed by Analytics clients.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-canonical-term-id"
        },
        {
          "name": "growth_window",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "MAP growth interval represented by this row.",
          "constraints": "Allowed values: growth_window enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-growth-window"
        },
        {
          "name": "norms_set",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "NWEA norms family used for projected growth and normed outputs.",
          "constraints": "Allowed values: norms_set enum; the same report can be regenerated by changing this filter.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-norms-set"
        },
        {
          "name": "rit_score",
          "type": "NUMERIC(6,2)",
          "requirement": "required",
          "meaning": "Report-ready RIT value from Results MAP test-of-record for this subject/term.",
          "constraints": "Positive numeric; no local test-of-record choice in Analytics clients.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-rit-score"
        },
        {
          "name": "achievement_percentile",
          "type": "NUMERIC(6,2)",
          "requirement": "nullable when the MAP source row has no achievement percentile",
          "meaning": "Achievement percentile for the test-of-record sitting.",
          "constraints": "0 to 100 when present; for hp_map_results this is normalized from testpercentile.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-achievement-percentile"
        },
        {
          "name": "growth_percentile",
          "type": "NUMERIC(6,2)",
          "requirement": "nullable when the selected growth_window has no conditional growth percentile",
          "meaning": "Conditional growth percentile for the selected MAP window; the Learning Report \"vs 1yr ago\" panel reads this from the winter_to_winter row.",
          "constraints": "0 to 100 when present; null requires null_reason for report windows that should have growth.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-growth-percentile"
        },
        {
          "name": "observed_growth",
          "type": "NUMERIC(7,3)",
          "requirement": "nullable when no paired window exists",
          "meaning": "Actual RIT growth for the growth_window.",
          "constraints": "Null for term-only observations; otherwise computed by Results MAP views.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-observed-growth"
        },
        {
          "name": "projected_growth",
          "type": "NUMERIC(7,3)",
          "requirement": "nullable when no projected growth exists",
          "meaning": "NWEA projected-growth value for the selected window.",
          "constraints": "Must be greater than 0 when growth_x is present; comes from Results/NWEAMap normalized projections and never from a client norms table.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-projected-growth"
        },
        {
          "name": "growth_x",
          "type": "NUMERIC(8,4)",
          "requirement": "nullable when observed or projected growth is unavailable",
          "meaning": "Observed growth divided by projected_growth, using the named norms_set and growth_window.",
          "constraints": "Null requires null_reason; target comparisons use growth_x_target.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-growth-x"
        },
        {
          "name": "growth_x_target",
          "type": "NUMERIC(8,4)",
          "requirement": "required",
          "meaning": "Alpha target Growth X for intervention/on-track decisions.",
          "constraints": "Normally 2 under current Alpha policy, but read from policy_ref.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-growth-x-target"
        },
        {
          "name": "on_track",
          "type": "BOOLEAN",
          "requirement": "nullable when growth_x or target is null",
          "meaning": "Whether the student is meeting the Growth X target for this row.",
          "constraints": "Computed under policy_ref; null requires null_reason.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-on-track"
        },
        {
          "name": "sitting_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of MAP sittings Results observed for this subject/term before test-of-record selection.",
          "constraints": "Nonnegative; includes source-visible sittings according to Results policy.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-sitting-count"
        },
        {
          "name": "retake_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of non-test-of-record sittings represented by the sitting_count.",
          "constraints": "Nonnegative; computed by Results/NWEAMap policy.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-retake-count"
        },
        {
          "name": "source_import_id",
          "type": "TEXT",
          "requirement": "required for report-tile rows; nullable for purely derived event-axis rows",
          "meaning": "Analytics source-import receipt that proves which named report-source adapter produced this report-grade fact.",
          "constraints": "Must reference alpha.analytics_source_import for non-null Learning Report tile values; no literal or fixture value may be reportable without this provenance.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-source-import-id"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-quality-status"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup-modified-at"
        }
      ]
    },
    {
      "id": "get-norms-resource",
      "method": "GET",
      "path": "/alpha/analytics/v1/norms",
      "title": "Read the NWEA norms resource",
      "summary": "Read the versioned achievement-status norms resource that powers percentile-to-RIT and RIT-to-percentile translation. Same contract as /norms/table; cache by table_version and never ship a private norms table.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/norms?subject=math&grade=5&season=winter&normsSet=2025&limit=1\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "table": "analytics.norms_table",
        "table_version": "analytics.norms.achievement.v2026-06-12",
        "data": [
          {
            "id": "norms_2025_math_student_5_winter",
            "norms_set": "2025",
            "subject_id": "math",
            "source_subject_name": "Math",
            "role": "student",
            "grade_key": "5",
            "grade_level": 5,
            "season": "winter",
            "mean_rit": 211.82,
            "sd_rit": 17.42,
            "calculator_version": "analytics.norms.achievement.v2026-06-12",
            "source_ref": "NWEA 2025 MAP Growth Norms Technical Manual (Hawthorne, Velazquez, Peng, Hall, Newburn, 2025)"
          }
        ],
        "limit": 1,
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/norms?subject=math&grade=5&season=winter&normsSet=2025&limit=1"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_norms_achievement",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement",
        "note": "Readable NWEA achievement-status norms resource for percentile-to-RIT and RIT-to-percentile translation. Apps may read/cache the surface table by table_version or call /norms/rit and /norms/percentile; they never maintain their own norms table."
      },
      "architecture": [
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "math, reading, language, or science. subjectId is accepted as an alias."
        },
        {
          "name": "grade",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "K or 1 through 12. gradeLevel is accepted as an alias."
        },
        {
          "name": "season",
          "type": "TEXT enum",
          "requirement": "Optional",
          "description": "fall, winter, or spring. termSeason is accepted as an alias."
        },
        {
          "name": "role",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "NWEA role/population label. Defaults to student for public student translations."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Optional",
          "description": "2020 or 2025. Omit to list both published sets."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Always list.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "table",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.norms_table list resource over alpha.analytics_norms_achievement.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "table_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the readable norms table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-table-version"
        },
        {
          "name": "data[].id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Stable Analytics id for this norms row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "data[].norms_set",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Norms family for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-norms-set"
        },
        {
          "name": "data[].subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical subject for the norms row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-subject-id"
        },
        {
          "name": "data[].source_subject_name",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Published source subject name for audit display.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].role",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "NWEA role/population label for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-role"
        },
        {
          "name": "data[].grade_key",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "NWEA grade key for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-grade-key"
        },
        {
          "name": "data[].grade_level",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Numeric grade level for sorting and display.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].season",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "MAP testing season for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-season"
        },
        {
          "name": "data[].mean_rit",
          "type": "NUMERIC(7,2)",
          "requirement": "required",
          "meaning": "Published mean RIT for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-mean-rit"
        },
        {
          "name": "data[].sd_rit",
          "type": "NUMERIC(6,3)",
          "requirement": "required",
          "meaning": "Published RIT standard deviation for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-sd-rit"
        },
        {
          "name": "data[].calculator_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the surface norms calculator/table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].source_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Opaque provenance pointer to NWEA-published norms.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-source-ref"
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows returned in this page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "hasMore",
          "type": "BOOLEAN",
          "requirement": "required",
          "meaning": "Whether another page exists.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "nextCursor",
          "type": "TEXT nullable",
          "requirement": "required",
          "meaning": "Opaque cursor for the next page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "links.self",
          "type": "URL",
          "requirement": "required",
          "meaning": "The request URL for this page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        }
      ]
    },
    {
      "id": "get-norms-table",
      "method": "GET",
      "path": "/alpha/analytics/v1/norms/table",
      "title": "Read the filterable NWEA norms table",
      "summary": "Read the paginated table rows for the current or requested NWEA achievement-status norms table version.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/norms/table?subject=math&grade=5&season=winter&normsSet=2025&limit=1\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "table": "analytics.norms_table",
        "table_version": "analytics.norms.achievement.v2026-06-12",
        "data": [
          {
            "id": "norms_2025_math_student_5_winter",
            "norms_set": "2025",
            "subject_id": "math",
            "source_subject_name": "Math",
            "role": "student",
            "grade_key": "5",
            "grade_level": 5,
            "season": "winter",
            "mean_rit": 211.82,
            "sd_rit": 17.42,
            "calculator_version": "analytics.norms.achievement.v2026-06-12",
            "source_ref": "NWEA 2025 MAP Growth Norms Technical Manual (Hawthorne, Velazquez, Peng, Hall, Newburn, 2025)"
          }
        ],
        "limit": 1,
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/norms/table?subject=math&grade=5&season=winter&normsSet=2025&limit=1"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_norms_achievement",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement",
        "note": "Readable NWEA achievement-status norms resource for percentile-to-RIT and RIT-to-percentile translation. Apps may read/cache the surface table by table_version or call /norms/rit and /norms/percentile; they never maintain their own norms table."
      },
      "architecture": [
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "math, reading, language, or science. subjectId is accepted as an alias."
        },
        {
          "name": "grade",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "K or 1 through 12. gradeLevel is accepted as an alias."
        },
        {
          "name": "season",
          "type": "TEXT enum",
          "requirement": "Optional",
          "description": "fall, winter, or spring. termSeason is accepted as an alias."
        },
        {
          "name": "role",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "NWEA role/population label. Defaults to student for public student translations."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Optional",
          "description": "2020 or 2025. Omit to list both published sets."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Always list.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "table",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.norms_table list resource over alpha.analytics_norms_achievement.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "table_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the readable norms table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-table-version"
        },
        {
          "name": "data[].id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Stable Analytics id for this norms row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "data[].norms_set",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Norms family for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-norms-set"
        },
        {
          "name": "data[].subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical subject for the norms row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-subject-id"
        },
        {
          "name": "data[].source_subject_name",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Published source subject name for audit display.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].role",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "NWEA role/population label for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-role"
        },
        {
          "name": "data[].grade_key",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "NWEA grade key for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-grade-key"
        },
        {
          "name": "data[].grade_level",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Numeric grade level for sorting and display.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].season",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "MAP testing season for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-season"
        },
        {
          "name": "data[].mean_rit",
          "type": "NUMERIC(7,2)",
          "requirement": "required",
          "meaning": "Published mean RIT for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-mean-rit"
        },
        {
          "name": "data[].sd_rit",
          "type": "NUMERIC(6,3)",
          "requirement": "required",
          "meaning": "Published RIT standard deviation for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-sd-rit"
        },
        {
          "name": "data[].calculator_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the surface norms calculator/table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].source_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Opaque provenance pointer to NWEA-published norms.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-source-ref"
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows returned in this page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "hasMore",
          "type": "BOOLEAN",
          "requirement": "required",
          "meaning": "Whether another page exists.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "nextCursor",
          "type": "TEXT nullable",
          "requirement": "required",
          "meaning": "Opaque cursor for the next page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "links.self",
          "type": "URL",
          "requirement": "required",
          "meaning": "The request URL for this page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        }
      ]
    },
    {
      "id": "translate-percentile-to-rit",
      "method": "GET",
      "path": "/alpha/analytics/v1/norms/rit",
      "title": "Translate percentile to RIT",
      "summary": "Convert a requested achievement percentile to a RIT score using the surface-owned achievement norms table for subject, grade, season, role, and norms set.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/norms/rit?subject=math&grade=5&season=winter&percentile=99&normsSet=2025\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "analytics.norms_rit_translation",
        "direction": "percentile_to_rit",
        "norms_set": "2025",
        "subject_id": "math",
        "grade_key": "5",
        "grade_level": 5,
        "season": "winter",
        "role": "student",
        "percentile": 99,
        "rit_score": 252,
        "output_rit": 252,
        "raw_rit": 252.345,
        "calculator_version": "analytics.norms.achievement.v2026-06-12",
        "mean_rit": 211.82,
        "sd_rit": 17.42,
        "source_ref": "NWEA 2025 MAP Growth Norms Technical Manual (Hawthorne, Velazquez, Peng, Hall, Newburn, 2025)",
        "links": {
          "table": "/alpha/analytics/v1/norms/table?subject=math&grade=5&season=winter&normsSet=2025&role=student"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_norms_achievement",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement",
        "note": "Readable NWEA achievement-status norms resource for percentile-to-RIT and RIT-to-percentile translation. Apps may read/cache the surface table by table_version or call /norms/rit and /norms/percentile; they never maintain their own norms table."
      },
      "architecture": [
        {
          "id": "aitd-016-scale-translation-apis",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Required",
          "description": "math, reading, language, or science. subjectId is accepted as an alias."
        },
        {
          "name": "grade",
          "type": "TEXT",
          "requirement": "Required",
          "description": "K or 1 through 12. gradeLevel is accepted as an alias."
        },
        {
          "name": "season",
          "type": "TEXT enum",
          "requirement": "Required",
          "description": "fall, winter, or spring. termSeason is accepted as an alias."
        },
        {
          "name": "role",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "NWEA role/population label. Defaults to student."
        },
        {
          "name": "percentile",
          "type": "NUMERIC",
          "requirement": "Required",
          "description": "Percentile to translate. Must be greater than 0 and less than 100."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Required",
          "description": "2020 or 2025."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.norms_rit_translation.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "direction",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "percentile_to_rit.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical subject used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-subject-id"
        },
        {
          "name": "grade_key",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Grade key used by the published norms resource.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-grade-key"
        },
        {
          "name": "grade_level",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Numeric grade level used by the calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "season",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "fall, winter, spring, or another published NWEA season label.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-season"
        },
        {
          "name": "role",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "NWEA role/population label used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-role"
        },
        {
          "name": "percentile",
          "type": "NUMERIC(5,2)",
          "requirement": "required",
          "meaning": "Requested percentile.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "rit_score",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Rounded RIT score returned by the surface calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "output_rit",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Stable output alias for the rounded RIT score.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "raw_rit",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Unrounded calculator output, rounded to three decimals.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "norms_set",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Norms family used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-norms-set"
        },
        {
          "name": "calculator_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the surface norms table and calculator used for the normal-model translation.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "mean_rit",
          "type": "NUMERIC(7,2)",
          "requirement": "required",
          "meaning": "Published mean RIT used by the calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-mean-rit"
        },
        {
          "name": "sd_rit",
          "type": "NUMERIC(6,3)",
          "requirement": "required",
          "meaning": "Published RIT standard deviation used by the calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-sd-rit"
        },
        {
          "name": "source_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Provenance pointer for the published norms row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-source-ref"
        },
        {
          "name": "links.table",
          "type": "URL",
          "requirement": "required",
          "meaning": "The /norms/table resource row used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        }
      ]
    },
    {
      "id": "translate-rit-to-percentile",
      "method": "GET",
      "path": "/alpha/analytics/v1/norms/percentile",
      "title": "Translate RIT to percentile",
      "summary": "Convert a RIT score to an achievement percentile using the same surface-owned norms table row.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/norms/percentile?subject=math&grade=5&season=winter&rit=247&normsSet=2025\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "analytics.norms_percentile_translation",
        "direction": "rit_to_percentile",
        "norms_set": "2025",
        "subject_id": "math",
        "grade_key": "5",
        "grade_level": 5,
        "season": "winter",
        "role": "student",
        "rit_score": 247,
        "input_rit": 247,
        "percentile": 98,
        "output_percentile": 98,
        "raw_percentile": 97.828,
        "calculator_version": "analytics.norms.achievement.v2026-06-12",
        "mean_rit": 211.82,
        "sd_rit": 17.42,
        "source_ref": "NWEA 2025 MAP Growth Norms Technical Manual (Hawthorne, Velazquez, Peng, Hall, Newburn, 2025)",
        "links": {
          "table": "/alpha/analytics/v1/norms/table?subject=math&grade=5&season=winter&normsSet=2025&role=student"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_norms_achievement",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement",
        "note": "Readable NWEA achievement-status norms resource for percentile-to-RIT and RIT-to-percentile translation. Apps may read/cache the surface table by table_version or call /norms/rit and /norms/percentile; they never maintain their own norms table."
      },
      "architecture": [
        {
          "id": "aitd-016-scale-translation-apis",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Required",
          "description": "math, reading, language, or science. subjectId is accepted as an alias."
        },
        {
          "name": "grade",
          "type": "TEXT",
          "requirement": "Required",
          "description": "K or 1 through 12. gradeLevel is accepted as an alias."
        },
        {
          "name": "season",
          "type": "TEXT enum",
          "requirement": "Required",
          "description": "fall, winter, or spring. termSeason is accepted as an alias."
        },
        {
          "name": "role",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "NWEA role/population label. Defaults to student."
        },
        {
          "name": "rit",
          "type": "NUMERIC",
          "requirement": "Required",
          "description": "RIT score to translate."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Required",
          "description": "2020 or 2025."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.norms_percentile_translation.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        },
        {
          "name": "direction",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "rit_to_percentile.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical subject used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-subject-id"
        },
        {
          "name": "grade_key",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Grade key used by the published norms resource.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-grade-key"
        },
        {
          "name": "grade_level",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Numeric grade level used by the calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "season",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "fall, winter, spring, or another published NWEA season label.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-season"
        },
        {
          "name": "role",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "NWEA role/population label used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-role"
        },
        {
          "name": "rit_score",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Requested RIT score, rounded for response stability.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "input_rit",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Requested RIT score.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "percentile",
          "type": "NUMERIC(5,2)",
          "requirement": "required",
          "meaning": "Achievement percentile returned by the surface calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "output_percentile",
          "type": "NUMERIC(5,2)",
          "requirement": "required",
          "meaning": "Stable output alias for the achievement percentile.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "raw_percentile",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Unrounded normal-model percentile, rounded to three decimals.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "norms_set",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Norms family used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-norms-set"
        },
        {
          "name": "calculator_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the surface norms table and calculator used for the normal-model translation.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "mean_rit",
          "type": "NUMERIC(7,2)",
          "requirement": "required",
          "meaning": "Published mean RIT used by the calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-mean-rit"
        },
        {
          "name": "sd_rit",
          "type": "NUMERIC(6,3)",
          "requirement": "required",
          "meaning": "Published RIT standard deviation used by the calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-sd-rit"
        },
        {
          "name": "source_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Provenance pointer for the published norms row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement-source-ref"
        },
        {
          "name": "links.table",
          "type": "URL",
          "requirement": "required",
          "meaning": "The /norms/table resource row used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement"
        }
      ]
    },
    {
      "id": "get-r90-resource",
      "method": "GET",
      "path": "/alpha/analytics/v1/r90/table",
      "title": "Read the R90 table",
      "summary": "Read the single versioned Alpha R90 table used for RIT-to-grade and GOALS track-position work.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/r90/table?subject=math&normsSet=2025&limit=1\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "table": "analytics.r90_table",
        "table_version": "analytics.rit_to_grade.powerpath.v2026-06-15",
        "data": [
          {
            "id": "r90_math_172",
            "table_version": "analytics.rit_to_grade.powerpath.v2026-06-15",
            "table_subject_id": "math",
            "subject_id": "math",
            "source_subject_name": "Math",
            "rit_score": 172,
            "r90_grade": 0,
            "effective_grade": 1,
            "r90_grade_level": 0,
            "r90_percent_complete": 0,
            "rit90_grade_band_percent": 0,
            "observation_count": 1,
            "source_ref": "powerpath:/powerpath/rit-to-grade",
            "ownerModule": "nweamap"
          }
        ],
        "limit": 1,
        "hasMore": true,
        "nextCursor": "eyJvZmZzZXQiOjF9",
        "links": {
          "self": "/alpha/analytics/v1/r90/table?subject=math&normsSet=2025&limit=1"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_r90_table",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table",
        "note": "Readable RIT-to-R90 and grade-position reference for GOALS target conversion, Learning Report grade-position display, and screener starting-grade hints. Final PowerPath placement comes from bottom-up grade-level mastery tests, not this table. Actual course and grade-level progress comes from completion-rollups. Analytics serves an Alpha-compatible mirror; the PowerPath RIT-to-grade master source is owned by NWEAMAP."
      },
      "architecture": [
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-017-r90-version-supersession",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-017-r90-version-supersession"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "math, reading, language, science, or a locked proxy subject such as vocabulary, writing, or fastmath. subjectId is accepted as an alias."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Optional",
          "description": "2020 or 2025. Accepted for caller symmetry; the current R90 table version is returned."
        },
        {
          "name": "tableVersion",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Immutable R90 table_version. Omit for the current version of the requested normsSet."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Always list.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table"
        },
        {
          "name": "table",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.r90_table list resource over alpha.analytics_r90_table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table"
        },
        {
          "name": "table_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the readable R90 table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-table-version"
        },
        {
          "name": "data[].id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Stable Analytics id for this R90 row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table"
        },
        {
          "name": "data[].table_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Immutable version id for the row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-table-version"
        },
        {
          "name": "data[].table_subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical table subject for this R90 row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-table-subject-id"
        },
        {
          "name": "data[].subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Subject returned by the table endpoint.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].source_subject_name",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Published source subject name for audit display.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].rit_score",
          "type": "NUMERIC(7,2)",
          "requirement": "required",
          "meaning": "RIT score represented by this row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-rit-score"
        },
        {
          "name": "data[].r90_grade",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Plain grade-position value for this row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-grade"
        },
        {
          "name": "data[].effective_grade",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Report-ready grade/effective-grade label.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-effective-grade"
        },
        {
          "name": "data[].r90_grade_level",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Governed grade-level bucket for this row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-grade-level"
        },
        {
          "name": "data[].r90_percent_complete",
          "type": "NUMERIC(7,3)",
          "requirement": "required",
          "meaning": "Compatibility field for the MAP-inferred percent through the R90 grade band.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-percent-complete"
        },
        {
          "name": "data[].rit90_grade_band_percent",
          "type": "NUMERIC(7,3)",
          "requirement": "required",
          "meaning": "Clear field name for the MAP-inferred percent through the R90 grade band. This is not actual course or grade-level progress.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-percent-complete"
        },
        {
          "name": "data[].observation_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Count carried by the Alpha R90 mirror for audit.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "data[].source_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Runtime provenance pointer for the NWEAMAP-owned seeded grade2rit source backing this current table row. It is not a route and clients do not read it to answer reports; cache and reproduce by table_version.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-source-norms-refs"
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows returned in this page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "hasMore",
          "type": "BOOLEAN",
          "requirement": "required",
          "meaning": "Whether another page exists.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "nextCursor",
          "type": "TEXT nullable",
          "requirement": "required",
          "meaning": "Opaque cursor for the next page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        },
        {
          "name": "links.self",
          "type": "URL",
          "requirement": "required",
          "meaning": "The request URL for this page.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#convergence"
        }
      ]
    },
    {
      "id": "translate-rit-to-r90",
      "method": "GET",
      "path": "/alpha/analytics/v1/r90",
      "title": "Translate RIT to R90 and grade position",
      "summary": "Return the R90 grade, effective grade, grade level, and MAP-inferred grade-band percent for a RIT score using the current exact PowerPath RIT-to-grade mirror.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/r90?subject=math&rit=239&normsSet=2025\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "analytics.r90_lookup",
        "table_version": "analytics.rit_to_grade.powerpath.v2026-06-15",
        "requested_subject_id": "math",
        "table_subject_id": "math",
        "subject_id": "math",
        "rit_score": 239,
        "table_rit_score": 239,
        "r90_grade": 4.8,
        "effective_grade": 5,
        "r90_grade_level": 4,
        "r90_percent_complete": 80,
        "rit90_grade_band_percent": 80,
        "source_point_kind": "exact",
        "calculator_version": "analytics.rit_to_grade.powerpath.v2026-06-15",
        "source_ref": "powerpath:/powerpath/rit-to-grade",
        "ownerModule": "nweamap",
        "links": {
          "table": "/alpha/analytics/v1/r90/table?subject=math"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_r90_table",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table",
        "note": "Readable RIT-to-R90 and grade-position reference for GOALS target conversion, Learning Report grade-position display, and screener starting-grade hints. Final PowerPath placement comes from bottom-up grade-level mastery tests, not this table. Actual course and grade-level progress comes from completion-rollups. Analytics serves an Alpha-compatible mirror; the PowerPath RIT-to-grade master source is owned by NWEAMAP."
      },
      "architecture": [
        {
          "id": "aitd-016-scale-translation-apis",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-017-r90-version-supersession",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-017-r90-version-supersession"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Required",
          "description": "math, reading, language, science, or a locked proxy subject such as vocabulary, writing, or fastmath. subjectId is accepted as an alias."
        },
        {
          "name": "rit",
          "type": "NUMERIC",
          "requirement": "Required",
          "description": "RIT score to translate. Exact table hits return source_point_kind=exact; missing rows return source_point_kind=source_missing rather than interpolation, step-flooring, upward clamping, or extrapolation."
        },
        {
          "name": "normsSet",
          "type": "norms_set enum",
          "requirement": "Optional",
          "description": "2020 or 2025. Accepted for caller symmetry; R90 table_version is returned in the body."
        },
        {
          "name": "tableVersion",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Immutable R90 table_version. Omit for the current version of the requested normsSet."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.r90_lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table"
        },
        {
          "name": "table_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the Alpha R90 mirror table.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-table-version"
        },
        {
          "name": "requested_subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Subject requested by the caller before locked proxy folding.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "table_subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical table subject used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-table-subject-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Subject returned to the caller after validation.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "rit_score",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "RIT table point used for the response.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-rit-score"
        },
        {
          "name": "table_rit_score",
          "type": "NUMERIC nullable",
          "requirement": "required",
          "meaning": "Selected table RIT. Exact lookups return the current-version row whose rit_score equals the requested RIT; missing rows return source_missing.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-rit-score"
        },
        {
          "name": "r90_grade",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Plain grade-position value for the RIT row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-grade"
        },
        {
          "name": "effective_grade",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Report-ready grade/effective-grade label.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-effective-grade"
        },
        {
          "name": "r90_grade_level",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Governed grade-level bucket for this R90 row.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-grade-level"
        },
        {
          "name": "r90_percent_complete",
          "type": "NUMERIC(7,3)",
          "requirement": "required",
          "meaning": "Compatibility field for the MAP-inferred percent through the R90 grade band.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-percent-complete"
        },
        {
          "name": "rit90_grade_band_percent",
          "type": "NUMERIC(7,3)",
          "requirement": "required",
          "meaning": "Clear field name for the MAP-inferred percent through the R90 grade band. This is not actual course or grade-level progress.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-r90-percent-complete"
        },
        {
          "name": "source_point_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "exact or source_missing. The current R90 lookup never interpolates, step-floors, clamps, or extrapolates.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-source-point-kind"
        },
        {
          "name": "calculator_version",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Version of the Alpha R90 mirror table and calculator.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources"
        },
        {
          "name": "source_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Runtime provenance pointer for the NWEAMAP-owned seeded grade2rit source row used by this lookup. It is not a route and clients do not read it to answer reports; cache and reproduce by table_version.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table-source-norms-refs"
        },
        {
          "name": "links.table",
          "type": "URL",
          "requirement": "required",
          "meaning": "The /r90/table resource family used for the lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table"
        }
      ]
    },
    {
      "id": "get-school-days-remaining",
      "method": "GET",
      "path": "/alpha/analytics/v1/school-days-remaining",
      "title": "Read school days remaining",
      "summary": "Return the forward instructional-day count and XP-to-time effort projection GOALS needs for its target-date column. GOALS asks Analytics for this read instead of doing calendar arithmetic locally.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/school-days-remaining?studentId=student-ada-001&asOf=2026-06-14&endDate=2026-07-24&xpRemaining=600&hoursPerSchoolDay=1.5&targetDate=2026-07-24\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "analytics.school_days_remaining",
        "student_id": "student-ada-001",
        "school_id": "school_alpha_demo",
        "as_of": "2026-06-14",
        "end_date": "2026-07-24",
        "school_day_policy_ref": "alpha.policy.school_day.v2026-06-10",
        "instructional_days_remaining": 29,
        "calendar_ref_count": 40,
        "first_instructional_date": "2026-06-15",
        "last_instructional_date": "2026-07-23",
        "instructional_dates": [
          "2026-06-15",
          "2026-06-16",
          "2026-06-17"
        ],
        "xp_unit": {
          "policy_ref": "alpha.policy.analytics.xp_expected_minute.v2026-06-14",
          "xp_per_expected_minute": 1,
          "xp_per_hour": 60,
          "meaning": "1 XP = 1 expected minute; XP hours = XP / 60."
        },
        "effort": {
          "xp_remaining": 600,
          "expected_minutes_remaining": 600,
          "hours_remaining": 10,
          "target_date": "2026-07-24",
          "school_days_until_target_date": 29,
          "required_hours_per_school_day_to_target_date": 0.345,
          "hours_per_school_day": 1.5,
          "school_days_needed_at_hours_per_school_day": 7,
          "target_date_at_hours_per_school_day": "2026-06-23",
          "can_finish_by_end_date_at_hours_per_school_day": true
        },
        "provenance": {
          "source": "alpha.school_calendar",
          "source_ref_sample": [
            "ed_fi.CalendarDate:school_alpha_demo:2026-06-15"
          ],
          "policy_ref": "alpha.policy.school_day.v2026-06-10",
          "xp_unit_policy_ref": "alpha.policy.analytics.xp_expected_minute.v2026-06-14"
        },
        "links": {
          "self": "/alpha/analytics/v1/school-days-remaining?studentId=student-ada-001&asOf=2026-06-14&endDate=2026-07-24",
          "schoolDayMinutes": "/alpha/analytics/v1/school-day-minutes?studentId=student-ada-001",
          "xpRollups": "/alpha/analytics/v1/xp-rollups?studentId=student-ada-001&windowKind=school_year"
        }
      },
      "sourceObject": {
        "name": "analytics.school_days_remaining",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining",
        "note": "GOALS response object over alpha.school_calendar, alpha.policy.school_day, and alpha.policy.analytics.xp_expected_minute.v2026-06-14; no app-side calendar table or XP-hour constant."
      },
      "architecture": [
        {
          "id": "aitd-018-goals-school-days-remaining",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-018-goals-school-days-remaining"
        },
        {
          "id": "aitd-006-school-day-minutes",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-006-school-day-minutes"
        },
        {
          "id": "aitd-007-xp-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        },
        {
          "id": "aitd-014-source-ownership-and-prerequisites",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-014-source-ownership-and-prerequisites"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Required",
          "description": "Canonical Alpha student id."
        },
        {
          "name": "schoolId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "School id for the calendar denominator. Omit to let Analytics infer the student's enrolled school."
        },
        {
          "name": "asOf",
          "type": "DATE",
          "requirement": "Required",
          "description": "Start date for the forward school-day count. startDate is accepted as an alias."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive end date for the forward window. schoolYearEnd is accepted as an alias; omit to use the surface's current GOALS school-year end."
        },
        {
          "name": "targetDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Date GOALS wants to test for the target-date column. Must be after asOf and on or before endDate."
        },
        {
          "name": "xpRemaining",
          "type": "NUMERIC",
          "requirement": "Optional",
          "description": "Remaining XP to convert into expected minutes by the surface unit 1 XP = 1 expected minute. Mutually exclusive with minutesRemaining and hoursRemaining."
        },
        {
          "name": "minutesRemaining",
          "type": "NUMERIC",
          "requirement": "Optional",
          "description": "Expected minutes remaining. Mutually exclusive with xpRemaining and hoursRemaining."
        },
        {
          "name": "hoursRemaining",
          "type": "NUMERIC",
          "requirement": "Optional",
          "description": "Expected hours remaining. Mutually exclusive with xpRemaining and minutesRemaining."
        },
        {
          "name": "hoursPerSchoolDay",
          "type": "NUMERIC",
          "requirement": "Optional",
          "description": "Planned hours per instructional day. When present, Analytics returns how many school days are needed and the date reached at that pace."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.school_days_remaining.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-object"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id used for the calendar/enrollment lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-student-id"
        },
        {
          "name": "school_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "School id whose alpha.school_calendar rows were read.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-school-id"
        },
        {
          "name": "as_of",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Inclusive start date for the forward count.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-as-of"
        },
        {
          "name": "end_date",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Exclusive end date for the forward count.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-end-date"
        },
        {
          "name": "school_day_policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Policy ref used to decide which calendar dates count as instructional days and which MAP days are excluded.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-school-day-policy-ref"
        },
        {
          "name": "instructional_days_remaining",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Count of school days after applying alpha.policy.school_day over the half-open [asOf, endDate) window.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-instructional-days-remaining"
        },
        {
          "name": "calendar_ref_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Count of calendar rows inspected before filtering to instructional days.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-calendar-ref-count"
        },
        {
          "name": "first_instructional_date",
          "type": "DATE nullable",
          "requirement": "required",
          "meaning": "First remaining instructional day, or null when no school day remains.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-first-instructional-date"
        },
        {
          "name": "last_instructional_date",
          "type": "DATE nullable",
          "requirement": "required",
          "meaning": "Last remaining instructional day in the requested window.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-last-instructional-date"
        },
        {
          "name": "instructional_dates",
          "type": "DATE[]",
          "requirement": "required",
          "meaning": "Instructional dates in the requested window. Render or cache these only as the surface-returned answer; do not recreate them from a private calendar.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-instructional-dates"
        },
        {
          "name": "xp_unit.policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Versioned policy that defines XP-to-expected-minute conversion.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-xp-unit-policy-ref"
        },
        {
          "name": "xp_unit.xp_per_expected_minute",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Surface-owned unit convention: 1 XP equals 1 expected minute.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-xp-unit-xp-per-expected-minute"
        },
        {
          "name": "xp_unit.xp_per_hour",
          "type": "NUMERIC",
          "requirement": "required",
          "meaning": "Surface-owned conversion: 60 XP equals one expected hour.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-xp-unit-xp-per-hour"
        },
        {
          "name": "xp_unit.meaning",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Plain-language statement of the XP time conversion.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-xp-unit-meaning"
        },
        {
          "name": "effort.xp_remaining",
          "type": "NUMERIC nullable",
          "requirement": "required",
          "meaning": "Caller-supplied remaining XP when xpRemaining was used.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-xp-remaining"
        },
        {
          "name": "effort.expected_minutes_remaining",
          "type": "NUMERIC nullable",
          "requirement": "required",
          "meaning": "Remaining effort in expected minutes after applying the surface XP/minutes/hours conversion.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-expected-minutes-remaining"
        },
        {
          "name": "effort.hours_remaining",
          "type": "NUMERIC nullable",
          "requirement": "required",
          "meaning": "Remaining effort in hours.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-hours-remaining"
        },
        {
          "name": "effort.target_date",
          "type": "DATE nullable",
          "requirement": "required",
          "meaning": "Requested target date, if supplied.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-target-date"
        },
        {
          "name": "effort.school_days_until_target_date",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "Instructional days between asOf and targetDate.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-school-days-until-target-date"
        },
        {
          "name": "effort.required_hours_per_school_day_to_target_date",
          "type": "NUMERIC nullable",
          "requirement": "required",
          "meaning": "Hours per remaining school day needed to finish by targetDate.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-required-hours-per-school-day-to-target-date"
        },
        {
          "name": "effort.hours_per_school_day",
          "type": "NUMERIC nullable",
          "requirement": "required",
          "meaning": "Caller-supplied pace assumption.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-hours-per-school-day"
        },
        {
          "name": "effort.school_days_needed_at_hours_per_school_day",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "Instructional days needed at the supplied pace.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-school-days-needed-at-hours-per-school-day"
        },
        {
          "name": "effort.target_date_at_hours_per_school_day",
          "type": "DATE nullable",
          "requirement": "required",
          "meaning": "Instructional date reached at the supplied pace, or null when the window is too short.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-target-date-at-hours-per-school-day"
        },
        {
          "name": "effort.can_finish_by_end_date_at_hours_per_school_day",
          "type": "BOOLEAN nullable",
          "requirement": "required",
          "meaning": "Whether the supplied pace finishes within the requested forward window.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-effort-can-finish-by-end-date-at-hours-per-school-day"
        },
        {
          "name": "provenance.source",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Calendar source read by Analytics.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-provenance-source"
        },
        {
          "name": "provenance.source_ref_sample",
          "type": "TEXT[]",
          "requirement": "required",
          "meaning": "Sample Ed-Fi CalendarDate-derived refs used for audit.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-provenance-source-ref-sample"
        },
        {
          "name": "provenance.policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Policy ref used for the school-day decision.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-provenance-policy-ref"
        },
        {
          "name": "provenance.xp_unit_policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "XP expected-minute policy ref used for effort projection.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-provenance-xp-unit-policy-ref"
        },
        {
          "name": "links.self",
          "type": "URL",
          "requirement": "required",
          "meaning": "The request URL for this read.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-links-self"
        },
        {
          "name": "links.schoolDayMinutes",
          "type": "URL",
          "requirement": "required",
          "meaning": "Related school-day-minutes rollup endpoint.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-links-schooldayminutes"
        },
        {
          "name": "links.xpRollups",
          "type": "URL",
          "requirement": "required",
          "meaning": "Related XP rollup endpoint.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining-links-xprollups"
        }
      ]
    },
    {
      "id": "get-grade-level-status",
      "method": "GET",
      "path": "/alpha/analytics/v1/grade-level-status",
      "title": "Read working and mastered age-grade status",
      "summary": "Return the two named GOALS age-grade comparisons. Analytics reads P&O age grade and Results grade positions, then returns working-vs-age and mastered-vs-age labels so clients do not recompute or rename ahead/at/behind.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/grade-level-status?studentId=b6fa7128-f641-4efd-9075-375411fd6c39&subject=math&asOfDate=2026-05-20\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "analytics.grade_level_status",
        "student_id": "b6fa7128-f641-4efd-9075-375411fd6c39",
        "subject_id": "math",
        "as_of_date": "2026-05-20",
        "age_grade": 5,
        "working_grade": 6,
        "highest_mastered_grade": 5,
        "working_age_grade_delta": 1,
        "working_age_grade_status": "working_above_age_grade",
        "mastered_age_grade_delta": 0,
        "mastered_age_grade_status": "mastered_at_age_grade",
        "source_refs": {
          "age_grade": "people_and_orgs.alpha.age_grade_history",
          "working_grade": "results.student_track_state.working_grade",
          "highest_mastered_grade": "results.highest_mastered_grade"
        },
        "deprecated_aliases": {
          "instructional_level_status": "working_age_grade_status",
          "strict_mastery_status": "mastered_age_grade_status"
        }
      },
      "sourceObject": {
        "name": "analytics.grade_level_status",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status",
        "note": "Read-time response over People & Orgs alpha.age_grade_history and Results working_grade/highest_mastered_grade; no Analytics-owned age grade table."
      },
      "architecture": [
        {
          "id": "aitd-008-mastery-and-grade-levels",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-008-mastery-and-grade-levels"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-014-source-ownership-and-prerequisites",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-014-source-ownership-and-prerequisites"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Required",
          "description": "Canonical Alpha student id."
        },
        {
          "name": "subject",
          "type": "subject_id enum",
          "requirement": "Required",
          "description": "Canonical subject id. subjectId is also accepted by the runtime."
        },
        {
          "name": "asOfDate",
          "type": "DATE",
          "requirement": "Required",
          "description": "Point-in-time date for P&O age grade and Results grade state."
        }
      ],
      "response": [
        {
          "name": "object",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "analytics.grade_level_status.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-object"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-student-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical subject id used for Results working/HMG lookup.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-subject-id"
        },
        {
          "name": "as_of_date",
          "type": "DATE",
          "requirement": "required",
          "meaning": "Point-in-time date for P&O age grade and Results state.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-as-of-date"
        },
        {
          "name": "age_grade",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "School-assigned cohort grade from People & Orgs alpha.age_grade_history.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-age-grade"
        },
        {
          "name": "working_grade",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "Results-owned working grade.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-working-grade"
        },
        {
          "name": "highest_mastered_grade",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "Results-owned highest mastered grade.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-highest-mastered-grade"
        },
        {
          "name": "working_age_grade_delta",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "working_grade - age_grade.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-working-age-grade-delta"
        },
        {
          "name": "working_age_grade_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "working_behind_age_grade, working_at_age_grade, working_above_age_grade, or unknown.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-working-age-grade-status"
        },
        {
          "name": "mastered_age_grade_delta",
          "type": "INTEGER nullable",
          "requirement": "required",
          "meaning": "highest_mastered_grade - age_grade.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-mastered-age-grade-delta"
        },
        {
          "name": "mastered_age_grade_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "mastered_behind_age_grade, mastered_at_age_grade, mastered_above_age_grade, or unknown.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-mastered-age-grade-status"
        },
        {
          "name": "source_refs",
          "type": "JSON object",
          "requirement": "required",
          "meaning": "Owner pointers for P&O age grade and Results grade positions.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-source-refs"
        },
        {
          "name": "deprecated_aliases",
          "type": "JSON object",
          "requirement": "required",
          "meaning": "Compatibility mapping only; not the preferred public contract.",
          "constraints": "",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status-deprecated-aliases"
        }
      ]
    },
    {
      "id": "list-completion-rollups",
      "method": "GET",
      "path": "/alpha/analytics/v1/completion-rollups",
      "title": "List completion rollups",
      "summary": "Read progress evidence used by Results and audit views. Course rows preserve app-reported Caliper percent and XP remaining evidence; student-facing course and grade-level progress comes from Results course-progress and grade-level-progress.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/completion-rollups?studentId=student_01HT7G3YZV7QB5N4YKQ1K0Z9A9&completionScope=course&scopeId=course_math_grade_4_powerpath\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/completion-rollups",
        "data": [
          {
            "id": "6d7d3b01-6b70-44ce-90dd-e7cf2f690006",
            "student_id": "student_01HT7G3YZV7QB5N4YKQ1K0Z9A9",
            "completion_scope": "course",
            "scope_id": "course_math_grade_4_powerpath",
            "subject_id": "math",
            "grade_level": 4,
            "is_main_course": true,
            "progress_source_kind": "app_reported_percent",
            "xp_earned": null,
            "xp_remaining": null,
            "completion_percent": 75,
            "denominator_policy_ref": "alpha.policy.analytics.course_progress.v2026-06-15",
            "curriculum_scope_refs": [
              "course_component_01HT8ROOT",
              "progress_source:app_reported_percent",
              "course_role:main",
              "grade_level:4"
            ],
            "source_import_id": "imp_01HT8COMPLETION_2026_SPRING",
            "null_reason": "none",
            "quality_status": "ok",
            "modified_at": "2026-06-01T01:03:00Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/completion-rollups"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_completion_rollup",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup",
        "note": "Progress evidence for Results and Analytics audits without MAP/RIT/R90 inference, client-side Curriculum tree walking, or Results-row counting."
      },
      "architecture": [
        {
          "id": "aitd-010-completion-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-010-completion-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        }
      ],
      "request": [
        {
          "name": "studentId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Canonical Alpha student id."
        },
        {
          "name": "completionScope",
          "type": "completion_scope enum",
          "requirement": "Optional",
          "description": "course, subject, track, track_level, grade_level, or segment."
        },
        {
          "name": "scopeId",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Course, subject, track, track-level, grade-level, or segment scope id. Grade-level scope ids are grade_level:{subject}:{grade}."
        },
        {
          "name": "subjectId",
          "type": "subject_id enum",
          "requirement": "Optional",
          "description": "Canonical Alpha subject id."
        },
        {
          "name": "startDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Inclusive reporting window start."
        },
        {
          "name": "endDate",
          "type": "DATE",
          "requirement": "Optional",
          "description": "Exclusive reporting window end."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "Poll for changed rows."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "id",
          "type": "UUID",
          "requirement": "required",
          "meaning": "Analytics-owned stable row id for this derived fact.",
          "constraints": "Generated by the platform; globally unique within alpha.analytics_* objects.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-id"
        },
        {
          "name": "student_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Canonical Alpha student id the source Event or Result resolved to at materialization time.",
          "constraints": "Must resolve through People and Orgs as a real student for the source timestamp/effective date.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-student-id"
        },
        {
          "name": "completion_scope",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Curriculum/reporting scope for this completion measure.",
          "constraints": "Allowed values: completion_scope enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-completion-scope"
        },
        {
          "name": "scope_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Identifier of the Curriculum or subject scope being measured.",
          "constraints": "Must match completion_scope: course id for course, subject id for subject, track id for track, etc.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-scope-id"
        },
        {
          "name": "subject_id",
          "type": "TEXT",
          "requirement": "nullable; required when completion_scope=subject or the scope resolves to one subject",
          "meaning": "Canonical Alpha subject used for reporting and grouping.",
          "constraints": "Closed Alpha subject enum after write-time alias folds; unknown source subject becomes an adapter finding or null_reason, not a new string.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-subject-id"
        },
        {
          "name": "grade_level",
          "type": "INTEGER",
          "requirement": "nullable for non-grade-level scopes without a course grade",
          "meaning": "Working grade level associated with the course progress row, or the grade represented by a grade_level aggregate.",
          "constraints": "Must come from the course/Caliper/Curriculum scope metadata, not from MAP/RIT/R90.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-grade-level"
        },
        {
          "name": "is_main_course",
          "type": "BOOLEAN",
          "requirement": "nullable when not applicable; true for main course and grade_level aggregate rows",
          "meaning": "Whether the course row counts toward grade-level progress.",
          "constraints": "Main grade-level courses count; remediation, hole-filling, catalog, practice, and review courses do not.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-is-main-course"
        },
        {
          "name": "progress_source_kind",
          "type": "TEXT enum",
          "requirement": "required for reportable progress rows",
          "meaning": "Which evidence source produced completion_percent.",
          "constraints": "Allowed values include app_reported_percent, xp_remaining, lesson_count, subject_aggregate, and main_course_aggregate.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-progress-source-kind"
        },
        {
          "name": "xp_earned",
          "type": "NUMERIC(14,3)",
          "requirement": "nullable when progress_source_kind is app_reported_percent or an aggregate without XP evidence",
          "meaning": "Earned XP for this completion scope when the row uses the XP fallback.",
          "constraints": "Nonnegative when present; source corrections are reflected through quality_status/corrections before this value is reportable.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-xp-earned"
        },
        {
          "name": "xp_remaining",
          "type": "NUMERIC(14,3)",
          "requirement": "nullable when progress_source_kind is app_reported_percent or an aggregate without XP evidence",
          "meaning": "Remaining expected XP for this completion scope when the row uses the XP fallback.",
          "constraints": "Nonnegative when present; computed from Curriculum expected XP refs under denominator_policy_ref.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-xp-remaining"
        },
        {
          "name": "completion_percent",
          "type": "NUMERIC(7,3)",
          "requirement": "nullable when no direct percent, XP denominator, lesson denominator, or source/policy is available",
          "meaning": "Report-ready completion measure for the scope.",
          "constraints": "Direct app percent wins. If absent, fallback formula is xp_earned / (xp_earned + xp_remaining) * 100. Normally 0 to 100; null requires null_reason.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-completion-percent"
        },
        {
          "name": "denominator_policy_ref",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Policy that decides which Curriculum expected-XP refs belong in the remaining-XP denominator.",
          "constraints": "Named versioned progress policy, for example alpha.policy.analytics.course_progress.v2026-06-15 or alpha.policy.curriculum.main_course_grade_level.v2026-06-15, or inherited Curriculum policy.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-denominator-policy-ref"
        },
        {
          "name": "curriculum_scope_refs",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Compact ids/cursor for Curriculum refs used to form the denominator.",
          "constraints": "Refs/hashes only; never copies Curriculum trees or Content rows.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-curriculum-scope-refs"
        },
        {
          "name": "source_import_id",
          "type": "TEXT",
          "requirement": "required for report-tile rows; nullable for purely derived event-axis rows",
          "meaning": "Analytics source-import receipt that proves which named report-source adapter produced this report-grade fact.",
          "constraints": "Must reference alpha.analytics_source_import for non-null Learning Report tile values; no literal or fixture value may be reportable without this provenance.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-source-import-id"
        },
        {
          "name": "null_reason",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Why completion_percent is null or not reportable.",
          "constraints": "Allowed values: null_reason enum; none means the metric is populated.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-null-reason"
        },
        {
          "name": "quality_status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Current materialization quality state for this fact.",
          "constraints": "Allowed values: quality_status enum. Ordinary report reads keep ok, corrected, and signed reversed rows according to the table rule; audit reads may include source_missing/source_unlinked/policy_pending/adapter_rejected.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-quality-status"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup-modified-at"
        }
      ]
    },
    {
      "id": "import-timeback-xp-time-accuracy",
      "method": "POST",
      "path": "/alpha/analytics/v1/source-imports/timeback-xp-time-accuracy",
      "title": "Import TimeBack XP, time, and accuracy facts",
      "summary": "Submit source-shaped reporting.processed_facts rows. Analytics normalizes subject, time, XP, and source refs server-side.",
      "auth": "Bearer JWT plus Idempotency-Key header.",
      "scopes": [
        "analytics:write"
      ],
      "curl": "curl -sS -X POST \"$ANALYTICS_BASE_URL/alpha/analytics/v1/source-imports/timeback-xp-time-accuracy\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\" \\\n  -H \"Idempotency-Key: pfacts-demo-2026-05-01\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"sourceBatchRef\":\"migration-demo-2026-05\",\"rows\":[{\"date\":\"2026-05-14\",\"subject\":\"Math\",\"app\":\"Math Academy\",\"active_seconds\":420,\"inactive_seconds\":0,\"waste_seconds\":0,\"xp_earned\":18}]}'",
      "sampleResponse": {
        "import_id": "import_01J0ANALYTICS",
        "status": "materialized",
        "submitted_row_count": 250,
        "accepted_row_count": 249,
        "materialized_row_count": 249,
        "rejected_row_count": 1,
        "problem_counts": {
          "analytics:source_unlinked": 1
        },
        "completed_at": "2026-06-12T17:05:00Z"
      },
      "sourceObject": {
        "name": "alpha.analytics_source_import",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import",
        "note": "Provenance spine for every ingested report-grade fact: adapter, source system/table, idempotency key, source-row natural-key/hash set, materialized counts, and per-row Problem summaries."
      },
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-007-xp-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        },
        {
          "id": "aitd-105-axis-idempotency",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-105-axis-idempotency"
        }
      ],
      "request": [
        {
          "name": "Idempotency-Key",
          "type": "HTTP header",
          "requirement": "Required",
          "description": "Required for source imports. Same key plus different body returns analytics:idempotency_conflict."
        },
        {
          "name": "sourceBatchRef",
          "type": "TEXT",
          "requirement": "Required",
          "description": "Operator-controlled batch reference for audit and reconciliation."
        },
        {
          "name": "rows",
          "type": "JSON array",
          "requirement": "Required",
          "description": "Raw source-shaped processed_facts rows. Do not pre-normalize subject, time, XP, or student identity."
        }
      ],
      "response": [
        {
          "name": "import_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Stable id for this source import request.",
          "constraints": "Generated by platform; unique per tenant.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-import-id"
        },
        {
          "name": "status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Processing state of the source import.",
          "constraints": "Allowed values: import_status enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-status"
        },
        {
          "name": "submitted_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of source-shaped rows submitted in the batch.",
          "constraints": "Nonnegative.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-submitted-row-count"
        },
        {
          "name": "accepted_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows accepted by request validation and adapter mapping.",
          "constraints": "Nonnegative and not greater than submitted_row_count.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-accepted-row-count"
        },
        {
          "name": "materialized_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows that produced readable Analytics facts.",
          "constraints": "Nonnegative; successful nonempty imports must produce readable rows unless status explains otherwise.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-materialized-row-count"
        },
        {
          "name": "rejected_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows rejected by validation or adapter mapping.",
          "constraints": "Nonnegative; submitted = accepted + rejected for completed imports.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-rejected-row-count"
        },
        {
          "name": "problem_counts",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Counts of typed Problem codes produced by the import.",
          "constraints": "Keys must be stable analytics:* codes; values nonnegative integers.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-problem-counts"
        },
        {
          "name": "completed_at",
          "type": "TIMESTAMPTZ",
          "requirement": "nullable until processing completes",
          "meaning": "When import processing reached a terminal status.",
          "constraints": "UTC timestamp; null while status is received/running.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-completed-at"
        }
      ]
    },
    {
      "id": "import-timeback-map",
      "method": "POST",
      "path": "/alpha/analytics/v1/source-imports/timeback-map",
      "title": "Import TimeBack MAP results",
      "summary": "Submit source-shaped reporting.hp_map_results rows. Analytics normalizes student, subject, term, norms, test-of-record, Growth X, and R90 position server-side.",
      "auth": "Bearer JWT plus Idempotency-Key header.",
      "scopes": [
        "analytics:write"
      ],
      "curl": "curl -sS -X POST \"$ANALYTICS_BASE_URL/alpha/analytics/v1/source-imports/timeback-map\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\" \\\n  -H \"Idempotency-Key: hp-map-demo-2026-winter\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"sourceBatchRef\":\"migration-demo-map-2026-winter\",\"rows\":[{\"id\":\"hp-map-demo-001\",\"studentid\":\"student_01HT7G3YZV7QB5N4YKQ1K0Z9A9\",\"course\":\"Math K-12\",\"termname\":\"Winter 2025-2026\",\"teststartdate\":\"2026-01-28\",\"testritscore\":239,\"testpercentile\":91,\"wintertowinterconditionalgrowthpercentile\":43,\"wintertowinterobservedgrowth\":6,\"wintertowinterprojectedgrowth\":7,\"typicalwintertowintergrowth\":2,\"normsreferencedata\":2025,\"growthmeasureyn\":\"true\",\"goal1name\":\"Operations and Algebraic Thinking\",\"goal1ritscore\":241}]}'",
      "sampleResponse": {
        "import_id": "import_01J0MAPRESULTS",
        "import_kind": "timeback-map",
        "adapter_name": "timeback-map",
        "source_system": "reporting",
        "source_table": "hp_map_results",
        "status": "materialized",
        "submitted_row_count": 12,
        "accepted_row_count": 12,
        "materialized_row_count": 12,
        "rejected_row_count": 0,
        "problem_counts": {},
        "completed_at": "2026-06-12T17:08:00Z"
      },
      "sourceObject": {
        "name": "alpha.analytics_source_import",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import",
        "note": "Provenance spine for every ingested report-grade fact: adapter, source system/table, idempotency key, source-row natural-key/hash set, materialized counts, and per-row Problem summaries."
      },
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-105-axis-idempotency",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-105-axis-idempotency"
        }
      ],
      "request": [
        {
          "name": "Idempotency-Key",
          "type": "HTTP header",
          "requirement": "Required",
          "description": "Required for source imports. Same key plus different body returns analytics:idempotency_conflict."
        },
        {
          "name": "sourceBatchRef",
          "type": "TEXT",
          "requirement": "Required",
          "description": "Operator-controlled batch reference for audit and reconciliation."
        },
        {
          "name": "rows",
          "type": "JSON array",
          "requirement": "Required",
          "description": "Full source-shaped reporting.hp_map_results rows. Submit the row as exported; do not pre-dedupe, parse terms, normalize subjects, compute Growth X, or apply norms/R90 locally."
        },
        {
          "name": "rows[].studentid",
          "type": "TEXT",
          "requirement": "Required",
          "description": "TimeBack/NWEA student id from hp_map_results. student_sourced_id is accepted only for migration compatibility; the adapter resolves the canonical Alpha student id."
        },
        {
          "name": "rows[].course or rows[].subject",
          "type": "TEXT",
          "requirement": "Required",
          "description": "Source MAP course/subject label such as Math K-12. The adapter writes the canonical subject_id."
        },
        {
          "name": "rows[].termname",
          "type": "TEXT",
          "requirement": "Required",
          "description": "Source MAP term label such as Winter 2025-2026. The adapter writes canonical_term_id; callers do not parse term strings."
        },
        {
          "name": "rows[].testritscore",
          "type": "INTEGER",
          "requirement": "Required",
          "description": "MAP RIT score. Missing RIT returns analytics:adapter_rejected."
        },
        {
          "name": "rows[].normsreferencedata",
          "type": "INTEGER enum",
          "requirement": "Required",
          "description": "NWEA norms family, normally 2020 or 2025. The adapter writes norms_set."
        },
        {
          "name": "rows[].wintertowinterobservedgrowth",
          "type": "NUMERIC",
          "requirement": "Required for winter_to_winter",
          "description": "Observed growth for the Learning Report MAP window."
        },
        {
          "name": "rows[].wintertowinterprojectedgrowth",
          "type": "NUMERIC",
          "requirement": "Required for winter_to_winter",
          "description": "Projected-growth denominator for Growth X. The adapter never uses typical growth as the Learning Report denominator when projected growth is present."
        },
        {
          "name": "rows[].testpercentile",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Achievement percentile from hp_map_results. If omitted, Analytics derives it from the surface-owned norms table and stamps the calculator/table version."
        }
      ],
      "response": [
        {
          "name": "import_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Stable id for this source import request.",
          "constraints": "Generated by platform; unique per tenant.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-import-id"
        },
        {
          "name": "import_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Which source/replay contract this batch follows.",
          "constraints": "Allowed values: import_kind enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-import-kind"
        },
        {
          "name": "adapter_name",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Named server-side adapter that normalized this source batch.",
          "constraints": "Must match one approved adapter: timeback-xp-time-accuracy, timeback-map, timeback-grade-mastery, or timeback-completion, plus internal replay kinds where applicable.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-adapter-name"
        },
        {
          "name": "source_system",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Producer system the adapter read from.",
          "constraints": "Closed governed values for approved adapters: reporting, events, results, migration_reconcile.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-source-system"
        },
        {
          "name": "source_table",
          "type": "TEXT",
          "requirement": "required for report-source adapters",
          "meaning": "Report-source table or producer collection read by the adapter.",
          "constraints": "For the four public report adapters: processed_facts, hp_map_results, assessment_results, or processed_facts+courses+course_components. For timeback-map, source_table=hp_map_results means the adapter accepts the full source-shaped row and ignores unknown extra columns.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-source-table"
        },
        {
          "name": "status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Processing state of the source import.",
          "constraints": "Allowed values: import_status enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-status"
        },
        {
          "name": "submitted_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of source-shaped rows submitted in the batch.",
          "constraints": "Nonnegative.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-submitted-row-count"
        },
        {
          "name": "accepted_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows accepted by request validation and adapter mapping.",
          "constraints": "Nonnegative and not greater than submitted_row_count.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-accepted-row-count"
        },
        {
          "name": "materialized_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows that produced readable Analytics facts.",
          "constraints": "Nonnegative; successful nonempty imports must produce readable rows unless status explains otherwise.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-materialized-row-count"
        },
        {
          "name": "rejected_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows rejected by validation or adapter mapping.",
          "constraints": "Nonnegative; submitted = accepted + rejected for completed imports.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-rejected-row-count"
        },
        {
          "name": "problem_counts",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Counts of typed Problem codes produced by the import.",
          "constraints": "Keys must be stable analytics:* codes; values nonnegative integers.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-problem-counts"
        },
        {
          "name": "completed_at",
          "type": "TIMESTAMPTZ",
          "requirement": "nullable until processing completes",
          "meaning": "When import processing reached a terminal status.",
          "constraints": "UTC timestamp; null while status is received/running.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-completed-at"
        }
      ]
    },
    {
      "id": "list-source-imports",
      "method": "GET",
      "path": "/alpha/analytics/v1/source-imports",
      "title": "List source imports",
      "summary": "Inspect source-import status, materialized row counts, and typed problem counts. This is the audit trail for migration and backfill.",
      "auth": "Bearer JWT.",
      "scopes": [
        "analytics:read"
      ],
      "curl": "curl -sS \"$ANALYTICS_BASE_URL/alpha/analytics/v1/source-imports?importKind=timeback-map&modifiedSince=2026-06-10T00:00:00Z\" \\\n  -H \"Authorization: Bearer $ANALYTICS_TOKEN\"",
      "sampleResponse": {
        "object": "list",
        "url": "/alpha/analytics/v1/source-imports",
        "data": [
          {
            "import_id": "imp_01HT8ANALYTICS",
            "import_kind": "timeback-xp-time-accuracy",
            "status": "materialized",
            "source_batch_ref": "migration-2026-06-10-reporting-processed-facts-001",
            "submitted_row_count": 5000,
            "accepted_row_count": 4970,
            "materialized_row_count": 4970,
            "rejected_row_count": 30,
            "problem_counts": {
              "analytics:adapter_rejected": 30
            },
            "modified_at": "2026-06-10T00:56:12Z"
          }
        ],
        "hasMore": false,
        "nextCursor": null,
        "links": {
          "self": "/alpha/analytics/v1/source-imports"
        }
      },
      "sourceObject": {
        "name": "alpha.analytics_source_import",
        "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import",
        "note": "Provenance spine for every ingested report-grade fact: adapter, source system/table, idempotency key, source-row natural-key/hash set, materialized counts, and per-row Problem summaries."
      },
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-110-axis-conformance-evidence",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-110-axis-conformance-evidence"
        }
      ],
      "request": [
        {
          "name": "importKind",
          "type": "import_kind enum",
          "requirement": "Optional",
          "description": "Adapter/import kind, such as timeback-xp-time-accuracy or timeback-map."
        },
        {
          "name": "status",
          "type": "import_status enum",
          "requirement": "Optional",
          "description": "received, running, materialized, rejected, or another governed import status."
        },
        {
          "name": "modifiedSince",
          "type": "TIMESTAMPTZ",
          "requirement": "Optional",
          "description": "Poll for import status changes."
        },
        {
          "name": "limit",
          "type": "INTEGER",
          "requirement": "Optional",
          "description": "Page size. Default 100; maximum 1000."
        },
        {
          "name": "cursor",
          "type": "TEXT",
          "requirement": "Optional",
          "description": "Opaque next-page cursor."
        }
      ],
      "response": [
        {
          "name": "import_id",
          "type": "TEXT",
          "requirement": "required",
          "meaning": "Stable id for this source import request.",
          "constraints": "Generated by platform; unique per tenant.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-import-id"
        },
        {
          "name": "import_kind",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Which source/replay contract this batch follows.",
          "constraints": "Allowed values: import_kind enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-import-kind"
        },
        {
          "name": "status",
          "type": "TEXT enum",
          "requirement": "required",
          "meaning": "Processing state of the source import.",
          "constraints": "Allowed values: import_status enum.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-status"
        },
        {
          "name": "source_batch_ref",
          "type": "TEXT",
          "requirement": "nullable",
          "meaning": "Operator/source identifier for the imported file, replay, or reconciliation run.",
          "constraints": "Opaque reference; no PII or raw row contents.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-source-batch-ref"
        },
        {
          "name": "submitted_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Number of source-shaped rows submitted in the batch.",
          "constraints": "Nonnegative.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-submitted-row-count"
        },
        {
          "name": "accepted_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows accepted by request validation and adapter mapping.",
          "constraints": "Nonnegative and not greater than submitted_row_count.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-accepted-row-count"
        },
        {
          "name": "materialized_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows that produced readable Analytics facts.",
          "constraints": "Nonnegative; successful nonempty imports must produce readable rows unless status explains otherwise.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-materialized-row-count"
        },
        {
          "name": "rejected_row_count",
          "type": "INTEGER",
          "requirement": "required",
          "meaning": "Rows rejected by validation or adapter mapping.",
          "constraints": "Nonnegative; submitted = accepted + rejected for completed imports.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-rejected-row-count"
        },
        {
          "name": "problem_counts",
          "type": "JSONB",
          "requirement": "required",
          "meaning": "Counts of typed Problem codes produced by the import.",
          "constraints": "Keys must be stable analytics:* codes; values nonnegative integers.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-problem-counts"
        },
        {
          "name": "modified_at",
          "type": "TIMESTAMPTZ",
          "requirement": "required",
          "meaning": "Last time the Analytics row changed for polling and modifiedSince queries.",
          "constraints": "UTC timestamp; list endpoints support modifiedSince against this field.",
          "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import-modified-at"
        }
      ]
    }
  ],
  "tables": [
    {
      "name": "alpha.analytics_event_time_fact",
      "title": "Event Time Fact",
      "api": "GET /alpha/analytics/v1/event-time-facts",
      "grain": "One source Event contribution per fact_kind, policy_ref, and calculation_version.",
      "purpose": "Stores signed active, inactive, and waste second contributions for the DERIVED Events axis, so reports can audit time-on-task without classifying raw Caliper events themselves.",
      "metricChecks": [
        "minutes|Caliper events"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-event-time-fact",
      "architecture": [
        {
          "id": "aitd-000-extend-only-storage",
          "title": "Analytics Is New Extend-Only Alpha Storage",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-000-extend-only-storage"
        },
        {
          "id": "aitd-002-derived-events-complement",
          "title": "Derived-From-Events Facts Complement, Never Substitute For, Ingested Tiles",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-002-derived-events-complement"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-005-time-facts-and-windows",
          "title": "Active, Inactive, And Waste Seconds Are Typed Derived Time Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-005-time-facts-and-windows"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-012-corrections-and-reversals",
          "title": "Corrections Are Signed Facts With Provenance",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-012-corrections-and-reversals"
        }
      ]
    },
    {
      "name": "alpha.analytics_time_window",
      "title": "Time Window",
      "api": "GET /alpha/analytics/v1/time-windows",
      "grain": "student_id x subject_id nullable x window_kind x window_start x window_end x policy_ref.",
      "purpose": "Report-ready active, inactive, and waste time totals for the DERIVED Events axis. These complement the ingested Time Commitment tile and support audit/Waste views.",
      "metricChecks": [
        "minutes|Caliper events"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-time-window",
      "architecture": [
        {
          "id": "aitd-005-time-facts-and-windows",
          "title": "Active, Inactive, And Waste Seconds Are Typed Derived Time Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-005-time-facts-and-windows"
        },
        {
          "id": "aitd-002-derived-events-complement",
          "title": "Derived-From-Events Facts Complement, Never Substitute For, Ingested Tiles",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-002-derived-events-complement"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "title": "API Axis: List Endpoints",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ]
    },
    {
      "name": "alpha.analytics_school_day_minutes",
      "title": "School-Day Minutes",
      "api": "GET /alpha/analytics/v1/school-day-minutes",
      "grain": "student_id x school_id x subject_id nullable x window_start x window_end x school_day_policy_ref.",
      "purpose": "Minutes per enrolled school day for the Time Commitment tile. Numerator is ingested from reporting.processed_facts.active_seconds; denominator is alpha.school_calendar intersected with enrollment/subject assignment, with MAP-day exclusion.",
      "metricChecks": [
        "minutes|Caliper events"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-school-day-minutes",
      "architecture": [
        {
          "id": "aitd-006-school-day-minutes",
          "title": "Minutes Per Enrolled School Day Uses The Alpha School Calendar",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-006-school-day-minutes"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-005-time-facts-and-windows",
          "title": "Active, Inactive, And Waste Seconds Are Typed Derived Time Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-005-time-facts-and-windows"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "name": "alpha.analytics_xp_rollup",
      "title": "XP Rollup",
      "api": "GET /alpha/analytics/v1/xp-rollups",
      "grain": "student_id x subject_id nullable x window_kind x window_start x window_end x policy_ref.",
      "purpose": "Report-ready XP total plus goal progress fields. The goal fields use the same materialized school-day denominator as time commitment.",
      "metricChecks": [
        "XP"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-xp-rollup",
      "architecture": [
        {
          "id": "aitd-007-xp-rollups",
          "title": "XP Totals, Goal, Remaining, And Completion Percent Are Ingested Report Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-012-corrections-and-reversals",
          "title": "Corrections Are Signed Facts With Provenance",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-012-corrections-and-reversals"
        }
      ]
    },
    {
      "name": "alpha.analytics_accuracy",
      "title": "Accuracy Rollup",
      "api": "GET /alpha/analytics/v1/accuracy-rollups",
      "grain": "student_id x subject_id nullable x window_kind x window_start x window_end x policy_ref.",
      "purpose": "Report-ready Accuracy panel facts: correct questions, total questions, incorrect questions, and percent correct without client-side processed_facts math.",
      "metricChecks": [
        "Learning Report accuracy"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-accuracy",
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-012-corrections-and-reversals",
          "title": "Corrections Are Signed Facts With Provenance",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-012-corrections-and-reversals"
        }
      ]
    },
    {
      "name": "alpha.analytics_mastery_delta",
      "title": "Mastery Delta",
      "api": "GET /alpha/analytics/v1/mastery-deltas",
      "grain": "One state transition per student_id, kc_id|grade_scope, state_dimension, effective_at, policy_ref, and calculation_version.",
      "purpose": "Grade Levels Mastered facts for the Learning Report plus a typed change log of mastery state movements; Results remains the current mastery state of record.",
      "metricChecks": [
        "mastery|student_kc_state"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-mastery-delta",
      "architecture": [
        {
          "id": "aitd-008-mastery-and-grade-levels",
          "title": "Grade Levels Mastered Are Ingested; Mastery Deltas Read Results State",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-008-mastery-and-grade-levels"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "name": "alpha.analytics_map_growth_rollup",
      "title": "MAP Growth Rollup",
      "api": "GET /alpha/analytics/v1/map-growth-rollups",
      "grain": "student_id x subject_id x canonical_term_id x growth_window x norms_set x policy_ref.",
      "purpose": "Report-ready RIT, achievement percentile, growth percentile, Growth X, MAP window, sitting-count, retake, and on-track facts without client-side norms tables, sitting selection, or term parsing.",
      "metricChecks": [
        "RIT|GrowthX|MAP growth windows",
        "MAP sittings/scores"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-map-growth-rollup",
      "architecture": [
        {
          "id": "aitd-009-map-growth-rollups",
          "title": "MAP RIT And Growth X Are Ingested From hp_map_results, Deduped, And Norms-Calculated",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "name": "alpha.analytics_norms_achievement",
      "title": "NWEA Achievement Norms",
      "api": "GET /alpha/analytics/v1/norms, GET /alpha/analytics/v1/norms/table, GET /alpha/analytics/v1/norms/rit, GET /alpha/analytics/v1/norms/percentile",
      "grain": "norms_set x table_version x subject_id x role x grade_key x season.",
      "purpose": "Readable NWEA achievement-status norms resource for percentile-to-RIT and RIT-to-percentile translation. Apps may read/cache the surface table by table_version or call /norms/rit and /norms/percentile; they never maintain their own norms table.",
      "metricChecks": [
        "RIT|GrowthX|MAP windows",
        "GOALS percentile-to-RIT"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-norms-achievement",
      "architecture": [
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "title": "NWEA Norms And NWEAMAP R90 Are Versioned, Readable Surface Reference Tables",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-016-scale-translation-apis",
          "title": "Percentile<->RIT And RIT->R90/Grade Are Server-Side Surface Translations",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "title": "MAP RIT And Growth X Are Ingested From hp_map_results, Deduped, And Norms-Calculated",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "title": "API Axis: List Endpoints",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ]
    },
    {
      "name": "alpha.analytics_r90_table",
      "title": "R90 Table",
      "api": "GET /alpha/analytics/v1/r90/table, GET /alpha/analytics/v1/r90",
      "grain": "table_version x table_subject_id x rit_score.",
      "purpose": "Readable RIT-to-R90 and grade-position reference for GOALS target conversion, Learning Report grade-position display, and screener starting-grade hints. Final PowerPath placement comes from bottom-up grade-level mastery tests, not this table. Actual course and grade-level progress comes from completion-rollups. Analytics serves an Alpha-compatible mirror; the PowerPath RIT-to-grade master source is owned by NWEAMAP.",
      "metricChecks": [
        "RIT|GrowthX|MAP windows",
        "GOALS RIT-to-grade/R90"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-r90-table",
      "architecture": [
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "title": "NWEA Norms And NWEAMAP R90 Are Versioned, Readable Surface Reference Tables",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-016-scale-translation-apis",
          "title": "Percentile<->RIT And RIT->R90/Grade Are Server-Side Surface Translations",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-017-r90-version-supersession",
          "title": "RIT-to-grade Table Versioning: PowerPath v2026-06-15 Is The Current Version, And One Named Config Picks It For Every Path",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-017-r90-version-supersession"
        },
        {
          "id": "aitd-009-map-growth-rollups",
          "title": "MAP RIT And Growth X Are Ingested From hp_map_results, Deduped, And Norms-Calculated",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "title": "API Axis: List Endpoints",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ]
    },
    {
      "name": "analytics.school_days_remaining",
      "title": "School Days Remaining Response",
      "api": "GET /alpha/analytics/v1/school-days-remaining",
      "grain": "One GOALS forward-calendar answer per student_id x school_id x half-open [as_of, end_date) request x school_day_policy_ref x XP expected-minute policy.",
      "purpose": "Forward instructional-day count and XP-to-time effort projection for GOALS target-date columns. Apps call this endpoint or follow this raw path instead of counting weekdays, excluding MAP days, or carrying XP-hour constants locally.",
      "metricChecks": [
        "GOALS target date",
        "GOALS school-days-remaining"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-school-days-remaining",
      "architecture": [
        {
          "id": "aitd-018-goals-school-days-remaining",
          "title": "GOALS School-Days-Remaining Read And XP Expected-Minute Unit Live On Analytics",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-018-goals-school-days-remaining"
        },
        {
          "id": "aitd-006-school-day-minutes",
          "title": "Minutes Per Enrolled School Day Uses The Alpha School Calendar",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-006-school-day-minutes"
        },
        {
          "id": "aitd-007-xp-rollups",
          "title": "XP Totals, Goal, Remaining, And Completion Percent Are Ingested Report Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        },
        {
          "id": "aitd-016-scale-translation-apis",
          "title": "Percentile<->RIT And RIT->R90/Grade Are Server-Side Surface Translations",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "name": "analytics.grade_level_status",
      "title": "Grade-Level Status Response",
      "api": "GET /alpha/analytics/v1/grade-level-status",
      "grain": "One student_id x subject_id x as_of_date answer assembled from People and Orgs age grade and Results grade positions.",
      "purpose": "GOALS age-grade status without local comparison logic: exactly two named comparisons, working vs age grade and mastered vs age grade.",
      "metricChecks": [
        "GOALS age-grade status",
        "GOALS ahead/at/behind"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#analytics-grade-level-status",
      "architecture": [
        {
          "id": "aitd-102-axis-read-shape",
          "title": "API Axis: Read Shape",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-102-axis-read-shape"
        },
        {
          "id": "aitd-008-mastery-and-grade-levels",
          "title": "Grade Levels Mastered Are Ingested; Mastery Deltas Read Results State",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-008-mastery-and-grade-levels"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        },
        {
          "id": "aitd-112-axis-list-endpoints",
          "title": "API Axis: List Endpoints",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-112-axis-list-endpoints"
        }
      ]
    },
    {
      "name": "alpha.analytics_completion_rollup",
      "title": "Completion Rollup",
      "api": "GET /alpha/analytics/v1/completion-rollups",
      "grain": "student_id x completion_scope x scope_id x window_start x window_end x policy_ref.",
      "purpose": "Progress evidence for Results and Analytics audits without MAP/RIT/R90 inference, client-side Curriculum tree walking, or Results-row counting.",
      "metricChecks": [
        "completion|curriculum refs"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-completion-rollup",
      "architecture": [
        {
          "id": "aitd-010-completion-rollups",
          "title": "Completion Percent Is Ingested Earned XP Over A Curriculum Denominator, Never Invented",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-010-completion-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "name": "alpha.analytics_source_import",
      "title": "Source Import",
      "api": "POST /alpha/analytics/v1/source-imports/{adapter} and GET /alpha/analytics/v1/source-imports",
      "grain": "One named-adapter ingestion run from one report-source producer.",
      "purpose": "Provenance spine for every ingested report-grade fact: adapter, source system/table, idempotency key, source-row natural-key/hash set, materialized counts, and per-row Problem summaries.",
      "metricChecks": [
        "all metric checks"
      ],
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#alpha-analytics-source-import",
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-101-axis-write-granularity",
          "title": "API Axis: Write Granularity",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-101-axis-write-granularity"
        },
        {
          "id": "aitd-105-axis-idempotency",
          "title": "API Axis: Idempotency Model",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-105-axis-idempotency"
        },
        {
          "id": "aitd-108-axis-error-envelope",
          "title": "API Axis: Error Envelope",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-108-axis-error-envelope"
        }
      ]
    }
  ],
  "problemCodes": [
    {
      "code": "analytics:validation_failed",
      "status": 400,
      "meaning": "The request envelope, query string, dates, enum values, or required fields are invalid before an adapter/materializer can run. Carries field-level codes, including the norms/R90 reference codes norms_subject_not_found, r90_subject_not_found, norms_point_not_found, r90_point_not_found (aitd-015/016). Also the status carrier for 401/403/404/405/415 envelope errors.",
      "clientAction": "Correct the request shape or query parameter. Do not retry the same body under a new idempotency key.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-validation-failed",
        "title": "normsSet=2026, completionScope=course_component, window_end before window_start, or tenantId supplied in the query string.",
        "status": 400,
        "code": "analytics:validation_failed",
        "detail": "normsSet=2026, completionScope=course_component, window_end before window_start, or tenantId supplied in the query string.",
        "fieldErrors": [
          {
            "path": "query.normsSet",
            "code": "invalid_enum"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-validation-failed"
    },
    {
      "code": "analytics:unsupported_parameter",
      "status": 400,
      "meaning": "A query parameter is not part of the typed query model (Vercel routing params such as path are stripped before validation).",
      "clientAction": "Use only documented filters from the table grain and endpoint contract; strip routing params before validation.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-unsupported-parameter",
        "title": "Filtering completion-rollups by raw course_component_kind instead of completion_scope/scope_id.",
        "status": 400,
        "code": "analytics:unsupported_parameter",
        "detail": "Filtering completion-rollups by raw course_component_kind instead of completion_scope/scope_id.",
        "fieldErrors": [
          {
            "path": "query.course_component_kind",
            "code": "unsupported"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-unsupported-parameter"
    },
    {
      "code": "analytics:adapter_rejected",
      "status": 422,
      "meaning": "A valid source-shaped row cannot be normalized, OR an expected report-source row is missing — a reconciliation error, never a silent default.",
      "clientAction": "Repair the source mapping or upstream row, then replay the same source-shaped row idempotently.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-adapter-rejected",
        "title": "A processed_facts row names an unknown subject, or a completion row points at a course the Curriculum surface cannot resolve.",
        "status": 422,
        "code": "analytics:adapter_rejected",
        "detail": "A processed_facts row names an unknown subject, or a completion row points at a course the Curriculum surface cannot resolve.",
        "fieldErrors": [
          {
            "path": "body.rows[0].subject",
            "code": "unknown_subject"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-adapter-rejected"
    },
    {
      "code": "analytics:idempotency_conflict",
      "status": 409,
      "meaning": "The same Idempotency-Key or source_fact_key was replayed with different content.",
      "clientAction": "Use the original body for replay, or submit a correction through the correction/reversal pathway.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-idempotency-conflict",
        "title": "A migration replay keeps the same source_fact_key but changes active_seconds from 300 to 360.",
        "status": 409,
        "code": "analytics:idempotency_conflict",
        "detail": "A migration replay keeps the same source_fact_key but changes active_seconds from 300 to 360.",
        "fieldErrors": [
          {
            "path": "headers.Idempotency-Key",
            "code": "body_mismatch"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-idempotency-conflict"
    },
    {
      "code": "analytics:schema_migration_failed",
      "status": 500,
      "meaning": "An internal/migration failure the surface could not recover from — surfaced honestly as 500, never a lying 200.",
      "clientAction": "Follow the endpoint contract and retry only after the documented input or source condition changes.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-schema-migration-failed",
        "title": "See the endpoint-specific Problem response.",
        "status": 500,
        "code": "analytics:schema_migration_failed",
        "detail": "See the endpoint-specific Problem response.",
        "fieldErrors": [],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-schema-migration-failed"
    },
    {
      "code": "analytics:source_missing",
      "status": 409,
      "meaning": "Analytics expected an Event, Result, calendar, enrollment, or Curriculum source row, but it was not available or not closed.",
      "clientAction": "Wait for the source close/import to finish or repair the upstream source row, then replay the affected source/window. For school-day minutes, the fix is to surface the upstream Alpha calendar source and replay the window.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-source-missing",
        "title": "A TimeSpentEvent close notification references an event id that Events has already tombstoned.",
        "status": 409,
        "code": "analytics:source_missing",
        "detail": "A TimeSpentEvent close notification references an event id that Events has already tombstoned.",
        "fieldErrors": [
          {
            "path": "source.event_id",
            "code": "not_available"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-source-missing"
    },
    {
      "code": "analytics:source_unlinked",
      "status": 422,
      "meaning": "The source row exists, but Analytics cannot link it to the required Alpha student, subject, KC, course, school calendar, or policy ref.",
      "clientAction": "Fix the upstream id mapping or governed alias/policy row. Do not supply a caller-normalized replacement id just for this import.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-source-unlinked",
        "title": "A processed_facts row has subject=Science-notqced and no accepted subject fold.",
        "status": 422,
        "code": "analytics:source_unlinked",
        "detail": "A processed_facts row has subject=Science-notqced and no accepted subject fold.",
        "fieldErrors": [
          {
            "path": "body.rows[0].studentid",
            "code": "unresolved_student"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-source-unlinked"
    },
    {
      "code": "analytics:policy_pending",
      "status": 422,
      "meaning": "A required alpha.policy.* row is missing, inactive for the effective date, or lacks a governed value needed to compute the fact.",
      "clientAction": "Seed or activate the policy row and replay. Reports and skill packs must not hard-code the missing value.",
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-policy-pending",
        "title": "alpha.policy.school_day has no reason mapping for a real Ed-Fi CalendarEventDescriptor.",
        "status": 422,
        "code": "analytics:policy_pending",
        "detail": "alpha.policy.school_day has no reason mapping for a real Ed-Fi CalendarEventDescriptor.",
        "fieldErrors": [
          {
            "path": "alpha.policy.school_day",
            "code": "policy_missing"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-policy-pending"
    }
  ],
  "authFailures": [
    {
      "status": 401,
      "code": "analytics:validation_failed",
      "title": "Unauthorized",
      "meaning": "The Authorization header is missing, not a compact JWT, has an invalid signature or payload, or the token is expired.",
      "clientAction": "Mint or refresh the token, then retry the exact same request. For polling clients, keep the last completed modifiedSince checkpoint; the rejected request did not run.",
      "fieldErrors": [
        "headers.Authorization code=required",
        "headers.Authorization code=invalid_jwt",
        "headers.Authorization code=invalid_signature",
        "headers.Authorization code=invalid_payload",
        "headers.Authorization code=expired"
      ],
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-validation-failed",
        "title": "Bearer token is expired.",
        "status": 401,
        "code": "analytics:validation_failed",
        "detail": "Bearer token is expired.",
        "fieldErrors": [
          {
            "path": "headers.Authorization",
            "code": "required"
          },
          {
            "path": "headers.Authorization",
            "code": "invalid_jwt"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "docsAnchor": "#status-401",
      "problemAnchor": "#problem-status-401",
      "analyticsProblemAnchor": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-validation-failed",
      "platformStatusAnchor": "https://platform3-andymontgomery-9773s-projects.vercel.app/platform/1edtech/customer_website#status-401"
    },
    {
      "status": 403,
      "code": "analytics:validation_failed",
      "title": "Forbidden",
      "meaning": "The token is valid, but it has no tenantId claim, the x-timeback-tenant header does not match the token tenant, or the token lacks the required Analytics read/write authority.",
      "clientAction": "Abort under the current token. Use a token with analytics:read for GET endpoints, analytics:write or analytics:import for source imports, and the correct student/cohort/tenant grant.",
      "fieldErrors": [
        "jwt.tenantId code=required",
        "headers.x-timeback-tenant code=tenant_mismatch",
        "jwt.scopes code=missing_scope required=analytics:read",
        "jwt.scopes code=missing_scope required=analytics:write"
      ],
      "exampleBody": {
        "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-validation-failed",
        "title": "Analytics reads require analytics:read authority.",
        "status": 403,
        "code": "analytics:validation_failed",
        "detail": "Analytics reads require analytics:read authority.",
        "fieldErrors": [
          {
            "path": "jwt.tenantId",
            "code": "required"
          },
          {
            "path": "headers.x-timeback-tenant",
            "code": "tenant_mismatch"
          }
        ],
        "requestId": "req_01J0ANALYTICS",
        "traceId": "trace_01J0ANALYTICS"
      },
      "docsAnchor": "#status-403",
      "problemAnchor": "#problem-status-403",
      "analyticsProblemAnchor": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#problem-analytics-validation-failed",
      "platformStatusAnchor": "https://platform3-andymontgomery-9773s-projects.vercel.app/platform/1edtech/customer_website#status-403"
    }
  ],
  "convergenceRules": [
    {
      "id": "tenant_scope",
      "domain": "tenant_scope",
      "question": "Which rows belong to this tenant?",
      "apiRule": "The API takes tenant_id only from the JWT claim; tenantId in URL/query/body is rejected or ignored according to the endpoint contract.",
      "rawRule": "Every raw query must filter alpha.analytics_* by tenant_id before joins, windows, counts, sorting, or paging.",
      "failureMode": "A raw report mixes demo/reviewer/production tenants and returns plausible but wrong totals.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-tenant-scope",
      "architecture": [
        {
          "id": "aitd-109-axis-tenant-routing",
          "title": "API Axis: Tenant Routing",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-109-axis-tenant-routing"
        },
        {
          "id": "aitd-106-axis-auth-shape",
          "title": "API Axis: Auth Shape",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-106-axis-auth-shape"
        }
      ]
    },
    {
      "id": "read_analytics_not_sources",
      "domain": "all_learning_report_metrics",
      "question": "How should a report answer a metric question?",
      "apiRule": "Reports call the named Analytics endpoint for the metric.",
      "rawRule": "Raw readers query the matching alpha.analytics_* table. They do not recompute from Events, Results, processed_facts, Curriculum trees, calendars, or private norms/R90 tables; for scale questions they read alpha.analytics_norms_achievement and the alpha.analytics_r90_table mirror sourced from the NWEAMAP-owned PowerPath RIT-to-grade master.",
      "failureMode": "Client-side math leaks platform-owned logic into skill packs and fails three-way convergence.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-read-analytics-not-sources",
      "architecture": [
        {
          "id": "aitd-003-close-time-materialization",
          "title": "Facts Are Written When Sources Close Or Import, Read Never Recomputed",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-003-close-time-materialization"
        },
        {
          "id": "aitd-110-axis-conformance-evidence",
          "title": "API Axis: Conformance Evidence",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-110-axis-conformance-evidence"
        }
      ]
    },
    {
      "id": "source_ref_not_source_copy",
      "domain": "storage_model",
      "question": "How do I audit a derived fact?",
      "apiRule": "Detail/sourceRefs subcollections expose authorized source ids and provenance summaries.",
      "rawRule": "Join through source_event_id, source_state_ref, source_result_refs, source_ledger_refs, map refs, or curriculum_scope_refs; do not expect copied source columns in Analytics tables.",
      "failureMode": "A raw query looks for Caliper payload, NWEA raw fields, Results scores, or Curriculum trees duplicated in Analytics.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-source-ref-not-source-copy",
      "architecture": [
        {
          "id": "aitd-000-extend-only-storage",
          "title": "Analytics Is New Extend-Only Alpha Storage",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-000-extend-only-storage"
        },
        {
          "id": "aitd-102-axis-read-shape",
          "title": "API Axis: Read Shape",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-102-axis-read-shape"
        }
      ]
    },
    {
      "id": "current_rows_only",
      "domain": "corrections_and_tombstones",
      "question": "Which derived rows are reportable by default?",
      "apiRule": "Ordinary list/detail endpoints exclude superseded/tombstoned rows unless includeSuperseded=true and the caller is authorized.",
      "rawRule": "Filter superseded_at IS NULL AND source_deleted_at IS NULL for ordinary reports, then apply table-specific quality_status rules.",
      "failureMode": "A raw report double-counts corrections or invalidated source rows.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-current-rows-only",
      "architecture": [
        {
          "id": "aitd-111-axis-privacy-retention",
          "title": "API Axis: Privacy And Retention",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-111-axis-privacy-retention"
        },
        {
          "id": "aitd-012-corrections-and-reversals",
          "title": "Corrections Are Signed Facts With Provenance",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-012-corrections-and-reversals"
        }
      ]
    },
    {
      "id": "signed_corrections",
      "domain": "signed_corrections",
      "question": "How do corrections affect totals?",
      "apiRule": "Analytics exposes signed source contributions and report-ready net/display totals.",
      "rawRule": "Use signed seconds_delta/negative_xp/net fields exactly as documented; do not clamp, drop, or recompute corrections locally.",
      "failureMode": "A report silently removes negative gaming XP or reversal seconds and stops reconciling.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-signed-corrections",
      "architecture": [
        {
          "id": "aitd-012-corrections-and-reversals",
          "title": "Corrections Are Signed Facts With Provenance",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-012-corrections-and-reversals"
        }
      ]
    },
    {
      "id": "typed_subjects",
      "domain": "subject_normalization",
      "question": "How are source subjects handled?",
      "apiRule": "Materializers write canonical subject_id or typed null_reason/adapter Problem at write time.",
      "rawRule": "Filter/group by subject_id, not source strings such as FastMath, Vocabulary, Science-notqced, ELA, or ISEE variants.",
      "failureMode": "A raw report creates extra subjects or mixes MAP proxy subjects after policy changes.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-typed-subjects",
      "architecture": [
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "id": "minutes_school_day",
      "domain": "minutes_per_enrolled_school_day",
      "question": "Is the school-day denominator available, and if so how many active minutes per enrolled school day did this student have?",
      "apiRule": "GET /school-day-minutes returns active_minutes, enrolled_school_day_count, excluded_school_day_count, minutes_per_enrolled_school_day, quality_status, and null_reason at the report grain.",
      "rawRule": "Query alpha.analytics_school_day_minutes at the documented grain with quality_status in ('ok','corrected') and null_reason='none' for ordinary reports. source_missing rows are repair states; do not intersect Events with alpha.school_calendar, enrollment windows, processed_facts active dates, or attendance dates in the consumer.",
      "failureMode": "A raw path returns an empty list for a known student, includes weekends/MAP testing days/current-only school assignment, fabricates a denominator from active dates, or renders a source_missing repair row as a completed time-commitment value.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-minutes-school-day",
      "architecture": [
        {
          "id": "aitd-006-school-day-minutes",
          "title": "Minutes Per Enrolled School Day Uses The Alpha School Calendar",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-006-school-day-minutes"
        }
      ]
    },
    {
      "id": "xp_totals",
      "domain": "xp_totals",
      "question": "How much XP did a student earn, how much remains, and what percent of the XP goal is complete?",
      "apiRule": "GET /xp-rollups returns xp_total, daily_xp_goal, enrolled_school_day_count, xp_goal, xp_remaining, xp_goal_percent, on_track, signed audit subtotals, source_import provenance, and null_reason.",
      "rawRule": "Query alpha.analytics_xp_rollup; use reporting.processed_facts and Results xp_ledger only through authorized source refs, not for report totals, remaining XP, or XP goal percent. Ordinary report rows carry stored denominator-derived goal fields; source_missing means repair/replay is required. Never cap xp_goal_percent at 100 when it is populated.",
      "failureMode": "A client sums TimeBack processed_facts.xp_earned or xp_ledger, then computes goals, remaining XP, or a capped percent locally.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-xp-totals",
      "architecture": [
        {
          "id": "aitd-007-xp-rollups",
          "title": "XP Totals, Goal, Remaining, And Completion Percent Are Ingested Report Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        }
      ]
    },
    {
      "id": "accuracy_rollup",
      "domain": "accuracy_percent",
      "question": "What percent of reportable questions did the student answer correctly?",
      "apiRule": "GET /accuracy-rollups returns correct_question_count, total_question_count, incorrect_question_count, accuracy_percent, source_import_id, quality_status, and null_reason at the documented student/subject/window grain.",
      "rawRule": "Query alpha.analytics_accuracy; use reporting.processed_facts only through source_import/source-ref audit views, never as report math. If total_question_count is zero, read null_reason=no_questions and do not substitute 0% or 100%.",
      "failureMode": "A report computes accuracy by summing raw processed_facts, counting QTI/Events attempts, keeping a private app/source allowlist, or dividing and rounding locally.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-accuracy-rollup",
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        },
        {
          "id": "aitd-011-policy-and-enum-normalization",
          "title": "Policy, Subject, Window, And Quality Values Are Typed Server-Side At Write Time",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-011-policy-and-enum-normalization"
        }
      ]
    },
    {
      "id": "mastery_delta_not_state",
      "domain": "mastery_delta",
      "question": "Which KCs changed between dates?",
      "apiRule": "GET /mastery-deltas filters by effective_at and state_dimension.",
      "rawRule": "Query alpha.analytics_mastery_delta; current state remains Results student_kc_state and mastery math remains Results/Policy.",
      "failureMode": "A report rebuilds mastery/decay/HMG from attempts or treats Analytics as current state of record.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-mastery-delta-not-state",
      "architecture": [
        {
          "id": "aitd-008-mastery-and-grade-levels",
          "title": "Grade Levels Mastered Are Ingested; Mastery Deltas Read Results State",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-008-mastery-and-grade-levels"
        }
      ]
    },
    {
      "id": "map_norms_windows",
      "domain": "rit_growthx_map_windows",
      "question": "What RIT and Growth X did the student have under a norms set?",
      "apiRule": "GET /map-growth-rollups accepts typed normsSet/growthWindow/term filters and returns report-ready values; the Learning Report \"vs 1yr ago\" panel requests growthWindow=winter_to_winter.",
      "rawRule": "Query alpha.analytics_map_growth_rollup by canonical_term_id, growth_window, and norms_set; for the Learning Report MAP panel read growth_percentile and growth_x from growth_window=winter_to_winter, not fall_to_winter. Do not parse terms, choose retakes, maintain a private norms table, or compute Growth X as observed/typical.",
      "failureMode": "A raw report mixes 2020/2025 norms, selects fall_to_winter for a one-year panel, computes observed/typical, ships a private norms/R90 table, or disagrees with Results/NWEAMap test-of-record.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-map-norms-windows",
      "architecture": [
        {
          "id": "aitd-009-map-growth-rollups",
          "title": "MAP RIT And Growth X Are Ingested From hp_map_results, Deduped, And Norms-Calculated",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-009-map-growth-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        }
      ]
    },
    {
      "id": "scale_reference_resources",
      "domain": "percentile_rit_r90_translation",
      "question": "What RIT maps to a percentile, and what R90/effective grade maps to a RIT?",
      "apiRule": "GET /norms and /r90/table return versioned readable resources; GET /norms/rit, /norms/percentile, and /r90 return translated values with norms_set, table_version, calculator_version, and source_point_kind where applicable.",
      "rawRule": "Read alpha.analytics_norms_achievement by norms_set/table_version/subject_id/role/grade_key/season and apply the documented normal model. Read alpha.analytics_r90_table by table_version='analytics.rit_to_grade.powerpath.v2026-06-15' and table_subject_id, then choose the row whose rit_score equals the requested RIT. Missing subjects/table points return typed missing/validation behavior; missing RIT rows return source_missing rather than a fabricated value.",
      "failureMode": "GOALS, Learning Report, and skill-pack examples disagree because one app cached a private norms table or R90 copy, silently changed versions, chose a nearest row, used an old between-row method, or skipped the current table_version filter.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-scale-reference-resources",
      "architecture": [
        {
          "id": "aitd-015-norms-r90-readable-resources",
          "title": "NWEA Norms And NWEAMAP R90 Are Versioned, Readable Surface Reference Tables",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-015-norms-r90-readable-resources"
        },
        {
          "id": "aitd-016-scale-translation-apis",
          "title": "Percentile<->RIT And RIT->R90/Grade Are Server-Side Surface Translations",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-016-scale-translation-apis"
        },
        {
          "id": "aitd-017-r90-version-supersession",
          "title": "RIT-to-grade Table Versioning: PowerPath v2026-06-15 Is The Current Version, And One Named Config Picks It For Every Path",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-017-r90-version-supersession"
        }
      ]
    },
    {
      "id": "goals_school_days_remaining",
      "domain": "goals_target_date_school_days",
      "question": "How many instructional days remain, and what daily effort is needed to finish by the target date?",
      "apiRule": "GET /school-days-remaining returns analytics.school_days_remaining with instructional_days_remaining, instructional_dates, xp_unit.*, effort.*, provenance.*, and links.*. The endpoint uses the half-open [asOf,endDate) window and alpha.policy.analytics.xp_expected_minute.v2026-06-14.",
      "rawRule": "Resolve the student's school through People and Orgs effective-dated enrollment, read alpha.school_calendar where calendar_date >= :asOf and calendar_date < :endDate, filter to instructional school days under alpha.policy.school_day.v2026-06-10, exclude MAP-testing days by policy, and apply alpha.policy.analytics.xp_expected_minute.v2026-06-14: 1 XP = 1 expected minute and 60 XP = 1 expected hour. Do not read consumed-day rollups for future dates, count weekdays, use attendance days, parse school_period labels, or hard-code XP_PER_HOUR.",
      "failureMode": "GOALS or a skill pack computes a different target date because it counts weekdays/summer gaps locally, includes MAP days, uses current-only enrollment, treats endDate as inclusive, or carries a private XP_PER_HOUR constant.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-goals-school-days-remaining",
      "architecture": [
        {
          "id": "aitd-018-goals-school-days-remaining",
          "title": "GOALS School-Days-Remaining Read And XP Expected-Minute Unit Live On Analytics",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-018-goals-school-days-remaining"
        },
        {
          "id": "aitd-006-school-day-minutes",
          "title": "Minutes Per Enrolled School Day Uses The Alpha School Calendar",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-006-school-day-minutes"
        },
        {
          "id": "aitd-007-xp-rollups",
          "title": "XP Totals, Goal, Remaining, And Completion Percent Are Ingested Report Facts",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-007-xp-rollups"
        }
      ]
    },
    {
      "id": "completion_scope",
      "domain": "completion_percent",
      "question": "What progress evidence exists for a course/subject/track?",
      "apiRule": "GET /completion-rollups returns xp_earned, xp_remaining, completion_percent, source_import_id, and null_reason as Analytics evidence.",
      "rawRule": "Query alpha.analytics_completion_rollup by completion_scope and scope_id for evidence. Course rows prefer app-reported Caliper percent, then XP remaining; grade_level rows preserve main-course evidence only. Student-facing progress reads come from Results. Do not derive progress from MAP/RIT/R90, walk Curriculum trees, count Results client-side, or use activity flags.",
      "failureMode": "The raw path diverges when a client treats Analytics evidence as the final app-facing answer, treats RIT grade-band percent as actual progress, includes hole-filling courses in grade-level progress, or invents 1-if-active completion.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-completion-scope",
      "architecture": [
        {
          "id": "aitd-010-completion-rollups",
          "title": "Completion Percent Is Ingested Earned XP Over A Curriculum Denominator, Never Invented",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-010-completion-rollups"
        },
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-004-provenance-no-literals",
          "title": "Every Report Value Traces To An Ingested Source Row, Or Reads Null",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-004-provenance-no-literals"
        }
      ]
    },
    {
      "id": "source_import_status",
      "domain": "source_shaped_imports",
      "question": "Did source-shaped import materialize rows?",
      "apiRule": "POST /source-imports/{adapter} accepts only named adapters; timeback-map accepts full source-shaped hp_map_results rows and ignores unknown extra columns; validation failures return analytics:validation_failed with HTTP 400; adapter rejections return analytics:adapter_rejected with HTTP 422; successful imports report accepted/materialized counts.",
      "rawRule": "Migration checks count readable alpha.analytics_* rows plus analytics_source_import.materialized_row_count, not submitted source rows or Problem bodies.",
      "failureMode": "A lying HTTP 200 with zero readable rows, or a timeback-map rejection caused only by unknown extra hp_map_results columns, recreates the migration failure Analytics exists to fix.",
      "dataDictionary": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/data_dictionary#rule-source-import-status",
      "architecture": [
        {
          "id": "aitd-001-report-source-ingestion",
          "title": "Report-Grade Facts Are Ingested From The Report Source, Never Re-Derived",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-001-report-source-ingestion"
        },
        {
          "id": "aitd-108-axis-error-envelope",
          "title": "API Axis: Error Envelope",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-108-axis-error-envelope"
        },
        {
          "id": "aitd-110-axis-conformance-evidence",
          "title": "API Axis: Conformance Evidence",
          "status": "Accepted",
          "owner": "TimeBack Platform Architecture",
          "href": "https://platform3-andymontgomery-9773s-projects.vercel.app/analytics/alpha/architecture#aitd-110-axis-conformance-evidence"
        }
      ]
    }
  ],
  "runtimeContracts": {
    "pagination": [
      [
        "Envelope",
        "Every GET list endpoint returns data, hasMore, nextCursor, and links.self."
      ],
      [
        "Page size",
        "limit defaults to 100 and has a maximum of 1000. Invalid limits return analytics:validation_failed."
      ],
      [
        "Cursor",
        "cursor is opaque and bound to tenant, endpoint, typed filters, and sort. Use it only to finish the active page walk."
      ],
      [
        "Sort order",
        "modifiedSince page walks order by modified_at then stable id."
      ],
      [
        "Checkpoint",
        "Persist modifiedSince only after a complete page walk. If interrupted, restart from the last complete checkpoint."
      ]
    ],
    "polling": [
      [
        "Parameter",
        "modifiedSince is a UTC ISO-8601 timestamp over modified_at."
      ],
      [
        "Source missing",
        "analytics:source_missing means the source Event, Result, calendar, enrollment, Curriculum row, or source import was not available for materialization. Repair or wait for the source and replay; do not fill the gap from source modules."
      ],
      [
        "Freshness model",
        "Poll plus modifiedSince is the shipped eventing model. Webhooks are deferred."
      ],
      [
        "Clock rule",
        "Use server-returned modified_at values for checkpoints, never the client clock."
      ]
    ],
    "retries": [
      [
        "401 Unauthorized (analytics:validation_failed)",
        "Authentication branch: missing, malformed, invalid-signature, invalid-payload, or expired Bearer token. Mint or refresh the token, retry the exact request, and do not advance a modifiedSince checkpoint until a 2xx page succeeds."
      ],
      [
        "403 Forbidden (analytics:validation_failed)",
        "Authorization branch: valid token but missing tenant, mismatched x-timeback-tenant, or missing analytics:read/write authority. Abort this credential path or obtain a token with the right scope/student/cohort grant; do not keep retrying."
      ],
      [
        "400 analytics:validation_failed",
        "Abort and correct the request shape or enum value."
      ],
      [
        "400 analytics:unsupported_parameter",
        "Abort and use only the endpoint's typed filters."
      ],
      [
        "409 analytics:source_missing",
        "Retry only after the source close/import/calendar prerequisite changes. Keep filters stable and use modifiedSince for sync."
      ],
      [
        "409 analytics:idempotency_conflict",
        "Abort the replay or reuse the exact original import body for that key."
      ],
      [
        "422 adapter/policy problems",
        "Repair the source mapping or policy/config row, then replay. Do not hard-code the missing value in the client."
      ],
      [
        "500 analytics:schema_migration_failed",
        "Operator fix only. Do not work around it by recomputing from source tables."
      ]
    ],
    "operational": [
      [
        "Tenant routing",
        "Tenant comes from the JWT. The API never accepts tenantId in query or body."
      ],
      [
        "Idempotency",
        "Source imports require Idempotency-Key. Reads do not require it."
      ],
      [
        "Retention",
        "Current reads exclude superseded and source-deleted rows unless an authorized audit endpoint explicitly includes them."
      ]
    ]
  },
  "noClientLogic": [
    "Do not classify source events or reporting rows into active, inactive, or waste seconds.",
    "Do not count school days, exclude MAP days, or intersect enrollment windows in the app.",
    "Do not compute XP rules, penalties, repeat-attempt discounts, or goal percentages.",
    "Do not compute accuracy percent from source rows; read alpha.analytics_accuracy or /accuracy-rollups.",
    "Do not recompute mastery, decay, highest mastered grade, working grade, or KC transitions.",
    "Do not choose MAP test-of-record sittings, parse term strings, carry private norm/R90 tables, compute Growth X, or compute percentile<->RIT/R90 translations app-side.",
    "Do not count remaining school days or convert XP to target-date pacing in GOALS; read /school-days-remaining or follow the documented raw path against alpha.school_calendar.",
    "Do not derive actual course or grade-level progress from MAP/RIT/R90, walk Curriculum trees, or count Results rows; read /completion-rollups.",
    "Do not normalize subject, app, or source names client-side. Analytics writes typed values under policy."
  ]
}
