Platform3 / Content / Alpha

TimeBack Platform Content Alpha Data Dictionary

The tracked semantic owner for Content fields and value spaces. Generated output is checked against architecture, implementation, OpenAPI, Integration, and the published skill.

29 objects247 fields27 enum sets296 aliases

Canonical value space

content_kind has exactly twelve values

questiontesttest_spectest_bankarticlevideoaudioimageinteractivemedia_assetexternal_linkscript
No public stimulus row exists. QTI assessmentStimulus stays inside question anatomy: stimulus + root + options + wrong-answer explanations.
ValueMeaning
questionA QTI assessment item or equivalent blank question a student can answer. Source artifact_kind=item.
testA QTI assessment test or equivalent blank assessment instrument. Source artifact_kind=test.
test_specA first-class test blueprint/table of specifications. Backed by QTI assessmentTest storage plus alpha.test_spec_extension; assessment_role=spec is retained for compatibility.
test_bankA first-class bank of equivalent test forms generated from one test_spec. Backed by QTI assessmentTest storage plus alpha.test_bank_extension and bank_member references; assessment_role=bank is retained for compatibility.
articleReadable student-facing text or explainer anchored to the base resource shape plus Alpha sidecars.
videoStudent-facing moving-image content. MIME and delivery details stay in media_type and media references; video remains its own content_kind.
audioStudent-facing audio content such as narration, listening practice, or a recorded explanation. MIME and delivery details stay in media_type and media references.
imageStudent-facing image content such as a diagram, primary visual, or standalone image prompt. File details stay in qti.package_file/media fields.
interactiveA student-facing simulation, embedded activity, or learning application resource anchored to the base resource shape plus Alpha sidecars.
media_assetA reusable or supporting asset row such as a caption, transcript, worksheet, source file, thumbnail, or package dependency. It can be student-touchable, but video/audio/image use their own first-class content_kind when they are the primary asset.
external_linkA student-touchable link to an external resource. The URL is Alpha-owned extension data and must not contain secrets.
scriptA first-class authored script used as source material for produced audio or video; produced media references it with relationship_kind=source_script_for.

Ownership and storage rule

Content owns one-row-per-asset blank student-touchable material through Alpha read views over QTI base rows plus extend-only Content sidecars. Content rows reference other Content rows through content_ref/content_reference rows and never nest them. Every Content rule serves render, discover, or interoperate. Results owns durable student outcomes and alpha.content_effectiveness; Content may read that Results-owned effectiveness view but never creates or writes it. Events owns moments. Curriculum owns the shared map. People & Orgs owns who/where/as-of-date facts; Content stores only the exact test/synthetic person_id reference needed for a demo-only test-serve grant and its immutable receipts, and revalidates People & Orgs reality on every authorization.

Content asset identity

Content is one row per asset. A Content row references other Content rows through content_ref/content_reference rows and never nests another Content row or stores collection membership.

  • one video row
  • one transcript media_asset row
  • content_reference relationship_kind=transcript_for
  • course/unit/playlist membership lives in Curriculum

Alpha read resources

SQL views over the approved qti.* and platform.* base tables. Rename, cut, and restrict add no storage.

  • alpha.content_item_view
  • alpha.content_version_view
  • alpha.media_asset_view
  • alpha.answer_slot_view
  • alpha.assessment_component_view
  • alpha.scoring_plan_view

Alpha extension storage

Tables that contain only new Alpha columns plus foreign keys to base rows. No extension table may copy a 1EdTech-sourced field.

  • alpha.content_item_extension.expected_xp
  • alpha.assessment_test_extension
  • alpha.media_asset_extension
  • alpha.content_reference
  • alpha.content_kc_tag
  • alpha.content_curriculum_link (frozen archive)
  • alpha.content_catalog_facet
  • alpha.content_catalog_facet_assignment
  • alpha.content_trust_evidence
  • alpha.content_test_serve_grant
  • alpha.content_test_serve_authorization

Results-owned read dependencies

Content may read Results-owned public views, but Content never creates, migrates, writes, or backfills those objects.

  • alpha.content_effectiveness public Results view with tenant_id, object_id, and data JSONB

Core writes

Writes that create or change QTI-backed core objects are write-through commands to the QTI 1EdTech base surface. Alpha does not own a parallel writable content catalog.

  • QTI package import
  • QTI artifact/version authoring save
  • manifest-resource/webcontent creation

Forbidden downstream output

Any CREATE TABLE alpha.content_item, alpha.content_version, alpha.answer_slot, alpha.answer_key, alpha.assessment_component, alpha.scoring_plan, alpha.video, alpha.audio, alpha.image, or alpha.media_asset that stores qti.* columns is a rollback failure.

  • Duplicated title/language/latest_version_id
  • Copied delivery_json/authoring_json
  • Copied correct_response/processing_rule

Provenance and lineage contract

No hidden lineage store. Content has no separate content_lineage table or generic lineage object. The complete contract is the four named dictionary primitives below; importers and consumers must not invent a fifth store.
JobOwning primitiveMeaning
Source/import identityadapter/source-table context + content_item.source_record_id (source_identifier is provenance/export spelling only)Accepted complete source identity. Current TimeBack import stores a generic external_content_import source_system and omits source_table from deterministic ids, so same record ids from different tables can collide until scoped identity lands.
Discovery provenance and qualitycontent_catalog_facet_assignment (facet_key=provenance|quality_rating)Stores governed catalog discovery values and safe assignment provenance without copying the base asset.
Validation trust evidencecontent_trust_evidenceLinks the Content identity to the owning conformance or validation evidence and its checked status.
Asset-to-source-asset production lineagecontent_reference (relationship_kind=source_file_for|source_script_for)Relates a produced Content asset to the exact reusable Content asset/version that sourced it.

Resource shapes

KindStorage shapeAlpha sidecarsRound-trip rule
questionQTI assessmentItem through qti.artifact where artifact_kind='item' plus qti.artifact_version.content_item_extension.expected_xp plus optional subject_id, target_grade_id, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve content_id, version_id, expected_xp, response identifiers, answer slots, scoring provenance, weighted KC tags, and sidecars without translation code.
testQTI assessmentTest through qti.artifact where artifact_kind='test' plus assessment_test_extension.assessment_role for form compatibility.content_item_extension.expected_xp, assessment_test_extension, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve expected_xp, assessment_role, test_family_id, test_type, version identity, QTI dependencies, and sidecars.
test_specQTI assessmentTest through qti.artifact where artifact_kind='test', public content_kind_override='test_spec', assessment_role='spec', plus alpha.test_spec_extension.content_item_extension.expected_xp, assessment_test_extension, test_spec_extension, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve content_kind=test_spec, assessment_role=spec, spec blueprint fields, version identity, QTI dependencies, and sidecars.
test_bankQTI assessmentTest through qti.artifact where artifact_kind='test', public content_kind_override='test_bank', assessment_role='bank', plus alpha.test_bank_extension and bank_member references.content_item_extension.expected_xp, assessment_test_extension, test_bank_extension, bank_member content_reference rows, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve content_kind=test_bank, assessment_role=bank, spec_id, membership_rule, bank membership references, version identity, QTI dependencies, and sidecars.
articleQTI/Common-Cartridge-compatible webcontent/resource row where available, plus alpha.content_item_extension for the article kind, optional subtype=decodable, and Alpha-only render facts.content_item_extension including expected_xp/subtype, alpha.decodable_extension when subtype=decodable, media_asset references, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve article content identity, subtype, decodable phonics constraints, expected_xp, render/source version identity, media references, weighted KC tags, and catalog sidecars with no custom translation layer.
scriptQTI/Common-Cartridge-compatible webcontent/resource row where available, plus alpha.content_item_extension publishing content_kind='script' and Alpha-only render/source facts.content_item_extension.expected_xp, media_asset references when applicable, content_reference source_script_for rows from produced audio/video, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve script content identity, content_kind=script, expected_xp, version identity, media/source references, weighted KC tags, catalog facets, and production lineage without collapsing script into article subtype.
videoQTI/Common-Cartridge-compatible webcontent/resource row plus qti.package_file media evidence where available; Alpha sidecars classify it as the primary video content row.content_item_extension.expected_xp, media_asset_extension/media references for captions or transcripts, content_reference source_script_for to a script row when produced from a script, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve video content identity, expected_xp, media_id/file evidence, caption/transcript/source-script references, weighted KC tags, catalog facets, and delivery URL/reference semantics without collapsing video into media_asset or translating it into a lesson.
audioQTI/Common-Cartridge-compatible webcontent/resource row plus qti.package_file audio evidence where available; Alpha sidecars classify it as the primary audio content row.content_item_extension.expected_xp, media_asset_extension/media references for transcripts or source files, content_reference source_script_for to a script row when produced from a script, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve audio content identity, expected_xp, media_id/file evidence, transcript/source-script references, weighted KC tags, catalog facets, and delivery URL/reference semantics without collapsing audio into media_asset.
imageQTI/Common-Cartridge-compatible webcontent/resource row plus qti.package_file image evidence where available; Alpha sidecars classify it as the primary image content row and optional subtype=diagram.content_item_extension.expected_xp/subtype, media_asset_extension/media references for thumbnails/source files, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve image content identity, subtype=diagram when applicable, expected_xp, media_id/file evidence, accessibility references, weighted KC tags, catalog facets, and delivery URL/reference semantics without collapsing image into media_asset.
interactiveQTI/Common-Cartridge-compatible webcontent or learning-application resource row where available, plus Alpha extension facts.content_item_extension including expected_xp, media_asset references, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve expected_xp, launch/render references, version identity, media dependencies, weighted KC tags, and catalog sidecars.
media_assetqti.package_resource/qti.package_file where the resource shape exists, plus alpha.media_asset_extension for media_kind and delivery_url/reference evidence.content_item_extension.expected_xp for standalone media items, media_asset_extension, optional content_catalog_facet_assignment, trust evidence, and references from content_item/content_version.Export and re-import must preserve expected_xp, media_id, media_kind, media_type, byte_length, content_hash, public storage_path, delivery_url/reference evidence, and assignments without copying file fields into Alpha storage.
external_linkBase resource identity where available plus alpha.external_link_extension for external_url and launch policy.content_item_extension.expected_xp, external_link_extension, weighted content_kc_tag, content_effectiveness, content_trust_evidence, and named catalog facets.Export and re-import must preserve content_id, expected_xp, external_url, launch policy, weighted KC tags, trust evidence, and catalog sidecars without translating the link into a Curriculum collection or bundle row.
transport-only: imscp_v1p1 / Common Cartridge bundleNot stored as Content. Produced on demand from a Curriculum collection and uniform Content references.None. Export history, if needed, belongs to audit/provenance, not a Content item.A bundle export followed by re-import must return the same Content rows and sidecars; if translation code is needed, the storage shape is wrong.

Query model

content_kind

SourceField: content_item.content_kind

AllowedValues: content_kind

Behavior: Filters catalog items to a public Content kind.

subtype

SourceField: content_item.subtype

AllowedValues: content_subtype

Behavior: Filters governed media/article subtypes, such as article+decodable or image+diagram.

dok

SourceField: content_item.dok

AllowedValues: dok

Behavior: Filters assessment items by Webb DOK tag without treating DOK as difficulty.

subject_id

SourceField: content_item.subject_id

AllowedValues: alpha_subject_id

Behavior: Filters by canonical subject id after alias folding on write/import.

alpha_subject_id

SourceField: content_item.subject_id

AllowedValues: alpha_subject_id

Behavior: Compatibility alias for subject_id. If both parameters are present they must name the same canonical subject or the request fails 400.

target_grade_id

SourceField: content_item.target_grade_id

AllowedValues: alpha_grade_id

Behavior: Filters by one canonical grade/level target, such as 7.

curriculum_node_id

SourceField: Read-only compatibility projection over content_curriculum_link.curriculum_node_id and Curriculum component target_ref

AllowedValues: historical Curriculum node ids present in the frozen archive or an exact active Curriculum component id in the same tenant

Behavior: Returns active Content items selected by either an active historical content_curriculum_link row matching the exact value or an active Content target on the exact Curriculum component and any active descendants. The current CASE-backed adapter reads target_ref from the Curriculum component tree; it never copies or writes placement rows into Content. Curriculum remains authoritative for lesson membership and order, so consumers that need positions read the Curriculum tree or parent-filtered component list. The filter does not query content_kc_tag or infer membership from KC scope. Existing archive rows have no automatic TTL.

usage_scope

SourceField: content_item.usage_scope

AllowedValues: usage_scope

Behavior: Filters by Content-owned routing exposure: practice_eligible, held_out_canary, or secure_form. Explicit reads may discover all three; routine routing selects only practice_eligible.

test_type

SourceField: assessment_test.test_type

AllowedValues: test_type

Behavior: Filters test content by educational purpose.

assessment_role

SourceField: assessment_test.assessment_role

AllowedValues: assessment_role

Behavior: Filters QTI-backed assessment rows by compatibility role; content_kind=test_spec and content_kind=test_bank are the preferred public filters for specs and banks.

is_mastery_gate

SourceField: assessment_test.is_mastery_gate

AllowedValues: true or false

Behavior: Filters tests that gate advancement separately from test_type.

source_system

SourceField: content_item.source_system

AllowedValues: source_system

Behavior: Filters by public provenance category.

source_record_id

SourceField: content_item.source_record_id

AllowedValues: non-empty source record identity

Behavior: Filters by the stored source record id. Read source_table with each imported row to recover the complete adapter identity; importing the same record id from a different source table fails with content.source_identity_collision and no partial mutation.

source_activity_ref

SourceField: content_item.source_activity_ref

AllowedValues: non-empty source activity/resource reference

Behavior: Filters by the stored source activity/resource correlation exactly as returned; it is not a Content family id or Curriculum node id.

facet

SourceField: content_catalog_facet_assignment.facet_key + facet_value

AllowedValues: facet_key:canonical_value where facet_key is one of subject, grade_band, language, accessibility_profile, rights_license, provenance, quality_rating, kc_refs, standards_framework_refs, content_kind, expected_xp_band, modality

Behavior: Filters by governed discovery sidecar values. For facet=expected_xp_band:VALUE only, runtime requires the stored assignment and also applies the governed numeric range to content_item.expected_xp; an inconsistent assignment is vetoed. Other named facets use the stored assignment without deriving the facet from base rows.

subject

SourceField: content_catalog_facet_assignment where facet_key='subject'

AllowedValues: content_catalog_facet.allowed_values for subject

Behavior: Direct alias for facet=subject:VALUE. Requires an active stored assignment; when both forms are supplied, the direct parameter replaces the repeated-facet value for this key.

grade_band

SourceField: content_catalog_facet_assignment where facet_key='grade_band'

AllowedValues: content_catalog_facet.allowed_values for grade_band

Behavior: Direct alias for facet=grade_band:VALUE. Requires an active stored assignment; the direct parameter takes precedence for this key.

language

SourceField: content_catalog_facet_assignment where facet_key='language'

AllowedValues: content_catalog_facet.allowed_values for language

Behavior: Direct alias for facet=language:VALUE. Requires an active stored assignment; it does not filter content_item.language directly.

accessibility_profile

SourceField: content_catalog_facet_assignment where facet_key='accessibility_profile'

AllowedValues: content_catalog_facet.allowed_values for accessibility_profile

Behavior: Direct alias for facet=accessibility_profile:VALUE. Requires an active stored assignment.

rights_license

SourceField: content_catalog_facet_assignment where facet_key='rights_license'

AllowedValues: content_catalog_facet.allowed_values for rights_license

Behavior: Direct alias for facet=rights_license:VALUE. Requires an active stored assignment.

provenance

SourceField: content_catalog_facet_assignment where facet_key='provenance'

AllowedValues: content_catalog_facet.allowed_values for provenance

Behavior: Direct alias for facet=provenance:VALUE. Requires an active stored assignment; it does not search arbitrary source metadata.

quality_rating

SourceField: content_catalog_facet_assignment where facet_key='quality_rating'

AllowedValues: content_catalog_facet.allowed_values for quality_rating

Behavior: Direct alias for facet=quality_rating:VALUE. Requires an active stored assignment.

kc_refs

SourceField: content_catalog_facet_assignment where facet_key='kc_refs'

AllowedValues: governed Curriculum KC references

Behavior: Direct alias for facet=kc_refs:VALUE. Requires an active stored discovery assignment and is distinct from the canonical weighted content_kc_tag relationship.

standards_framework_refs

SourceField: content_catalog_facet_assignment where facet_key='standards_framework_refs'

AllowedValues: governed standards-framework references

Behavior: Direct alias for facet=standards_framework_refs:VALUE. Requires an active stored assignment.

expected_xp_band

SourceField: content_item.expected_xp (runtime convenience filter; not the stored facet assignment)

AllowedValues: expected_xp_band values 0_to_10, 10_to_20, 20_to_45, 45_plus; compatibility aliases quick, standard, extended, intensive; numeric range aliases such as 10-20 normalize to the matching governed value.

Behavior: Current runtime maps the named band to governed numeric bounds and filters content_item.expected_xp directly; it does not require a content_catalog_facet_assignment row. facet=expected_xp_band:VALUE instead requires both the stored assignment and the same numeric-range match. The two filters can differ until runtime unifies their semantics.

modality

SourceField: content_catalog_facet_assignment where facet_key='modality'

AllowedValues: content_catalog_facet.allowed_values for modality

Behavior: Direct alias for facet=modality:VALUE. Requires an active stored assignment; it is not inferred from content_kind or media_type.

modifiedSince

SourceField: content_item.updated_at

AllowedValues: ISO-8601 timestamp

Behavior: Polls content_item representation changes. It does not currently include independent facet, curriculum-link, reference, trust, or effectiveness changes unless the parent item is also updated. It is not a learner activity feed.

cursor

SourceField: opaque page state

AllowedValues: opaque cursor returned by previous response

Behavior: Continues a paginated list without exposing implementation sort keys.

limit

SourceField: page size

AllowedValues: integer 1 through 100; default 25

Behavior: Bounds list response size. When omitted, runtime uses 25; values above 100 fail validation rather than being silently clamped.

Migration contract

Physical DDL. Every table/view DDL block below is the exact deployed CREATE statement projected from its owning Content implementation migration. Hand-authored source sketches are ignored and are not published. Migration 014 (#2015) collapsed the release-evidence/requirement lane to trust: the content_release_evidence and content_release_requirement tables and the content_release_eligibility v1 view are dropped, and test-serve is trust-only. Migration 002 adds the weighted content_kc_tag attribution. Migration 009 adds the governed test-serve grant and append-only exact bank/form authorization receipt. Deployed migration 018 adds the Alpha-owned runtime-readiness receipt written only after full migration-grade semantic verification and read-only to compatibility runtimes. Pending migration 019 is the fail-closed content_reference structural repair and bounded graph-index migration. Pending migration 020 separately owns the later generated-state ALTERs and conditional foreign key that make an active tag require an active Curriculum KC. The remaining pending #2164 chain uses migration 021 for exact-version QC-receipt hardening, migration 022 for fail-closed legacy-claim reconciliation, migration 023 for the mixed-version claim-admission fence, and migration 024 for graph-writer database guards. Migration 025 (#2476) is a DML-only, exact-manifest-bound bridge that releases only 48 producer-certified legacy AP CSA QTI form versions; it does not widen publication APIs or publish their spec/banks. Later ALTER, backfill, constraint, trigger, comment, and index statements remain in their cited migration source.

alpha.content_item_extension

Kind: extend table

Purpose: Holds only Alpha-owned catalog fields that QTI does not define.

Gate: This table must not contain workspace_id/tenant_id, title, language, qti_identifier, latest_version_id, package_id, resource_id, created_at, delivery_json, authoring_json, or any other QTI-sourced field. content_kind_override may publish first-class test_spec/test_bank over QTI test storage or non-QTI Content extension kinds including script; subtype is governed only for image/article variants diagram and decodable; dok is Webb DOK and never difficulty; subject_id is the closed eight-value Alpha authoring/catalog enum after write-time alias folding; removed candidate subjects require owner approval; expected_xp is the required Alpha-owned content config field; awarded XP remains in Results.

Trace: [{"id":"content-itd-002-shared-qti-truth-no-content-fork","title":"Shared QTI Truth Through Views And Extend Tables","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-002-shared-qti-truth-no-content-fork"},{"id":"content-itd-006-typed-content-and-test-fields","title":"Typed Content And Test Fields","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-006-typed-content-and-test-fields"},{"id":"content-itd-015-expected-xp-content-config","title":"Expected XP On Every Content Row","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-015-expected-xp-content-config"},{"id":"content-itd-019-governed-subtypes-within-ten-kinds","title":"Governed Subtypes And First-Class Spec/Bank Kinds","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-019-governed-subtypes-within-ten-kinds"},{"id":"content-itd-020-test-spec-and-test-bank","title":"test_spec And test_bank As First-Class, Storable Assessment Blueprints (#72)","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-020-test-spec-and-test-bank"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_item_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, content_kind_override text, subtype text, dok text, subject_id text, target_grade_id text, expected_xp numeric(10,2) NOT NULL, usage_scope text NOT NULL DEFAULT 'practice_eligible', source_system text NOT NULL DEFAULT 'qti', source_table text, source_record_id text, source_activity_ref text, status text NOT NULL DEFAULT 'draft', updated_at timestamptz NOT NULL DEFAULT now(), retired_at timestamptz, PRIMARY KEY (tenant_id, content_artifact_id), CONSTRAINT content_item_extension_kind_ck CHECK (content_kind_override IS NULL OR content_kind_override IN ('test_spec', 'test_bank', 'article', 'video', 'audio', 'image', 'interactive', 'media_asset', 'external_link', 'script')), CONSTRAINT content_item_extension_subtype_ck CHECK ( subtype IS NULL OR (subtype = 'diagram' AND content_kind_override = 'image') OR (subtype = 'decodable' AND content_kind_override = 'article') ), CONSTRAINT content_item_extension_dok_ck CHECK (dok IS NULL OR dok IN ('dok1', 'dok2', 'dok3', 'dok4')), CONSTRAINT content_item_extension_source_ck CHECK (source_system IN ('qti', 'alpha_content', 'external_content_import')), CONSTRAINT content_item_extension_expected_xp_ck CHECK (expected_xp >= 0), CONSTRAINT content_item_extension_usage_scope_ck CHECK (usage_scope IN ('practice_eligible', 'held_out_canary', 'secure_form')), CONSTRAINT content_item_extension_status_ck CHECK (status IN ('draft', 'published', 'retired', 'archived')) );

alpha.content_item_view

Kind: read view

Purpose: Publishes the Alpha content_item object by joining QTI base truth to Alpha-only sidecar facts.

Gate: The view may expose QTI columns because it stores nothing. The view must not make QTI section/container or manifest-resource internals look like student-touchable catalog items unless the Alpha sidecar classifies the anchored resource as test_spec, test_bank, article, video, audio, image, interactive, media_asset, external_link, or script.

Trace: [{"id":"content-itd-001-module-boundary-and-alias-map","title":"Content Module Boundary And Alias Map","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-001-module-boundary-and-alias-map"},{"id":"content-itd-003-content-kind-taxonomy","title":"Content Kind Taxonomy","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-003-content-kind-taxonomy"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE VIEW alpha.content_item_view AS SELECT t.tenant_key AS tenant_id, a.artifact_id::text AS content_id, t.tenant_id::text AS workspace_id, COALESCE( e.content_kind_override, CASE a.artifact_kind WHEN 'item' THEN 'question' WHEN 'test' THEN 'test' ELSE NULL END ) AS content_kind, e.subtype, e.dok, a.title, a.language, a.qti_identifier AS source_identifier, e.subject_id, e.target_grade_id, e.expected_xp, COALESCE(e.usage_scope, 'practice_eligible') AS usage_scope, a.latest_version_id::text AS latest_version_id, COALESCE(e.source_system, 'qti') AS source_system, e.source_table, e.source_record_id, e.source_activity_ref, COALESCE(e.status, 'draft') AS status, a.created_at, COALESCE(e.updated_at, a.created_at) AS updated_at, e.retired_at FROM qti.artifact a JOIN platform.tenant t ON t.tenant_id = a.tenant_id LEFT JOIN alpha.content_item_extension e ON e.tenant_id = a.tenant_id AND e.content_artifact_id = a.artifact_id WHERE COALESCE( e.content_kind_override, CASE a.artifact_kind WHEN 'item' THEN 'question' WHEN 'test' THEN 'test' ELSE NULL END ) IS NOT NULL AND e.expected_xp IS NOT NULL;

alpha.assessment_component_view

Kind: read view

Purpose: Publishes school-language assessment structure rows from QTI components.

Gate: The view stores nothing and exposes only blank-instrument structure. It must not copy qti.component rows into Alpha storage or include student response values, outcome_state, processing_trace, AI grading audit entries, or post-attempt feedback.

Trace: [{"id":"content-itd-008-answer-slots-not-student-answers","title":"Answer Slots, Not Student Answers","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-008-answer-slots-not-student-answers"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE VIEW alpha.assessment_component_view AS SELECT t.tenant_key AS tenant_id, c.component_id::text AS assessment_component_id, av.artifact_id::text AS content_id, c.artifact_version_id::text AS version_id, c.parent_component_id::text AS parent_assessment_component_id, CASE WHEN c.element_name IN ('qti-assessment-test', 'assessmentTest') THEN 'test' WHEN c.element_name IN ('qti-assessment-section', 'assessmentSection') THEN 'section' WHEN c.element_name IN ('qti-choice-interaction', 'choiceInteraction', 'qti-text-entry-interaction', 'textEntryInteraction', 'qti-extended-text-interaction', 'extendedTextInteraction') THEN 'part' WHEN c.element_name IN ('qti-assessment-item', 'assessmentItem') THEN 'question' WHEN c.element_name IN ('qti-assessment-item-ref', 'assessmentItemRef') THEN 'question_ref' WHEN c.element_name IN ('qti-simple-choice', 'simpleChoice') THEN 'distractor' WHEN c.element_name IN ('qti-rubric-block', 'rubricBlock') THEN 'rubric' WHEN c.element_name IN ('qti-modal-feedback', 'modalFeedback', 'qti-feedback-block', 'feedbackBlock', 'qti-feedback-inline', 'feedbackInline', 'qti-test-feedback', 'testFeedback') THEN 'preauthored_feedback' ELSE NULL END AS component_role, c.ordinal, c.element_name, c.qti_identifier, COALESCE(c.attributes->>'responseIdentifier', c.attributes->>'response-identifier') AS response_identifier, COALESCE(c.attributes->>'outcomeIdentifier', c.attributes->>'outcome-identifier') AS outcome_identifier, COALESCE(c.attributes->>'feedbackIdentifier', c.attributes->>'identifier') AS feedback_identifier, COALESCE(c.attributes->>'showHide', c.attributes->>'show-hide') AS show_hide, c.text_value AS display_text, c.source_trace FROM qti.component c JOIN qti.artifact_version av ON av.artifact_version_id = c.artifact_version_id JOIN qti.artifact a ON a.artifact_id = av.artifact_id JOIN platform.tenant t ON t.tenant_id = a.tenant_id WHERE c.element_name IN ( 'qti-assessment-test', 'assessmentTest', 'qti-assessment-section', 'assessmentSection', 'qti-choice-interaction', 'choiceInteraction', 'qti-text-entry-interaction', 'textEntryInteraction', 'qti-extended-text-interaction', 'extendedTextInteraction', 'qti-assessment-item', 'assessmentItem', 'qti-assessment-item-ref', 'assessmentItemRef', 'qti-simple-choice', 'simpleChoice', 'qti-rubric-block', 'rubricBlock', 'qti-modal-feedback', 'modalFeedback', 'qti-feedback-block', 'feedbackBlock', 'qti-feedback-inline', 'feedbackInline', 'qti-test-feedback', 'testFeedback' );

alpha.assessment_test_extension

Kind: extend table

Purpose: Stores Alpha-owned typed test facts that QTI does not define, keyed to the base QTI test artifact.

Gate: This is the deployed physical table shape. It contains only Alpha-owned typed test fields, tenant scope, and the base content FK. test_type and test_family_id are nullable; the current API/database enforce the test_type enum when present and do not enforce a test_family_id lexical grammar. It must not copy QTI test title, identifier, XML, version, package, delivery_json, authoring_json, score data, attempts, thresholds, retake policy, or gate-failure behavior. assessment_role keeps QTI test storage compatible: content_kind=test implies form, content_kind=test_spec implies spec, and content_kind=test_bank implies bank.

Trace: [{"id":"content-itd-002-shared-qti-truth-no-content-fork","title":"Shared QTI Truth Through Views And Extend Tables","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-002-shared-qti-truth-no-content-fork"},{"id":"content-itd-006-typed-content-and-test-fields","title":"Typed Content And Test Fields","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-006-typed-content-and-test-fields"},{"id":"content-itd-019-governed-subtypes-within-ten-kinds","title":"Governed Subtypes And First-Class Spec/Bank Kinds","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-019-governed-subtypes-within-ten-kinds"},{"id":"content-itd-020-test-spec-and-test-bank","title":"test_spec And test_bank As First-Class, Storable Assessment Blueprints (#72)","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-020-test-spec-and-test-bank"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.assessment_test_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, assessment_role text NOT NULL DEFAULT 'form', test_type text, is_mastery_gate boolean NOT NULL DEFAULT false, test_family_id text, PRIMARY KEY (tenant_id, content_artifact_id), CONSTRAINT assessment_test_extension_role_ck CHECK (assessment_role IN ('form', 'spec', 'bank')), CONSTRAINT assessment_test_extension_type_ck CHECK (test_type IS NULL OR test_type IN ('end_of_course', 'end_of_grade', 'test_out', 'placement', 'diagnostic', 'screener')) );

alpha.decodable_extension

Kind: extend table

Purpose: Stores the phonics constraint set for article rows where subtype='decodable'.

Gate: This table contains only decodable-specific Alpha facts plus the base content FK. It must not copy article body, title, language, QTI version JSON, Curriculum KC text, student reading attempts, scores, or mastery.

Trace: [{"id":"content-itd-019-governed-subtypes-within-ten-kinds","title":"Governed Subtypes And First-Class Spec/Bank Kinds","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-019-governed-subtypes-within-ten-kinds"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.decodable_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, phonics_constraint jsonb NOT NULL DEFAULT '{}'::jsonb, constraint_set_id text, policy_version text, updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (tenant_id, content_artifact_id) );

alpha.test_spec_extension

Kind: extend table

Purpose: Stores the current table-of-specifications payload for content_kind='test_spec' rows. A governed PP100 spec also freezes its complete launch blueprint inside the exact Content version at editing_draft.sourceTrace.pp100_blueprint, so later mutable sidecar edits cannot alter an in-flight or pinned gate. The owner API enforces positive integer item/DOK counts and exact agreement between the interaction and KC-coverage totals; cross-module KC resolution remains an accepted target.

Gate: This table stores only Alpha blueprint facts plus the base test FK. It must not copy QTI XML, form item rows, test title, Curriculum KC statement text, gate thresholds, retake policy, student answers, scores, or mastery. The owner API rejects empty, zero, negative, or fractional item/DOK counts and rejects mismatched item_type_mix and kc_coverage totals. Resolving kc_coverage against active identities in the Curriculum-owned alpha.knowledge_component registry remains an accepted pending target.

Trace: [{"id":"content-itd-020-test-spec-and-test-bank","title":"test_spec And test_bank As First-Class, Storable Assessment Blueprints (#72)","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-020-test-spec-and-test-bank"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.test_spec_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, spec_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, kc_coverage jsonb NOT NULL DEFAULT '{}'::jsonb, item_type_mix jsonb NOT NULL DEFAULT '{}'::jsonb, difficulty_constraints jsonb NOT NULL DEFAULT '{}'::jsonb, passing_rule jsonb NOT NULL DEFAULT '{}'::jsonb, min_forms integer, max_item_overlap numeric(5,4), enemy_item_rule jsonb NOT NULL DEFAULT '{}'::jsonb, updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (tenant_id, spec_artifact_id), CONSTRAINT test_spec_extension_min_forms_ck CHECK (min_forms IS NULL OR min_forms >= 1), CONSTRAINT test_spec_extension_overlap_ck CHECK (max_item_overlap IS NULL OR (max_item_overlap >= 0 AND max_item_overlap <= 1)) );

alpha.test_bank_extension

Kind: extend table

Purpose: Stores bank identity and spec linkage for content_kind='test_bank' rows.

Gate: This table stores only the bank id, spec FK, membership rule, and audit timestamp. Fixed-form members are alpha.content_reference rows with relationship_kind='bank_member' and ascending positive-integer form_index; native adaptive pools remain inside QTI qti-selection/qti-adaptive-selection and cannot carry parallel bank_member rows. PP100 adaptive pools use the explicit pp100_adaptive_shards rule: ordered exact form shards are storage containers whose pinned embeds union to one immutable question pool, and Results—not Content or Curriculum—performs runtime score-band selection. Every fixed-form or PP100 shard member must reference an assessment_role='form' test with an exact owned version, at least one embedded question, and active canonical alpha.content_kc_tag attribution for every question occurrence. A fixed-form or PP100 exact bank version must have at least one valid active member and no index coercion is permitted. It must not copy member form XML, item rows, titles, cut scores, gate fields, retake policy, attempts, scores, mastery, or KC mappings.

Trace: [{"id":"content-itd-020-test-spec-and-test-bank","title":"test_spec And test_bank As First-Class, Storable Assessment Blueprints (#72)","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-020-test-spec-and-test-bank"},{"id":"content-itd-016-uniform-content-reference-contract","title":"Uniform Content Reference Contract","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-016-uniform-content-reference-contract"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.test_bank_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, bank_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, spec_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE RESTRICT, membership_rule text NOT NULL, updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (tenant_id, bank_artifact_id), CONSTRAINT test_bank_extension_membership_rule_ck CHECK (membership_rule IN ('same_blueprint_fixed_forms', 'qti_adaptive_selection', 'pp100_adaptive_shards')) );

alpha.media_asset_extension

Kind: extend table

Purpose: Stores Alpha-owned media kind and delivery URL/reference facts beside QTI package_file/package_resource rows.

Gate: This table stores only tenant and relationship keys, media_kind, and delivery_url/reference fields. It must never copy QTI package_file byte_length, title, content_hash, media_type, package_path, file bytes, signed URLs, tokens, or secrets. media_kind is not content_kind; primary video/audio/image rows keep their first-class content_kind.

Trace: [{"id":"content-itd-004-non-qti-media-extension","title":"Non-QTI Content Extensions","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-004-non-qti-media-extension"},{"id":"content-itd-013-lossless-common-cartridge-round-trip","title":"Lossless Common Cartridge Round Trip","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-013-lossless-common-cartridge-round-trip"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.media_asset_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, package_file_id uuid NOT NULL REFERENCES qti.package_file(package_file_id) ON DELETE CASCADE, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, media_kind text NOT NULL, delivery_url text, PRIMARY KEY (tenant_id, package_file_id), CONSTRAINT media_asset_extension_kind_ck CHECK (media_kind IN ('primary', 'supporting', 'thumbnail', 'caption', 'transcript', 'worksheet', 'source_file')) );

alpha.external_link_extension

Kind: extend table

Purpose: Stores Alpha-owned URL facts for content_kind='external_link'.

Gate: Stores only URL/policy facts and a base FK. It must not store copied QTI title/language/kind/version fields, permanent signed URLs, tokens, secrets, or student credentials.

Trace: [{"id":"content-itd-004-non-qti-media-extension","title":"Non-QTI Content Extensions","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-004-non-qti-media-extension"},{"id":"content-itd-013-lossless-common-cartridge-round-trip","title":"Lossless Common Cartridge Round Trip","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-013-lossless-common-cartridge-round-trip"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.external_link_extension ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, external_url text NOT NULL, display_url text, open_policy text NOT NULL DEFAULT 'new_tab', last_validated_at timestamptz, PRIMARY KEY (tenant_id, content_artifact_id), CONSTRAINT external_link_extension_url_ck CHECK (external_url ~ '^https?://[^[:space:]]+$' AND external_url !~* '(token|secret|password|credential|api[_-]?key)='), CONSTRAINT external_link_extension_open_policy_ck CHECK (open_policy IN ('same_tab', 'new_tab', 'embedded_iframe_allowed', 'external_app_handoff')) );

alpha.content_kc_tag

Kind: extend relationship table (release 002)

Purpose: Stores the canonical weighted many-to-many relationship from base Content identities to governed Knowledge Component registry identities.

Gate: Release 002 fails closed unless the governed alpha.knowledge_component registry already exists. Pending migration 020 adds alpha.knowledge_component.content_kc_tag_active_state = (retired_at IS NULL) and alpha.content_kc_tag.required_kc_active_state = CASE WHEN retired_at IS NULL THEN true ELSE NULL END as stored generated booleans, a unique parent key on (tenant_id, kc_id, content_kc_tag_active_state), and the non-deferrable MATCH SIMPLE content_kc_tag_active_kc_fk from the tag triple to that parent key. Therefore every active tag must reference an active same-tenant KC, while a retired tag carries NULL state and remains as historical evidence. The migration rejects zombie active tags and noncanonical reserved columns/constraints before DDL; startup readiness verifies the exact generated expressions, unique index, native RI triggers, FK actions, and absence of zombies. Friendly application prechecks still produce typed errors, but PostgreSQL native referential integrity, not a lock-only assumption, is the final concurrent arbiter. Ordinary reads and bank-graph validation also join the unretired registry row. weight is an independent relevance strength, confidence describes mapping quality, and at most one active row per Content item is primary. QTI may read-project the active kc_id and Curriculum-owned standard_kc_map GUIDs beside an immutable package-member identity, but QTI never stores, infers, or accepts writes for either learning fact.

Trace: [{"id":"content-itd-005-curriculum-links-are-relationships","title":"Weighted Registry-KC Relationships And Frozen Curriculum-Link Archive","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-005-curriculum-links-are-relationships"},{"id":"content-itd-017-lor-clones-no-specific-storage","title":"LOR Clones Add No Specific Storage","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-017-lor-clones-no-specific-storage"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/002_content_kc_tag.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_kc_tag ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_id uuid NOT NULL, kc_id uuid NOT NULL, weight numeric(8,6) NOT NULL, is_primary boolean NOT NULL DEFAULT false, provenance text NOT NULL, confidence numeric(4,3) NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), retired_at timestamptz, CONSTRAINT content_kc_tag_pkey PRIMARY KEY (tenant_id, content_id, kc_id), CONSTRAINT content_kc_tag_content_fk FOREIGN KEY (tenant_id, content_id) REFERENCES qti.artifact(tenant_id, artifact_id) ON DELETE CASCADE, CONSTRAINT content_kc_tag_kc_fk FOREIGN KEY (tenant_id, kc_id) REFERENCES alpha.knowledge_component(tenant_id, kc_id) ON DELETE RESTRICT, CONSTRAINT content_kc_tag_weight_ck CHECK (weight > 0 AND weight <= 1), CONSTRAINT content_kc_tag_confidence_ck CHECK (confidence >= 0 AND confidence <= 1), CONSTRAINT content_kc_tag_provenance_ck CHECK (btrim(provenance) <> ''), CONSTRAINT content_kc_tag_lifecycle_ck CHECK (retired_at IS NULL OR retired_at >= created_at) );

alpha.content_curriculum_link

Kind: frozen archive relationship table

Purpose: Preserves historical unweighted Content-to-Curriculum component links for readback and migration evidence; no current write authority remains.

Gate: The table stores only historical relationship keys and lifecycle. GET remains available; POST returns 410 and no current import or authoring workflow may use this archive as KC alignment.

Trace: [{"id":"content-itd-005-curriculum-links-are-relationships","title":"Curriculum Links Are Relationships","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-005-curriculum-links-are-relationships"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_curriculum_link ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_curriculum_link_id uuid NOT NULL, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, curriculum_node_id text NOT NULL, link_kind text NOT NULL DEFAULT 'teaches', created_at timestamptz NOT NULL DEFAULT now(), retired_at timestamptz, CONSTRAINT content_curriculum_link_ext_pkey PRIMARY KEY (tenant_id, content_curriculum_link_id), CONSTRAINT content_curriculum_link_ext_kind_ck CHECK (link_kind IN ('teaches', 'practices', 'assesses', 'supports', 'extends')), CONSTRAINT content_curriculum_link_ext_unique_active UNIQUE (tenant_id, content_artifact_id, content_version_id, curriculum_node_id, link_kind) );

alpha.content_reference

Kind: extend relationship table

Purpose: Stores content-to-content embedding, dependency, accessibility, thumbnail, transcript, source-file, source-script, bank-member, and related-material relationships.

Gate: This is the deployed physical table shape. It stores only tenant/relationship keys, parent/referenced artifact and optional version FKs, the server-derived parent_content_kind snapshot, relationship_kind, display_order, form_index, usage_scope, and lifecycle. It has no referenced_content_kind column: alpha.content_reference_view and repository reads derive that public field from the referenced artifact plus Content extension. Public APIs expose parent_content_id/parent_version_id/referenced_content_id/referenced_version_id aliases. DELETE /items/{contentId}/references/{referenceId} soft-retires a row and active list reads hide it. Bank members use relationship_kind='bank_member' plus a database-enforced unique active form_index per bank; form_index is an exact PostgreSQL int4 in 1..2147483647 and display_order, when present, is an exact int4 in 0..2147483647, with no string, fractional, unsafe-number, alias-conflict, or out-of-range coercion. On create, parent_version_id and referenced_version_id must be supplied exact UUIDs owned by their corresponding artifacts; omitted or explicit-null values fail closed and never resolve latest_version_id. A fresh bank-member create acquires the exclusive tenant graph fence, repeats completed-replay arbitration while fenced, then locks parent artifacts before reference rows and validates before claiming; retirement revalidates lifecycle/trust before soft-retiring the selected row. PostgreSQL bank-graph integrity reads first acquire the shared tenant writer fence on client A, then begin the stable reader transaction on distinct client B; the writer-before-reader order guarantees that a previously waiting writer commits before B takes its snapshot, while readers may overlap and later writers wait. Scripts use relationship_kind='source_script_for'. It must not copy titles, media bytes, XML, Curriculum statement text, student answers, scores, or collection membership.

Trace: [{"id":"content-itd-016-uniform-content-reference-contract","title":"Uniform Content Reference Contract","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-016-uniform-content-reference-contract"},{"id":"content-itd-013-lossless-common-cartridge-round-trip","title":"Lossless Common Cartridge Round Trip","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-013-lossless-common-cartridge-round-trip"},{"id":"content-itd-019-governed-subtypes-within-ten-kinds","title":"Governed Subtypes And First-Class Spec/Bank Kinds","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-019-governed-subtypes-within-ten-kinds"},{"id":"content-itd-020-test-spec-and-test-bank","title":"test_spec And test_bank As First-Class, Storable Assessment Blueprints (#72)","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-020-test-spec-and-test-bank"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_reference ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_reference_id uuid NOT NULL, parent_content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, parent_content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, parent_content_kind text NOT NULL, referenced_content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, referenced_content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, relationship_kind text NOT NULL DEFAULT 'embeds', display_order integer, form_index integer, usage_scope text NOT NULL DEFAULT 'practice_eligible', created_at timestamptz NOT NULL DEFAULT now(), retired_at timestamptz, CONSTRAINT content_reference_ext_pkey PRIMARY KEY (tenant_id, content_reference_id), CONSTRAINT content_reference_parent_content_kind_ck CHECK (parent_content_kind IN ('question', 'test', 'test_spec', 'test_bank', 'article', 'video', 'audio', 'image', 'interactive', 'media_asset', 'external_link', 'script')), CONSTRAINT content_reference_relationship_kind_ck CHECK (relationship_kind IN ('embeds', 'depends_on', 'transcript_for', 'caption_for', 'thumbnail_for', 'source_file_for', 'source_script_for', 'alternative_form_of', 'bank_member', 'related_material')), CONSTRAINT content_reference_display_order_ck CHECK (display_order IS NULL OR display_order >= 0), CONSTRAINT content_reference_form_index_ck CHECK ((relationship_kind = 'bank_member' AND form_index IS NOT NULL AND form_index > 0) OR (relationship_kind <> 'bank_member' AND form_index IS NULL)), CONSTRAINT content_reference_usage_scope_ck CHECK (usage_scope IN ('practice_eligible', 'held_out_canary', 'secure_form')) );

alpha.interactive_composition

Kind: extend table

Purpose: Stores typed interactive article/video delivery composition owned by Content: ordered article segment-to-question refs and video cue timestamp-to-question refs.

Gate: This table stores only delivery composition keys and validation facts. It must not copy question body XML, answer keys, scoring rules, media bytes, Curriculum sequencing, gate policy, student answers, attempts, scores, or XP awards. QTI remains question/scoring structure; Curriculum references and gates the Content object.

Trace: [{"id":"content-itd-022-interactive-composition","title":"Interactive Article/Video Composition","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-022-interactive-composition"},{"id":"content-itd-008-answer-slots-not-student-answers","title":"Answer Slots, Not Student Answers","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-008-answer-slots-not-student-answers"},{"id":"content-itd-005-curriculum-links-are-relationships","title":"Curriculum Links Are Relationships","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-005-curriculum-links-are-relationships"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.interactive_composition ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, interactive_composition_id uuid NOT NULL, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, composition_type text NOT NULL, sequence_index integer NOT NULL, segment_ref text, at_seconds numeric(10,3), duration_seconds numeric(10,3), media_package_file_id uuid REFERENCES qti.package_file(package_file_id) ON DELETE RESTRICT, question_content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE RESTRICT, question_content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, question_assessment_component_id uuid REFERENCES qti.component(component_id) ON DELETE SET NULL, tests_prior_content boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), retired_at timestamptz, CONSTRAINT interactive_composition_pkey PRIMARY KEY (tenant_id, interactive_composition_id), CONSTRAINT interactive_composition_type_ck CHECK (composition_type IN ('interactive_article', 'interactive_video')), CONSTRAINT interactive_composition_sequence_ck CHECK (sequence_index > 0), CONSTRAINT interactive_composition_article_shape_ck CHECK (composition_type <> 'interactive_article' OR at_seconds IS NULL), CONSTRAINT interactive_composition_video_shape_ck CHECK ( composition_type <> 'interactive_video' OR ( at_seconds IS NOT NULL AND at_seconds > 0 AND duration_seconds IS NOT NULL AND duration_seconds > 0 AND at_seconds < duration_seconds AND media_package_file_id IS NOT NULL ) ), CONSTRAINT interactive_composition_prior_content_ck CHECK (tests_prior_content = true) );

alpha.content_catalog_facet

Kind: extend registry table

Purpose: Defines governed discovery facets beside the base Content views.

Gate: The registry stores the twelve named governed facet definitions only. It must not copy QTI base fields, Curriculum statement text, secrets, direct student PII, or free-form ungoverned metadata; UIs query assignments directly instead of recomputing facets at read time.

Trace: [{"id":"content-itd-014-catalog-facets-sidecar","title":"Catalog Facets Sidecar","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-014-catalog-facets-sidecar"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_catalog_facet ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, facet_key text NOT NULL, label text NOT NULL, value_type text NOT NULL, grain text NOT NULL, allowed_values jsonb, status text NOT NULL DEFAULT 'active', updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (tenant_id, facet_key), CONSTRAINT content_catalog_facet_key_ck CHECK (facet_key IN ( 'subject', 'grade_band', 'language', 'accessibility_profile', 'rights_license', 'provenance', 'quality_rating', 'kc_refs', 'standards_framework_refs', 'content_kind', 'expected_xp_band', 'modality' )), CONSTRAINT content_catalog_facet_value_type_ck CHECK (value_type IN ('enum', 'boolean', 'number', 'text', 'reference')), CONSTRAINT content_catalog_facet_grain_ck CHECK (grain IN ('content_item', 'content_version', 'media_asset')), CONSTRAINT content_catalog_facet_status_ck CHECK (status IN ('active', 'retired')), CONSTRAINT content_catalog_facet_allowed_values_ck CHECK (value_type <> 'enum' OR (allowed_values IS NOT NULL AND jsonb_typeof(allowed_values) = 'array')) );

alpha.content_catalog_facet_assignment

Kind: extend assignment table

Purpose: Assigns governed discovery facet values to Content without copying base rows.

Gate: Stores only assignment keys, facet_value, lifecycle, and safe provenance. It must not replace real relationship columns such as content_kc_tag, subject_id, target_grade_id, or test_family_id.

Trace: [{"id":"content-itd-014-catalog-facets-sidecar","title":"Catalog Facets Sidecar","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-014-catalog-facets-sidecar"},{"id":"content-axis-003-query-model","title":"API Axis: Query Model","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-axis-003-query-model"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_catalog_facet_assignment ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, facet_assignment_id uuid NOT NULL, facet_key text NOT NULL, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, content_version_id uuid REFERENCES qti.artifact_version(artifact_version_id) ON DELETE SET NULL, package_file_id uuid REFERENCES qti.package_file(package_file_id) ON DELETE SET NULL, facet_value text NOT NULL, provenance jsonb NOT NULL DEFAULT '{}'::jsonb, retired_at timestamptz, PRIMARY KEY (tenant_id, facet_assignment_id), CONSTRAINT content_catalog_facet_assignment_facet_fk FOREIGN KEY (tenant_id, facet_key) REFERENCES alpha.content_catalog_facet(tenant_id, facet_key), CONSTRAINT content_catalog_facet_assignment_provenance_ck CHECK (jsonb_typeof(provenance) = 'object') );

alpha.content_effectiveness

Kind: Results-owned read dependency; no Content DDL

Purpose: Documents the raw read contract for the Results-owned derived rollup that Content displays beside a Content item.

Ddl: -- Content Alpha MUST NOT create, replace, migrate, write, or backfill -- the canonical alpha.content_effectiveness object. -- Results Alpha owns: -- alpha.content_effectiveness_extension -- alpha.content_effectiveness(tenant_id, object_id, data jsonb) -- -- Content/raw readers use this projection: SELECT data ->> 'content_id' AS content_id, data ->> 'content_version_id' AS content_version_id, data ->> 'kc_id' AS kc_id, data ->> 'subject_id' AS subject_id, (data ->> 'validated_by_count')::integer AS validated_by_count, (data ->> 'failed_by_count')::integer AS failed_by_count, (data ->> 'effectiveness_rate')::numeric AS effectiveness_rate, (data ->> 'evidence_count')::integer AS evidence_count, data ->> 'policy_version' AS policy_version, data -> 'source_result_refs' AS source_result_refs, (data ->> 'last_recomputed_at')::timestamptz AS last_recomputed_at FROM alpha.content_effectiveness WHERE tenant_id = :tenant_id AND data ->> 'content_id' = :content_id;

Gate: Any Content migration that creates alpha.content_effectiveness, creates alpha.content_effectiveness_view, writes to the canonical object, inserts placeholder rows, or queries a top-level content_id column violates Content Alpha architecture. If legacy Content-owned storage exists, implementation must preserve it under an audit name and release the canonical name for Results.

Trace: [{"id":"content-itd-009-content-effectiveness-derived-rollup","title":"Content Effectiveness Derived Rollup","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-009-content-effectiveness-derived-rollup"},{"id":"ritd-016-content-effectiveness-derived-read","title":"Results Content Effectiveness Derived Read","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/results/alpha/architecture/#ritd-016-content-effectiveness-derived-read"}]

alpha.content_trust_evidence

Kind: extend table

Purpose: Stores safe validation and conformance evidence for a base Content artifact.

Gate: This table stores read-only evidence for the surface and operators. It must never contain secrets, credentials, raw validation job mutation state, public write controls, student answers, score data, or copied QTI content fields.

Trace: [{"id":"content-axis-010-conformance-evidence","title":"API Axis: Conformance Evidence","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-axis-010-conformance-evidence"},{"id":"content-itd-012-plain-language-problems-and-provenance","title":"Plain-Language Problems And Provenance","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-012-plain-language-problems-and-provenance"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/001_content_alpha.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_trust_evidence ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, content_artifact_id uuid NOT NULL REFERENCES qti.artifact(artifact_id) ON DELETE CASCADE, trust_status text NOT NULL DEFAULT 'unknown', evidence_url text, checked_at timestamptz, problem_code text, CONSTRAINT content_trust_evidence_ext_pkey PRIMARY KEY (tenant_id, content_artifact_id), CONSTRAINT content_trust_evidence_ext_status_ck CHECK (trust_status IN ('trusted', 'degraded', 'failed', 'unknown')) );

alpha.content_test_serve_grant

Kind: extend table

Purpose: Names one soft-revocable demo test/synthetic identity and producer surface without changing Content lifecycle, trust, or ordinary release policy.

Gate: A row is only one half of authorization: runtime also resolves the same active People & Orgs person_id with reality=test or reality=synthetic. Grants do not authorize non-demo tenants, real identities, non-practice Content, failed trust, retired Content, or explicit producer/Content rejection, block, or revocation.

Trace: [{"id":"content-itd-024-governed-test-serve","title":"Governed Test Serve","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-024-governed-test-serve"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/009_governed_test_serve.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_test_serve_grant ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, test_serve_grant_id uuid NOT NULL, test_identity_id text NOT NULL, producer_surface text NOT NULL, authorization_ref text NOT NULL, expires_at timestamptz, revoked_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT content_test_serve_grant_pkey PRIMARY KEY (test_serve_grant_id), CONSTRAINT content_test_serve_grant_tenant_identity_producer_unique UNIQUE (tenant_id, test_identity_id, producer_surface), CONSTRAINT content_test_serve_grant_receipt_binding_unique UNIQUE ( tenant_id, test_serve_grant_id, test_identity_id, producer_surface ), CONSTRAINT content_test_serve_grant_identity_ck CHECK (btrim(test_identity_id) <> '' AND length(test_identity_id) <= 200), CONSTRAINT content_test_serve_grant_producer_surface_ck CHECK (producer_surface ~ '^[a-z0-9][a-z0-9_-]*/[a-z0-9][a-z0-9_-]*$'), CONSTRAINT content_test_serve_grant_authorization_ref_ck CHECK (btrim(authorization_ref) <> '' AND length(authorization_ref) <= 500), CONSTRAINT content_test_serve_grant_expiry_ck CHECK (expires_at IS NULL OR expires_at > created_at), CONSTRAINT content_test_serve_grant_revocation_ck CHECK (revoked_at IS NULL OR revoked_at >= created_at) );

alpha.content_test_serve_authorization

Kind: extend table

Purpose: Appends one immutable receipt after Content atomically revalidates an exact test bank, exact member form, grant, and People & Orgs test reality.

Gate: Rows are insert-only and a database trigger rejects UPDATE or DELETE. The receipt records the exact grant, identity, producer, gate, bank/form ids and versions, caller, request/trace ids, and authorization time; it never changes ordinary release eligibility.

Trace: [{"id":"content-itd-024-governed-test-serve","title":"Governed Test Serve","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-024-governed-test-serve"}]

PhysicalDdlSource: loop/content/artifacts/alpha/implementation/impl/migrations/009_governed_test_serve.sql

Ddl: CREATE TABLE IF NOT EXISTS alpha.content_test_serve_authorization ( tenant_id uuid NOT NULL REFERENCES platform.tenant(tenant_id) ON DELETE CASCADE, test_serve_authorization_id uuid NOT NULL DEFAULT gen_random_uuid(), test_serve_grant_id uuid NOT NULL, caller_subject text NOT NULL, test_identity_id text NOT NULL, producer_surface text NOT NULL, gate_component_id uuid NOT NULL, bank_content_id uuid NOT NULL, bank_content_version_id uuid NOT NULL, form_content_id uuid NOT NULL, form_content_version_id uuid NOT NULL, request_id text NOT NULL, trace_id text NOT NULL, authorized_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT content_test_serve_authorization_pkey PRIMARY KEY (test_serve_authorization_id), CONSTRAINT content_test_serve_authorization_grant_binding_fk FOREIGN KEY ( tenant_id, test_serve_grant_id, test_identity_id, producer_surface ) REFERENCES alpha.content_test_serve_grant( tenant_id, test_serve_grant_id, test_identity_id, producer_surface ), CONSTRAINT content_test_serve_authorization_bank_tenant_fk FOREIGN KEY (tenant_id, bank_content_id) REFERENCES qti.artifact(tenant_id, artifact_id), CONSTRAINT content_test_serve_authorization_bank_version_fk FOREIGN KEY (bank_content_id, bank_content_version_id) REFERENCES qti.artifact_version(artifact_id, artifact_version_id), CONSTRAINT content_test_serve_authorization_form_tenant_fk FOREIGN KEY (tenant_id, form_content_id) REFERENCES qti.artifact(tenant_id, artifact_id), CONSTRAINT content_test_serve_authorization_form_version_fk FOREIGN KEY (form_content_id, form_content_version_id) REFERENCES qti.artifact_version(artifact_id, artifact_version_id), CONSTRAINT content_test_serve_authorization_caller_ck CHECK (btrim(caller_subject) <> '' AND length(caller_subject) <= 200), CONSTRAINT content_test_serve_authorization_identity_ck CHECK (btrim(test_identity_id) <> '' AND length(test_identity_id) <= 200), CONSTRAINT content_test_serve_authorization_producer_surface_ck CHECK (producer_surface ~ '^[a-z0-9][a-z0-9_-]*/[a-z0-9][a-z0-9_-]*$'), CONSTRAINT content_test_serve_authorization_request_id_ck CHECK (btrim(request_id) <> '' AND length(request_id) <= 200), CONSTRAINT content_test_serve_authorization_trace_id_ck CHECK (btrim(trace_id) <> '' AND length(trace_id) <= 300) );

Published content by governed KC

Kind: join query

Purpose: The reviewer persona's query: published Content items weighted to one governed registry Knowledge Component.

Ddl: SELECT ci.content_id, ci.content_kind, ci.title, ci.subject_id, ci.target_grade_id, tag.weight, tag.is_primary, tag.confidence FROM alpha.content_item_view ci JOIN alpha.content_kc_tag tag ON tag.tenant_id = ci.tenant_id AND tag.content_id = ci.content_id JOIN alpha.knowledge_component kc ON kc.tenant_id = tag.tenant_id AND kc.kc_id = tag.kc_id AND kc.retired_at IS NULL WHERE ci.tenant_id = $1 AND ci.status = 'published' AND tag.retired_at IS NULL AND tag.kc_id = $2 ORDER BY tag.is_primary DESC, tag.weight DESC, ci.updated_at DESC, ci.content_id;

Gate: The query joins the canonical relationship on tenant_id plus content_id, requires both the tag and the exact registry KC to be unretired, and filters the governed registry kc_id. It does not parse facets, titles, CASE text, Curriculum components, or QTI XML.

Trace: [{"id":"content-axis-003-query-model","title":"API Axis: Query Model","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-axis-003-query-model"},{"id":"content-itd-005-curriculum-links-are-relationships","title":"Curriculum Links Are Relationships","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-005-curriculum-links-are-relationships"}]

Published video content by KC and accessibility profile

Kind: join query

Purpose: The customer-eval raw SQL query: list all published video Content for one workspace and governed registry KC, filtered by the accessibility_profile catalog facet.

Ddl: SELECT ci.content_id, ci.title, ci.subject_id, ci.expected_xp, tag.kc_id, tag.weight, tag.is_primary, cfa.facet_value AS accessibility_profile FROM alpha.content_item_view ci JOIN alpha.content_kc_tag tag ON tag.tenant_id = ci.tenant_id AND tag.content_id = ci.content_id JOIN alpha.knowledge_component kc ON kc.tenant_id = tag.tenant_id AND kc.kc_id = tag.kc_id AND kc.retired_at IS NULL JOIN alpha.content_catalog_facet_assignment_view cfa ON cfa.tenant_id = ci.tenant_id AND cfa.content_id = ci.content_id WHERE ci.tenant_id = $1 AND ci.status = 'published' AND ci.content_kind = 'video' AND tag.retired_at IS NULL AND tag.kc_id = $2 AND cfa.retired_at IS NULL AND cfa.facet_key = 'accessibility_profile' AND cfa.facet_value = $3 ORDER BY tag.is_primary DESC, tag.weight DESC, ci.updated_at DESC, ci.content_id;

Gate: This query reaches the same answer as the API path through typed guardrails: tenant_id, status, content_kind, active tag lifecycle, active registry-KC lifecycle, registry kc_id, weight, facet_key, facet_value, and facet-assignment retired_at. It does not parse titles, QTI XML, media MIME type, CASE statements, Curriculum components, or free-form tags.

Trace: [{"id":"content-itd-003-content-kind-taxonomy","title":"Content Kind Taxonomy","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-003-content-kind-taxonomy"},{"id":"content-itd-005-curriculum-links-are-relationships","title":"Curriculum Links Are Relationships","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-005-curriculum-links-are-relationships"},{"id":"content-itd-014-catalog-facets-sidecar","title":"Catalog Facets Sidecar","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-itd-014-catalog-facets-sidecar"},{"id":"content-axis-003-query-model","title":"API Axis: Query Model","href":"https://platform3-andymontgomery-9773s-projects.vercel.app/content/alpha/architecture/#content-axis-003-query-model"}]

Staff-engineer recipes

Decide where a new Alpha Content column belongs

Use this before writing a migration.

  • If the value is already a QTI/1EdTech fact, expose it as a read-view column and route writes to the QTI 1EdTech base surface.
  • If the value is a new Content fact needed for every student-touchable content row, store it in a Content-owned extend table keyed to the base row; never copy a QTI field.
  • If the value aligns Content to learned knowledge, store it as a weighted content_kc_tag row referencing the governed KC registry; content_curriculum_link is a frozen archive, not a write target.
  • If the value is a governed discovery-only facet, store it in content_catalog_facet_assignment until it becomes a join target or computed input.
  • If the value describes an attempt, score, mastery, awarded XP, or effectiveness recomputation, route it to Results or Events, not Content.

Example

-- Allowed: required author-calibrated Alpha fact beside a QTI base row; no fake default.
ALTER TABLE alpha.content_item_extension
  ADD COLUMN IF NOT EXISTS expected_xp numeric(10,2) NOT NULL;

-- Forbidden: copied 1EdTech/QTI fields in an Alpha extend table.
-- ALTER TABLE alpha.content_item_extension ADD COLUMN title text;

Join a content_item to a governed KC with weight

Use this when finding Content aligned to a governed registry Knowledge Component.

  • Join through alpha.content_kc_tag on tenant_id plus content_id, then join alpha.knowledge_component on tenant_id plus kc_id with kc.retired_at IS NULL before filtering the exact registry kc_id.
  • Use weight as independent relevance strength and is_primary as the single principal-KC marker. Do not normalize weights into probabilities or require them to sum to one.
  • Require both tag.retired_at IS NULL and kc.retired_at IS NULL. Use content_curriculum_link_view only when explicitly reading historical archive evidence.

Example

SELECT ci.content_id, ci.content_kind, ci.title, tag.kc_id, tag.weight, tag.is_primary
FROM alpha.content_item_view ci
JOIN alpha.content_kc_tag tag
  ON tag.tenant_id = ci.tenant_id
 AND tag.content_id = ci.content_id
JOIN alpha.knowledge_component kc
  ON kc.tenant_id = tag.tenant_id
 AND kc.kc_id = tag.kc_id
 AND kc.retired_at IS NULL
WHERE ci.tenant_id = $1
  AND ci.status = 'published'
  AND tag.retired_at IS NULL
  AND tag.kc_id = $2
ORDER BY tag.is_primary DESC, tag.weight DESC;

Filter by a catalog facet assignment

Use this for LOR/library/catalog discovery filters such as accessibility_profile:captioned or rights_license:cc_by.

  • Filter on content_catalog_facet_assignment_view.facet_key plus facet_value; the view projects the twelve named first-class sidecars.
  • Use facet=expected_xp_band:VALUE for the hybrid stored-assignment plus numeric-range query. The separate expected_xp_band=VALUE shortcut filters only numeric content_item.expected_xp and is not proof that a facet assignment exists.
  • Do not recompute subject, language, modality, KC refs, standards refs, or curated expected_xp_band assignments in an app by reading base rows or related Curriculum rows at request time.
  • Relationships needed for joins, especially content_kc_tag, must stay real columns instead of facet assignments; kc_refs remains discovery metadata only.

Example

SELECT ci.content_id, ci.title, cfa.facet_key, cfa.facet_value
FROM alpha.content_item_view ci
JOIN alpha.content_catalog_facet_assignment_view cfa
  ON cfa.tenant_id = ci.tenant_id
 AND cfa.content_id = ci.content_id
WHERE ci.tenant_id = $1
  AND ci.status = 'published'
  AND cfa.retired_at IS NULL
  AND cfa.facet_key = 'accessibility_profile'
  AND cfa.facet_value = 'captioned';

List published videos for one KC and accessibility profile

Use this for the staff-engineer raw SQL path: published video Content in one workspace, weighted to one governed registry KC, filtered by the accessibility_profile catalog facet.

  • Filter video through content_item.content_kind, the canonical public enum.
  • Join KC alignment through content_kc_tag on tenant_id plus content_id, require tag.retired_at IS NULL, and join the exact alpha.knowledge_component with kc.retired_at IS NULL; do not parse QTI XML, CASE text, Curriculum components, titles, or facet strings to infer KC coverage.
  • Join accessibility_profile through content_catalog_facet_assignment_view on tenant_id plus content_id; catalog facets are sidecars queried directly, not recomputed from media rows at read time.
  • Use canonical stored values only. If a caller has a source subject alias, fold it at write/import time before it becomes subject_id.

Example

SELECT
  ci.content_id,
  ci.title,
  ci.subject_id,
  ci.expected_xp,
  tag.kc_id,
  tag.weight,
  tag.is_primary,
  cfa.facet_value AS accessibility_profile
FROM alpha.content_item_view ci
JOIN alpha.content_kc_tag tag
  ON tag.tenant_id = ci.tenant_id
 AND tag.content_id = ci.content_id
JOIN alpha.knowledge_component kc
  ON kc.tenant_id = tag.tenant_id
 AND kc.kc_id = tag.kc_id
 AND kc.retired_at IS NULL
JOIN alpha.content_catalog_facet_assignment_view cfa
  ON cfa.tenant_id = ci.tenant_id
 AND cfa.content_id = ci.content_id
WHERE ci.tenant_id = $1
  AND ci.status = 'published'
  AND ci.content_kind = 'video'
  AND tag.retired_at IS NULL
  AND tag.kc_id = $2
  AND cfa.retired_at IS NULL
  AND cfa.facet_key = 'accessibility_profile'
  AND cfa.facet_value = $3
ORDER BY tag.is_primary DESC, tag.weight DESC, ci.updated_at DESC, ci.content_id;

Move authored Content to trusted, serveable exact versions

Use this integrator-invocable workflow after authoring governed Content and before Curriculum or a gate is allowed to launch it.

  • Route by artifact kind. Import QTI assessmentItem questions and assessmentTest forms through POST /imports/qti-package with application/zip, Idempotency-Key, a tenant-scoped author:content credential, and explicit governed X-Content-Subject-Id, X-Content-Target-Grade-Id, and X-Content-Expected-Xp headers; package metadata is not classification authority, missing or invalid values reject before idempotency or Content mutation, and target_grade_id=ungraded means Content is intentionally not tied to one grade. A successful import materializes the returned exact versions as published and trusted with Content-owned receipts.
  • Author test_spec, test_bank, article, and video as drafts through the Alpha item, version, media, and graph endpoints, then POST /items/{contentId}/publish with Idempotency-Key and a body containing only content_version_id. Primary Incept video first uses the existing media endpoint's narrow fetch-once source_asset handoff and an exact-version interactive_video composition. The generic publication endpoint intentionally rejects question and form artifacts.
  • For a freshly rendered Incept video, POST the exact current version plus media_kind=primary, duration, caption_track and/or transcript, and the closed source_asset {url,bucket,path,sha256,byte_length,media_type=video/mp4} to /items/{contentId}/media. Content fetches only the exact allowlisted first-party object, rejects redirects/private addresses/timeouts/overflow/type-length-hash mismatch, stores the verified bytes, returns its own media UUID/delivery URL, and never persists or returns the signed query token. The idempotency fingerprint includes the stable descriptor and attachment semantics but excludes source_asset.url, so the same key may safely carry a fresh signature for the same immutable bytes after expiry and a completed replay never refetches.
  • The authorization asymmetry is deliberate: Content semantically parses and receipts standardized QTI package materialization under author:content, while an authored spec/bank graph, article body, or video requires the stronger publisher role and automatic kind-owned QC.
  • Use a service, reviewer, or operator token with publish:content; writer, demo, teacher, and student principals cannot publish.
  • An app integrator may call these endpoints directly with the documented Platform-issued tenant-scoped credentials. Ordinary publication needs no per-course owner ruling and no #1769-class manual trust grant. A caller that lacks the narrow role/scope requests credential provisioning through Platform tenant onboarding; this contract defines no provisioning SLA.
  • Content, not the caller, verifies the exact current immutable version and the complete type-specific dependency graph.
  • For a test_spec, Content validates the complete seven-field blueprint. For a test_bank, Content also requires the published exact spec, minimum contiguous form membership, exact eligible forms/questions, and governed KC attribution. For an article, Content validates the stored sha256 content_hash, exact article student_view, nonempty renderable body, absence of student-forbidden answer/scoring/teacher/mastery/progress/credential fields, the governed tb-* value-space, unique same-body ids, and same-body data-catalog-idref resolution. For article/video composition, every question ref must name the canonical QTI content_id plus exact imported content_version_id and that exact version must be release eligible. Video also requires same-item/same-version primary verified MP4 bytes, valid cue timing for the declared duration, and caption or transcript evidence.
  • A passing check atomically sets status=published and records server-computed trusted evidence. The caller cannot submit trust_status, checked_at, evidence_url, or a verdict.
  • The passing transaction appends the QC receipt for the exact content_version_id as append-only provenance. Item-level trust is the compatible summary, and its failed state is the all-version revocation switch; neither the receipt nor positive trust is a release precondition (owner ruling #2534).
  • A failed check returns content.publication_rejected without changing lifecycle, trust, receipt, graph, or the fresh idempotency claim. Correct the graph and retry with a new idempotency key.
  • After publication, test_spec/test_bank item metadata, blueprint/bank sidecars, and versions are immutable. A revision uses a new Content identity and repeats publication; forbidden mutation returns content.published_assessment_immutable. Articles and videos remain append-only-versioned: every successor exact version must independently pass governed publication and receives fresh server-owned trust evidence plus its own receipt.
  • Owner FREEZE ruling (#1201, 2026-08-05): approval freezes the exact chain, not only the spec/bank rows. While an approved bank's active bank_member edges pin a chain, each member form's item row, the pinned exact form-version embeds graph, and active knowledge-component attribution on member forms and embedded questions are immutable; item PATCH, KC-tag upsert/retire, and active embeds reference create/retire return content.published_assessment_immutable, and bank_member writes keep content.bank_membership_frozen. Appending a new immutable form version remains allowed and never moves an approved bank's pinned exact reference; deploy-time persistent-seed bootstrap convergence replays the canonical seed rows themselves under the tenant seed lock and is not a mutation of the approved chain; the sanctioned revision path is a new Content identity through governed publication.
  • Read GET /items/{contentId}/trust, then GET /items/{contentId}/versions/{contentVersionId}/release-eligibility?producer_surface={producerSurface}. Require matching ids, trust_status trusted or degraded, serveable=true, release_eligible=true, and problem_code=null. release_eligible is exactly serveable and producer_surface is query-only compatibility, never caller evidence.
  • Authorized import and publication return synchronously. There is no content-by-content approval turnaround; credential onboarding is the only separate owner action when the caller is not yet authorized.

Example

# QTI question/form path
POST /tenants/demo/alpha/content/imports/qti-package
Authorization: Bearer {authorToken}
Content-Type: application/zip
Idempotency-Key: ap-lit-qti-{packageSha256}
X-Content-Subject-Id: science
X-Content-Target-Grade-Id: ungraded
X-Content-Expected-Xp: 8

{packageBytes}

# optional primary Incept-video byte handoff before video composition/publication
POST /tenants/demo/alpha/content/items/{videoContentId}/media
Authorization: Bearer {authorToken}
Content-Type: application/json
Idempotency-Key: incept-video-{videoContentId}-{videoVersionId}

{"version_id":"{videoVersionId}","media_kind":"primary","source_asset":{"url":"{ephemeralSignedUrl}","bucket":"loop-artifacts","path":"incept-skill-pack/video/{run}/media/{job}.mp4","sha256":"{bareSha256}","byte_length":12345,"media_type":"video/mp4"},"duration_seconds":60,"caption_track":[{"start_seconds":0,"end_seconds":60,"text":"{caption}"}]}

# test_spec/test_bank/article/video path
POST /tenants/demo/alpha/content/items/{contentId}/publish
Authorization: Bearer {publisherToken}
Content-Type: application/json
Idempotency-Key: ap-lit-publish-{contentId}-{contentVersionId}

{"content_version_id":"{contentVersionId}"}

# exact-version proof before placement
GET /tenants/demo/alpha/content/items/{contentId}/versions/{contentVersionId}/release-eligibility?producer_surface=incept%2Falpha

Read exact-version release eligibility

Use this when Curriculum, Incept, gates, or a launch surface needs Content current answer for one exact immutable version.

  • GET release-eligibility for the exact content_id and content_version_id, with the existing producer_surface compatibility query.
  • Accept release_eligible=true only when serveable=true; the two fields are identical by contract.
  • Content computes serveability from status=published, retired_at=null, and item trust not failed. Positive QC evidence and per-version receipts are recorded provenance and never gate the answer (owner ruling #2534).
  • Treat content.version_not_serveable as a closed gate. Failed item trust is the single post-visibility revocation lever and revokes every version on the next read (owner ruling #2534).
  • Retain the exact content_id, content_version_id, and content_kind reference and ask Content again at launch; do not copy or recompute the verdict.

Example

# No producer handoff or append is required.
GET /tenants/demo/alpha/content/items/58612cab-9c46-426c-8c20-0e9f19c807c5/versions/efcf3561-3a66-4825-9588-e792ef20c312/release-eligibility?producer_surface=incept%2Falpha

Read Content effectiveness without owning the rollup

Use this when displaying validated_by_count, failed_by_count, and effectiveness_rate next to a Content item.

  • Content documents the read contract, but Results owns alpha.content_effectiveness storage and recomputation.
  • Raw DB readers filter tenant_id and data ->> 'content_id'. There is no top-level alpha.content_effectiveness.content_id column in the canonical Results-owned view.
  • Apps display effectiveness; they never increment counters or recompute the rate from raw Results.

Example

SELECT
  data ->> 'content_id' AS content_id,
  (data ->> 'validated_by_count')::integer AS validated_by_count,
  (data ->> 'failed_by_count')::integer AS failed_by_count,
  (data ->> 'effectiveness_rate')::numeric AS effectiveness_rate,
  (data ->> 'last_recomputed_at')::timestamptz AS last_recomputed_at
FROM alpha.content_effectiveness
WHERE tenant_id = $1
  AND data ->> 'content_id' = $2;

Construct an RFC 7807 content_problem

Use this for validation, stale-version, authorization, relationship, or tenant errors.

  • Use the shared RFC 7807 envelope fields plus the Content code enum.
  • Put machine-readable field errors in fieldErrors; clients must not parse human text in detail.
  • Use the stable runtime type URI rooted at https://platform.timeback.com/problems/.

Example

{
  "type": "https://platform.timeback.com/problems/content/curriculum-node-not-found",
  "title": "Curriculum node was not found",
  "status": 404,
  "detail": "The supplied curriculum_node_id does not resolve to an active Curriculum node for this tenant.",
  "code": "content.curriculum_node_not_found",
  "fieldErrors": [
    {
      "name": "curriculum_node_id",
      "reason": "No active Curriculum node exists for case:math:7.ee.b.4 in this workspace."
    }
  ],
  "requestId": "req_01jz_content_demo",
  "traceId": "trace_01jz_content_demo"
}

Emit the uniform content_ref contract

Use this when Curriculum, Results, Events, LOR export, or a downstream app needs to point at any Content kind.

  • Emit content_id, content_version_id, and content_kind for Curriculum placements and exact-version eligibility reads; content_version_id may be omitted only by a separately documented unversioned discovery/read contract.
  • Take content_version_id from the materialization/import response that created the immutable version. Never substitute mutable latest_version_id.
  • Do not create kind-specific question_ref, test_ref, article_ref, media_ref, or external_link_ref tables.
  • Do not copy title, Curriculum statement text, or Results values into the reference payload.

Example

{
  "content_id": "2f4b4c12-7c41-4b40-a33a-9637581d0e51",
  "content_version_id": "918fcb3d-2df7-4a4c-93a6-5e74016ea001",
  "content_kind": "test"
}

Store a content-to-content reference

Use this when a video needs a transcript, an article embeds an image, a question references a supporting image while stimulus text remains inside question anatomy, or an import adapter sees embedded/dependent source assets.

  • Write one alpha.content_reference row with real parent/referenced content FKs and the governed relationship_kind.
  • Keep the referenced Content row separate; do not nest its body, file bytes, title, answer slots, or version payload inside the parent.
  • Use display_order only inside the parent relationship set. Curriculum owns instructional sequence, playlists, question banks, and course collections.

Example

{
  "content_reference_id": "7bcb0edb-7df1-4f1c-89b8-b7f5f0ca2451",
  "parent_content_id": "2f4b4c12-7c41-4b40-a33a-9637581d0e51",
  "parent_content_kind": "video",
  "referenced_content_id": "91fa40b1-f8a1-4f4a-8a60-c19a93dce4f1",
  "referenced_content_kind": "media_asset",
  "relationship_kind": "transcript_for"
}

Project governed KC and standard identities for immutable QTI package members

Use this when an adaptive selector needs each ordered qti-assessment-item-ref resolved without creating an app-local Q-matrix.

  • Resolve the ref inside its owning QTI package to qti.artifact.imported_version_id. Never use mutable latest_version_id, title search, identifier search across packages, or caller-supplied membership.
  • Join the resolved same-tenant artifact_id to active alpha.content_kc_tag. Content owns this item-to-KC fact; QTI only projects it.
  • Resolve CASE standard GUIDs from Curriculum-owned active alpha.standard_kc_map rows for each governed kc_id. Never treat a CASE standard as a KC or derive either identity from XML text.
  • An untagged member projects empty KC/standard arrays and adaptive consumers fail closed. Only an authorized POST /kc-tags workflow with explicit provenance and confidence can supply the missing fact.
  • The reviewed AcmeTest Grade 3 NBT mapping input is implementation/impl/src/data/acmetest-m3-nbt-kc-tags.json; its publisher defaults to dry-run, rejects conflicting active tags, writes through Content POST /kc-tags, and verifies every read-back.

Example

SELECT a.artifact_id, a.imported_version_id AS artifact_version_id, tag.kc_id, map.standard_id
FROM qti.artifact a
JOIN alpha.content_kc_tag tag ON tag.tenant_id = a.tenant_id AND tag.content_id = a.artifact_id AND tag.retired_at IS NULL
JOIN alpha.knowledge_component kc ON kc.tenant_id = tag.tenant_id AND kc.kc_id = tag.kc_id AND kc.retired_at IS NULL
LEFT JOIN alpha.standard_kc_map map ON map.tenant_id = tag.tenant_id AND map.kc_id = tag.kc_id AND map.retired_at IS NULL
WHERE a.tenant_id = $1 AND a.package_id = $2 AND a.imported_version_id IS NOT NULL;

List forms in a test bank in form_index order

Use this when implementing GET /items/{contentId}/bank-members or validating a Curriculum mastery_gate target_ref.

  • A bank is a first-class content row with content_kind='test_bank' and assessment_role='bank' retained for QTI compatibility.
  • Fixed-form members are ordinary test form rows referenced through content_reference.relationship_kind='bank_member'.
  • For references_linkage and every other new-course path, obtain an active governed KC from Curriculum POST /alpha/curriculum/v1/kcs with stored_as=alpha.knowledge_component, definition, and no document_id; require the response to repeat stored_as=alpha.knowledge_component before sending its kc_id to Content /kc-tags. A CASE cf_item KC id, Curriculum component id, standard id, title-derived tag, or whole-gate scope is not canonical Content attribution.
  • The write boundary permits bank_member creation or retirement only while the parent test_bank is an unretired draft (owner ruling #2534: a trust verdict never locks the draft lane). Every other current lifecycle state returns 409 content.bank_membership_frozen. A visible completed same-key request replays immediately. A fresh create acquires the exclusive tenant graph fence, repeats replay arbitration while fenced, then validates before claiming; the authoritative state locks, relationship mutation, item touch, idempotency claim/finalization, and fence share one transaction. A rejected fresh request leaves no graph or ledger row, while a request that completed during the fence wait still replays even after the bank freezes.
  • PATCH /items/{bankId} may sparsely change spec_id or membership_rule under If-Match. Explicit null for either required field returns 400 content.validation_failed. The spec_id must resolve in the routed tenant to an unretired, non-archived, non-status-retired content_kind='test_spec', assessment_role='spec' item with a readable blueprint sidecar. An actual value change requires status='draft', retired_at IS NULL, and trust_status='unknown' (including a missing trust row). Otherwise it returns 409 content.bank_membership_frozen. If active bank_member rows exist—fixed forms or PP100 adaptive shards—changing spec_id or choosing membership_rule='qti_adaptive_selection' returns 409 content.invalid_test_bank_member_contract. Each rejection leaves the item, bank sidecar, timestamp/ETag, and member graph unchanged. Full member-form blueprint comparability and active-KC coverage validation remain pending.
  • For content_kind='test_bank' item creation, completed/in-progress/conflicting same-key ledger state is arbitrated before current target validation. A fresh request acquires the tenant graph fence and resolves the spec_id target before creating an idempotency claim or item row. Invalid targets return 400 content.validation_failed with no item or ledger row; a corrected body may reuse that same previously unclaimed Idempotency-Key.
  • For an otherwise-mutable bank, the write boundary requires the parent to be content_kind='test_bank' plus assessment_role='bank' with membership_rule='same_blueprint_fixed_forms' or 'pp100_adaptive_shards', and requires the referenced item to be content_kind='test' plus assessment_role='form'. qti_adaptive_selection rejects parallel bank_member rows. parent_version_id and referenced_version_id must be supplied exact UUIDs owned by their corresponding artifacts; omitted or explicit-null values fail closed and never resolve mutable latest_version_id pointers. Wrong kind, role, rule, missing or wrong-owner version, active-row semantics, or admission of a 1,025th active member returns 409 content.invalid_test_bank_member_contract before a fresh idempotency claim or graph/timestamp mutation. Retiring a member restores capacity; a completed same-key replay remains valid at the ceiling and does not consume capacity again.
  • The exact referenced form version must have at least one unambiguous ordered embedded-question graph and every question occurrence in that graph must carry an active canonical content_kc_tag. A missing, empty, or ambiguous exact graph or missing KC attribution returns 409 content.bank_kc_attribution_incomplete.
  • GET /items/{contentId}/bank-members resolves each member by referenced_content_id plus referenced_version_id and returns that exact immutable graph's ordered question_id occurrences, kc_refs, canonical kc_tags, attribution status, and aggregate attributed/unattributed counts. Before projection it validates every active bank_member row, including historical bank-version rows, and returns 409 content.invalid_test_bank_member_contract for any malformed row instead of hiding it. The supported inclusive ceilings are 1,024 active bank-member facts for one bank and 4,096 joined question/KC facts for one integrity read; the cap-plus-one sentinel is rejected before row mapping with fieldErrors.name=bank_members or form_graph, respectively, and the graph must be split before retry. A fixed-form exact version with no valid active member also fails closed; an empty native-QTI bank remains valid. It preserves multiplicity, never substitutes latest, unions another version, or coerces form_index, and callers never infer tags from titles, order, QTI XML, facets, or the whole gate scope.
  • Accepted target: validate member forms against the bank's same-tenant test_spec and the LS comparable-forms rule. Current runtime does not perform that full comparability validation; the string bank_member alone is not equivalence evidence.

Example

SELECT
  cr.parent_content_id AS bank_id,
  cr.referenced_content_id AS form_id,
  cr.form_index,
  ci.title,
  tb.spec_id
FROM alpha.content_reference_view cr
JOIN alpha.test_bank_view tb
  ON tb.tenant_id = cr.tenant_id
 AND tb.bank_id = cr.parent_content_id
JOIN alpha.test_spec_view ts
  ON ts.tenant_id = tb.tenant_id
 AND ts.spec_id = tb.spec_id
JOIN alpha.content_item_view ci
  ON ci.tenant_id = cr.tenant_id
 AND ci.content_id = cr.referenced_content_id
JOIN alpha.assessment_test_view ate
  ON ate.tenant_id = cr.tenant_id
 AND ate.content_id = cr.referenced_content_id
WHERE cr.tenant_id = $1
  AND cr.parent_content_id = $2
  AND cr.relationship_kind = 'bank_member'
  AND cr.retired_at IS NULL
  AND ate.assessment_role = 'form'
ORDER BY cr.form_index ASC;

Read a test spec blueprint

Use this when implementing GET /items/{contentId}/blueprint or validating generated forms before they join a bank.

  • Read alpha.test_spec_view by tenant_id and spec_id. Treat active-Curriculum-KC resolution and full blueprint validation as an accepted pending target; current runtime enforces JSON/type/enum shape only.
  • Use passing_rule as a rule reference and loss model; do not restate cutoff numbers in Content.
  • Apply the LS pins as validation semantics: one primary KC per counted item, binary same-blueprint comparable-forms check, and policy-owned loss/cutoff numbers.

Example

SELECT
  spec_id,
  kc_coverage,
  item_type_mix,
  difficulty_constraints,
  passing_rule,
  min_forms,
  max_item_overlap,
  enemy_item_rule
FROM alpha.test_spec_view
WHERE tenant_id = $1
  AND spec_id = $2;

Dictionary objects

public read view · Content. Belongs here because this is the blank question, test, test spec, test bank, article, video, audio, image, interactive, external link, media asset, or script a student interacts with.

content_item — Content Item

The catalog row for one student-touchable thing, across versions.

Primary keycontent_id
Backing storealpha.content_item_view over qti.artifact plus alpha.content_item_extension sidecar.
Storage gateThe view may expose qti.artifact fields and Alpha extension fields together. The extension table stores only the content_id FK, content_kind_override when needed, subtype, dok, subject_id, target_grade_id, expected_xp, usage_scope, source_system, source_table, source_record_id, source_activity_ref, status, retired_at, updated_at, and audit columns; it must not store qti.artifact.tenant_id/workspace_id, title, language, qti_identifier, latest_version_id, package_id, resource_id, or created_at.
Source classAlpha public read view over QTI base plus extend-only sidecar
LifecycleCreated by QTI package import, QTI write-through Content authoring, or a named content adapter that first creates the base qti.artifact/qti.package_resource row. Alpha writes then add only sidecar fields. Storage supports retention and the API exposes no DELETE route, but coherent public retirement write/readback is pending: callers must not rely on PATCH status/retired_at combinations as a retirement workflow. A form item whose exact versions are pinned by an approved bank's active bank_member edge is chain-frozen: every PATCH returns 409 content.published_assessment_immutable (#1201 owner FREEZE ruling, 2026-08-05), and only the governed publication transition may advance its own artifact's draft status to published.

Purpose

Use content_item to find and classify things students can open, read, watch, answer, take, launch, or follow. The public object is a read view: QTI-backed identity and descriptive fields come from qti.artifact, while Alpha-only facts come from extension sidecars. GET /items and item detail flatten the assessment_test fields onto test/test_spec/test_bank rows and decodable fields onto subtype=decodable article rows; the fields array below documents the base slice, while publicApiProjection is the exact union returned by publicItem.

Relationships

  • Belongs to exactly one platform workspace/tenant.
  • Has zero or more immutable content_version view rows over qti.artifact_version; TimeBack adopts a deployed legacy :v1 identity only when its complete immutable projection matches, while every new exact version UUIDv5 is bound to canonical source bytes and receives the next version_number.
  • May join to media_asset views and extension tables: canonical content_kc_tag, frozen content_curriculum_link archive, content_effectiveness, and content_trust_evidence.
  • Does not contain student answers, attempts, events, mastery, or gradebook results.

Constraints

  • content_item is not a physical copied table. Downstream migrations create alpha.content_item_view and alpha.content_item_extension, not alpha.content_item with sourced QTI columns.
  • The public item response conditionally flattens assessment_role, test_type, is_mastery_gate, test_family_id, phonics_constraint, constraint_set_id, and policy_version. The assessment_test and decodable dictionary objects document those conditional slices; they are not separate decodable or assessment-test endpoints.
  • content_kind is exactly one of question, test, test_spec, test_bank, article, video, audio, image, interactive, media_asset, external_link, or script and must not be inferred from title, URL, package path, MIME type, or XML text at read time.
  • subtype is nullable and governed: diagram only when content_kind='image'; decodable only when content_kind='article'; no subtype value can create a new content_kind.
  • dok is nullable and governed by Webb DOK. It is required for question items that count toward a test_spec's kc_coverage and for each kc_coverage cell; it is never used as difficulty.
  • expected_xp is required for every Content row and is student-independent. The accepted authoring policy uses speed-running or an approved calibration process, but current runtime enforces only a finite nonnegative number and import/seed paths may publish policy-derived or default values without calibration evidence. Awarded XP lives only in the Results XP ledger.
  • usage_scope storage is non-null and defaults to practice_eligible. Public reads from deployments before this field existed may omit it; clients and routers must interpret omission as practice_eligible. Routine instruction, practice, next-task, and next-form routing may select only practice_eligible items; held_out_canary and secure_form remain explicitly readable but are not routine-routing candidates.
  • subject_id is exactly one of math, reading, language, science, computer_science, vocabulary, writing, social_studies after write-time alias folding; target_grade_id is a canonical id. Economics, history, geography, and civics remain course-grain disciplines rather than subject ids. Neither field is a free-form display label.
  • latest_version_id is advance-only and resolves default student-view reads to the highest content_version.version_number for the item. GET student-view with an exact version_id instead projects that immutable version and its matching answer-slot/component rows; test/form renderers use this exact read so a later successor cannot change a pinned launch. An already-stored historical source hash is a no-op and must not move latest_version_id backward.
  • status='retired' or archived rows remain retained in storage when Events or Results still reference their versions. Current public Content item/version reads return not-found for retired items; a historical-read surface is pending rather than implied here.
  • updated_at is the item-row change-polling input for modifiedSince; consumers must not use created_at as an activity feed or assume that independent facet, link, reference, trust, or effectiveness changes advance this timestamp.
  • Common Cartridge bundles and imscp_v1p1 packages are generated transport output from Curriculum collections plus Content references; they are never content_kind values or stored Content rows.

Invalid examples

  • A mastery value stored on content_item instead of Results.
  • A student response JSON blob stored on content_item metadata.
  • A KC stored as the tag 'fractions', a kc_refs facet, a CASE CFItem, or a Curriculum component instead of a weighted content_kc_tag registry relationship.
  • content_kind parsed from a filename such as spring-placement-test.xml.
  • A lesson, unit, chapter, playlist, question bank, library, Common Cartridge bundle, or imscp_v1p1 package stored as a Content item.

Example

{
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "workspace_id": "0d4ce2f4-1c42-4f3c-9f0d-03fb7f5271d3",
  "content_kind": "question",
  "subtype": null,
  "dok": "dok2",
  "title": "Linear equations checkpoint",
  "subject_id": "math",
  "target_grade_id": "7",
  "expected_xp": 12,
  "source_system": "qti",
  "source_identifier": "RESPONSE-001",
  "latest_version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "status": "published",
  "usage_scope": "practice_eligible"
}

Queries

GET /tenants/{tenantId}/alpha/content/items?content_kind=question&subject_id=math&target_grade_id=7&limit=50
GET /tenants/{tenantId}/alpha/content/items?usage_scope=held_out_canary&content_kind=test&limit=50
GET /tenants/{tenantId}/alpha/content/items?curriculum_node_id=case:math:7.ee.b.4&modifiedSince=2026-06-01T00:00:00Z
GET /tenants/{tenantId}/alpha/content/items/{contentId}

Fields (21)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.artifact_id Stable Alpha identity for one content item across all versions. Valid UUID and unique in the workspace. For QTI-backed content, this is the same value as qti.artifact.artifact_id. · Not a UUID, reused for two student-touchable things, or derived from mutable source_identifier. content-itd-001-module-boundary-and-alias-map, itd-011-artifact-versioning
workspace_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.tenant_id Workspace/tenant that owns this content. Must reference platform.tenant(tenant_id). It must match the owning package tenant when package_id is present. · Missing tenant or different from the owning package tenant. content-axis-009-tenant-routing, itd-008-tenant-boundary, itd-011-artifact-versioning, itd-025-platform-substrate-inheritance
content_kindTEXTyes Public alpha.content_item_view projection over qti.artifact plus alpha.content_item_extension.content_kind_override. The two QTI-native kinds use base storage; the other ten public kinds use the Alpha sidecar. · restrict + extend · Alpha view restriction over QTI artifact_kind plus Content extension override Plain Content category used for filtering and display. Required governed enum. QTI item and test values are restricted and renamed; assessmentStimulus stays inside question anatomy; test_spec and test_bank are first-class QTI-backed Alpha extensions; article, video, audio, image, interactive, media_asset, external_link, and script are explicit Alpha extensions. QTI section and curriculum-container values are routed to Curriculum. · content_kind · Outside the public enum, parsed from the title/path/MIME type, or set to a QTI internal/container kind such as section, lesson, result, response-processing, playlist, library, imscp_v1p1, or Common Cartridge bundle. content-itd-003-content-kind-taxonomy, content-itd-004-non-qti-media-extension, itd-012-artifact-kind, itd-032-results-reporting
subtypeTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Optional governed subtype used only when image/article content needs a precise school-language subtype. Nullable. Allowed values are diagram and decodable. diagram is valid only on image rows; decodable is valid only on article rows. A subtype never changes content_kind and is set at write/import time, never parsed from title, path, or MIME type. · content_subtype · Set to passage, lesson, worksheet, or any value outside the governed subtype enum; used to create a new public content_kind; inferred at read time. content-itd-019-governed-subtypes-within-ten-kinds
dokTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Webb Depth of Knowledge tag for a question item or blueprint coverage cell. Nullable for non-assessment content. Required for every item that participates in test_spec coverage counting and for every test_spec.kc_coverage cell. DOK describes cognitive process, not difficulty; difficulty lives in test_spec.difficulty_constraints. · dok · Used as a difficulty proxy, missing on a coverage-counted question, or stored as free text such as recall or hard. content-itd-020-test-spec-and-test-bank
titleTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.title Human-readable title shown in catalogs, authoring tools, and student views. Nullable text. Preserve QTI title when present; generated labels must keep provenance evidence. Must not contain direct student PII. · Used as identity, translated without retaining source XML, or contains direct learner PII. content-itd-001-module-boundary-and-alias-map, itd-004-xml-authority, itd-007-provenance-labels, itd-026-tenant-enumeration
languageTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.language BCP 47 language tag for the content when known. Nullable BCP 47 language tag when known. · Not a language tag, invented without source/default evidence, or used to filter tenant access. content-itd-001-module-boundary-and-alias-map, itd-004-xml-authority
source_identifierTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.qti_identifier Original QTI identifier or external source identifier retained for provenance and export. Nullable text. Preserve source spelling. Do not use as the database primary key or assume it is unique outside the source scope. · Invented when absent, rewritten to a UUID, or assumed unique outside artifact scope. content-itd-001-module-boundary-and-alias-map, itd-004-xml-authority, itd-007-provenance-labels, itd-026-tenant-enumeration
subject_idTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Canonical subject id assigned at write/import time. Nullable only when the content genuinely has no subject. Stored values must be exactly one of math, reading, language, science, computer_science, vocabulary, writing, social_studies. Maintained aliases for those families, including Mathematics, Math, ELA, English, Language Arts, Vocab, Reading, Science, Writing, Social Studies, Computer Science, AP Computer Science A, and AP CSA, fold before storage; FastMath is proxy-only and stores math. Economics, history, geography, and civics remain course-grain disciplines, while other unapproved subject families are rejected rather than stored. Other, Unknown, General, and source junk are rejected or reconciled, not stored. · alpha_subject_id · Parsed from title or URL at read time, mixed with display labels, or stored as an unconstrained tag. content-itd-006-typed-content-and-test-fields, content-axis-003-query-model, CURR-ITD-004, CURR-ITD-008
target_grade_idTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Canonical grade or level the content is meant for. Nullable only for content without a grade target. Values must come from alpha_grade_id; Content stores one canonical grade id such as 7, not local display labels such as Grade 07. · alpha_grade_id · Parsed from '7th Grade Review' at read time or stored as display text only. content-itd-006-typed-content-and-test-fields, content-axis-003-query-model, CURR-ITD-004, CURR-ITD-008
expected_xpNUMERIC(10,2)yes Alpha extension/config column in alpha.content_item_extension; no 1EdTech source field is copied. · extend · Alpha Content extension Student-independent XP value the platform expects a focused student to earn from this content when speed-running it successfully. Required for every Content row and must be a finite number greater than or equal to 0. The accepted authoring policy sets it by speed-running or an approved calibration workflow, never by averaging student actuals. Current runtime does not store or require calibration proof before publication, and import/seed paths can use policy-derived or default values. This value is Content config; awarded_xp is computed per attempt and stored in the Results XP ledger. · Null, negative, computed from actual student attempts, used as an awarded XP ledger value, or changed by a mastery gate/pass event. content-itd-015-expected-xp-content-config
usage_scopeTEXTno Alpha extension/config column in alpha.content_item_extension; no 1EdTech source field is copied. · extend · Alpha Content exposure-control extension Content-owned routing exposure scope for the blank item. Stored as a governed enum with default practice_eligible. Current implementations emit the field on reads; older deployed reads may omit it, and callers must interpret omission as practice_eligible. Routine instruction, practice, next-task, and next-form selection must exclude held_out_canary and secure_form items unless a route explicitly asks for that protected scope. · usage_scope · Free-form text, inferred from a title/test_type/is_mastery_gate flag, treated as only a catalog facet instead of a routing constraint, or interpreted as held_out_canary/secure_form when omitted from a legacy read. content-itd-020-test-spec-and-test-bank
latest_version_idUUIDno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.latest_version_id Highest-version-number row to use for default reads and launches. TimeBack changed-byte imports append the next immutable version_number, while an identical or historical source-hash replay leaves this pointer unchanged. Nullable until first save. Must point to a version for this same content item and match the highest version_number before an editable read returns an ETag. Source re-imports must never regress this pointer from a newer authoring version back to the import adapter's deterministic version. · Points to another artifact's version, lags the highest version_number without repair evidence, listArtifacts surfaces a stale latestArtifactVersionId, or is treated as authoritative history instead of the artifact_version table. content-itd-007-versioned-authoring-and-student-view, itd-011-artifact-versioning, itd-018-api-boundary, itd-020-validation-policy, itd-026-tenant-enumeration
source_systemTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Public provenance category for the content item. Required governed enum. It explains where the authoritative blank content came from without exposing raw qti.* browsing as the catalog. · source_system · Used as an authorization decision, left null, or set to a secret producer token. content-itd-001-module-boundary-and-alias-map, content-axis-010-conformance-evidence
source_tableTEXTno Nullable alpha.content_item_extension.source_table column exposed by alpha.content_item_view. Legacy imported rows are backfilled from their exact version source trace. · extend · Alpha Content source-adapter extension Canonical lower-case source table or stream name for an imported Content identity. Required and non-empty when source_system=external_content_import. The pair (source_table, source_record_id) is immutable for one deterministic Content id; a conflicting table returns content.source_identity_collision. · Changed for an existing imported Content id, treated as a payload body field instead of identity, or populated with credentials or student PII. content-itd-018-source-shaped-production-ingest
source_record_idTEXTno Nullable alpha.content_item_extension.source_record_id column exposed by alpha.content_item_view; no source payload is copied here. · extend · Alpha Content source-adapter extension Opaque originating record id; it is a complete reconciliation identity only when paired with adapter/source-table scope. Required and non-empty on each source-shaped import record; nullable on Content with no external source record. For TimeBack, source_table + source_record_id is immutable after first materialization; equal record ids from different tables return content.source_identity_collision without partial mutation. · Guessed from title, changed across retries for the same scoped source row, treated as globally unique without adapter/source-table context, or populated with credentials or student PII. content-itd-018-source-shaped-production-ingest
source_activity_refTEXTno Nullable alpha.content_item_extension.source_activity_ref column exposed by alpha.content_item_view; no source payload is copied here. · extend · Alpha Content source-adapter extension Opaque upstream activity or resource reference retained for source-to-Curriculum correlation. Nullable outside source-shaped imports. Treat as an opaque source reference; do not parse it into subject, grade, content kind, or authorization facts. · Parsed for platform-owned classifications, treated as a Curriculum node id without adapter reconciliation, or populated with credentials or student PII. content-itd-018-source-shaped-production-ingest
statusTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stored lifecycle state intended for catalog use and authoring. Required governed enum. Current runtime does not yet provide a coherent retirement contract: status='retired' alone remains readable, while a retired_at mutation causes ordinary readback to return not-found. Do not infer a working retirement workflow from this field. · content_status · Used to hide broken validation instead of trust_status, or used to hard-delete content still referenced by Results/Events. content-itd-007-versioned-authoring-and-student-view, content-axis-011-privacy-retention
created_atTIMESTAMPTZyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact.created_at Timestamp when the logical content item was created. Required timestamp with time zone. listArtifacts orders by created_at then artifact_id and returns this value as createdAt. · Null or used as version_number. content-axis-007-eventing-model, itd-022-operational-ddl, itd-026-tenant-enumeration
updated_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Timestamp of the latest content_item representation change used by modifiedSince polling. Required timestamp with time zone. Current runtime advances it for item metadata/latest-version changes; independent media, facet, curriculum-link, reference, trust, and effectiveness writes do not reliably touch the parent item and therefore require separate reads. · Null or used as learner activity time. Do not present this current field as a complete child-collection change cursor. content-axis-007-eventing-model
retired_atTIMESTAMPTZno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stored retirement timestamp intended to remove content from new launches once coherent lifecycle semantics exist. Nullable. Current PATCH can persist this value but then returns not-found through ordinary readback; deterministic success plus authorized historical exact-version reads are pending. If populated, status should be retired or archived. · Used as a hard-delete timestamp, or populated while status remains published without migration evidence. content-axis-011-privacy-retention

public API projection over the canonical Alpha weighted relationship table · Content. Belongs here because it states which governed units of learned knowledge one student-touchable Content item addresses and with what strength.

content_kc_tag — Content Knowledge Component Tag

The canonical weighted many-to-many Q-matrix row from Content to a governed registry KC.

Primary keytenant_id + content_id + kc_id
Backing storealpha.content_kc_tag with same-tenant FKs to qti.artifact Content identity and the Curriculum-owned alpha.knowledge_component registry; pending migration 020 adds an internal generated-state conditional FK for active-KC integrity.
Storage gateStores only relationship identity, independent weight, one-primary role, mapping provenance/confidence, lifecycle timestamps, and the internal generated required_kc_active_state used by native referential integrity. Accepted provenance is preserved exactly but must be well-formed Unicode without U+0000 and is bounded to 256 UTF-8 bytes so PostgreSQL representation and graph hydration remain deterministic and resource-bounded. It never copies KC definitions, Curriculum components, Content titles, learner mastery, or probability estimates. required_kc_active_state is not a public API field.
Source classAlpha Content extension relationship table
LifecyclePOST /kc-tags creates or replaces the same tenant/content/KC row after both identities resolve and the KC is active. DELETE /items/{contentId}/kc-tags/{kcId} soft-retires that exact row under the tenant graph mutation fence, hides it from active reads, touches the parent Content item's updated_at/ETag, and atomically completes the idempotency response. A completed same-key DELETE replays without another touch; DELETE of an already-retired row with a new key is a successful no-op. A later POST revives the retained row by replacing mapping facts, advancing updated_at, clearing retired_at, and touching the parent. At most one active tag per Content item is_primary=true. Once the tagged item participates in an approved test-bank chain — as an active member form or as a question embedded in a pinned active member form version of a bank that is no longer an unretired draft — upsert, revival, and retirement return 409 content.published_assessment_immutable (#1201 owner FREEZE ruling, 2026-08-05); the revision path is a new Content identity through governed publication.

Purpose

Use content_kc_tag and GET /kc-tags as the authoritative governed alignment read to select, compare, assess, teach, and analyze Content by exact registry KC identity. kc_refs is only a non-authoritative discovery hint; content_curriculum_link is only historical reconciliation evidence. Never infer alignment from Curriculum components, CASE CFItems, facet strings, or app-local Q-matrices.

Relationships

  • Belongs to exactly one Content item identity in the same tenant and survives ordinary Content version changes.
  • References exactly one active alpha.knowledge_component registry identity in the same tenant; it never references case.cf_item or alpha.curriculum_components.
  • The native content_kc_tag_active_kc_fk makes the active-tag/active-KC rule a commit-time database invariant across concurrent Content revival and Curriculum retirement; application reads and row locks are friendly prechecks, not the sole race guarantee.
  • Many Content items may reference one KC and one Content item may reference many KCs.
  • GET /kc-tags is authoritative for alignment reads. kc_refs may aid catalog discovery but cannot prove alignment; the frozen curriculum-link archive cannot be merged into current answers.

Constraints

  • weight is an independent relevance strength greater than 0 and at most 1. It is not a probability, does not represent learner mastery, and active weights are not required to sum to 1.
  • is_primary identifies the principal KC addressed by this Content item. Zero or one active row per Content item may be primary.
  • confidence is confidence in the correctness of the mapping itself from 0 through 1, not confidence that a learner has mastered the KC.
  • provenance is required non-blank, well-formed Unicode text without U+0000, names the source, approval, import, or authoring process that asserted the mapping, and is at most 256 UTF-8 bytes. It is rejected rather than truncated, trimmed, coerced, or Unicode-repaired.
  • The same tenant_id scopes Content, KC, and tag; unknown, cross-tenant, or retired KC identities are rejected.
  • Active reads require both tag.retired_at IS NULL and knowledge_component.retired_at IS NULL, even though pending migration 020 also prevents a committed active-tag/retired-KC state.
  • The relationship is item-scoped and version-invariant. It applies across ordinary Content versions; version-specific alignment requires a distinct Content identity.

Invalid examples

  • kc_id points to case.cf_item or alpha.curriculum_components instead of alpha.knowledge_component.
  • weight=70 to mean 70 percent; the stored value is 0.70.
  • Three active rows for one Content item all claim is_primary=true.
  • confidence stores a learner mastery probability rather than confidence in the tag assertion.
  • A kc_refs facet string is treated as a substitute for this governed relationship.

Example

{
  "tenant_id": "0d4ce2f4-1c42-4f3c-9f0d-03fb7f5271d3",
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "kc_id": "001c6d5d-b370-559a-93d4-3483845ad2f2",
  "weight": 0.8,
  "is_primary": true,
  "provenance": "incept:course-approval:linear-equations-v3",
  "confidence": 0.95,
  "created_at": "2026-07-16T14:00:00Z",
  "updated_at": "2026-07-16T14:00:00Z",
  "retired_at": null
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/kc-tags
POST /tenants/{tenantId}/alpha/content/items/{contentId}/kc-tags with Idempotency-Key
DELETE /tenants/{tenantId}/alpha/content/items/{contentId}/kc-tags/{kcId} with Idempotency-Key

Public API fields (10)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
tenant_idUUIDyes alpha.content_kc_tag.tenant_id · extend · Platform tenant identity Tenant that jointly owns the Content item, registry KC, and mapping. Must match both referenced identities and the authenticated route tenant. · Different from the Content or KC tenant. content-itd-005-curriculum-links-are-relationships
content_idUUIDyes alpha.content_kc_tag.content_id · extend · Alpha rename from qti.artifact.artifact_id Stable Content identity being tagged. Must resolve to qti.artifact in the same tenant; the mapping is not version-scoped. · Unknown, cross-tenant, or a Content version id. content-itd-005-curriculum-links-are-relationships
kc_idUUIDyes alpha.content_kc_tag.kc_id · extend · Curriculum-owned registry identity Governed Knowledge Component registry identity addressed by the Content item. Must reference an active alpha.knowledge_component(tenant_id, kc_id); CASE items and Curriculum components are invalid targets. · Unknown, retired, cross-tenant, a CASE CFItem, or a Curriculum component. content-itd-005-curriculum-links-are-relationships
weightNUMERIC(8,6)yes alpha.content_kc_tag.weight · extend · Alpha Content relationship fact Independent strength of this KC's relevance to the Content item. Greater than 0 and at most 1. Not a probability, mastery score, percent integer, or normalized allocation; sibling weights need not sum to 1. · Zero, negative, greater than 1, non-finite, or interpreted as learner mastery. content-itd-005-curriculum-links-are-relationships
is_primaryBOOLEANyes alpha.content_kc_tag.is_primary · extend · Alpha Content relationship fact Whether this is the single principal KC addressed by the Content item. At most one active row per tenant_id + content_id may be true; zero primary rows are allowed. · A second active row for the Content item is also primary. content-itd-005-curriculum-links-are-relationships
provenanceTEXTyes alpha.content_kc_tag.provenance · extend · Alpha Content relationship audit fact Non-empty source, approval, import, or authoring process that asserted the mapping. Required non-blank, well-formed Unicode text without U+0000 and of at most 256 UTF-8 bytes; preserved exactly and rejected rather than truncated, trimmed, coerced, or Unicode-repaired; must not contain credentials or secrets. · Blank, above 256 UTF-8 bytes, contains U+0000 or an unpaired UTF-16 surrogate, secret-bearing, or merely repeats the KC definition. content-itd-005-curriculum-links-are-relationships
confidenceNUMERIC(4,3)yes alpha.content_kc_tag.confidence · extend · Alpha Content relationship audit fact Confidence that this Content-to-KC mapping assertion is correct. From 0 through 1 inclusive. It is not learner mastery, item difficulty, or the relationship weight. · Outside 0..1 or used as learner mastery probability. content-itd-005-curriculum-links-are-relationships
created_atTIMESTAMPTZyes alpha.content_kc_tag.created_at · extend · Alpha Content lifecycle fact Time this Content-to-KC identity pair was first stored. Server-owned timestamp; an upsert does not replace it. · Client-forged or later than retired_at. content-axis-011-privacy-retention
updated_atTIMESTAMPTZyes alpha.content_kc_tag.updated_at · extend · Alpha Content lifecycle fact Time weight, primary role, provenance, confidence, or retirement state last changed. Server-owned and advanced by each successful replacement. · Older than created_at after a successful replacement. content-axis-011-privacy-retention
retired_atTIMESTAMPTZno alpha.content_kc_tag.retired_at · extend · Alpha Content lifecycle fact Time this mapping stopped being current while remaining available as historical evidence. Null for active rows; when present it is not earlier than created_at. · Hard-deleted to conceal prior tag evidence or earlier than created_at. content-axis-011-privacy-retention

public read view · Content. Belongs here because immutable authoring and TimeBack-import versions identify the exact blank version a student saw or an author edited; answers and scores still live in Results.

content_version — Content Version

One immutable exact edition of a content item.

Primary keyversion_id
Backing storealpha.content_version_view over qti.artifact_version plus extension-only version evidence where QTI lacks a media/render field.
Storage gateThe public view exposes QTI version fields without copying them. Any Content extension storage is keyed to artifact_version_id/content_id and stores only new render-policy or non-QTI evidence columns.
Source classAlpha public read view over qti.artifact_version
LifecycleQTI import, write-through save, and changed-byte TimeBack re-import append a qti.artifact_version row, then advance content_item.latest_version_id to the highest version_number. Identical canonical TimeBack source bytes reuse the already-stored exact version without mutation; historical hash replay never rolls the pointer backward. A deployed legacy TimeBack :v1 UUID is retained only when its complete source-owned immutable projection matches. Every new TimeBack exact-version UUIDv5 is bound to tenant + source_record_id + canonical content hash; changed hashes receive the next version_number and supersedes_version_id under an item lock. Import materialization and idempotency completion commit atomically.

Purpose

Use content_version when you need the exact student view, authoring draft, or QTI XML/projection that existed at a point in time. Launches, trust-based release reads, references, Events, and Results bind to exact versions rather than mutable content_item alone.

Relationships

  • Belongs to exactly one content_item.
  • Any exact version, including a TimeBack-import version, may be referenced by trust-based release reads, Content relationships, Events, and Results to identify the reviewed or served bytes.
  • Parent of answer_slot, answer_key, and scoring_plan for QTI-backed questions/tests.

Constraints

  • Unique (content_id, version_number).
  • Every stored version is immutable. A database trigger allows an identical no-op UPDATE but rejects any changed qti.artifact_version UPDATE; callers append instead.
  • student_view must not include teacher-only answer keys.
  • editing_draft requires author:content and may include source-trace needed to preserve QTI authoring fidelity. A governed PP100 QTI import writes the validated exact item_family_id and rigor_calibration under editing_draft.sourceTrace and writes its matching DOK on content_item; malformed, duplicate, DOK/tier-mismatched, or sub-standard hard authority is rejected before mutation.
  • For content_kind=question, submitted canonical_xml must be a complete QTI assessment-item document; its choices, response declarations, correct responses, mappings, and response-processing projection are regenerated under the new version identity in the same transaction.
  • A prompt-only question version that omits canonical_xml must preserve the most recent canonical grading structure while assigning the carried-forward projection to the new version identity.
  • Version ETags derive from version_number plus immutable content_hash evidence, not from a mutable timestamp.

Invalid examples

  • Updating any stored student_view, authoring body, canonical XML, hash, ordinal, or supersession link in place.
  • Building editing_draft from student_view and losing authoring fields.
  • Putting a student's submitted answers in student_view.

Example

{
  "version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "version_number": 1,
  "student_view": {
    "kind": "question",
    "identifier": "RESPONSE-001"
  },
  "etag": "W/\"content:58612cab:v1:sha256-e8a86d\"",
  "created_by": "system:package-ingest"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions
GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions/{versionId}
POST /tenants/{tenantId}/alpha/content/items/{contentId}/versions with Idempotency-Key; for a question, canonical_xml atomically regenerates version-scoped grading projections
PATCH /tenants/{tenantId}/alpha/content/items/{contentId} with If-Match: W/"content:..."

Fields (11)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
version_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.artifact_version_id Stable id for this immutable version row. TimeBack retains a deployed legacy :v1 id only after complete-projection ownership checks; every new exact-version id is deterministic UUIDv5 over tenant + source_record_id + canonical content hash, independent of its sequential version_number. Valid UUID and unique primary key. · Not a UUID or reused. content-itd-007-versioned-authoring-and-student-view, itd-011-artifact-versioning
content_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.artifact_id Content item this version belongs to. Must reference qti.artifact(artifact_id). Cascades on artifact delete. Any tenant-scoped read must join qti.artifact and filter qti.artifact.tenant_id. · Missing artifact or cross-tenant mismatch through artifact. content-itd-007-versioned-authoring-and-student-view, itd-011-artifact-versioning, itd-026-tenant-enumeration, itd-008-tenant-boundary
version_numberINTEGERyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.version_number Forward-only version number within a content item. Required integer and unique with artifact_id. Should increase by one for each saved edition. · Zero or negative by convention, duplicated for an artifact, skipped without migration evidence, or reused after rollback. content-itd-007-versioned-authoring-and-student-view, itd-011-artifact-versioning, itd-026-tenant-enumeration
student_viewJSONBno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.delivery_json Generated student-safe projection for launch, reading, or viewing. Nullable before projection. Must preserve identifiers needed for responses, feedback, scoring, accessibility, and replay. QTI-backed question interactions must expose a stable nonempty answer-slot identifier, answer-slot cardinality/base type, and for choice interactions stable distinct nonempty QTI choice identifiers with labels sourced from component metadata or canonical QTI text/image metadata; source-empty or duplicate labels are disambiguated with the stable QTI choice identifier as the student-safe fallback label. Must not include answer keys or teacher-only source trace. When student_view contains HTML, governed tb-* tokens are defined by content_html_body_contract; QTI XML/scoring remains QTI-owned, and durable progress flows through Caliper Events/Results. · Contains correct_response, raw learner data, or drops response identifiers needed by Results. content-itd-007-versioned-authoring-and-student-view, itd-006-json-projections, itd-015-delivery-session, itd-027-timed-delivery, itd-028-test-navigation, itd-029-catalog-pnp, itd-030-portable-custom-interaction, itd-031-item-templates, itd-032-results-reporting, content-itd-021-tb-markup-body-contract
editing_draftJSONBno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.authoring_json Teacher/authoring projection that preserves all fields needed for another edit. Nullable. Requires author:content. Must round-trip to QTI or non-QTI source without declared field loss. · Built from a lossy student_view, contains raw tokens, or loses source trace needed for export. content-itd-007-versioned-authoring-and-student-view, itd-006-json-projections, itd-011-artifact-versioning, itd-018-api-boundary, itd-020-validation-policy, itd-030-portable-custom-interaction, itd-031-item-templates
canonical_xmlTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.canonical_xml Canonical QTI XML for QTI-backed versions. Required for QTI-backed versions; null for non-QTI media unless an adapter explicitly produced QTI XML. · Not reproducible from object_graph, hash mismatch, or changed after delivery sessions point to this version. content-itd-007-versioned-authoring-and-student-view, itd-004-xml-authority
content_hashTEXTno Public view column over QTI base storage; no Alpha storage. · rename + extend · Alpha rename + extend from qti.artifact_version.xml_hash Stable hash of canonical source used for idempotency, ETags, and trust evidence. Required for QTI-backed versions. Store algorithm prefix. For non-QTI versions, may point to render/source hash evidence. · Does not match canonical_xml, algorithm omitted, or duplicates a prior version for the same artifact. content-axis-004-concurrency-model, itd-004-xml-authority, itd-010-idempotency, itd-026-tenant-enumeration
supersedes_version_idUUIDno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.supersedes_version_id Previous version replaced by this version, when the save was an edit or replacement. Nullable. If present, must reference qti.artifact_version(artifact_version_id), normally for the same artifact. · Points forward in time, points to another artifact without explicit migration evidence, or creates a cycle. content-itd-007-versioned-authoring-and-student-view, itd-011-artifact-versioning
etagTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Read-only validator returned on editable representations and required by If-Match writes. Derived from content_id, version_number, and immutable content_hash evidence. Clients send it unchanged in If-Match. · Derived only from updated_at, accepted after a newer version exists, or omitted from a preconditioned write. content-axis-004-concurrency-model, content-itd-007-versioned-authoring-and-student-view
created_atTIMESTAMPTZyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.created_at Timestamp recorded once for this immutable version row and used after version_number as a stable ordering tie-breaker. Required timestamp with time zone. listArtifactVersions orders by created_at then artifact_version_id and returns this value as createdAt. · Null or mutated to reorder version history. content-itd-007-versioned-authoring-and-student-view, itd-022-operational-ddl, itd-026-tenant-enumeration
created_byTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.artifact_version.created_by Principal or system actor that created the version. Nullable safe principal label. Never store raw JWTs, tokens, or direct learner PII. · Raw access token, raw JWT subject that identifies a learner, email address, or other direct learner PII. content-axis-011-privacy-retention, itd-019-security-boundary, itd-024-candidate-learner-data-privacy

virtual value-space dictionary · Content. Belongs here because the tokens define what stored Content HTML bodies mean before any Curriculum member selects a renderer.

content_html_body_contract — Content HTML Body Markup Contract

Governed tb-* HTML vocabulary for student-safe Content bodies.

Primary keytoken
Backing storecontent_version.student_view.html and editing_draft HTML payloads over qti.artifact_version delivery/authoring JSON
Storage gateNo alpha.content_html_body_contract table is created. This dictionary owns the value-space of stored Content HTML bodies; renderer implementations consume it outside platform3.
Source classContent HTML body value-space, consumed by the registered Applications renderer capability
LifecycleVersioned with the immutable Content version. TimeBack changed-source re-import appends a new exact version, so earlier markup-token bodies remain replay-safe history. Add tokens by extending this value-space; do not infer semantics from arbitrary CSS class names.

Purpose

Use this contract when a Content version stores instructional HTML that the registered instructional renderer will display. The contract mirrors the owner-provided Instructional content renderer vocabulary into the Content dictionary so renderer docs are consumer guides, not a competing source of truth.

Relationships

  • content_version.student_view may carry HTML using these classes/attributes.
  • Curriculum course_component_member.target_ref selects the Content row; Curriculum course_component_member.renderer_ref selects the registered renderer.
  • tb-qti-assessment-item points to tb-qti-config entries, but QTI XML and scoring semantics remain in QTI-owned objects.
  • Durable learner progress is reported as Caliper events through Events/Results, not stored in Content, host app local state, or renderer private state.

Constraints

  • Only the listed tb-* classes and data-catalog-idref attribute are governed by this contract; ordinary presentational classes carry no Platform3 business semantics.
  • Article blocks are renderable only when they carry nonempty text or exact type=html with nonempty HTML; HTML blocks use the same centralized first-party player sanitizer as top-level student_view.html.
  • data-catalog-idref must resolve to an id in the same hidden tb-catalog body.
  • tb-qti-config entries may link to QTI XML, but response processing, scoring, outcomes, and answer semantics are QTI-owned.
  • tb-applet-config entries may link to an application manifest; application code is outside platform3.
  • The renderer/host may exchange CONTENT_READY, CONTENT_LOAD, CONTENT_STATE_CHANGE, CONTENT_RESIZE, and TTS messages, but must not become the durable progress store.

Invalid examples

  • Treating a renderer README as the only definition of stored Content HTML semantics.
  • Putting gate thresholds, attempts, scores, or mastery state into tb-catalog or renderer contentState.
  • Using data-catalog-idref to reference a global/private catalog outside the Content body.
  • Copying QTI outcome processing into Content HTML instead of referencing QTI-owned XML.

Example

{
  "html": "<div class=\"tb-article-container\"><section class=\"tb-segment\"><div class=\"tb-interaction tb-qti-assessment-item\" data-catalog-idref=\"qti-1\"></div></section><div class=\"tb-catalog\" hidden><div id=\"qti-1\" class=\"tb-qti-config\"><a href=\"/qti/items/qti-1.xml\" type=\"application/xml\">QTI item</a></div></div></div>",
  "renderer_ref": "renderer:interactive-lesson",
  "iframe_url": "https://platform3-andymontgomery-9773s-projects.vercel.app/player",
  "versioned_iframe_url": "https://platform3-andymontgomery-9773s-projects.vercel.app/player/versions/2026-08-05.issue-2501-article-html/",
  "player_version": "2026-08-05.issue-2501-article-html",
  "capability_matrix_url": "https://platform3-andymontgomery-9773s-projects.vercel.app/player/renderer-capabilities.json",
  "registered_for_routing": true,
  "verified_rendering": true,
  "rendering_state": "verified_partial",
  "content_load_fields": [
    "html",
    "qtiXml",
    "testForm",
    "title",
    "contentId",
    "contentRef",
    "gateComponentId",
    "studentId",
    "interactiveComposition",
    "contentState",
    "config"
  ],
  "host_messages": [
    "CONTENT_LOAD",
    "TTS_GENERATE_RESPONSE"
  ],
  "renderer_messages": [
    "CONTENT_READY",
    "CONTENT_STATE_CHANGE",
    "CONTENT_RESIZE",
    "CONTENT_ERROR",
    "TTS_GENERATE_REQUEST"
  ],
  "preview_affordances": [
    "ad_hoc_html",
    "ad_hoc_qti_xml_a1_text_structural",
    "exact_test_form_fixture"
  ]
}

Queries

{"name":"renderer_launch_contract","sql":"Host selects Curriculum renderer_ref, separately checks verified_rendering and rendering_state against https://platform3-andymontgomery-9773s-projects.vercel.app/player/renderer-capabilities.json, and loads https://platform3-andymontgomery-9773s-projects.vercel.app/player (or pins https://platform3-andymontgomery-9773s-projects.vercel.app/player/versions/2026-08-05.issue-2501-article-html/ for automated QC). Article/interactive hosts post CONTENT_LOAD { html, contentId, contentState?, config? } or ad hoc preview { qtiXml, title?, contentId?, config? }. Exact governed articles may also carry type=html blocks; the player joins those blocks into the same centralized sanitized lesson corridor. Exact tests post one exact Content test contentRef. Exact test_bank launches also post gateComponentId and studentId; the player delegates deterministic selection to Curriculum next-form, verifies the returned bank identity, reads the selected exact Content form's ordered embeds and exact-version student views, and renders only selected_form_ref. Durable progress flows through Caliper Events/Results. Registry acceptance alone is not rendering proof, and unsupported form-member interactions fail visibly."}

Fields (8)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
htmlHTML stringyes QTI delivery/authoring JSON projection; no new Content storage table. · extend · Content version projection Student-safe Content body HTML that may contain governed tb-* tokens. Must not contain answer keys, scores, attempts, gate thresholds, credentials, or durable learner progress. If QTI is embedded, reference QTI XML through tb-qti-config rather than copying scoring semantics. content-itd-021-tb-markup-body-contract
tb_markup_tokenENUMyes Dictionary contract only. · extend · Content HTML body value-space Governed token used as a class name or attribute in Content HTML bodies. Must be one of enumSets.tb_markup_token.values. · tb-instructional-content, tb-article-container, tb-segment, tb-interaction, tb-qti-assessment-item, tb-applet, tb-catalog, tb-qti-config, tb-applet-config, data-catalog-idref, practice-step, example-practice-container, headers-row, header, step-row, step, example-step, answer-box, tb-glossary-term, tb-glossary-definition, tb-narration, tb-narration-audio content-itd-021-tb-markup-body-contract
catalog_idrefTEXTno Inside Content HTML body only. · extend · Content HTML body attribute data-catalog-idref value on an interaction, applet, term, or narration marker. Must resolve to an id in the same tb-catalog; must not point at a global/private renderer catalog. content-itd-021-tb-markup-body-contract
catalog_entry_idTEXTno Inside Content HTML body only. · extend · Content HTML body local catalog id attribute for a hidden tb-catalog entry. Unique within the Content body and resolved only inside that body. content-itd-021-tb-markup-body-contract
qti_xml_refURIno Reference only; QTI stores XML/scoring. · reference · QTI reference from Content HTML catalog Link from tb-qti-config to QTI XML for an assessment item/test body. QTI response processing, scoring, outcomes, and answer semantics remain QTI-owned. content-itd-021-tb-markup-body-contract
renderer_refTEXTno Stored on Curriculum member, not Content. · reference · Cross-module renderer capability reference Registered renderer selected by the Curriculum member for this Content row. Renderer selection is not stored as Content ownership; Curriculum course_component_member.renderer_ref points at the Applications registry. · renderer:interactive-lesson, renderer:qti-item, renderer:qti-test content-itd-021-tb-markup-body-contract
renderer_messageENUMno Runtime protocol only; not Content storage. · extend · Renderer integration protocol iframe/postMessage verbs used by the sanctioned renderer integration. CONTENT_STATE_CHANGE may update host UI state, but durable learner progress must be emitted through Caliper Events/Results. · CONTENT_READY, CONTENT_LOAD, CONTENT_STATE_CHANGE, CONTENT_RESIZE, TTS_GENERATE_REQUEST, TTS_GENERATE_RESPONSE content-itd-021-tb-markup-body-contract
progress_event_contractTEXTyes Outside Content; no renderer private store. · clarify · Cross-module learner-progress seam Durable progress and outcome seam for rendered Content. Renderer contentState is opaque UI state and must not replace Events/Results progress, attempts, scores, mastery, or gradebook rows. · Caliper Events/Results content-itd-021-tb-markup-body-contract

public read view · Content. Belongs here because it is a file, video, audio, image, caption, transcript, or source asset a content item needs to render.

media_asset — Media Asset

Renderable or support media attached to Content.

Primary keymedia_id
Backing storealpha.media_asset_view over qti.package_file/qti.package_resource plus alpha.media_asset_extension.
Storage gateThe extension table stores only tenant/package/content/version foreign keys, media_kind, and delivery_url/reference facts. It must not store qti.package_file.media_type, byte_length, content_hash, package_path, content_bytes, or package metadata copies.
Source classAlpha public read view over qti.package_file plus media sidecar
LifecycleCreated by QTI package ingest, governed media attach, or content adapter. Primary Incept video uses one fetch of the closed immutable source_asset reference; Content verifies and stores the bytes in the existing qti.package_file row under a unique content/{contentId}/media/{serverMediaId} package path before writing only Alpha media-kind and delivery-reference sidecar fields. Retained while any content version or export path needs it.

Purpose

Use media_asset to serve and audit files behind media_asset content items and supporting files used by questions, tests, articles, interactives, and external-link previews. Stimulus text remains question anatomy rather than a public media or Content row.

Relationships

  • Belongs to one content_item and optionally one content_version.
  • May map to qti.package_file when the asset came from an IMS/QTI package.

Constraints

  • media_type is a MIME type. media_kind is the governed public API classification.
  • byte_length and content_hash must match stored bytes or external object evidence.
  • Primary video/mp4 on a freshly authored Incept video must use top-level source_asset with the exact allowlisted HTTPS origin, loop-artifacts bucket, canonical incept-skill-pack/video/{run}/media/{job}.mp4 path, bare lowercase SHA-256, positive byte length at most 128 MiB, and video/mp4 media type.
  • Content disables redirects and encoded responses, rejects private/local DNS answers, timeout, overflow, non-MP4 bytes, and type/length/hash mismatch, then owns and serves the verified bytes.
  • Governed source_asset attach rejects caller-supplied media_id/mediaId and mints the media UUID only after byte verification, so a request cannot alias an existing qti.package_file row.
  • The original Incept bucket/path remains sanitized provenance metadata; qti.package_file.package_path is the unique Content-owned content/{contentId}/media/{serverMediaId} path, so successor versions may reuse one immutable source object without colliding.
  • Caller metadata.inline_base64, metadata.inline_text, metadata.inlineText, and metadata.source_asset cannot create governed primary video. The signed source URL/query token is neither persisted nor returned.
  • delivery_url must not contain secret tokens. Signed delivery is handled by authenticated endpoints or short-lived platform URLs.

Invalid examples

  • A permanent signed URL with embedded secret stored in delivery_url.
  • A governed source_asset request that selects an existing media_id/package_file UUID.
  • A transcript stored as a free-form tag instead of a media_asset row.
  • byte_length not matching the stored asset.

Example

{
  "media_id": "30225f0a-949d-49d5-a7fc-e2ea43863e96",
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "media_kind": "supporting",
  "media_type": "image/png",
  "byte_length": 18422,
  "delivery_url": "/tenants/demo/alpha/content/items/58612cab/media/30225f0a"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/media
POST /tenants/{tenantId}/alpha/content/items/{contentId}/media with Idempotency-Key

Public API fields (11)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
media_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.package_file_id Stable id for one media asset row. Valid UUID and unique primary key. · Not a UUID or reused. content-itd-004-non-qti-media-extension, itd-009-package-ingest
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Content item this media supports or renders. Must reference content_item(content_id) in the same workspace. · References a missing content item or a content item in another workspace. content-itd-004-non-qti-media-extension
version_idUUIDno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Specific version this media belongs to when the asset is version-scoped. Nullable for content-wide assets. Current storage enforces only an independent content_version UUID foreign key; same-content ownership validation is pending and callers must not treat the FK alone as proof that the version belongs to content_id. · Points to a version for another content item or is used to mutate an old version in place. content-itd-007-versioned-authoring-and-student-view
media_kindTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Governed public API classification for the role this media asset plays for students or authors. Required governed enum. Do not infer from file extension at read time. · media_kind · Parsed from .vtt at read time or stored as a free-form tag. content-itd-004-non-qti-media-extension, content-itd-006-typed-content-and-test-fields
media_typeTEXTyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.media_type MIME media type used for serving, export, and validation. Required valid media type string. Defaults to application/octet-stream only when unknown and still validated. · Null, unparseable as a media type, or trusted more than validation of the actual content. content-itd-004-non-qti-media-extension, itd-009-package-ingest
byte_lengthINTEGERyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.byte_length Original or stored byte length of the media bytes. Required integer. Must be zero or positive and equal to the stored bytea length. · Negative, null, or mismatched with content_bytes. content-itd-004-non-qti-media-extension, itd-009-package-ingest
content_hashTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.content_hash Cryptographic hash of the media bytes or external object. Nullable only when the asset has not finished ingestion. Store algorithm prefix with digest. · Missing, digest does not match content_bytes, or algorithm is not recorded. content-itd-004-non-qti-media-extension, itd-010-idempotency
storage_pathTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.package_path Public storage locator for the media object; for packaged files this is the normalized package-relative path. Nullable when no package-relative path exists. When present, normalized and must not escape the package root. · Contains ../ escape, backslash ambiguity, an absolute scheme, duplicate normalized path, or a path not present in the uploaded package. content-itd-004-non-qti-media-extension, itd-009-package-ingest, itd-020-validation-policy
delivery_urlTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Authenticated or public URL path a student client uses to fetch the asset. Nullable until media is ready. Must not embed raw secrets, permanent signed tokens, or student credentials. · Contains a vault secret, raw token, student credential, or URL that bypasses tenant authorization. content-itd-004-non-qti-media-extension, content-axis-011-privacy-retention
metadataJSONByes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.metadata Generated non-secret evidence about this media asset, such as manifest listing, validation role, dimensions, or duration. Required JSON object. Must not contain raw bytes, auth tokens, student app credentials, or direct student PII. For governed primary video, Content derives only safe source bucket/path/hash/type/length, duration, and accessibility evidence after the verified fetch; callers cannot submit inline bytes or forge metadata.source_asset. · Null, non-object JSON, auth tokens, direct learner PII, or raw file bytes duplicated as JSON. content-axis-011-privacy-retention, itd-009-package-ingest, itd-020-validation-policy
created_atTIMESTAMPTZyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.package_file.created_at Timestamp when the file row was inserted. Required timestamp with time zone. · Null or used as a proxy for QTI content versioning. content-itd-004-non-qti-media-extension, itd-022-operational-ddl

Alpha extension sidecar for an article subtype · Content. Belongs here because a decodable is a student-readable article with a phonics constraint set; it is not a new content_kind and not Curriculum sequence.

decodable — Decodable Article

Phonics-constraint sidecar for content_item rows where content_kind='article' and subtype='decodable'.

Primary keycontent_id
Backing storealpha.decodable_extension keyed to content_item.content_id where content_kind='article' and subtype='decodable'.
Storage gateStores only content_id, phonics_constraint, constraint_set_id, policy_version, and audit fields. It must not copy QTI title, language, article body, version JSON, Curriculum node text, or student outcomes.
Source classAlpha Content extension sidecar for governed article subtype
LifecycleCreated after the article content item exists and subtype='decodable' has been set at write/import time. Updated with the article authoring workflow when the phonics constraint set changes. Retired with the parent article, not as a separate collection.

Purpose

Use decodable when an article must be rendered, searched, exported, and validated as text constrained to a specific phonics set. The article remains the one Content row; this sidecar stores only the constraint facts QTI does not define.

Relationships

  • One-to-one with content_item where content_kind='article' and subtype='decodable'.
  • May be referenced by Curriculum through the same content_ref contract as any other article.
  • May reference images or audio through content_reference rows; it does not nest those rows.

Constraints

  • content_item.content_kind must be article and content_item.subtype must be decodable.
  • phonics_constraint is required JSONB and must be validated at write time against the governed phonics policy version.
  • The constraint set is a Content render/discover fact; student reading attempts and scores live in Events/Results.

Invalid examples

  • content_kind='decodable'.
  • A phonics constraint stored as a catalog facet string instead of the decodable sidecar.
  • Student reading accuracy or mastery stored in phonics_constraint.

Example

{
  "content_id": "4fd04a3e-2e51-4dd6-92d1-0ef196878fea",
  "phonics_constraint": {
    "focus_patterns": [
      "short_a",
      "short_i"
    ],
    "allowed_graphemes": [
      "a",
      "i",
      "m",
      "s",
      "t",
      "p"
    ],
    "exception_words": [
      "the"
    ]
  },
  "constraint_set_id": "alpha-phonics-k-01",
  "policy_version": "alpha.policy.decodable_constraints.v1"
}

Queries

GET /tenants/{tenantId}/alpha/content/items?content_kind=article&subtype=decodable
GET /tenants/{tenantId}/alpha/content/items/{contentId}

Fields (5)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The article content item this decodable sidecar constrains. Must reference content_item(content_id) in the same workspace where content_kind='article' and subtype='decodable'. · References a non-article, a non-decodable article, a missing row, or a row in another workspace. content-itd-019-governed-subtypes-within-ten-kinds
phonics_constraintJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The governed phonics constraint set that makes this article a decodable. Required JSON object. Must name the focus patterns, allowed graphemes or phoneme-grapheme correspondences, any exception words, and the policy version used to validate the text. The storage layer validates shape and known values at write time. · Null, free text, missing the policy version, includes student performance, or is inferred from the article title at read time. content-itd-019-governed-subtypes-within-ten-kinds
constraint_set_idTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable id of the phonics constraint set used by this decodable. Required platform-governed id. The id is a policy/reference label, not a free-form title. · A display label, missing for a decodable, or changed without revalidating phonics_constraint. content-itd-019-governed-subtypes-within-ten-kinds
policy_versionTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Named policy version used to validate the phonics constraint set. Required alpha.policy reference. Policy changes that invalidate the constraint require revalidation before publication. · Missing, free-form, or used to store the actual phonics table instead of a version reference. content-itd-019-governed-subtypes-within-ten-kinds
updated_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When the decodable constraint sidecar last changed. Required timestamp with time zone. · Null or used as learner activity time. content-axis-007-eventing-model

public read view over content_item and assessment_test sidecars · Content. Belongs here because it is the plain public object for a blank renderable assessment form; blueprints are test_spec, banks are test_bank, and sittings/scores/mastery/gradebook rollups live outside Content.

test — Test

Plain public view for renderable content_item rows where content_kind='test'.

Primary keycontent_id
Backing storealpha.content_item_view joined to alpha.assessment_test_extension; no physical alpha.test table.
Storage gateThis object stores nothing by itself. It exposes QTI-backed content identity and Alpha role sidecars, and must not copy QTI XML, version JSON, titles, attempts, scores, gate fields, retake policy, or mastery.
Source classAlpha public read object over QTI test rows plus role sidecars
LifecycleCreated as a content_item row with content_kind='test'. Form-specific assessment facts live in assessment_test; QTI XML and versions remain in the QTI base.

Purpose

Use test when an app-builder wants the plain Alpha object for a renderable form. Use test_spec for the blueprint and test_bank for the set of equivalent forms.

Relationships

  • One-to-one with content_item where content_kind='test'.
  • assessment_role='form' is a renderable test form and may be a bank member.
  • test_spec and test_bank are separate first-class content_kind values, not hidden forms.

Constraints

  • assessment_role is required and exactly form for content_kind='test' unless a legacy compatibility row is being read.
  • test_spec and test_bank are content_kind values.
  • Gate fields and cutoff numbers stay in Curriculum/Policy; Results owns attempts, scores, and mastery.

Invalid examples

  • A blueprint or bank stored only as content_kind='test' with no first-class test_spec/test_bank kind.
  • A bank membership list stored in a test JSON blob rather than content_reference bank_member rows.
  • A student score stored on the test object.

Example

{
  "content_id": "8b41a559-98e3-4e33-9ad2-61a575f7fb3f",
  "content_kind": "test",
  "assessment_role": "form",
  "title": "Math diagnostic form A",
  "expected_xp": 30
}

Queries

GET /tenants/{tenantId}/alpha/content/items?content_kind=test&assessment_role=form
GET /tenants/{tenantId}/alpha/content/items?content_kind=test_spec
GET /tenants/{tenantId}/alpha/content/items?content_kind=test_bank
GET /tenants/{tenantId}/alpha/content/items/{contentId}/blueprint
GET /tenants/{tenantId}/alpha/content/items/{contentId}/bank-members

Fields (3)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename over QTI base identity Stable id for the test content row. Must reference content_item(content_id) where content_kind='test'. · References a non-test content item, missing row, or another workspace. content-itd-020-test-spec-and-test-bank
assessment_roleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension QTI compatibility discriminator for renderable test forms. Required governed enum set at write/import time. For first-class public kinds, test_spec implies spec and test_bank implies bank. · assessment_role · Free text, parsed from the title, or set to a new content_kind value. content-itd-019-governed-subtypes-within-ten-kinds, content-itd-020-test-spec-and-test-bank
test_typeTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Educational purpose of a renderable form when applicable. Required for assessment_role='form'; normally null for specs and banks. · test_type · Parsed from display name or used to encode assessment_role. content-itd-006-typed-content-and-test-fields

Alpha extension sidecar joined into public test view · Content. Belongs here because this is the blank test instrument; sittings, submitted answers, scores, and gradebook rollups live outside Content.

assessment_test — Assessment Test

Typed Alpha fields for QTI-backed test, test_spec, and test_bank rows.

Primary keycontent_id
Backing storealpha.assessment_test_extension physically keys rows by (tenant_id, content_artifact_id), where content_artifact_id references qti.artifact.artifact_id and the QTI artifact kind is test. Public reads expose content_artifact_id as content_id.
Storage gateStores only tenant_id, content_artifact_id, assessment_role, nullable test_type, is_mastery_gate, and nullable test_family_id. It must not store QTI XML, title, qti_identifier, version data, scores, sittings, student answers, cut scores, retake policy, or gate-failure behavior.
Source classAlpha Content extension sidecar for typed test fields
LifecycleCreated with a test content item or set by import adapter. Updated through versioned Content authoring with If-Match.

Purpose

Use assessment_test to classify QTI-backed assessment rows by educational purpose, external test family identity, and assessment_role before Results records arrive. Public content_kind is test, test_spec, or test_bank; assessment_role keeps form/spec/bank compatibility over shared QTI storage.

Relationships

  • One-to-one with content_item where content_kind is test, test_spec, or test_bank.
  • assessment_role='spec' links to alpha.test_spec_extension; assessment_role='bank' links to alpha.test_bank_extension.
  • test_family_id is an intended future Results reconciliation target. Current Results ingest can persist producer family text without resolving it to Content.

Constraints

  • assessment_role is exactly form, spec, or bank; content_kind=test_spec implies spec and content_kind=test_bank implies bank.
  • test_type and is_mastery_gate are separate fields. test_type is optional for form, spec, and bank rows; when present it must use the governed enum.
  • test_family_id is an optional opaque storage value for adapters, not a secret and not a score. The current API/database impose no lexical grammar, Content has no family resolver, TimeBack import writes null, and Results has no Content foreign key; a present string is not proof of reconciled family identity.
  • Do not infer test_type from title, URL, producer, or QTI identifier at read time.
  • Gate fields, passing_criteria, retake cooldown, and mastery cutoff numbers stay in Curriculum/Policy. Content owns only the blank forms, spec blueprint, and bank membership.

Invalid examples

  • Setting is_mastery_gate by checking whether the URL contains mastery.
  • Using placement as a display tag instead of assessment_test.test_type.
  • Storing a student's test score on assessment_test.
  • Creating content_kind='test_spec' with assessment_role other than spec, or content_kind='test_bank' with assessment_role other than bank.

Example

{
  "content_id": "8b41a559-98e3-4e33-9ad2-61a575f7fb3f",
  "assessment_role": "form",
  "test_type": "diagnostic",
  "is_mastery_gate": false,
  "test_family_id": "nwea:map-growth:math"
}

Queries

GET /tenants/{tenantId}/alpha/content/items?content_kind=test&test_type=diagnostic
GET /tenants/{tenantId}/alpha/content/items?content_kind=test_bank
GET /tenants/{tenantId}/alpha/content/items/{contentId}

Fields (5)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The test content item this profile describes. Must reference content_item(content_id) with content_kind='test'. · References a question, article, video, audio, image, interactive, media_asset, external_link, or script content item. content-itd-006-typed-content-and-test-fields
assessment_roleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Governed role for a test content row: renderable form, blueprint spec, or bank of equivalent forms. Required governed enum. spec and bank correspond to public content_kind values test_spec and test_bank, and are validated at write time. · assessment_role · Set to diagnostic, mastery_gate, inferred from title/path, or inconsistent with content_kind test/test_spec/test_bank. content-itd-019-governed-subtypes-within-ten-kinds, content-itd-020-test-spec-and-test-bank
test_typeTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Educational purpose of the test. Optional for assessment_role='form', 'spec', and 'bank'. When present, it must use the governed enum and be set at write/import time; consumers must not infer it from display text. · test_type · Parsed from display name or mixed with is_mastery_gate. content-itd-006-typed-content-and-test-fields
is_mastery_gateBOOLEANyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Whether this test gates advancement or unlocks a path when passed. Required boolean. Kept separate from test_type because a diagnostic or test_out can be a mastery gate or not. · Inferred from producer URL, title, tag, or passing score at read time. content-itd-006-typed-content-and-test-fields
test_family_idTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Nullable Content-side candidate identity for a family of tests; governed cross-form/source reconciliation is pending. Current storage accepts opaque text with no lexical grammar or resolver, TimeBack import writes null, and Results does not enforce a foreign key to this field. A present value must not be presented as proof that multiple forms or producer results resolved to one Content family. It must not contain producer credentials or other secrets. · Contains a secret, changes between retakes of the same family, or is guessed from display title during Results ingest. content-itd-010-external-test-family-identity

Alpha extension sidecar for a test role · Content. Belongs here because a test spec is the blank blueprint for equivalent test forms; gate decisions and student outcomes stay in Curriculum/Policy and Results.

test_spec — Test Spec

The validated table of specifications for a bank of equivalent test forms.

Primary keyspec_id
Backing storealpha.test_spec_extension keyed to the QTI-backed test_spec content row; public test_spec object joins assessment_test where assessment_role='spec'.
Storage gateStores only spec_id plus blueprint fields QTI does not define. It must not copy QTI XML, test title, version JSON, item rows, Curriculum statement text, gate thresholds, retake cooldown, attempts, scores, or mastery state.
Source classAlpha Content extension sidecar for assessment blueprint facts
LifecycleCreated as a content_item row where content_kind='test_spec' plus assessment_test.assessment_role='spec' for QTI compatibility. The blueprint lives in alpha.test_spec_extension. Current runtime checks JSON/type/enum shape; release eligibility that proves active KC resolution and full blueprint/member validation remains pending.

Purpose

Use test_spec when a mastery gate, generator, or reviewer needs to inspect the KC coverage, DOK coverage, difficulty constraints, passing rule, minimum form count, overlap limit, and enemy-item rule that define equivalent forms.

Relationships

  • One-to-one with content_item where content_kind='test_spec' and assessment_test where assessment_role='spec'.
  • Referenced by test_bank.spec_id.
  • kc_coverage references active identities in the Curriculum-owned alpha.knowledge_component registry; Content stores ids and counts, not copied KC statements.

Constraints

  • kc_coverage is a KC x DOK grid with target item counts and instructional weights. The accepted target requires every KC to resolve to an active Curriculum Knowledge Component at write time; current runtime does not yet perform that cross-module resolution.
  • The accepted target requires every coverage cell and every counted item to carry one governed Webb DOK value (dok1 through dok4). Current runtime does not inspect coverage-cell contents or prove item-to-cell DOK conformance.
  • passing_rule is canonical for every form generated from this spec, but the cutoff number and false-pass/false-fail loss weights stay in alpha.policy.
  • min_forms is at least 1 for ordinary banks and at least 5 for grade gates; a Curriculum grade gate pointing at a bank below min_forms is a spec violation.
  • Learning Scientists own the three blueprint semantics adopted here: caitd-016 item-to-KC cardinality, caitd-017 comparable-forms check, and caitd-018 passing-rule loss encoding.
  • caitd-016 Item-to-KC cardinality: One primary KC per coverage-counted item; optional secondary Q-matrix tags may exist but are not double-counted in kc_coverage. Reopen trigger: If Learning Scientists revise caitd-016, this dictionary rolls back before changing coverage counting.
  • caitd-017 Comparable-forms check: Two fixed forms are equivalent only when both satisfy the same blueprint constraints and the max_item_overlap rule; this is a binary same-blueprint validation, not a string label. Reopen trigger: If Learning Scientists revise caitd-017, test_bank membership validation rolls back before accepting new forms.
  • caitd-018 Passing-rule loss encoding: The spec's passing_rule encodes the per-KC false-pass versus false-fail loss assumption; the cutoff number itself remains alpha.policy config. Reopen trigger: If Learning Scientists revise caitd-018, passing_rule validation rolls back before changing the schema contract.

Invalid examples

  • A blueprint stored only inside editing_draft JSON with no queryable kc_coverage.
  • A passing_rule that restates 89.5 or another cutoff number instead of referencing policy.
  • A KC label copied into kc_coverage without a Curriculum KC id.
  • DOK used as difficulty, or difficulty stored without a separate mastery-probability constraint.

Example

{
  "spec_id": "2d461e05-2148-4ec9-a4c0-eafc013cb8e7",
  "assessment_role": "spec",
  "kc_coverage": [
    {
      "curriculum_node_id": "case:math:7.ee.b.4",
      "dok": "dok2",
      "target_item_count": 4,
      "instructional_weight": 0.4
    },
    {
      "curriculum_node_id": "case:math:7.ee.b.3",
      "dok": "dok3",
      "target_item_count": 2,
      "instructional_weight": 0.2
    }
  ],
  "passing_rule": {
    "rule_ref": "alpha.policy.mastery_gate.strict_per_kc_v1"
  },
  "min_forms": 5,
  "max_item_overlap": 0
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/blueprint
GET /tenants/{tenantId}/alpha/content/items?content_kind=test_spec

Fields (10)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
spec_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The test_spec content item whose assessment_role is spec for QTI compatibility. Must reference content_item(content_id) in the same workspace where content_kind='test_spec' and assessment_role='spec'. · References a form, bank, non-test_spec row, missing row, or row in another workspace. content-itd-020-test-spec-and-test-bank
assessment_roleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Role value that makes this test row a blueprint. Required value spec. Stored on assessment_test.assessment_role for QTI compatibility; public object discriminator is content_kind='test_spec'. · assessment_role · Any value other than spec for a test_spec object. content-itd-019-governed-subtypes-within-ten-kinds, content-itd-020-test-spec-and-test-bank
kc_coverageJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension KC x DOK table of specifications: which Curriculum KCs are sampled, at which cognitive level, with what item count and instructional weight. Required JSON array/object. The accepted target requires every row to include an active Curriculum KC id, a DOK enum value, a positive target_item_count, and an instructional_weight. Current runtime validates JSON/type/enum shape but does not yet resolve KC existence or validate the full blueprint semantics. · dok · Missing KC ids, stale/retired KCs, free-text standards, DOK outside dok1..dok4, or weights that do not match the instructional emphasis policy. content-itd-020-test-spec-and-test-bank
item_type_mixJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Allowed item types and exact target counts for generated forms. Required non-empty JSON object of positive integer counts. The total must exactly equal the positive integer DOK counts nested under kc_coverage. Item type labels must be governed by the generator/policy for this spec and cannot be inferred from item titles. · Free-form text; an empty mix; zero, negative, or fractional counts; a total different from kc_coverage; or a mix inconsistent with generated member forms. content-itd-020-test-spec-and-test-bank
difficulty_constraintsJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Item difficulty requirements, such as target mastery probability at the mastery cut. Required JSON object. Difficulty is separate from DOK and should be expressed in policy-backed numeric ranges. · Uses DOK as difficulty, uses student actual results as the constraint, or omits the mastery-cut reference. content-itd-020-test-spec-and-test-bank
passing_ruleJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The spec-level rule every generated form uses to decide pass/fail meaning. Required JSON object. It names the policy/rule and loss assumption; it must not restate the cutoff number. The cutoff number and false-pass/false-fail loss weights are alpha.policy config. · Contains a hard-coded cutoff such as 89.5, is duplicated on every form, or omits the false-pass/false-fail loss reference. content-itd-020-test-spec-and-test-bank
min_formsINTEGERyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Minimum count of equivalent forms required for a bank generated from this spec. Required positive integer. Grade gates require at least 5 forms. A bank below min_forms is invalid for a gate. · Less than 1, less than 5 for grade gates, or ignored by Curriculum gate validation. content-itd-020-test-spec-and-test-bank
max_item_overlapNUMERIC(5,4)yes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Maximum allowed item-overlap ratio between any two fixed forms generated from this spec. Required number from 0 through 1. A value of 0 means no shared items across fixed forms. · Outside 0..1, not enforced when adding bank members, or treated as a vague similarity label. content-itd-020-test-spec-and-test-bank
enemy_item_ruleJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Rule preventing two mutually incompatible items from appearing in the same form, including no two items on the same KC/standard when the policy says so. Required JSON object. Must be evaluated when validating each generated form. · Missing, unenforced, or stored only as prose that generators cannot validate. content-itd-020-test-spec-and-test-bank
updated_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When the blueprint sidecar last changed. Required timestamp with time zone. Changing a shipped spec requires revalidating banks generated from it. · Null or used as learner activity time. content-axis-007-eventing-model

Alpha extension sidecar plus content_reference membership · Content. Belongs here because a test bank is a reusable blank pool of equivalent test forms; Curriculum references it but does not own its members.

test_bank — Test Bank

A stored fixed-form set or immutable adaptive question pool governed by one test_spec.

Primary keybank_id
Backing storealpha.test_bank_extension keyed to the base test content row; member forms live in alpha.content_reference rows where relationship_kind='bank_member'.
Storage gateStores only bank_id, spec_id, membership_rule, and audit fields. bank_member rows for same_blueprint_fixed_forms or pp100_adaptive_shards, plus actual spec_id/membership_rule changes, are allowed only while the owning content_item is an unretired draft (owner ruling #2534: a trust verdict never locks the draft lane). The mutation guard reads and locks the authoritative base artifact, Alpha lifecycle extension, and trust row before changing the definition or locking/writing a reference. qti_adaptive_selection uses only its native QTI graph. Content must not copy member form QTI XML, test titles, item rows, Curriculum gate fields, retake policy, cut scores, student attempts, scores, or mastery state.
Source classAlpha Content extension sidecar for test-bank identity and membership rule
LifecycleCreated as a content_item row where content_kind='test_bank' plus assessment_test.assessment_role='bank' for QTI compatibility. Existing same-key ledger state is arbitrated first; a fresh create acquires the graph fence and resolves its active same-tenant test_spec before claim or item mutation, so invalid targets leave no item/ledger row and a corrected body may reuse the unclaimed key. The bank sidecar points at one spec. Fixed-form members and PP100 adaptive pool shards may be content_reference rows from the bank to exact form versions with relationship_kind='bank_member'; stock QTI adaptive structure is also valid. Membership authoring and actual spec_id/membership_rule changes close as soon as the current bank is no longer an unretired draft; later edits require a new draft bank graph rather than changing served evidence.

Purpose

Use test_bank when Curriculum needs one exact target_ref for a mastery gate and Content must expose either equivalent forms or the complete immutable adaptive pool. Ordered exact form shards are storage containers, not a claim that Results should select a whole form.

Relationships

  • One-to-one with content_item where content_kind='test_bank' and assessment_test where assessment_role='bank'.
  • Belongs to exactly one test_spec through spec_id.
  • Has fixed-form members or adaptive pool shards through content_reference rows: parent_content_id=bank_id, referenced_content_id=form content id, referenced_version_id exact form version, relationship_kind='bank_member', form_index ascending.
  • Adaptive/CAT pools may stay inside one adaptive QTI test through qti-selection or qti-adaptive-selection. PP100 v2 uses ordered exact form shards and the union of each shard's exact-version embeds as the frozen pool; Results owns runtime question selection and score state. No parallel membership table is created.

Constraints

  • Create and PATCH require spec_id to resolve in the routed tenant to an unretired, non-archived, non-status-retired content_kind='test_spec', assessment_role='spec' item with a readable test_spec sidecar. Missing, cross-tenant, wrong-kind/role, retired, archived, or sidecar-less targets return 400 content.validation_failed before mutation.
  • A fresh test_bank create resolves that spec target under the tenant graph fence before its idempotency claim. Completed/in-progress/conflicting same-key state is arbitrated first; a fresh invalid target creates neither item nor ledger row, and a corrected body may reuse the still-unclaimed key.
  • PATCH requires If-Match and preserves an omitted bank-definition field from the existing sidecar. Explicit null spec_id or membership_rule returns 400 content.validation_failed. An actual definition change requires status='draft', retired_at IS NULL, and trust_status='unknown' (including missing trust); otherwise 409 content.bank_membership_frozen preserves the base item, sidecar, timestamp/ETag, and graph. With any active bank_member row—fixed form or PP100 adaptive shard—spec_id cannot change and membership_rule cannot become qti_adaptive_selection; either returns 409 content.invalid_test_bank_member_contract with the same atomic preservation.
  • Create and soft-retire bank_member writes are allowed only when the parent bank has status='draft', retired_at IS NULL, and trust_status='unknown' (including a missing trust row). Published, trusted, degraded, failed, archived, retired, and draft-with-retired_at states return 409 content.bank_membership_frozen with no graph, item identity, timestamp, ETag, or fresh-idempotency-ledger mutation. Completed retries replay their prior response.
  • Every new fixed-form or PP100 adaptive-shard member must pin a referenced_version_id that belongs to its assessment_role='form' test, embed at least one question in that exact form-version graph, and have at least one active canonical content_kc_tag on every ordered question occurrence in that exact graph. Parent/member role, exact-version graph, and question-attribution validation are enforced atomically at the bank_member write boundary; full same-blueprint comparability remains pending.
  • The accepted target requires at least test_spec.min_forms unseen-equivalent forms before a Curriculum grade gate can target the bank. Current runtime does not enforce this release-eligibility rule.
  • For same_blueprint_fixed_forms, equivalent form selection is Curriculum-owned. For pp100_adaptive_shards, Results unions the exact shard embeds, freezes that pool on the attempt, and owns deterministic runtime score-band selection. Content reads provide the ordered member list, usage_scope, referenced_usage_scope, exact referenced form version, that immutable version's ordered/multiplicity-preserving per-question canonical KC tags, and an explicit attribution-readiness audit. A missing, empty, or ambiguously mixed exact-version graph is incomplete; latest-version substitution and cross-version union are forbidden. PostgreSQL acquires the shared writer fence on client A before beginning the stable repeatable-read/serializable snapshot on client B, so a writer already waiting cannot be hidden behind a stale reader snapshot. After a fixed number of identity/metadata reads, two set queries hydrate active member facts and exact form/question/KC facts, keeping database round trips constant as graph cardinality grows. Each query uses a cap-plus-one sentinel and rejects before row mapping when one bank exceeds the inclusive ceiling of 1,024 active bank-member facts or one integrity read exceeds 4,096 joined question/KC facts. Both return 409 content.invalid_test_bank_member_contract with fieldErrors.name=bank_members or form_graph and require the graph to be split before retry. Full spec-validation evidence is a pending target. Routine selection is limited to practice_eligible members whose referenced form is also practice_eligible.
  • membership_rule='qti_adaptive_selection' requires stock QTI adaptive structure and forbids parallel bank_member rows. membership_rule='pp100_adaptive_shards' requires ordered exact bank_member shards whose pinned embeds union to the immutable pool. A PP100 v2 blueprint additionally requires a minimum pool of eight unique item families spanning easy, medium, and hard, accepted tier calibration for every item, standardized-test-rigor evidence for hard items, mastery and spaced retrieval only at score 100, unseen-before-repeat, immediate-repeat avoidance, and no 90+ downward fallback unless prerequisite.

Invalid examples

  • A bank with no spec_id.
  • A PATCH that sets required spec_id or membership_rule to null.
  • A published, trusted, retired, or otherwise non-draft bank whose definition is rewritten in place.
  • A bank with active fixed-form or PP100 adaptive-shard members whose spec_id is swapped or whose membership_rule becomes qti_adaptive_selection.
  • A string label saying equivalent with no blueprint validation.
  • A one-form grade gate when the spec's min_forms is greater than 1.
  • A local question-bank or playlist collection stored as Content instead of Curriculum.

Example

{
  "bank_id": "18f4995b-1326-45f1-b04d-4be3861da324",
  "assessment_role": "bank",
  "spec_id": "2d461e05-2148-4ec9-a4c0-eafc013cb8e7",
  "membership_rule": "same_blueprint_fixed_forms"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/bank-members
GET /tenants/{tenantId}/alpha/content/items?content_kind=test_bank
PATCH /tenants/{tenantId}/alpha/content/items/{contentId} with If-Match for sparse spec_id or membership_rule changes

Fields (5)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
bank_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The test_bank content item whose assessment_role is bank for QTI compatibility. Must reference content_item(content_id) in the same workspace where content_kind='test_bank' and assessment_role='bank'. · References a spec, form, non-test_bank row, missing row, or row in another workspace. content-itd-020-test-spec-and-test-bank
assessment_roleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Role value that makes this test row a bank. Required value bank. Stored on assessment_test.assessment_role; repeated here as the public object discriminator. · assessment_role · Any value other than bank for a test_bank object, or content_kind other than test_bank. content-itd-019-governed-subtypes-within-ten-kinds, content-itd-020-test-spec-and-test-bank
spec_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension The test_spec blueprint that all member forms must satisfy. Required UUID. Create and PATCH resolve it in the routed tenant to an unretired, non-archived, non-status-retired content_kind='test_spec', assessment_role='spec' item with a readable blueprint sidecar; invalid targets return 400 before mutation. PATCH omission preserves the current value; explicit null returns 400. An actual change requires an unretired draft, and active fixed-form or PP100 adaptive-shard members forbid a swap. Full member-form blueprint comparability remains pending. · Missing, references a form or bank, or crosses workspaces. content-itd-020-test-spec-and-test-bank
membership_ruleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension How the bank's member forms are represented and validated. Required governed enum. PATCH omission preserves the current value; explicit null returns 400. An actual change requires an unretired draft. same_blueprint_fixed_forms uses ordered content_reference bank_member rows and Curriculum selects a form. qti_adaptive_selection uses only stock QTI adaptive structure, rejects parallel bank_member rows, and cannot be selected while active bank_member rows remain. pp100_adaptive_shards uses ordered exact form shards whose pinned embeds union to the immutable pool; Results owns runtime selection and score state. · test_bank_membership_rule · Free-form text, contradicts the stored member representation, or hides a parallel collection table. content-itd-020-test-spec-and-test-bank
updated_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When the bank identity or membership rule last changed. Required timestamp with time zone for bank identity or membership-rule changes. Adding or removing an active bank_member advances the parent Content item's updated_at/ETag in the same transaction, so item-list modifiedSince polling observes the graph change. · Null or used as learner activity time. content-axis-007-eventing-model

public API aggregate projection over an Alpha extension composition table · Content. Belongs here because cue timing, article segment order, and embedded-question placement are instructional-delivery structure for a student-touchable Content object.

interactive_composition — Interactive Article/Video Composition

Typed segment/cue to QTI-backed question bindings for interactive articles and videos.

Primary keyPublic aggregate lookup: content_id. Active physical row uniqueness: tenant_id + content_id + composition_type + sequence_index; version_id is not part of that key.
Backing storealpha.interactive_composition plus alpha.interactive_composition_view over qti.artifact, qti.artifact_version, qti.package_file, and qti.component references.
Storage gateStores only Content-owned delivery composition: article segment order, video cue timestamps, media reference, question Content reference, optional QTI assessment_component reference, and validation attestations. It must not copy QTI question bodies, answer keys, scoring rules, media bytes, Curriculum sequence/gate policy, student responses, attempts, scores, or XP awards.
Source classAlpha Content extension composition
LifecycleCreated by authoring after the article/video and QTI-backed question Content rows exist. PUT upserts the requested active sequence slots, retires active rows outside that requested composition/sequence set, and touches the parent item; it does not create a new qti.artifact_version. Keep historical Events/Results pinned by emitted component_id/question_id provenance.

Purpose

Use interactive_composition when an article or video needs embedded questions at known article segments or video timestamps. The renderer reads this canonical structure instead of parsing tb-* markup for composition.

Relationships

  • Belongs to one content_item and may carry optional content_version UUIDs on its physical rows. Current storage enforces independent version FKs only; validating that every version belongs to the parent item and that all active rows use one aggregate version is pending.
  • interactive_video media_asset_ref references a media_asset attached to the same Content item.
  • segments and cues contain question_ref objects that resolve to content_kind=question.
  • Each question_ref may include an assessment_component_id that resolves through the question's assessment_component rows.
  • Curriculum sequences and gates the parent Content item through its own Content references and registry-KC scope; content_kc_tag records Content-to-KC relevance, and QTI stores the referenced questions only.
  • interactive_cluster is a third interactive composition kind stored on the version student_view (student_view.kind=interactive_cluster), not as interactive_composition rows: it carries cluster-owned shared_stimuli plus exact-version Content component references, and is authored via POST /items/{contentId}/versions rather than this endpoint.

Constraints

  • composition_type is interactive_article or interactive_video.
  • interactive_cluster (a coherent set of interdependent items — shared stimulus plus part-a/part-b components — judged at arc grain) is stored on the version student_view with student_view.kind=interactive_cluster, never as interactive_composition rows; composition_type on this table remains interactive_article or interactive_video.
  • interactive_cluster components are exact-version Content reference tuples (content_id plus content_version_id), never inlined copies, so each member keeps its own exact-version eligibility answer and provenance identity.
  • interactive_cluster component part_label is a non-empty string; component stimulus_ref, when supplied, resolves to a declared shared_stimuli id (shared_stimuli ids are unique).
  • interactive_cluster expected_xp is the sum of component expected_xp and is never double-counted with the referenced members; the arc-grain quality judgment of a cluster is the producer's (Incept), not Content's.
  • interactive_article responses contain ordered segments with positive sequence_index values and may carry segment_ref; cues are omitted.
  • interactive_video responses require media_asset_ref, duration_seconds > 0, and ordered cues whose at_seconds values are >0, less than duration_seconds, and strictly increasing.
  • Governed article/video publication requires every question_ref to carry canonical content_id plus exact content_version_id returned by QTI import; each exact question version must exist and be release eligible.
  • Governed video publication requires media_asset_ref to name same-item, same-exact-version, primary video/mp4 bytes created by the verified Incept handoff, with matching duration and a valid caption track or nonempty transcript.
  • Each segment or cue carries tests_prior_content=true to attest that the referenced question tests already-shown material.
  • Optional parent and question version UUIDs currently have independent foreign keys; same-item version ownership validation is pending and must not be inferred from the FK alone.
  • The HTTP body currently accepts a version_id on each segment/cue. Active-row uniqueness omits version_id, GET loads all active rows for the content_id, and the aggregate response reports the first row's version_id. Rejecting mixed parent versions or defining an explicit mixed-version contract is pending; consumers must not infer aggregate version coherence today.
  • No answer keys, correctness, scores, attempts, XP thresholds, or Curriculum gate fields belong here.

Invalid examples

  • Embedding video cue timings inside a QTI assessmentItem or assessmentTest.
  • Putting article segment order on a Curriculum node.
  • Parsing tb-qti-assessment-item positions as the canonical source after a typed composition row exists.
  • Referencing a non-question Content row as question_content_id.

Example

{
  "content_id": "2f4b4c12-7c41-4b40-a33a-9637581d0e51",
  "composition_type": "interactive_video",
  "media_asset_ref": {
    "media_id": "30225f0a-51fd-4a7e-b3b2-ecfe24bca7b6"
  },
  "duration_seconds": 120,
  "cues": [
    {
      "sequence_index": 1,
      "at_seconds": 10,
      "question_ref": {
        "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
        "content_version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
        "assessment_component_id": "51ef0fdf-7ebf-4cc7-9242-45432b04ad4f"
      },
      "tests_prior_content": true
    }
  ]
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/interactive-composition
PUT /tenants/{tenantId}/alpha/content/items/{contentId}/interactive-composition

Public API fields (9)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes API aggregate only; row-level physical keys remain in the generated Physical DDL section. · Content public API projection Parent interactive article/video Content item. Must reference content_kind=article, video, or interactive as compatible with composition_type. content-itd-022-interactive-composition
version_idUUIDno API aggregate over alpha.interactive_composition.content_version_id. · Content public API projection Optional parent Content version UUID reported for this composition aggregate. Nullable when the composition follows the parent item's current resolved version. Current storage enforces an independent version FK only; validating that version_id belongs to content_id is pending. PUT currently accepts per-entry version_id values and GET reports the first active row's value, so uniform aggregate version coherence is not enforced. content-itd-022-interactive-composition
composition_typeENUMyes API aggregate over alpha.interactive_composition.composition_type. · Content public API projection Discriminator for article-segment or video-cue composition. Must be one of enumSets.interactive_composition_type.values. · interactive_composition_type content-itd-022-interactive-composition
media_asset_refOBJECTno API object projection; no JSON media reference is stored in the row table. · Content public API aggregate Reference to the primary media asset for an interactive video. Required for interactive_video; contains content_id and media_id for a media_asset attached to the parent item. content-itd-022-interactive-composition
duration_secondsNUMBERno API aggregate over alpha.interactive_composition.duration_seconds. · Content public API projection Duration of the interactive video used to validate cue positions. Required and greater than 0 for interactive_video; null for interactive_article. content-itd-022-interactive-composition
segmentsARRAYno API array projection; row-level fields remain in the generated Physical DDL section. · Content public API aggregate Ordered interactive-article segment bindings with question_ref and tests_prior_content evidence. Present for interactive_article and ordered by positive sequence_index; omitted when empty. content-itd-022-interactive-composition
cuesARRAYno API array projection; row-level fields remain in the generated Physical DDL section. · Content public API aggregate Ordered interactive-video cue bindings with timestamps, question_ref, and tests_prior_content evidence. Present for interactive_video; at_seconds values are strictly increasing, greater than 0, and less than duration_seconds; omitted when empty. content-itd-022-interactive-composition
validation_contractOBJECTyes Derived at read time; not stored as a physical JSON column. · Content public API derived projection Server-produced explanation of the Content, QTI, Curriculum, ordering, and prior-content validation boundary. Read-only. Consumers must not treat it as learner progress or submit it as canonical stored state. content-itd-022-interactive-composition
updated_atTIMESTAMPTZno Derived aggregate; exact row lifecycle columns remain in the generated Physical DDL section. · Content public API derived projection Creation time of the highest-sequence active composition row, falling back to the parent item update time. Read-only ISO-8601 timestamp; null only when neither composition nor parent update evidence exists. content-itd-022-interactive-composition

Alpha extension registry table · Content. Belongs here because it defines governed discovery values used to find Content; it is not the curriculum graph and not a copy of QTI metadata.

content_catalog_facet — Content Catalog Facet

Governed catalog-facet definition for discovery metadata.

Primary keyfacet_key
Backing storealpha.content_catalog_facet sidecar beside QTI-backed Content views.
Storage gateStores only facet key, label, value_type, grain, allowed_values, status, policy/provenance, and audit fields. It must not store qti.artifact title/language/kind/version fields, qti.package_file media_type, or Curriculum statement/code text.
Source classAlpha catalog-facet sidecar extension
LifecycleCreated by platform/content catalog operations. A facet is retired when the value set should no longer be assigned, but existing assignments remain for audit and historical catalog behavior. Promotion to a real column is one-way when a facet becomes a join target, constraint key, or computed input.

Purpose

Use content_catalog_facet to define report-only or discovery-only values such as difficulty band, format grouping, accessibility label, or authoring collection when those values are not relationship keys or computed inputs.

Relationships

  • Parent of content_catalog_facet_assignment through facet_key.
  • Does not reference Curriculum nodes. Knowledge coverage uses weighted content_kc_tag rows to registry KCs.

Constraints

  • facet_key must be exactly one of the twelve named catalog discovery facets: subject, grade_band, language, accessibility_profile, rights_license, provenance, quality_rating, kc_refs, standards_framework_refs, content_kind, expected_xp_band, or modality.
  • allowed_values is required for value_type='enum' and must be an array of governed values with plain-language labels.
  • Facet definitions are not relationship targets for app joins. Promote the facet to a real column before consumers compute or join on it.
  • Facet assignments are stored by authoring/import/catalog workflows and read directly by LOR/library/catalog UIs; they are never recomputed at read time from Content base rows or related Curriculum rows.

Invalid examples

  • facet_key='curriculum_node_id' because current knowledge alignment uses weighted content_kc_tag relationship rows.
  • Copying qti.artifact.title into a facet definition.
  • A free-form bag of tags with no allowed values or grain.

Example

{
  "facet_key": "accessibility_profile",
  "label": "Accessibility profile",
  "value_type": "enum",
  "grain": "media_asset",
  "status": "active"
}

Queries

GET /tenants/{tenantId}/alpha/content/catalog-facets
GET /tenants/{tenantId}/alpha/content/items?facet=accessibility_profile:captioned

Fields (7)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
facet_keyTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable governed key for one catalog discovery facet. Required unique key from the catalog_facet_key enum. No other facet keys ship in the Alpha Content surface until architecture explicitly adds one. · catalog_facet_key · Free-form display text, duplicates another facet, uses an unapproved key, or names a relationship that should be a real FK. content-itd-014-catalog-facets-sidecar
labelTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Plain-language name shown in catalog filters. Required short text. Safe for teachers/students and cannot contain secrets or direct student PII. · Internal-only jargon with no plain-language meaning, raw SQL, or copied QTI title text. content-itd-014-catalog-facets-sidecar
value_typeTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Type of values this facet can assign. Required governed enum. Determines how facet_value is validated. · catalog_facet_value_type · Missing, free-form, or used to smuggle a relationship instead of promoting to a real column. content-itd-014-catalog-facets-sidecar
grainTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Object level where this facet may be assigned. Required governed enum. A facet assigned at the wrong grain is invalid even if the value is allowed. · catalog_facet_grain · Ambiguous, absent, or applied to both content_item and media_asset without separate facet definitions. content-itd-014-catalog-facets-sidecar
allowed_valuesJSONBno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Governed value list for enum facets, with per-value labels and optional descriptions. Required when value_type='enum'. Nullable for boolean/number/reference/text facets when validation policy is defined elsewhere. · A raw string list with no labels, values outside the documented type, or values copied from QTI metadata without governance. content-itd-014-catalog-facets-sidecar
statusTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Whether this facet may receive new assignments. Required value active or retired. Retired facets remain readable for historical assignments. · Hard-deleted while assignments exist or used to hide invalid facet values. content-itd-014-catalog-facets-sidecar, content-axis-011-privacy-retention
updated_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When the facet definition last changed. Required timestamp with time zone. Must advance when allowed_values, status, value_type, or grain changes. · Null or older than a semantic registry change. content-axis-007-eventing-model

Alpha extension assignment table · Content. Belongs here because it assigns governed discovery metadata to a Content item, version, or media asset; it is not a curriculum link, event, result, or copied base row.

content_catalog_facet_assignment — Content Catalog Facet Assignment

Assignment of one governed catalog facet value to Content.

Primary keyfacet_assignment_id
Backing storealpha.content_catalog_facet_assignment keyed to base content/version/media ids and content_catalog_facet.
Storage gateStores only assignment id, facet_key, content_id, optional version_id/media_id, facet_value, lifecycle/provenance, and audit fields. It must not copy title, kind, subject, target grade, media_type, byte_length, package path, or Curriculum statement text.
Source classAlpha catalog-facet sidecar assignment
LifecycleCreated by authoring/import/catalog workflows after the facet definition exists. Retired when the assignment no longer applies. Replaced by a real column if the value becomes a join key, uniqueness key, or computed input.

Purpose

Use content_catalog_facet_assignment to drive catalog discovery filters without copying Content base fields, Curriculum statements, or QTI metadata into a parallel catalog table.

Relationships

  • Belongs to one content_catalog_facet.
  • Belongs to one content_item and optionally one content_version or media_asset depending on facet grain.
  • Does not replace content_kc_tag, subject_id, target_grade_id, test_family_id, expected_xp, or other real operational columns.

Constraints

  • facet_value must validate against content_catalog_facet.value_type and allowed_values.
  • Only one active assignment may exist for the same facet_key/content_id/version_id/media_id/facet_value at the same grain.
  • Assignments must not contain secrets, direct student PII, or copied QTI/Curriculum text.
  • LOR/library/catalog UIs query assigned facets directly. They must not rebuild subject, language, standards, expected_xp_band, or modality by reading base rows or related Curriculum rows at request time.

Invalid examples

  • Assigning a KC id only as a facet instead of a weighted content_kc_tag row.
  • Using a facet assignment for subject_id or target_grade_id after those are real fields.
  • facet_value contains a bearer token or copied standard statement.

Example

{
  "facet_assignment_id": "47a637af-7f0f-45a1-a042-dcad51ed2761",
  "facet_key": "accessibility_profile",
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "media_id": "30225f0a-949d-49d5-a7fc-e2ea43863e96",
  "facet_value": "captioned",
  "retired_at": null
}

Queries

GET /tenants/{tenantId}/alpha/content/items?facet=accessibility_profile:captioned
POST /tenants/{tenantId}/alpha/content/items/{contentId}/catalog-facets with Idempotency-Key

Fields (8)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
facet_assignment_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable id for this one facet assignment. Valid UUID and unique primary key. · Reused or derived from display text. content-itd-014-catalog-facets-sidecar
facet_keyTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Facet definition being assigned. Must reference an active or historically retained content_catalog_facet(facet_key). · catalog_facet_key · Facet definition missing, retired for new assignment, or free-form. content-itd-014-catalog-facets-sidecar
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Content item this facet assignment applies to. Must reference content_item(content_id) in the same workspace. · References missing content, cross-workspace content, or copied item fields instead of an id. content-itd-014-catalog-facets-sidecar
version_idUUIDno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Specific content version when the facet grain is content_version. Nullable unless content_catalog_facet.grain='content_version'. If present, must belong to the same content_id. · Present for a content_item-grain facet or points to another item's version. content-itd-014-catalog-facets-sidecar, content-itd-007-versioned-authoring-and-student-view
media_idUUIDno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Specific media asset when the facet grain is media_asset. Nullable unless content_catalog_facet.grain='media_asset'. If present, must belong to the same content_id. · Present for a content_item-grain facet or points to another item's media. content-itd-014-catalog-facets-sidecar, content-itd-004-non-qti-media-extension
facet_valueTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Governed value assigned for this facet. Required. Validate against the facet definition's value_type and allowed_values. Store canonical value, not display label. · Free-form ungoverned value, copied QTI/Curriculum text, secret, or display label where a canonical value exists. content-itd-014-catalog-facets-sidecar
provenanceJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Safe evidence for who or what assigned this discovery facet. Required JSON object. May name importer, authoring workflow, or policy version; must not include raw tokens, credentials, or direct student PII. · Contains secrets, raw package bytes, raw QTI metadata copied wholesale, or enough data to become a second source of truth. content-itd-014-catalog-facets-sidecar, content-axis-010-conformance-evidence
retired_atTIMESTAMPTZno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When this facet assignment stopped being active. Nullable. Historical assignments remain readable for audit and reproducibility. · Hard-deletes the assignment while historical catalog decisions cite it. content-itd-014-catalog-facets-sidecar, content-axis-011-privacy-retention

reference contract, not a table · Content. Belongs here as the uniform reference contract other modules use to point at any Content kind; it is not a stored Content table and not a Curriculum member.

content_ref — Content Reference

The one reference shape for every Content kind.

Primary keycontent_id + optional content_version_id
Backing storeReferences alpha.content_item_view and alpha.content_version_view over QTI base rows plus extension-only sidecars.
Storage gatecontent_ref adds no storage. It must not fork references into question_ref, test_ref, article_ref, media_ref, or external_link_ref tables.
Source classAlpha uniform reference contract
LifecycleConstructed from content_item/content_version reads and accepted by APIs that reference Content. It stores nothing by itself; the referenced content_id/version_id remain in the QTI base view or Alpha extension sidecars.

Purpose

Use content_ref when Curriculum, LOR/library exports, or another module needs to refer to a question, test, test_spec, test_bank, article, video, audio, image, interactive, media_asset, external_link, or script without kind-specific foreign keys.

Relationships

  • content_id references exactly one content_item.
  • content_version_id is intended to reference zero or one version for content_id. Current concrete relationship storage enforces independent UUID foreign keys only; same-item validation is pending.
  • content_kind is the discriminator used for validation and renderer routing hints; renderers must still dereference content_id.

Constraints

  • Allowed for all Content kinds: question, test, test_spec, test_bank, article, video, audio, image, interactive, media_asset, external_link, and script.
  • No kind-specific reference tables or fields are allowed unless a future architecture ITD supersedes the uniform contract.
  • A reference to a retired item remains valid for historical Events/Results, but new Curriculum assignments should use published content.

Invalid examples

  • course_component_member.question_id/test_id/article_id separate columns.
  • A playlist table stored in Content instead of Curriculum referencing content_ref rows.
  • A reference that stores the content title or Curriculum statement instead of ids.

Example

{
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "content_version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "content_kind": "question"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}
GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions/{versionId}

Fields (3)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes No content_ref storage; downstream references store this FK or typed ref value. · rename · Alpha rename/reference over QTI base identity The Content item being referenced. Required valid UUID. Must resolve to one content_item visible to the caller's workspace. · Missing, references another workspace, or is replaced by kind-specific question/test/article id columns. content-itd-016-uniform-content-reference-contract
content_version_idUUIDno No content_ref storage; downstream references store this optional FK or typed ref value. · rename · Alpha rename/reference over QTI base version identity The immutable exact version row to use when the reference must be replayable, including TimeBack import versions. Nullable for references that intentionally follow the current raw latest_version_id/newest-version behavior. Resolving an explicit latest published version is an accepted pending target. If present, same-content ownership is also a pending validation; current storage enforces only an independent version UUID foreign key. · Points to another content item, points to a mutable draft, or is omitted when a historical Event/Result replay requires the exact version. content-itd-016-uniform-content-reference-contract
content_kindTEXTyes No content_ref storage; may be included in typed reference payloads for validation. · restrict · Alpha restrict/reference over content_item.content_kind Content kind for validation and renderer routing hints. Required governed enum and must match the referenced content_item.content_kind. · content_kind · Outside the public enum, mismatched to content_id, or used to choose a kind-specific reference table. content-itd-016-uniform-content-reference-contract

public API projection over an Alpha extension relationship table · Content. Belongs here because it records that one Content row embeds, depends on, captions, thumbnails, or otherwise references another Content row; it is not Curriculum sequencing and not nested Content storage.

content_reference — Content Reference Relationship

A stored relationship from one Content row to another using the uniform content_ref contract.

Primary keycontent_reference_id
Backing storealpha.content_reference physically stores tenant_id, parent_content_artifact_id/referenced_content_artifact_id FKs, optional version FKs, and parent_content_kind. alpha.content_reference_view exposes public parent_content_id/referenced_content_id aliases and derives referenced_content_kind from the referenced QTI artifact plus Content extension; there is no referenced_content_kind table column.
Storage gateStores only relationship identity, tenant key, parent/referenced artifact and version FKs, the server-derived parent kind snapshot, relationship_kind, display_order, form_index, usage_scope, and lifecycle. referenced_content_kind and referenced_usage_scope are read projections, not stored columns. For relationship_kind='bank_member', create and soft-retire use one transaction that locks parent artifacts before reference rows and verifies the parent bank's current lifecycle/trust. Both version IDs must be supplied exact UUIDs owned by their corresponding artifacts; omitted or explicit-null values fail closed and never resolve latest pointers. form_index must be an exact PostgreSQL int4 in 1..2147483647, and display_order must be null or an exact int4 in 0..2147483647; numeric strings, fractions, unsafe JavaScript integers, conflicting snake/camel aliases, and overflow are rejected before SQL. Creation takes the exclusive graph fence, repeats replay arbitration, then validates before its idempotency claim or graph/timestamp mutation; retirement soft-retires the selected existing row without revalidating its form graph. Bank-graph integrity reads reserve two distinct pool clients: client A acquires the shared tenant writer fence before client B begins its stable repeatable-read/serializable snapshot. That writer-before-reader ordering prevents a previously waiting writer from being omitted, allows readers to overlap, and makes later writers wait. No historical marker or parallel membership store is added. It must not copy titles, XML, media bytes, Curriculum statement text, student answers, scores, or collection membership.
Source classAlpha Content extension relationship
LifecycleCreated by authoring, Common Cartridge/QTI import, media upload, or the TimeBack production ingest adapter. Retire instead of hard-delete when historical exports, Events, or Results could cite the relationship. A bank_member may be created or retired only while its parent bank is currently an unretired draft (owner ruling #2534: a trust verdict never locks the draft lane). Both mutations lock parent artifacts before reference rows and atomically commit the relationship change, item touch, and idempotency result; creation also validates the complete bank/form/version/KC graph, while retirement validates lifecycle/trust and soft-retires the selected existing row. Other relationship kinds retain their existing lifecycle under the same parent-before-reference mutation order. Under the #1201 owner FREEZE ruling (2026-08-05), an embeds row whose parent is a pinned exact form version referenced by an approved bank's active bank_member edge may be neither created nor retired; those writes return 409 content.published_assessment_immutable while bank_member writes keep content.bank_membership_frozen.

Purpose

Use content_reference when a content item needs another Content item for rendering, accessibility, provenance, lossless export, script lineage, or bank membership. Examples: a video points to a transcript, an article embeds an image, a question points to a supporting image while its stimulus text stays inside question anatomy, a produced video points to its script Content item, and a test_bank points to member test forms whose usage_scope controls whether routine routing may select them.

Relationships

  • Is tenant-scoped by the route and JWT; the tenant key is not repeated in the public payload.
  • parent_content_id references exactly one content_item.
  • referenced_content_id references exactly one content_item.
  • For bank_member rows, both exact version ids must be supplied and belong to their corresponding content ids. Omitted or explicit-null inputs fail closed and never resolve latest_version_id.
  • Not a Curriculum sequence, playlist, question bank, lesson section, or course-component member.

Constraints

  • Both parent and referenced sides use the same content_ref contract and the same public content_kind enum.
  • Clients do not submit parent_content_kind or referenced_content_kind. The server derives both from Content; it stores only the parent snapshot needed by the physical relationship table and derives referenced_content_kind on reads.
  • A content item may reference another item, but the referenced item remains its own row and version history.
  • relationship_kind is required and governs renderer/export behavior; consumers must not infer it from filenames or MIME type.
  • display_order is only order within this parent relationship set; it is null or an exact PostgreSQL int4 in 0..2147483647, and Curriculum owns instructional sequence order.
  • form_index is required only for relationship_kind='bank_member', must already be an exact PostgreSQL int4 in 1..2147483647 without coercion, and orders equivalent fixed forms inside a test_bank; it is null for non-bank relationships.
  • usage_scope is required and defaults to practice_eligible. For relationship_kind='bank_member', routing may select only rows whose member usage_scope and referenced content_item usage_scope are both practice_eligible.
  • relationship_kind='source_script_for' must point from produced audio/video to a script Content item; relationship_kind='bank_member' must point from a content_kind='test_bank', assessment_role='bank' parent using membership_rule='same_blueprint_fixed_forms' or 'pp100_adaptive_shards' to a content_kind='test', assessment_role='form' target. qti_adaptive_selection cannot carry parallel bank_member rows. The bank and form version UUIDs must be owned by their corresponding artifacts, and KC attribution is resolved only from embeds whose parent_version_id equals the stored referenced_version_id.
  • A bank_member may be added or soft-retired only when its parent is status='draft', retired_at IS NULL, and trust_status='unknown'; missing trust normalizes to unknown. Every other current lifecycle/trust state returns 409 content.bank_membership_frozen. Wrong parent/member kind or assessment role, wrong-owner versions, native-QTI parallel rows, non-integer/invalid indexes, malformed active historical rows, and empty fixed-form exact versions return 409 content.invalid_test_bank_member_contract; a missing, empty, or ambiguous exact question graph or missing KC attribution retains 409 content.bank_kc_attribution_incomplete. Empty native-QTI banks remain valid because their selection graph is native. A fresh create takes the exclusive graph fence and repeats replay arbitration before semantic validation and claim; the relationship write, item touch, claim, and completion are atomic. Integrity reads acquire the shared writer fence on client A before starting the stable reader snapshot on client B. After fixed identity/metadata reads, the active-member and exact form/question/KC hydrations are two set queries, so database round trips do not grow with the graph. The supported inclusive ceilings are 1,024 active bank-member facts for one bank and 4,096 joined question/KC facts for one integrity read. PostgreSQL selects at most cap plus one and rejects the sentinel before mapping; in-memory contract tests apply the same limits before cloning. An overflow returns 409 content.invalid_test_bank_member_contract with fieldErrors.name=bank_members or form_graph and requires the graph to be split before retry. Rejected fresh requests leave no graph or idempotency row and completed retries still replay.

Invalid examples

  • Embedding a transcript JSON blob directly inside the video content_item.
  • A playlist or question bank stored as content_reference rows instead of Curriculum collection membership.
  • A referenced content title copied onto the relationship row.
  • A relationship_kind parsed from a package path such as /captions/.

Example

{
  "content_reference_id": "7bcb0edb-7df1-4f1c-89b8-b7f5f0ca2451",
  "parent_content_id": "2f4b4c12-7c41-4b40-a33a-9637581d0e51",
  "parent_content_kind": "video",
  "referenced_content_id": "91fa40b1-f8a1-4f4a-8a60-c19a93dce4f1",
  "referenced_content_kind": "media_asset",
  "relationship_kind": "transcript_for",
  "display_order": 1,
  "form_index": null,
  "usage_scope": "practice_eligible",
  "referenced_usage_scope": "practice_eligible"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/references
GET /tenants/{tenantId}/alpha/content/items/{contentId}/bank-members

Public API fields (14)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_reference_idUUIDyes Stored physically as alpha.content_reference.content_reference_id and returned on public reads. · extend · Alpha Content extension Stable identity for one relationship from one Content row to another. Required UUID generated by the surface. Unique within alpha.content_reference. · Reused for two parent/referenced pairs or derived from mutable source paths. content-itd-016-uniform-content-reference-contract
parent_content_idUUIDyes Physical alpha.content_reference.parent_content_artifact_id FK; alpha.content_reference_view/repository renames it to parent_content_id. · extend relationship · Alpha FK over QTI base identity The Content item that owns or renders the relationship. Required UUID. Must reference content_item(content_id) in the same workspace. · Missing, references another workspace, or points at a Curriculum component instead of Content. content-itd-016-uniform-content-reference-contract
parent_version_idUUIDno Physical alpha.content_reference.parent_content_version_id FK; alpha.content_reference_view/repository renames it to parent_version_id. · extend relationship · Alpha FK over QTI base version identity Immutable exact parent version row when the relationship is version-scoped. Nullable for item-wide relationships. For bank_member writes, parent_version_id is required and must be an exact version owned by parent_content_id; omitted, explicit-null, or wrong-owner values return 409 content.invalid_test_bank_member_contract before a fresh idempotency claim or mutation. It never resolves mutable latest_version_id. · Points to a version for another parent item or silently tracks latest when historical replay needs exact version. content-itd-016-uniform-content-reference-contract
parent_content_kindTEXTyes Stored alpha.content_reference.parent_content_kind snapshot derived by the server; public clients cannot submit it. · extend · Alpha restriction over content_item.content_kind Content kind of the parent row for validation and renderer routing hints. Required on public reads. The server derives and stores it from the parent Content item; create/update clients must not submit it. · content_kind · Mismatched to parent_content_id, parsed from MIME type, or used to route to a kind-specific reference table. content-itd-016-uniform-content-reference-contract
referenced_content_idUUIDyes Physical alpha.content_reference.referenced_content_artifact_id FK; alpha.content_reference_view/repository renames it to referenced_content_id. · extend relationship · Alpha FK over QTI base identity The Content item being embedded, depended on, captioned, thumbnailed, or otherwise referenced. Required UUID. Must reference content_item(content_id) in the same workspace. · Missing, references another workspace, or stores a nested content object instead of an id. content-itd-016-uniform-content-reference-contract
referenced_version_idUUIDno Physical alpha.content_reference.referenced_content_version_id FK; alpha.content_reference_view/repository renames it to referenced_version_id. · extend relationship · Alpha FK over QTI base version identity Immutable exact referenced version row for render/export, including TimeBack import versions. Nullable for item-wide relationships. For bank_member writes, referenced_version_id is required and must be an exact version owned by referenced_content_id; omitted, explicit-null, or wrong-owner values return 409 content.invalid_test_bank_member_contract before a fresh idempotency claim or mutation. It never resolves mutable latest_version_id. · Points to a version for another referenced item or omitted when exact Common Cartridge round-trip requires it. content-itd-016-uniform-content-reference-contract
referenced_content_kindTEXTyes alpha.content_reference_view/repository projection; no referenced_content_kind column exists on alpha.content_reference. · derive · Alpha read projection over QTI base identity plus the Content kind sidecar Content kind of the referenced row. Required on public reads and equal to the resolved referenced Content item kind. The server derives it; create/update clients must not submit it. · content_kind · Stored as a relationship-table column, accepted from a client write, mismatched to referenced_content_id, parsed from file extension, or used to create media-only reference columns. content-itd-016-uniform-content-reference-contract
relationship_kindTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Plain role the referenced content plays for the parent content. Required governed enum. Set at write/import time and never inferred from path, filename, MIME type, or URL. · content_reference_relationship_kind · Free-form text, parsed from a package folder, or used to store Curriculum sequencing. content-itd-016-uniform-content-reference-contract
display_orderINTEGERno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Optional order among references for the same parent content and relationship kind. Nullable exact PostgreSQL int4 from 0 through 2147483647. Numeric strings, fractions, unsafe JavaScript integers, and out-of-range values are rejected rather than coerced. Applies only inside this parent content's reference set. · Used as course sequence order, supplied as a numeric string/fraction/unsafe integer, or outside 0..2147483647. content-itd-016-uniform-content-reference-contract
form_indexINTEGERno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Deterministic order of a fixed-form member or PP100 adaptive shard inside a test_bank. Required exact PostgreSQL int4 from 1 through 2147483647 when relationship_kind='bank_member'; null for every other relationship_kind. Numeric strings, fractions, unsafe JavaScript integers, conflicting form_index/formIndex aliases, and out-of-range values are rejected rather than coerced. The lowest-index unseen form is the equivalent-form retry candidate for Curriculum. · Null on bank_member, populated on non-bank relationships, duplicated inside one bank, supplied through conflicting aliases, outside 1..2147483647, or used as Curriculum course sequence order. content-itd-020-test-spec-and-test-bank
usage_scopeTEXTyes Alpha extension/config column in alpha.content_reference; no 1EdTech source field is copied here. · extend · Alpha Content relationship exposure-control extension Exposure scope for this Content-to-Content relationship row. Required governed enum. Defaults to practice_eligible. For bank_member rows, next-form and practice routing must exclude held_out_canary and secure_form members even when the referenced form is otherwise published. · usage_scope · Null, free-form text, stored only as a catalog tag, or ignored when routing through bank_member rows. content-itd-020-test-spec-and-test-bank
referenced_usage_scopeTEXTyes Public alpha.content_reference_view projection from referenced alpha.content_item_extension.usage_scope; not separately stored on content_reference. · derive · Alpha public read projection Exposure scope of the referenced content item, repeated on read rows for routing safety. Required on public reads. Routine routing may select a bank_member only when both usage_scope and referenced_usage_scope are practice_eligible. · usage_scope · Persisted as a stale copy instead of derived from the referenced content item, or ignored during next-form/practice filtering. content-itd-020-test-spec-and-test-bank
created_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When this relationship was created by authoring/import. Required timestamp with time zone. · Used as a student interaction timestamp. content-itd-016-uniform-content-reference-contract, content-axis-007-eventing-model
retired_atTIMESTAMPTZno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When this relationship stopped being active for new renders. Nullable. Historical renders/exports may still cite retired rows. · Hard-deletes the relationship while Events, Results, or exports still depend on it. content-itd-016-uniform-content-reference-contract, content-axis-011-privacy-retention

public read view · Content. Belongs here because it describes the blank place a student can answer; the student's actual answer lives in Events or Results.

answer_slot — Answer Slot

QTI response declaration exposed in plain language.

Primary keyanswer_slot_id
Backing storealpha.answer_slot_view over qti.variable_declaration where variable_kind='response'.
Storage gateNo Alpha answer_slot table. The view exposes blank response declarations only and never stores student answer values.
Source classAlpha public read view over qti.variable_declaration
LifecycleGenerated from QTI variable declarations when a content_version is projected. A full corrected question canonical_xml regenerates the declarations for the new version; a prompt-only question version carries the last canonical declarations forward unchanged under the new version identity. Exact version projections are never refreshed in place.

Purpose

Use answer_slot to know what responses a question or test expects without scanning QTI XML or treating student submissions as Content.

Relationships

  • Belongs to one content_version and content_item.
  • May have one answer_key row for authorized teacher/author reads.

Constraints

  • Only variable_kind='response' rows are public answer slots.
  • identifier, cardinality, and base_type preserve QTI semantics.
  • No student response values are stored here.

Invalid examples

  • A student selected choice stored as answer_slot.value.
  • A variable_kind='outcome' row exposed as a student answer slot.
  • Cardinality parsed from an interaction title.

Example

{
  "answer_slot_id": "0c6f5271-9d9e-4df1-8d5d-2ad59dacde66",
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "identifier": "RESPONSE",
  "cardinality": "single",
  "base_type": "identifier"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/answer-slots for the latest effective grading version
GET /tenants/{tenantId}/alpha/content/items/{contentId}/answer-slots?version_id={versionId} for immutable history

Fields (7)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
answer_slot_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.variable_declaration.variable_declaration_id Stable row identifier for one promoted variable declaration. Valid UUID and unique primary key. · Not a UUID or reused. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Content item that owns this answer slot. Must reference content_item(content_id). · References a Results attempt or another student's submission. content-itd-008-answer-slots-not-student-answers
version_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.variable_declaration.artifact_version_id Artifact version that declares the variable. Must reference qti.artifact_version(artifact_version_id). Cascades on version delete. · Missing version or mismatch with component_id artifact_version. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection, itd-011-artifact-versioning
identifierTEXTyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.variable_declaration.identifier QTI response variable identifier students submit against. Required text. Unique with artifact_version_id and variable_kind. · Blank, duplicated within kind/version, rewritten to UUID, or mismatched with processing operands. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection, itd-004-xml-authority
cardinalityTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.variable_declaration.cardinality How many values the answer slot can hold. Nullable only when the source declaration allows absence. When present, use QTI cardinality values such as single, multiple, ordered, or record. · qti_cardinality · Outside QTI cardinality vocabulary, inconsistent with associated interaction, or inconsistent with JSON value shape. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection, itd-021-runtime-profile
base_typeTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.variable_declaration.base_type Atomic QTI value type expected in this answer slot. Nullable for record variables or declarations where QTI permits no base-type. Values should be QTI base types such as boolean, directedPair, duration, file, float, identifier, integer, pair, point, string, or uri. · qti_base_type · Outside QTI base-type vocabulary, present for record in a way QTI forbids, or inconsistent with correct_response/default_value. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection, itd-021-runtime-profile
source_traceJSONByes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.variable_declaration.source_trace Generated trace back to the QTI declaration source. Required JSON object. No student response values or direct PII. · Null, non-object JSON, or not tied to the declaring component. content-itd-008-answer-slots-not-student-answers, itd-001-source-bundle, itd-007-provenance-labels

authorized public read view · Content. Belongs here because it is part of the blank instrument; access is teacher/author-only and it is never a student's submitted answer.

answer_key — Answer Key

Teacher-only correct response and mapping for an answer slot.

Primary keyanswer_slot_id
Backing storealpha.answer_key_view over qti.variable_declaration.correct_response/mapping for authorized scopes.
Storage gateNo Alpha answer_key table. Correct response and mapping remain QTI fields and are exposed only through authorized views; student answers stay in Events/Results.
Source classAlpha authorized read view over qti.variable_declaration
LifecycleGenerated from QTI correct_response and mapping projection for each immutable version. A full corrected question canonical_xml regenerates the key for the new version; a prompt-only question version carries the last canonical key forward unchanged under the new version identity. Exact version projections are never refreshed in place.

Purpose

Use answer_key to inspect what the blank question expects. Choice identifiers and text-entry string answers both stay in correct_response.values. Results owns whether a specific student was correct.

Relationships

  • One-to-one with answer_slot when a correct response exists.
  • Belongs to content_version through the answer_slot.

Constraints

  • Requires read:answer_key scope.
  • Never included in student_view.
  • correct_response JSON shape must match answer_slot.cardinality and base_type.
  • For textEntryInteraction answer slots with base_type string, each accepted string answer appears as one exact correct_response.values entry.

Invalid examples

  • Answer keys returned to a student-safe content read.
  • correct_response used as a student's answer.
  • Values coerced from identifiers to display text.

Example

{
  "answer_slot_id": "0c6f5271-9d9e-4df1-8d5d-2ad59dacde66",
  "correct_response": {
    "values": [
      "choiceA"
    ]
  },
  "required_scope": "read:answer_key"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/answer-keys with scope read:answer_key for the latest effective grading version
GET /tenants/{tenantId}/alpha/content/items/{contentId}/answer-keys?version_id={versionId} with scope read:answer_key for immutable history

Fields (4)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
answer_slot_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Answer slot this key belongs to. Must reference answer_slot(answer_slot_id). · References a missing slot or a slot from another version. content-itd-008-answer-slots-not-student-answers
correct_responseJSONBno Public view column over QTI base storage; no Alpha storage. · restrict · Alpha restrict from qti.variable_declaration.correct_response Correct response values for this blank answer slot, including identifier values for choice interactions and string values for textEntryInteraction. Nullable when the item has no declared correct response. Requires read:answer_key. Shape must match cardinality/base_type exactly; textEntryInteraction with base_type string stores exact accepted strings in correct_response.values. · Correct response values are coerced, ordered values are stored as unordered, value type conflicts with base_type, or a templated correct response is realized by the client instead of the server. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection, itd-021-runtime-profile, itd-031-item-templates
mappingJSONBno Public view column over QTI base storage; no Alpha storage. · restrict · Alpha restrict from qti.variable_declaration.mapping QTI mapping details needed to understand scoring for this slot. Nullable. Requires read:answer_key when mapping reveals correct-answer behavior. · Drops default mapping value, loses area coordinates, changes scoring numeric precision, or omits source trace. content-itd-008-answer-slots-not-student-answers, itd-013-variable-projection, itd-021-runtime-profile
required_scopeTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Minimum OAuth/JWT scope required to read this row through public Content APIs. Always read:answer_key unless a stricter admin policy applies. · Missing, weaker than read:answer_key, or used to grant student access. content-axis-006-auth-shape

public read view · Content. Belongs here because it describes the blank test or question structure before any student attempt exists.

assessment_component — Assessment Component

Sections, parts, choices, rubrics, and pre-authored feedback from the QTI component tree.

Primary keyassessment_component_id
Backing storealpha.assessment_component_view over qti.component.
Storage gateNo Alpha assessment_component table. QTI component rows remain the source; Content exposes only the blank assessment structure needed by renderers, authors, and migration auditors.
Source classAlpha public read view over qti.component
LifecycleGenerated from QTI component rows for each immutable content version. A full corrected question canonical_xml regenerates the component tree for the new version; a prompt-only question version carries the last canonical structure forward unchanged under the new version identity. Exact version projections are never refreshed in place.

Purpose

Use assessment_component to inspect how a blank assessment is assembled: sections, parts/interactions, question references, distractors, rubrics, and pre-authored feedback. Results owns the student's responses, scores, AI grading, and feedback after an attempt.

Relationships

  • Belongs to one content_version and content_item.
  • May point to a parent assessment_component for section/part/choice hierarchy.
  • Works alongside answer_slot, answer_key, and scoring_plan; it does not replace them.

Constraints

  • component_role must be one of the published assessment_component_role values.
  • Only blank-instrument structure belongs here.
  • Distractors are authored choices, not a record of what a student selected.
  • Rubrics and feedback are authored instrument text, not AI grading audit logs.

Invalid examples

  • A student's selected distractor stored as an assessment_component.
  • AI-generated feedback from a completed attempt stored as preauthored_feedback.
  • A section title parsed from display text instead of read from the QTI component row.

Example

{
  "assessment_component_id": "51ef0fdf-7ebf-4cc7-9242-45432b04ad4f",
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "parent_assessment_component_id": "3f2bf843-b8d7-49d0-b4d1-17dbb3152c43",
  "component_role": "distractor",
  "ordinal": 1,
  "element_name": "qti-simple-choice",
  "qti_identifier": "choiceA",
  "response_identifier": "RESPONSE",
  "display_text": "x = 4"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/assessment-components for the latest effective grading version
GET /tenants/{tenantId}/alpha/content/items/{contentId}/assessment-components?version_id={versionId} for immutable history
GET /tenants/{tenantId}/alpha/content/items/{contentId}/assessment-components?component_role=rubric

Fields (14)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
assessment_component_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.component_id Stable identifier for one generated object node row. Valid UUID and unique primary key. · Not a UUID or reused. content-itd-008-answer-slots-not-student-answers, itd-005-relational-projection
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Content item that owns this assessment component. Must reference content_item(content_id). · References a student attempt, result, class, course, or event instead of blank content. content-itd-008-answer-slots-not-student-answers
version_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.artifact_version_id Artifact version containing this component. Must reference qti.artifact_version(artifact_version_id). Cascades on version delete. · Missing version or cross-artifact projection. content-itd-008-answer-slots-not-student-answers, itd-005-relational-projection, itd-011-artifact-versioning
parent_assessment_component_idUUIDno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.parent_component_id Parent object node, preserving the XML/object hierarchy. Nullable for root node. If present, references qti.component(component_id) and cascades on parent delete. · Parent is in a different artifact_version, creates a cycle, or is missing for non-root nodes. content-itd-008-answer-slots-not-student-answers, itd-005-relational-projection
component_roleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension School-language role for this QTI component row. Must be one of assessment_component_role. · assessment_component_role · Inferred from title text, used to store student response type, or left as a raw QTI element name when a governed role exists. content-itd-008-answer-slots-not-student-answers
ordinalINTEGERyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.ordinal Order within the parent component. Required integer. Use zero-based or one-based consistently in the repository; order must be stable for XML canonicalization. · Null, negative by repository convention, duplicated among siblings without deterministic tie-break, or changed after hashing. content-itd-008-answer-slots-not-student-answers, itd-005-relational-projection, itd-004-xml-authority
element_nameTEXTyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.element_name Original QTI element name used to produce the role. Required text. Must match the generated object node and source XML; deferring runtime navigation, PNP selection, PCI execution, or Caliper event emission does not permit dropping or renaming the source element. · Unknown to the generated model, mismatched with qualified_name, rewritten to an Alpha name, or omitted because the platform delegates that construct's runtime behavior. content-itd-008-answer-slots-not-student-answers, itd-002-generated-object-model, itd-005-relational-projection, itd-028-test-navigation, itd-029-catalog-pnp, itd-030-portable-custom-interaction, itd-031-item-templates, itd-032-results-reporting
qti_identifierTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.qti_identifier QTI identifier for this component, when present. Nullable. Preserve source value; identifier scope is QTI-defined and not always global. · Invented, coerced to UUID, or assumed globally unique across artifacts. content-itd-008-answer-slots-not-student-answers, itd-004-xml-authority, itd-007-provenance-labels
response_identifierTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension QTI response variable identifier this interaction, choice, or feedback refers to. Nullable. Must match an answer_slot.identifier when present. · Used as a student answer value. content-itd-008-answer-slots-not-student-answers
outcome_identifierTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension QTI outcome variable identifier referenced by a feedback component. Nullable. Blank-instrument reference only. · Used to store a student's computed outcome value. content-itd-008-answer-slots-not-student-answers
feedback_identifierTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Identifier for a pre-authored feedback block. Nullable. Applies primarily to preauthored_feedback rows. · Used for post-attempt AI feedback or human override audit. content-itd-008-answer-slots-not-student-answers
show_hideTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension QTI show/hide behavior for a feedback component. Nullable; must preserve QTI behavior when present. · Used as an authorization decision. content-itd-008-answer-slots-not-student-answers
display_textTEXTno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.text_value Author-visible text carried by the component, such as a choice, rubric line, or feedback text. Nullable text. Preserve source text needed for canonical XML round trip. · Dropped for mixed content, normalized in a way that changes semantics, or used to store learner responses. content-itd-008-answer-slots-not-student-answers, itd-004-xml-authority, itd-005-relational-projection
source_traceJSONByes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.component.source_trace Generated trace back to the QTI component source. Required JSON object. No student response values or direct PII. · Null, non-object JSON, live-only link, not aligned with element_name/type_name, or missing evidence for a preserved navigation, PNP, PCI, template, result, or usage-data node. content-itd-008-answer-slots-not-student-answers, itd-001-source-bundle, itd-007-provenance-labels, itd-028-test-navigation, itd-029-catalog-pnp, itd-030-portable-custom-interaction, itd-031-item-templates, itd-032-results-reporting

public read view · Content. Belongs here because it documents how the blank instrument will be scored; actual scored outcomes live in Results.

scoring_plan — Scoring Plan

QTI processing provenance for scoring a content version.

Primary keyscoring_plan_id
Backing storealpha.scoring_plan_view over qti.processing_rule.
Storage gateNo Alpha scoring_plan table. Processing rules, operands, and source_trace remain QTI fields; Content exposes blank scoring provenance only.
Source classAlpha public read view over qti.processing_rule
LifecycleGenerated from QTI processing projection when a content_version is created. A full corrected question canonical_xml regenerates the processing projection for the new version; a prompt-only question version carries the last canonical scoring plan forward unchanged under the new version identity.

Purpose

Use scoring_plan to inspect processing rules and operands without confusing the plan with a student's processed result.

Relationships

  • Belongs to one content_version and content_item.
  • May reference answer_slot identifiers through operands.

Constraints

  • Only blank-instrument scoring provenance belongs here.
  • No outcome_state, processing_trace for a student, or gradebook rollup is stored here.
  • rule_scope must use the governed processing scope.

Invalid examples

  • A student's SCORE value stored on scoring_plan.
  • Processing trace from a live attempt exposed through Content.
  • rule_name rewritten into school-language text that cannot round-trip to QTI.

Example

{
  "scoring_plan_id": "74b1c279-e85f-407e-971e-16408ad792c0",
  "version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "rule_scope": "response",
  "rule_name": "qti-map-response",
  "sequence_number": 10
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/scoring-plan for the latest effective grading version
GET /tenants/{tenantId}/alpha/content/items/{contentId}/scoring-plan?version_id={versionId} for immutable history

Fields (9)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
scoring_plan_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.processing_rule_id Stable row identifier for one promoted processing rule or expression node. Valid UUID and unique primary key. · Not a UUID or reused. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Content item this scoring plan belongs to. Must reference content_item(content_id). · References a student attempt or result instead of blank content. content-itd-008-answer-slots-not-student-answers
version_idUUIDyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.artifact_version_id Artifact version containing the processing rule. Must reference qti.artifact_version(artifact_version_id). Cascades on version delete. · Missing version or mismatch with component_id artifact_version. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection, itd-011-artifact-versioning
parent_scoring_plan_idUUIDno Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.parent_processing_rule_id Parent processing rule for nested expression and rule trees. Nullable for root rules. If present, references qti.processing_rule(processing_rule_id). Cascades on parent delete. · Parent is in another artifact_version, creates a cycle, or changes execution semantics. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection
rule_scopeTEXTyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.rule_scope Processing scope used for query and execution grouping. Must satisfy processing_rule_scope_ck. · scoring_rule_scope · Outside enum set, used to claim QTI defines this SQL row scope, or stores qti-template-processing under response/outcome scope. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection, itd-031-item-templates
rule_nameTEXTyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.rule_name Original QTI processing rule or expression name. Required QTI element/operator name. Do not rename this value because it is needed for faithful processing provenance. · Not a QTI processing/expression element, renamed for Alpha, mismatched with component.element_name, or drops template-processing rules because realization is server-side. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection, itd-021-runtime-profile, itd-031-item-templates
sequence_numberINTEGERyes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.sequence_number Order within the scoring plan scope. Required integer. Must preserve QTI processing order and be stable across rehydration. · Null, order differs from object graph, or ties cause nondeterministic execution. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection, itd-021-runtime-profile
operandsJSONByes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.operands Generated operand references and literals used by the scoring plan. Required JSON array. Must preserve variable references and literal values. Must not include direct learner identity. · Null, non-array JSON, points to undeclared variables, loses numeric precision, loses template-variable operands, or contains unredacted learner identity. content-itd-008-answer-slots-not-student-answers, itd-014-processing-projection, itd-021-runtime-profile, itd-031-item-templates
source_traceJSONByes Public view column over QTI base storage; no Alpha storage. · rename · Alpha rename from qti.processing_rule.source_trace Generated trace back to the QTI processing source. Required JSON object and reproducible from the source bundle. · Null, non-object JSON, or not tied to the rule_name/component. content-itd-008-answer-slots-not-student-answers, itd-001-source-bundle, itd-007-provenance-labels

Results-owned public read dependency · Content documents this read contract because apps display it beside Content, but Results owns the storage, recomputation, and public alpha.content_effectiveness view.

content_effectiveness — Content Effectiveness

Results-owned derived effectiveness read for one content item.

Primary keycontent_id
Backing storeResults Alpha owns alpha.content_effectiveness_extension and publishes alpha.content_effectiveness(tenant_id, object_id, data jsonb). Content never creates, migrates, writes, or backfills the canonical alpha.content_effectiveness object.
Storage gateRaw DB readers filter tenant_id and data ->> 'content_id'. They must not query a top-level content_id column, because the public Results view exposes tenant_id, object_id, and data JSONB. Content migrations must not CREATE TABLE alpha.content_effectiveness, CREATE VIEW alpha.content_effectiveness_view, insert rows, increment counters, or store raw Results/student-answer payloads.
Source classResults-owned Alpha public view read by Content
LifecycleRecomputed by the Results surface after settled result evidence changes. Content reads the Results-owned public view and returns a safe insufficient_data fallback when no Results evidence exists. Apps never insert, increment, or manually repair these values.

Purpose

Use content_effectiveness to see whether content helped students validate or fail later outcomes without making apps maintain counters.

Relationships

  • The Content endpoint aggregates Results-owned rows by content_id and returns exactly the seven fields in publicApiProjection.
  • The raw Results view may carry content_version_id, kc_id, subject_id, evidence_count, policy_version, and source_result_refs; those fields are inputs to aggregation/provenance and are not top-level Content endpoint members.

Constraints

  • Read-only to Content and to consumers; Results is the only writer/recompute owner.
  • Raw DB contract: alpha.content_effectiveness has top-level tenant_id, object_id, and data JSONB. Fields marked Results raw view only are projected from data JSON and are not top-level members of GET /items/{contentId}/effectiveness.
  • Content API contract: GET /items/{contentId}/effectiveness returns exactly content_id, validated_by_count, failed_by_count, effectiveness_rate, freshness_status, last_recomputed_at, and provenance.
  • validated_by_count and failed_by_count are non-negative integers.
  • effectiveness_rate is null until policy says enough data exists; otherwise 0.0000 through 1.0000.
  • freshness_status is the Content response status derived from Results view presence/freshness and fallback policy; it is not a client-maintained field.

Invalid examples

  • An app increments validated_by_count after a quiz.
  • A dashboard recomputes effectiveness_rate from raw Results.
  • A Content migration creates alpha.content_effectiveness or alpha.content_effectiveness_view.
  • A raw query filters alpha.content_effectiveness.content_id instead of data ->> 'content_id'.
  • Mastery state stored here.

Example

{
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "validated_by_count": 42,
  "failed_by_count": 8,
  "effectiveness_rate": 0.84,
  "freshness_status": "fresh",
  "last_recomputed_at": "2026-06-03T18:22:00Z",
  "provenance": {
    "sourceModule": "results",
    "policy": "alpha.policy.content_effectiveness.v1",
    "resultCount": 50
  }
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/effectiveness
SELECT data ->> 'content_id', (data ->> 'validated_by_count')::int, (data ->> 'effectiveness_rate')::numeric FROM alpha.content_effectiveness WHERE tenant_id = :tenant_id AND data ->> 'content_id' = :content_id

Fields (13)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idTEXT / UUID-shapedyes No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Content item whose effectiveness is summarized. Projected from alpha.content_effectiveness.data ->> 'content_id'. Must resolve to content_item(content_id). Raw DB readers must not expect alpha.content_effectiveness.content_id as a top-level column. · References missing content or a student id. content-itd-009-content-effectiveness-derived-rollup
content_version_idTEXT / UUID-shapedno No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Raw Results row dimension for an exact content version; not returned as a top-level Content effectiveness field. Projected from data ->> 'content_version_id'. Nullable for item-level raw rows. The Content endpoint aggregates by content_id and omits this member. · Points to a different content item or is used as mutable latest-version state. content-itd-009-content-effectiveness-derived-rollup
kc_idTEXTno No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Raw Results row KC dimension when evidence is tied to one KC; not returned as a top-level Content effectiveness field. Projected from data ->> 'kc_id'. Nullable for content-wide raw rows. The Content endpoint aggregates by content_id and omits this member; it never stores student mastery. · Stores a student's mastery state, or points to a free-form topic tag instead of a Curriculum KC. content-itd-009-content-effectiveness-derived-rollup
subject_idTEXTno No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Raw Results row subject dimension; not returned as a top-level Content effectiveness field. Projected from data ->> 'subject_id'. Must use the governed subject registry when present. The current Content endpoint omits this member. · alpha_subject_id · Parsed from a title, mixed with display labels, or used as an NWEA account boundary. content-itd-009-content-effectiveness-derived-rollup
validated_by_countINTEGERyes No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Number of eligible Results records where the content was followed by validated student success. Projected from (data ->> 'validated_by_count')::integer. Read-only non-negative integer. Eligibility and window policy live under alpha.policy.content_effectiveness. · Negative, manually incremented by an app, or computed with a dashboard-specific policy. content-itd-009-content-effectiveness-derived-rollup
failed_by_countINTEGERyes No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Number of eligible Results records where the content was followed by failed or unvalidated outcomes. Projected from (data ->> 'failed_by_count')::integer. Read-only non-negative integer. Same eligibility policy as validated_by_count. · Negative, manually maintained, or includes Events that never became Results. content-itd-009-content-effectiveness-derived-rollup
effectiveness_rateNUMERIC(6,4)no No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection validated_by_count divided by eligible validated+failed count after policy guards. Projected from (data ->> 'effectiveness_rate')::numeric. Nullable until sufficient data. When present, range 0.0000 through 1.0000. Read-only. · Outside 0..1, computed by a consumer, or published before minimum sample policy is met. content-itd-009-content-effectiveness-derived-rollup
evidence_countINTEGERyes No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Raw Results evidence count; Content may summarize it inside provenance but does not return evidence_count as a top-level field. Projected from (data ->> 'evidence_count')::integer. Usually validated_by_count + failed_by_count after policy filters. Read-only and omitted from the top-level Content response. · Negative, consumer-maintained, or inconsistent with the named policy's eligible evidence. content-itd-009-content-effectiveness-derived-rollup
freshness_statusTEXTyes No Content storage. Not a client-writable field. · read dependency · Content response projection over Results-owned read Whether the materialized effectiveness read is current enough for display. Required governed enum in the Content response. When the Results-owned view is absent for the content item, Content returns insufficient_data with zero counts and null rate rather than inserting a placeholder row. · effectiveness_status · Used as a content publication status or set by consumers. content-itd-009-content-effectiveness-derived-rollup
last_recomputed_atTIMESTAMPTZno No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection When the surface last recomputed the derived rollup. Projected from data ->> 'last_recomputed_at'. Nullable before first computation or when Content returns the insufficient_data fallback. Must update after successful Results recomputation. · Consumer-written or newer than the provenance evidence it claims to include. content-itd-009-content-effectiveness-derived-rollup, content-axis-007-eventing-model
policy_versionTEXTyes No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Raw Results policy version used for recomputation; Content may include it inside provenance but does not return policy_version as a top-level field. Projected from data ->> 'policy_version'. Must name an alpha.policy.content_effectiveness entry. Omitted from the top-level Content response. · Missing, app-defined, or used to hide locally copied thresholds. content-itd-009-content-effectiveness-derived-rollup
source_result_refsJSONByes No Content storage. Results-owned alpha.content_effectiveness public view data JSON field. · read dependency · Results-owned public view projection Opaque Results evidence references included in the raw recomputation row; not a top-level Content effectiveness field. Projected from data -> 'source_result_refs'. Required JSON array on the raw Results row. Content exposes only a governed provenance object; raw student responses and copied result payloads remain forbidden. · Contains raw answers, direct student PII, secrets, or copied result payloads. content-itd-009-content-effectiveness-derived-rollup
provenanceJSONByes No Content storage. Derived response object from the Results-owned read and fallback rule. · read dependency · Content response projection over Results-owned read Content response evidence object that names Results as the source module and includes policy/evidence pointers. Required JSON object in the Content response. May contain opaque Results ids and policy version, but not raw student answer payloads or student credentials. When no row exists, Content returns provenance.sourceModule='results' with insufficient_data. · Contains student responses, PII beyond allowed opaque ids, or enough copied Results data to become a second record. content-itd-009-content-effectiveness-derived-rollup

Alpha extension table · Content. Belongs here because it is validation and provenance evidence for a blank content item; it is not a conformance job runner or a learner event.

content_trust_evidence — Content Trust Evidence

Read-only trust status and validation provenance for Content.

Primary keycontent_id
Backing storealpha.content_trust_evidence supplies the item-level revocation state; internal append-only alpha.content_version_qc_receipt preserves exact-version QC provenance written by Content-owned import/publication.
Storage gateStores only item revocation state plus exact-version server-owned QC receipts, safe evidence references, timestamps, problem codes, and FKs. It must not store caller verdicts, package bytes, signed secrets, raw tokens, or copied QTI conformance rows.
Source classAlpha Content trust/provenance extension table
LifecycleThe item summary is created or refreshed by Content-owned import/publication. Each passing exact version gets one append-only internal provenance receipt; ordinary public callers can read the summary but cannot create a receipt, submit a verdict, or trigger a generic conformance job.

Purpose

Use content_trust_evidence to read the compatible item-level validation summary and emergency revocation state. trust_status=failed is the single post-visibility revocation lever; positive trust and the internal append-only QC receipts written by QTI import or governed publication are recorded provenance, never release preconditions (owner ruling #2534: approval never gates student visibility).

Relationships

  • One-to-one with content_item.
  • Internal content_version_qc_receipt has one row per exact immutable version that passed a Content-owned QC path.

Constraints

  • Read-only to ordinary consumers.
  • Public evidence must redact package bytes, secrets, tokens, and direct student PII.
  • trust_status is not publication status; a published item can become degraded or failed.
  • Positive trust and append-only version receipts are recorded provenance; release never waits for them. trust_status=failed fails every version closed on the next read (owner ruling #2534).
  • Only Content-owned QTI import or governed spec, bank, or article publication writes a version receipt. No caller verdict, producer attestation, or generic trust mutation participates.

Invalid examples

  • A public route that starts a conformance run.
  • trust_status used to hide a retired content item.
  • Problem detail includes raw package bytes.

Example

{
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "trust_status": "trusted",
  "evidence_url": "https://platform3-andymontgomery-9773s-projects.vercel.app/qti/1edtech/surface_qc/",
  "checked_at": "2026-06-03T18:20:00Z"
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/trust

Fields (5)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Content item whose trust evidence is summarized. Must reference content_item(content_id). · References a missing content item or a Results record. content-axis-010-conformance-evidence
trust_statusTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Current validation or conformance state for this content item. Required governed enum. Derived from QTI conformance/surface QC or Content validation. · trust_status · Set by a consumer, used as content lifecycle status, or left trusted after validation fails. content-axis-010-conformance-evidence
evidence_urlTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable URL or opaque reference to the evidence behind trust_status. Nullable when status is unknown. Must be safe to show to authorized content readers and must not include secrets. · Contains signed secrets, points to a mutable local file, or starts a job when fetched. content-axis-010-conformance-evidence
checked_atTIMESTAMPTZno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When trust evidence was last checked or refreshed. Nullable before first validation. Required when trust_status is trusted, degraded, or failed. · Missing for a trusted status or newer than the referenced evidence. content-axis-010-conformance-evidence
problem_codeTEXTno Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable Content problem code when trust_status is degraded or failed. Nullable for trusted/unknown states. When populated, use the Content problem code enum. · problem_code · Free-form error text only, leaked raw package data, or code not stable across releases. content-itd-012-plain-language-problems-and-provenance, content-axis-008-error-envelope

module-local policy table/view plus bundled source-adapter policy · Content. Belongs here only for Content-specific policy names and values; cross-student outcome formulas stay in Results or platform policy.

content_policy — Content Policy

Current Content policy projection, including module-local rows and the bundled versioned source-adapter policy.

Primary keypolicy_key
Backing storeCurrent runtime stores tenant-visible rows in alpha.content_policy / alpha.content_policy_view and loads the TimeBack source-adapter policy from the versioned bundled content-source-adapter-policy.json resource at module startup.
Storage gateContent policy values are named config, not content rows and not client constants. Current source-adapter execution uses the bundled versioned resource; migration to a shared alpha.policy authority is a target, not a current claim. Secrets and student credentials are forbidden.
Source classCurrent module-local policy projection plus bundled versioned implementation resource
LifecycleCurrent demo/reviewer policy rows are seeded into the module-local table and the source-adapter policy is versioned with the implementation bundle. Shared operational provisioning and request-time lookup are pending.

Purpose

Use content_policy to inspect policy metadata the Content surface exposes. Current TimeBack import behavior is governed by the bundled content-source-adapter-policy.json resource loaded by the implementation; it does not dynamically read alpha.content_policy. Consumers must not copy magic numbers or source-kind mappings into dashboards or skill packs.

Relationships

  • Referenced by content_effectiveness.provenance.
  • The bundled content-source-adapter-policy.json resource, not a request-time database lookup, is referenced by the TimeBack production import adapter for processed-facts and resources content_kind folding plus expected_xp calibration.
  • Does not own Results formulas, K-8 advancement, tenure buckets, or NWEA norms policy.

Constraints

  • policy_key starts with alpha.policy.content.
  • value_json must be typed and versioned where a policy row exists; clients must not duplicate policy numbers.
  • alpha.policy.content.expected_xp_band declares bands 0_to_10, 10_to_20, 20_to_45, and 45_plus with thresholds, legacy aliases, and numeric range filter aliases.
  • The bundled alpha.policy.content.source_adapter resource declares TimeBack production processed-facts recognition, raw resources identity fields, specific content-kind text mappings, an interactive fallback for otherwise opaque application-backed resources, duration-to-XP calibration, and per-content-kind expected_xp fallbacks. This is the Content half of Curriculum's course_components -> component_resources -> resources reconcile; the adapter response returns source_record_id with normalized content_id/content_kind/expected_xp for the Curriculum import to consume.
  • Secrets are never policy values.

Invalid examples

  • A dashboard hardcodes minimum effectiveness sample size.
  • NWEA Growth X target stored in Content policy.
  • A student app credential stored as policy JSON.

Example

{
  "policy_key": "alpha.policy.content.source_adapter.v2026-07-15",
  "value_json": {
    "resources": {
      "source_identity_fields": [
        "sourced_id",
        "vendor_resource_id"
      ],
      "fallback_content_kind": "interactive"
    },
    "processed_facts": {
      "content_kind": "interactive"
    },
    "expected_xp": {
      "seconds_to_xp": {
        "divisor": 8,
        "round": "nearest_integer",
        "min": 1,
        "max": 90
      },
      "defaults_by_content_kind": {
        "interactive": 15,
        "article": 8,
        "test": 25
      }
    }
  },
  "policy_version": "2026-07-15.1"
}

Queries

GET /tenants/{tenantId}/alpha/content/policies

Fields (4)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
policy_keyTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Named Content policy setting. Required text beginning alpha.policy.content or alpha.policy.content_effectiveness; source-adapter policy keys are versioned as alpha.policy.content.source_adapter.*. · Free-form label, copied dashboard key, secret name, or policy owned by Results/NWEAMap. content-itd-009-content-effectiveness-derived-rollup
value_jsonJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Typed policy value for the named setting. Required JSON object. Schema depends on policy_key and must be documented in policy metadata. For alpha.policy.content.source_adapter, value_json includes processed_facts recognition, raw TimeBack resources identity and fallback behavior, content_kind mappings, duration conversion, and per-kind expected_xp defaults. · Raw number with no key/schema, secret value, or unversioned policy that changes historical rollups. content-itd-009-content-effectiveness-derived-rollup
policy_versionTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Version label cited by derived reads that used this policy. Required stable version string. Must change when value_json changes semantically. · Missing, reused after a semantic policy change, or not cited in content_effectiveness provenance. content-itd-009-content-effectiveness-derived-rollup
updated_atTIMESTAMPTZyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension When this policy value was last updated. Required timestamp with time zone. · Null or used instead of policy_version for historical reproducibility. content-itd-009-content-effectiveness-derived-rollup

derived public read · Content owns the single exact-version lifecycle and item-revocation answer consumed by Curriculum, Incept, gates, and launch surfaces.

content_release_eligibility — Content Release Eligibility

Current lifecycle and item-revocation answer for one exact Content version.

Primary keycontent_id + content_version_id
Backing storeRuntime projection over the exact qti.artifact_version and its owning Content item lifecycle/item revocation state.
Storage gateStores nothing. Computes release_eligible exactly equal to serveable on every read.
Source classAlpha Content derived public read
LifecycleRecomputed on every read. A published unretired item is eligible for its exact versions unless item trust is the failed revocation state (owner ruling #2534: approval/QC signals never gate visibility). Draft, retirement, or failed item trust makes it ineligible immediately.

Purpose

Return one exact immutable Content version identity, its kind and usage scope, and a fail-closed answer where release_eligible always equals Content serveability.

Relationships

  • One answer per requested exact content_id/content_version_id.
  • content_kind and usage_scope are projected from the owning Content item.
  • trust_status is the current item-level trust state: failed for item revocation, trusted or degraded when positive evidence exists, otherwise unknown; unknown never blocks release.
  • producer_surface remains a validated compatibility query input but is not returned and does not select an eligibility lane.
  • release_eligible is exactly equal to serveable.
  • Curriculum retains the exact version reference and asks Content again at launch; it does not copy or recompute the verdict.

Constraints

  • The exact version must belong to the requested Content item in the caller tenant; a same-tenant mismatch is content.release_wrong_version and a cross-tenant or unknown version is content.not_found.
  • Every success repeats the requested content_id and content_version_id plus that item's governed content_kind and usage_scope; consumers must fail closed on any identity or kind mismatch.
  • serveable=true exactly when status is published, retired_at is null, and item trust is not failed; positive trust or a per-version QC receipt is never a precondition (owner ruling #2534).
  • release_eligible must always equal serveable.
  • Failed item trust is the all-version revocation lever and fails closed on the next read; per-version QC receipts are append-only provenance evidence and never gate the answer.
  • No producer release evidence, required quality-bar tuple, owner acceptance tuple, or version allowlist participates.
  • A non-serveable exact version fails closed as content.version_not_serveable.
  • Routine Curriculum launch and next-form routing additionally require usage_scope=practice_eligible.

Invalid examples

  • A published version is hidden while waiting for a QC receipt, producer sign-off, or any other positive approval signal.
  • A published trusted version waits for a producer evidence append.
  • An owner allowlist makes a draft, retired, or failed-trust version eligible.
  • release_eligible differs from serveable.
  • A consumer copies the verdict instead of reading the exact version at launch.

Example

{
  "content_id": "58612cab-9c46-426c-8c20-0e9f19c807c5",
  "content_version_id": "efcf3561-3a66-4825-9588-e792ef20c312",
  "content_kind": "question",
  "usage_scope": "practice_eligible",
  "trust_status": "trusted",
  "serveable": true,
  "release_eligible": true,
  "problem_code": null
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions/{versionId}/release-eligibility?producer_surface=incept%2Falpha

Public API fields (8)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Derived from qti.artifact.artifact_id; the view stores nothing. · extend · Alpha derived read Content item identity for this exact-version answer. Tenant-scoped and paired with content_version_id. · Version belongs to another item. content-itd-023-trust-based-release-eligibility
content_version_idUUIDyes Derived from qti.artifact_version.artifact_version_id; the view stores nothing. · extend · Alpha derived read Exact immutable Content version evaluated. Never replaced by latest_version_id or an unversioned item reference. · Null or a mutable latest pointer. content-itd-023-trust-based-release-eligibility
content_kindTEXTyes Derived from alpha.content_item_extension.content_kind_override or the restricted qti.artifact.artifact_kind mapping; the release view stores nothing. · restrict + extend · Alpha derived read Governed Content kind owned by the item containing this exact version. Required governed content_kind enum and must match the caller's typed exact-version target; consumers fail closed rather than coercing or inferring a different kind. · content_kind · Missing, outside the governed enum, inferred from a title or renderer, or different from the requested target kind. content-itd-023-trust-based-release-eligibility
usage_scopeTEXTyes Derived from alpha.content_item_extension.usage_scope with its practice_eligible default; the release view stores nothing. · extend · Alpha derived read Current Content-owned routing exposure scope for the item containing this exact version. Required governed usage_scope enum. Routine instruction, next-task, and next-form consumers require practice_eligible; held_out_canary and secure_form remain explicit non-routine scopes even when release_eligible is true. · usage_scope · Missing, free-form, inferred from assessment labels, or treated as permission for routine routing when held_out_canary or secure_form. content-itd-023-trust-based-release-eligibility
trust_statusTEXTyes Derived from current alpha.content_trust_evidence for the owning item; the release answer stores nothing. · extend · Alpha derived read Current item-level trust state for the owning Content item: failed is the revocation kill switch; trusted/degraded record positive evidence; unknown means no verdict is recorded and never blocks. Required governed trust_status enum. Only failed makes a published unretired version non-serveable; trusted, degraded, unknown, and missing trust all serve (owner ruling #2534). · trust_status · Missing, copied from a producer, or inconsistent with the current item revocation state. content-itd-023-trust-based-release-eligibility
serveableBOOLEANyes Computed on read from Content item lifecycle and current content_trust_evidence. · extend · Alpha derived read Content-owned lifecycle and revocation verdict for this exact version. True exactly when status=published, retired_at is null, and item trust is not failed (owner ruling #2534). · True for a draft, retired, or failed-trust version, or false merely because no positive QC verdict or receipt was recorded. content-itd-023-trust-based-release-eligibility
release_eligibleBOOLEANyes Computed on read as release_eligible = serveable; never stored. · extend · Alpha derived read Exact alias of serveable for release routing. Must always equal serveable. No producer evidence, quality-bar tuple, or owner allowlist participates. · Different from serveable or dependent on a second attestation. content-itd-023-trust-based-release-eligibility
problem_codeTEXTno Computed on read from the same lifecycle and item-revocation predicate. · extend · Alpha derived read Stable fail-closed Content problem code for an ineligible exact version. Null when serveable; otherwise content.version_not_serveable. · problem_code · A removed release-evidence or quality-bar problem code is emitted. content-itd-023-trust-based-release-eligibility

virtual field dictionary · Content. Belongs here as the Content-specific field dictionary for the inherited platform RFC 7807 error envelope.

content_problem — Content Problem

Stable problem codes and field errors returned by Content APIs.

Primary keycode
Backing storeInherited platform RFC 7807 envelope plus Content problem-code registry.
Storage gateProblem rows are response shapes, not domain storage. Audit/idempotency may retain redacted copies under Platform policy.
Source classInherited platform problem envelope with Content codes
LifecycleReturned by API handlers. Stored only in audit/idempotency records where platform policy requires replay evidence.

Purpose

Use content_problem to implement clients that react to validation, stale-version, authorization, and relationship errors without parsing human text.

Relationships

  • May be replayed by platform.idempotency_key for failed_permanent requests.
  • requestId and traceId tie to platform request tracing, not Content rows.

Constraints

  • Every Problem response includes type, title, status, code, detail, requestId, traceId, and a fieldErrors array. cause and docUrl are the only optional envelope fields.
  • detail text is plain language and must not leak package bytes, secrets, tokens, or direct student PII.
  • Unsupported filters are rejected, never silently ignored.

Invalid examples

  • A 400 response with only 'bad request'.
  • A problem detail that includes raw QTI package bytes.
  • A stale If-Match save accepted instead of content.stale_version.

Example

{
  "type": "https://platform.timeback.com/problems/content/stale-version",
  "title": "Content version is stale",
  "status": 409,
  "code": "content.stale_version",
  "detail": "Read the content again and retry with the current ETag.",
  "requestId": "req_01HX...",
  "traceId": "tr_01HX...",
  "fieldErrors": []
}

Queries

Returned from all Content API endpoints when a documented constraint fails.

Fields (10)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
typeURIyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable URI identifying the problem type. Required absolute URI. It must remain stable for clients. · Generic about:blank for known Content failures or mutable docs URL that changes meaning. content-axis-008-error-envelope
titleTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Short human-readable problem title. Required. Plain language; no raw stack traces. · Contains internal exception class or raw SQL error. content-axis-008-error-envelope
statusINTEGERyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension HTTP status code for this problem. Required integer matching the HTTP response status. · Does not match the actual HTTP status. content-axis-008-error-envelope
codeTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Stable Content problem code for client branching. Required governed enum. · problem_code · Free-form text, changes between releases for the same failure, or requires parsing title. content-itd-012-plain-language-problems-and-provenance, content-axis-008-error-envelope
detailTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Safe, plain-language explanation of the specific failure. Required. Must redact package bytes, tokens, secrets, raw credentials, and direct student PII. · Leaks raw XML bytes, secret_ref target, JWT, or stack trace. content-axis-008-error-envelope
requestIdTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Opaque request id for support and audit correlation. Required safe opaque id. · Missing or derived from a student identifier. content-axis-008-error-envelope
traceIdTEXTyes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Opaque trace id for distributed request tracing. Required safe opaque id. · Missing or contains tenant secrets. content-axis-008-error-envelope
causeTEXTno Response-only diagnostic field; not a Content storage column. · extend · Alpha Content extension Safe public classification of an underlying failure when one is available. Optional. Must be sanitized and must not expose exception text, SQL, credentials, tokens, or direct student PII. · Contains a raw exception, database connection string, credential, token, or student identifier. content-axis-008-error-envelope
docUrlURIno Response-only documentation link; not a Content storage column. · extend · Alpha Content extension Public documentation URL for resolving or escalating the problem. Optional absolute HTTPS URL. Must not contain credentials, tokens, or tenant-specific secrets. · Relative, non-HTTPS, private, credential-bearing, or unrelated to the returned problem. content-axis-008-error-envelope
fieldErrorsJSONByes Alpha extension/config column; no 1EdTech source field is copied here. · extend · Alpha Content extension Always-present array of per-field validation errors for request bodies or query parameters; empty when no field-level errors apply. Required JSON array. Each entry has sanitized name and reason fields; names use Alpha Content names, not raw qti.* names, unless upstream provenance is explicitly included. · Missing, not an array, names only raw database fields, includes raw submitted secrets, or omits a name or reason. content-axis-008-error-envelope

Content-owned authorization configuration · Content owns the exception to its own ordinary release lane; People & Orgs remains the identity/reality authority.

content_test_serve_grant — Content Test-Serve Grant

Soft-revocable demo authorization for one test/synthetic identity.

Primary keytest_serve_grant_id
Backing storealpha.content_test_serve_grant
Storage gateStores only a bounded identity reference, producer surface, authorization provenance, and soft expiry/revocation state. It copies no People & Orgs profile fields and grants no authority unless the live person reality is independently test or synthetic.
Source classAlpha Content test-serving policy
LifecycleCreated by governed Content policy/migration, optionally expires, and is soft-revoked by setting revoked_at. Revocation never removes prior authorization receipts.

Purpose

Permit governed draft-bank exercise without publishing, trusting, or making the material ordinarily serveable.

Relationships

  • tenant_id resolves platform.tenant and test_identity_id resolves the same tenant's People & Orgs alpha.person at authorization time.
  • One row exists per tenant, test_identity_id, and producer_surface.
  • Successful authorizations reference this row through test_serve_grant_id.

Constraints

  • Runtime authorizes only tenant_key=demo and a live enabled person with reality in test or synthetic and an active source status.
  • expires_at and revoked_at fail closed; no caller flag or header can create or bypass a grant.
  • The grant changes no Content item status, trust status, serveable value, or release_eligible value.

Invalid examples

  • A real student person_id or non-demo tenant.
  • A wildcard identity, tenant, or producer surface.
  • An upsert that clears revoked_at during deploy.

Example

{
  "test_serve_grant_id": "18240000-0000-4000-8000-000000000001",
  "test_identity_id": "person_reality_test_student",
  "producer_surface": "incept/alpha",
  "authorization_ref": "https://github.com/andymontgomery-byte/platform3/issues/1824",
  "expires_at": null,
  "revoked_at": null
}

Queries

SELECT test_serve_grant_id, test_identity_id, producer_surface, authorization_ref, expires_at, revoked_at FROM alpha.content_test_serve_grant WHERE tenant_id=:tenant_uuid AND test_identity_id=:person_id AND producer_surface=:producer_surface

Fields (8)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
tenant_idUUIDyes alpha.content_test_serve_grant.tenant_id · reference · Platform reference Owning platform tenant. FK to platform.tenant; runtime additionally requires tenant_key=demo. · Missing, cross-tenant, or treated as permission outside demo. content-itd-024-governed-test-serve
test_serve_grant_idUUIDyes alpha.content_test_serve_grant.test_serve_grant_id · extend · Alpha Content extension Stable Content-owned grant identity. Primary key. · Reused for another identity or producer. content-itd-024-governed-test-serve
test_identity_idTEXTyes alpha.content_test_serve_grant.test_identity_id · reference · People & Orgs reference Exact People & Orgs person_id reference that must independently resolve to active test/synthetic reality. Nonblank, at most 200 characters; one row per tenant/identity/producer. · Wildcard, real identity, display name, email, or cached reality. content-itd-024-governed-test-serve
producer_surfaceTEXTyes alpha.content_test_serve_grant.producer_surface · extend · Alpha Content extension Governed producer whose draft material this grant may test. Canonical lowercase module/surface token. · Wildcard or display label. content-itd-024-governed-test-serve
authorization_refTEXTyes alpha.content_test_serve_grant.authorization_ref · extend · Alpha Content policy provenance Durable ruling or issue that authorized the bounded grant. Nonblank and at most 500 characters. · Missing or unauditable. content-itd-024-governed-test-serve
expires_atTIMESTAMPTZno alpha.content_test_serve_grant.expires_at · extend · Alpha Content extension Optional time after which new authorizations fail. Null or later than created_at. · Ignored after expiry. content-itd-024-governed-test-serve
revoked_atTIMESTAMPTZno alpha.content_test_serve_grant.revoked_at · extend · Alpha Content extension Soft revocation time; non-null immediately denies new authorizations. Null or no earlier than created_at. · Cleared automatically by migration or ignored by runtime. content-itd-024-governed-test-serve
created_atTIMESTAMPTZyes alpha.content_test_serve_grant.created_at · extend · Alpha Content extension Grant creation time. Server timestamp with timezone. · Missing or rewritten on deploy. content-itd-024-governed-test-serve

append-only Content authorization audit · Content records the exact exceptional asset serve; Results still owns attempts, answers, scores, seen-form evidence, and remediation state.

content_test_serve_authorization — Content Test-Serve Authorization

Immutable exact bank/form test-serve receipt.

Primary keytest_serve_authorization_id
Backing storealpha.content_test_serve_authorization
Storage gateInserted only after one transaction revalidates grant, People & Orgs reality, exact Content states, and exact active practice-eligible bank_member relationship. A database trigger rejects UPDATE and DELETE.
Source classAlpha Content authorization evidence
LifecycleAppend once on successful final authorization and retain immutably for audit.

Purpose

Prove who exercised which draft material under which grant without changing production governance.

Relationships

  • test_serve_grant_id references the exact Content grant.
  • bank/form ids and versions reference qti.artifact and qti.artifact_version.
  • gate_component_id references the Curriculum gate by immutable identifier; Content does not copy the gate.

Constraints

  • Eligibility and final authorization routes require an authenticated service, demo, or operator role; ordinary student, teacher, writer, reviewer, and reader tokens cannot invoke the lane even when they know the test identity.
  • Bank must be content_kind=test_bank and form content_kind=test with an active exact bank_member relationship.
  • Both exact items must be practice eligible, unretired, non-failed trust, and not explicitly rejected, blocked, or revoked.
  • UPDATE and DELETE fail in the database.

Invalid examples

  • A receipt written before bank membership validation.
  • Latest-version substitution.
  • Mutation or deletion of a historical receipt.
  • A receipt containing bearer credentials, answers, scores, or real-student PII.

Example

{
  "test_serve_authorization_id": "18240000-0000-4000-8000-000000000051",
  "test_serve_grant_id": "18240000-0000-4000-8000-000000000001",
  "test_identity_id": "person_reality_test_student",
  "producer_surface": "incept/alpha",
  "gate_component_id": "18240000-0000-4000-8000-000000000030",
  "bank_content_version_id": "18240000-0000-4000-8000-000000000011",
  "form_content_version_id": "18240000-0000-4000-8000-000000000021",
  "authorized_at": "2026-07-24T12:00:00Z"
}

Queries

SELECT * FROM alpha.content_test_serve_authorization WHERE tenant_id=:tenant_uuid AND test_identity_id=:person_id ORDER BY authorized_at DESC

Fields (14)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
tenant_idUUIDyes alpha.content_test_serve_authorization.tenant_id · reference · Platform reference Owning platform tenant. FK to platform.tenant. · Cross-tenant. content-itd-024-governed-test-serve
test_serve_authorization_idUUIDyes alpha.content_test_serve_authorization.test_serve_authorization_id · extend · Alpha Content extension Stable receipt identity returned to Curriculum. Primary key generated once. · Reused or mutable. content-itd-024-governed-test-serve
test_serve_grant_idUUIDyes alpha.content_test_serve_authorization.test_serve_grant_id · reference · Alpha Content reference Grant that authorized the serve. FK to content_test_serve_grant. · Missing or inferred after the fact. content-itd-024-governed-test-serve
caller_subjectTEXTyes alpha.content_test_serve_authorization.caller_subject · extend · Platform auth provenance Authenticated service subject that requested final authorization. Nonblank, at most 200 characters; never a bearer. · Token, secret, or unverified header. content-itd-024-governed-test-serve
test_identity_idTEXTyes alpha.content_test_serve_authorization.test_identity_id · reference · People & Orgs reference Exact test/synthetic person_id exercised by the authorization. Nonblank, at most 200 characters; must match the grant and live People & Orgs reality at insert. · Real identity, display name, email, or cached reality. content-itd-024-governed-test-serve
producer_surfaceTEXTyes alpha.content_test_serve_authorization.producer_surface · extend · Alpha Content extension Producer surface whose material was authorized. Canonical lowercase module/surface token matching the grant. · Wildcard or mismatch. content-itd-024-governed-test-serve
gate_component_idUUIDyes alpha.content_test_serve_authorization.gate_component_id · reference · Curriculum reference Exact Curriculum mastery-gate component that selected the form. UUID reference; Content stores no gate payload. · Missing, latest alias, or non-gate label. content-itd-024-governed-test-serve
bank_content_idUUIDyes alpha.content_test_serve_authorization.bank_content_id · reference · QTI-backed Content reference Exact parent test_bank Content identity. Tenant-scoped FK to qti.artifact and kind=test_bank at authorization. · Wrong tenant or kind. content-itd-024-governed-test-serve
bank_content_version_idUUIDyes alpha.content_test_serve_authorization.bank_content_version_id · reference · QTI-backed Content reference Immutable exact bank version. FK to qti.artifact_version for bank_content_id. · Latest substitution or belongs to another item. content-itd-024-governed-test-serve
form_content_idUUIDyes alpha.content_test_serve_authorization.form_content_id · reference · QTI-backed Content reference Exact selected test form Content identity. Tenant-scoped FK to qti.artifact, kind=test, and exact active bank member. · Not an exact bank member or wrong kind. content-itd-024-governed-test-serve
form_content_version_idUUIDyes alpha.content_test_serve_authorization.form_content_version_id · reference · QTI-backed Content reference Immutable exact selected form version. FK to qti.artifact_version for form_content_id and exact active bank membership. · Latest substitution or membership is for another version. content-itd-024-governed-test-serve
request_idTEXTyes alpha.content_test_serve_authorization.request_id · extend · Platform provenance Opaque request correlation id. Nonblank, at most 200 characters. · Bearer, PII, or missing. content-itd-024-governed-test-serve
trace_idTEXTyes alpha.content_test_serve_authorization.trace_id · extend · Platform provenance Opaque distributed trace correlation id. Nonblank, at most 300 characters. · Bearer, PII, or missing. content-itd-024-governed-test-serve
authorized_atTIMESTAMPTZyes alpha.content_test_serve_authorization.authorized_at · extend · Alpha Content extension Server time when final authorization committed. Immutable timestamp with timezone. · Client-authored or mutable. content-itd-024-governed-test-serve

current authorization read · Content is the only authority for exceptional draft material serving.

content_test_serve_eligibility — Content Test-Serve Eligibility

Current fail-closed answer for one exact Content version and one test identity.

Primary keycontent_id + content_version_id + producer_surface + test_identity_id
Backing storeComputed per request from exact Content rows, current trust status, content_test_serve_grant, and People & Orgs alpha.person reality; revocation is trust_status='failed'.
Storage gateStores nothing. Returns eligible only for demo, an active grant, an enabled active test/synthetic person, exact draft/published practice-eligible unretired Content, and trust_status <> 'failed'. producer_surface is only a validated input matched to the active grant, not a requirement-row gate.
Source classAlpha Content current-state projection
LifecycleComputed anew for each request and never cached by Curriculum.

Purpose

Allow Curriculum to validate every exact bank/form candidate before final atomic authorization.

Relationships

  • Reads one exact content_item/content_version pair, active grant, live person reality, and current trust.
  • Final bank/form authorization repeats these checks and additionally proves exact bank membership in one transaction.

Constraints

  • The route requires an authenticated service, demo, or operator role before repository resolution.
  • Eligibility never makes serveable or release_eligible true and never mutates lifecycle/trust.
  • A grant mismatch (including a producer_surface not matching the active grant), revoked/expired grant, real identity, failed trust, retired/archived lifecycle, or non-practice use returns a typed 403/409 Problem.
  • A successful eligibility read is not a launch receipt; final authorization is mandatory.

Invalid examples

  • A preview=true parameter.
  • A cached eligible answer reused after revocation.
  • An eligible answer for a real identity or non-demo tenant.

Example

{
  "content_id": "18240000-0000-4000-8000-000000000010",
  "content_version_id": "18240000-0000-4000-8000-000000000011",
  "content_kind": "test_bank",
  "usage_scope": "practice_eligible",
  "producer_surface": "incept/alpha",
  "test_identity_id": "person_reality_test_student",
  "test_serve_grant_id": "18240000-0000-4000-8000-000000000001",
  "test_serve_eligible": true,
  "problem_code": null
}

Queries

GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions/{versionId}/test-serve-eligibility?producer_surface=incept%2Falpha&test_identity_id=person_reality_test_student

Public API fields (9)

FieldTypeRequiredStorage / changeMeaningConstraints and valuesOwner
content_idUUIDyes Response projection from alpha.content_item_view. · read dependency · Content projection Exact Content item identity. Must own content_version_id in the route tenant. · Mismatched with version. content-itd-024-governed-test-serve
content_version_idUUIDyes Response projection from alpha.content_version_view. · read dependency · Content projection Exact immutable Content version. No latest substitution. · Missing or replaced by latest. content-itd-024-governed-test-serve
content_kindTEXTyes Response projection from alpha.content_item_view. · read dependency · Content projection Owning Content kind for target-match validation. Exact current item kind. · Does not match caller target. content-itd-024-governed-test-serve
usage_scopeTEXTyes Response projection from alpha.content_item_view. · read dependency · Content projection Content-owned exposure scope. Must be practice_eligible. · Teacher-only, internal, or otherwise non-practice. content-itd-024-governed-test-serve
producer_surfaceTEXTyes Response request projection. · extend · Alpha Content projection Governed producer token used to select the exact test-serve grant. Exact canonical token. · Wildcard or mismatch. content-itd-024-governed-test-serve
test_identity_idTEXTyes Response projection from request plus People & Orgs join. · read dependency · People & Orgs read dependency Exact authorized test/synthetic person_id. Matches grant and live People & Orgs person. · Real identity or mismatch. content-itd-024-governed-test-serve
test_serve_grant_idUUIDyes Response projection from alpha.content_test_serve_grant. · reference · Alpha Content projection Active Content grant supporting the answer. Non-revoked and non-expired. · Missing or stale. content-itd-024-governed-test-serve
test_serve_eligibleBOOLEANyes Computed response field. · extend · Alpha Content projection Current conjunction of every test-serve guard. True only when problem_code is null; API returns non-200 for false. · Inferred by Curriculum or treated as ordinary release eligibility. content-itd-024-governed-test-serve
problem_codeTEXTno Computed response field. · extend · Alpha Content projection Typed safe failure when the conjunction is false. Null only when eligible; otherwise one of content.test_serve_forbidden, content.test_serve_wrong_version, content.test_serve_content_blocked, or content.test_serve_membership_mismatch. · Free text or contains private identity facts. content-itd-024-governed-test-serve

Governed enum sets

content_subtype

The Brainlift's diagram and decodable vocabulary is represented as governed subtypes; test_spec, test_bank, and script are first-class content_kind values.

ValueMeaning
diagramAn image whose instructional purpose is a diagram; content_kind remains image.
decodableAn article constrained by a phonics set; the constraint set lives in alpha.decodable_extension.

interactive_composition_type

Interactive article and interactive video are first-class Content objects whose segment/cue question bindings are Content-owned typed structure, not QTI or Curriculum storage.

ValueMeaning
interactive_articleOrdered article segment-to-question composition for a Content article/interactive object.
interactive_videoVideo media plus strictly increasing cue timestamp-to-question composition for a Content video/interactive object.

assessment_role

test_spec and test_bank are first-class content_kind values backed by QTI assessmentTest storage; assessment_role keeps form/spec/bank compatibility over that shared storage.

ValueMeaning
formA renderable test form a student can take.
specA blueprint/table of specifications used to generate equivalent forms; never rendered to a student.
bankA stored pool of equivalent forms generated from one spec; Curriculum mastery gates target this role.

assessment_component_role

QTI stores sections, item references, interactions, choices, rubric blocks, and feedback elements as component rows. Content exposes the parts needed to render and inspect a blank assessment without exposing raw QTI internals or student results.

ValueMeaning
testThe top-level assessment test component when a QTI test element is present.
sectionA section inside a test, such as a group of questions.
partAn answerable interaction or question part, such as a choice interaction or text-entry interaction.
questionAn inline assessment item component when QTI stores the full question in the same component tree.
question_refA reference from a test section to a question item.
distractorAn incorrect or selectable option in a choice interaction. The student's selected option is not stored here.
rubricA question-level grading rubric block for the blank instrument.
preauthored_feedbackFeedback text authored before the student attempts the assessment, including correct/incorrect feedback.

dok

DOK is the process an item requires, not its difficulty. Difficulty constraints remain separate on the test_spec blueprint.

ValueMeaning
dok1Recall and reproduction.
dok2Skills and concepts.
dok3Strategic thinking.
dok4Extended thinking.

test_bank_membership_rule

The bank declares how members are represented, while actual fixed-form membership and PP100 adaptive shards use exact-version content_reference rows.

ValueMeaning
same_blueprint_fixed_formsEach member is a fixed test form satisfying the same spec blueprint; members are ordered by content_reference.form_index.
qti_adaptive_selectionThe adaptive QTI test owns its pool through qti-selection or qti-adaptive-selection inside QTI; Content does not create a parallel bank-member table.
pp100_adaptive_shardsOrdered exact form shards are storage containers whose pinned embeds union to one immutable PP100 question pool; Results selects questions adaptively.

alpha_subject_id

The machine-readable authoring subject policy alpha.policy.authoring_subject_registry.v2026-07-16.issue-771 is referenced by the Content and Curriculum dictionaries and generates runtime, SQL, descriptor, and skill-pack consumers.

ValueMeaning
mathMath
readingReading
languageLanguage
scienceScience
computer_scienceComputer Science
vocabularyVocabulary
writingWriting
social_studiesSocial Studies

alpha_grade_id

Curriculum owns the grade-id registry for the shared learning map. Content stores one target grade id for catalog filtering; publisher labels remain provenance elsewhere.

ValueMeaning
pre_kPre-kindergarten or early-childhood level.
kKindergarten.
1Grade 1.
2Grade 2.
3Grade 3.
4Grade 4.
5Grade 5.
6Grade 6.
7Grade 7.
8Grade 8.
9Grade 9.
10Grade 10.
11Grade 11.
12Grade 12.
postsecondaryCollege, career, adult, or postsecondary learning target.
ungradedContent intentionally not tied to one grade band.

content_kind

QTI item/test kinds are renamed for Alpha; assessmentStimulus is internal question anatomy; test_spec and test_bank are first-class Content kinds backed by QTI assessmentTest storage; article, video, audio, image, interactive, media_asset, external_link, and script are explicit Content extensions. Diagram and decodable are governed subtypes. QTI sections, lessons, course components, collections, and transport bundles route out of Content.

ValueMeaning
questionA QTI assessment item or equivalent blank question a student can answer. Source artifact_kind=item.
testA QTI assessment test or equivalent blank assessment instrument. Source artifact_kind=test.
test_specA first-class test blueprint/table of specifications. Backed by QTI assessmentTest storage plus alpha.test_spec_extension; assessment_role=spec is retained for compatibility.
test_bankA first-class bank of equivalent test forms generated from one test_spec. Backed by QTI assessmentTest storage plus alpha.test_bank_extension and bank_member references; assessment_role=bank is retained for compatibility.
articleReadable student-facing text or explainer anchored to the base resource shape plus Alpha sidecars.
videoStudent-facing moving-image content. MIME and delivery details stay in media_type and media references; video remains its own content_kind.
audioStudent-facing audio content such as narration, listening practice, or a recorded explanation. MIME and delivery details stay in media_type and media references.
imageStudent-facing image content such as a diagram, primary visual, or standalone image prompt. File details stay in qti.package_file/media fields.
interactiveA student-facing simulation, embedded activity, or learning application resource anchored to the base resource shape plus Alpha sidecars.
media_assetA reusable or supporting asset row such as a caption, transcript, worksheet, source file, thumbnail, or package dependency. It can be student-touchable, but video/audio/image use their own first-class content_kind when they are the primary asset.
external_linkA student-touchable link to an external resource. The URL is Alpha-owned extension data and must not contain secrets.
scriptA first-class authored script used as source material for produced audio or video; produced media references it with relationship_kind=source_script_for.

catalog_facet_key

Content names the twelve catalog discovery facets once. LOR, library, and catalog UIs query these sidecar assignments directly; they are never recomputed at read time from Content base rows or related Curriculum rows.

ValueMeaning
subjectSubject discovery facet used by LOR, library, and catalog UIs. Stored as sidecar assignment data, not recomputed from the Content base at read time.
grade_bandGrade-band discovery facet for browsing by school level or learner age band.
languageLanguage discovery facet for catalog filtering; this is sidecar discovery metadata, not a read-time copy of qti.artifact.language.
accessibility_profileAccessibility discovery facet such as captioned, transcript_available, audio_description, keyboard_accessible, or screen_reader_ready.
rights_licenseRights and license discovery facet for reuse, remix, and export decisions.
provenanceSource/provenance discovery facet for imported, authored, vendor, or OER origin.
quality_ratingGoverned quality signal for catalog ranking or review status.
kc_refsKnowledge-component reference discovery facet used for catalog slicing; operational Content-to-KC relevance remains weighted content_kc_tag relationship rows.
standards_framework_refsStandards-framework discovery facet used for catalog browsing; operational standards alignment remains in Curriculum.
content_kindDiscovery facet over the public Content kinds: question, test, test_spec, test_bank, article, video, audio, image, interactive, media_asset, external_link, and script. Stored by the surface as catalog metadata, not parsed from package paths or titles.
expected_xp_bandDiscovery band for expected_xp using governed values 0_to_10, 10_to_20, 20_to_45, and 45_plus under alpha.policy.content.expected_xp_band. Legacy labels quick, standard, extended, and intensive are compatibility aliases, not stored canonical values. The band is sidecar metadata; expected_xp itself is the numeric Content config field.
modalityDiscovery facet for modality such as reading, video, simulation, audio, printable, or external app handoff.

expected_xp_band

The curated expected_xp_band facet is stored at write/import/catalog curation time and queried with facet=expected_xp_band:VALUE. The separate expected_xp_band=VALUE convenience filter currently derives numeric bounds from content_item.expected_xp at read time and can match without a stored assignment; apps must not copy that policy logic locally.

ValueMeaning
0_to_10Expected XP from 0 inclusive to 10 exclusive; legacy alias quick.
10_to_20Expected XP from 10 inclusive through 20 inclusive; legacy alias standard.
20_to_45Expected XP greater than 20 through 45 inclusive; legacy alias extended.
45_plusExpected XP greater than 45; legacy alias intensive.

catalog_facet_value_type

Catalog facets are governed discovery values beside the base Content view. They are not qti.metadata and they are promoted to real columns when they become join keys or computed inputs.

ValueMeaning
enumThe facet value must be one of the allowed_values listed on the facet definition.
booleanThe facet stores true or false and is useful for simple discovery toggles.
numberThe facet stores a numeric value for display or range filtering while it remains report-only.
textThe facet stores governed short text; free-form long notes belong in authoring metadata, not the catalog facet registry.
referenceThe facet stores an opaque reference to another governed object but must be promoted to a real FK column before consumers join on it.

catalog_facet_grain

Facet grain makes discovery metadata explicit and prevents consumers from guessing whether a value applies to the whole item, one version, or one media asset.

ValueMeaning
content_itemThe facet applies to the logical content item across versions.
content_versionThe facet applies to one immutable version row, including a TimeBack import version.
media_assetThe facet applies to one attached media asset.

test_type

QTI does not classify TimeBack tests by educational purpose; Alpha sets this typed field on write/import.

ValueMeaning
end_of_courseA summative test at the end of a course or full learning sequence.
end_of_gradeA summative test for grade-level readiness or completion.
test_outA one permitted PowerPath attempt to prove a too-easy grade level is already mastered and unlock the next grade-level path.
placementA grade-level mastery test used inside PowerPath bottom-up onboarding; passing/failing it contributes placement evidence, but the workflow chooses final entry_track_level.
diagnosticA test used to find strengths, gaps, or next instruction targets.
screenerA short/adaptive check used to choose the starting grade for bottom-up placement; it never certifies final placement.

media_kind

Media type remains the MIME value. media_kind is the deployed public/API and extension classification a teacher or LLM filters on.

ValueMeaning
primaryThe main asset that renders the content item, such as the video file for a video.
supportingA supporting asset needed by the content, such as an image used inside an article.
thumbnailA small preview image used for catalog display.
captionTimed captions or subtitles for audio/video accessibility.
transcriptText transcript for audio/video accessibility or search.
worksheetA printable or downloadable student worksheet associated with the item.
source_fileOriginal source file preserved for export, audit, or re-rendering.

content_reference_relationship_kind

QTI resources can refer to other resources, but Alpha needs one governed school-language relationship for every Content kind without nesting the referenced asset inside the parent.

ValueMeaning
embedsThe parent content renders the referenced content inline, such as an article embedding an image or interactive.
depends_onThe parent content needs the referenced content to render or export correctly, but the renderer decides how to present it.
transcript_forThe referenced content is a transcript for the parent video or audio content.
caption_forThe referenced content is timed caption/subtitle material for the parent video or audio content.
thumbnail_forThe referenced content is a thumbnail or preview image for the parent content.
source_file_forThe referenced content is the original source file retained for audit, editing, or round-trip export.
source_script_forThe referenced content is a script Content item used to produce the parent audio or video content.
bank_memberThe referenced content is one fixed-form test member of a parent test_bank; form_index orders deterministic selection.
alternative_form_ofThe referenced content is an equivalent accessibility, language, or modality alternative.
related_materialThe referenced content is intentionally related but not required for rendering.

source_system

Public provenance distinguishes QTI-backed content from Content-owned media without exposing raw qti.* internals as ordinary objects.

ValueMeaning
qtiThe content item is backed by approved QTI persistence rows.
alpha_contentThe content item is a Content-owned extension such as an article, video, audio, image, interactive, external link, or media asset anchored to the base resource shape.
external_content_importThe content item was imported through a named content adapter and normalized into the Alpha Content shape.

content_status

Content status gives a plain lifecycle around immutable versions while QTI versions remain the source of QTI-backed content.

ValueMeaning
draftAuthors can still edit unpublished versions; students should not launch this item.
publishedThe item has a student-safe version available for launch or reading.
retiredThe item remains for history and linked Events/Results, but new launches should not use it.
archivedThe item is retained for audit/export and hidden from ordinary catalog use.

effectiveness_status

Results recomputes effectiveness after Results changes. Content exposes whether the Results-owned read or fallback is fresh enough for display.

ValueMeaning
freshThe rollup includes all Results inputs known at last_recomputed_at.
staleOne or more Results inputs changed after last_recomputed_at; apps should display but not recompute.
pendingThe surface has queued the first computation or a recomputation.
insufficient_dataThe item has too few eligible Results inputs for the policy to publish a stable rate.

trust_status

Current runtime may expose generic producer/import metadata or unknown/null trust. Exact QTI run binding and named non-QTI validation evidence are accepted pending targets.

ValueMeaning
trustedValidation/conformance evidence currently supports delivery.
degradedEvidence exists, but a warning or stale dependency should be visible to authors.
failedValidation or conformance evidence blocks delivery until repaired.
unknownNo trustworthy validation evidence has been recorded yet.

qti_cardinality

QTI defines how many values a response variable can hold.

ValueMeaning
singleThe slot holds one value.
multipleThe slot can hold an unordered set of values.
orderedThe slot can hold an ordered list of values.
recordThe slot holds named fields rather than one atomic value.

qti_base_type

QTI defines the atomic value type for response and outcome variables.

ValueMeaning
booleanTrue or false.
directedPairAn ordered pair of identifiers.
durationA time duration.
fileA submitted file value.
floatA decimal number.
identifierA QTI identifier string, often a choice id.
integerA whole number.
pairAn unordered pair of identifiers.
pointA coordinate point.
stringText.
uriA URI value.

scoring_rule_scope

The row scope is a repository classification for query and execution order; QTI defines the processing elements and expressions themselves.

ValueMeaning
responseRule belongs to response processing and computes outcome variables from candidate responses.
outcomeRule belongs to outcome processing at test or section level.
templateRule belongs to qti-template-processing and initializes template state before delivery. qti-set-template-value, qti-template-constraint, and qti-template-default run server-side at session start under the ITD-021 finite retry bound.
expressionRow represents an expression subtree or operator nested inside response, outcome, or template processing.

problem_code

Content inherits typed RFC 7807 Problem Details and adds stable Content-specific code values.

ValueMeaning
content.validation_failedThe submitted content, media, QTI XML, or relationship row failed semantic validation.
content.payload_too_largeAn authenticated JSON request exceeded Content's bounded request-body limit; return HTTP 413 before repository or idempotency work and never echo request bytes.
content.adapter_rejectedA well-formed source-shaped import row could not be reconciled to the canonical Content shape, such as an out-of-scope subject value; return HTTP 422, not HTTP 200.
content.unsupported_filterA list request used a filter or sort key the data dictionary does not publish.
content.stale_versionA write used an old ETag or version and must be retried after a fresh read.
content.missing_preconditionA writable request omitted the required If-Match precondition.
content.idempotency_conflictA retry reused an Idempotency-Key with a different request body or operation.
content.source_identity_collisionA deterministic imported Content id is already bound to another tenant, source table, or source record identity; return HTTP 409 with no partial mutation.
content.source_semantic_driftThe same imported source identity resolved to a different immutable item-grain content_kind; return HTTP 409 with no partial mutation.
content.release_wrong_versionThe requested version exists in this tenant but belongs to a different Content item; versions outside the caller's tenant remain content.not_found.
content.version_not_serveableThe exact version is not currently published and unretired with non-failed item trust (owner ruling #2534: failed trust is the single revocation lever).
content.test_serve_forbiddenThe caller, tenant, producer surface, or learner identity is not authorized by an active governed test-serve grant.
content.test_serve_wrong_versionThe requested exact bank or form version does not belong to the requested Content item in the same tenant.
content.test_serve_content_blockedThe exact draft or published bank or form is retired, not practice-eligible, failed trust, or currently rejected, revoked, or blocked.
content.test_serve_membership_mismatchThe requested exact form version is not an active exact-version member of the requested test-bank version.
content.answer_key_forbiddenThe caller lacks read:answer_key authority for answer-key fields.
content.invalid_test_bank_member_contractA test-bank graph violates the canonical fixed-form member contract through a wrong parent/member kind or assessment role, unsupported membership rule, missing resolved or wrong-owner exact version, native-QTI parallel rows, invalid or duplicate form_index, or another malformed active-row semantic; or a bounded active write exceeds its complete post-write graph. Every active graph writer budgets under the tenant graph fence: public and repository/direct active embeds and bank_member writes, KC-tag upsert/revival, QTI package import, and TimeBack materialization, including cardinality-neutral active repository/materializer replays. A completed API idempotency replay does not execute a graph writer. One write may affect at most 1,024 banks; every affected bank may contain at most 1,024 active members and 4,096 joined form/question/active-KC facts. Those ceilings are inclusive: the 1,025th affected bank or active member and the 4,097th joined fact return HTTP 409 content.invalid_test_bank_member_contract. Member overflow identifies fieldErrors.name=bank_members; affected-bank and joined-fact overflow identify fieldErrors.name=form_graph. The rejected transaction leaves no lasting graph, parent timestamp/ETag, or fresh idempotency-ledger effect. Retire active member/embed/KC-tag facts or split shared forms/questions/banks to reduce fanout, then retry.
content.bank_kc_attribution_incompleteA semantically valid fixed-form test-bank member has no exact ordered embedded-question graph or one of its embedded question occurrences lacks an active canonical Content KC tag; return HTTP 409 and do not infer the whole gate scope.
content.bank_membership_frozenA bank_member create or retirement targeted a bank outside the only mutable state: unretired draft. Visible completed same-key requests replay immediately; a fresh create takes the exclusive graph fence and repeats replay arbitration before returning HTTP 409 without an idempotency claim or graph mutation. A rejected retirement leaves no graph change.
content.assessment_dependency_conflictA form cannot be retired or archived while an active test-bank member still points to it. Return HTTP 409 before changing the item, its ETag, or its idempotency state; retire the bank_member edge first.
content.graph_writer_fence_requiredThe runtime could not obtain the canonical guarded graph-writer fence because another writer owns it, or could not prove the guard catalog during a rolling deployment. Return HTTP 503 with Retry-After=2 before graph mutation; retry the same request after the requested delay.
content.publication_rejectedGoverned exact-version publication checks failed. Return HTTP 422 with bounded, deduplicated field errors and roll back lifecycle, trust, receipt, graph, and the fresh idempotency claim.
content.published_assessment_immutableA governed test_spec or test_bank outside the editable unretired-draft state cannot be rewritten in place. Return HTTP 409 and create a new Content identity for a revised instrument.
content.curriculum_node_not_foundA curriculum link points to a missing, retired, or unauthorized Curriculum node.
content.knowledge_component_not_foundA KC tag points to a missing, retired, unauthorized, or cross-tenant governed registry Knowledge Component.
content.curriculum_link_write_deprecatedThe caller attempted to write the frozen curriculum-link archive. Route one ordered Content use per item through Curriculum; the current CASE adapter uses one targeted child practice/review component per additional lesson item, while the accepted target is one course_component_member per use. Use weighted /kc-tags only for item-to-governed-KC attribution.
content.retention_conflictThe caller attempted to hard-delete content that Events or Results still reference.
content.tenant_mismatchThe route tenant and JWT tenant claim do not match.
content.authentication_requiredThe request did not include the trusted bearer authentication required by the Content operation.
content.preview_database_isolation_requiredA Content serverless runtime without exact Vercel production metadata refused before repository initialization; return HTTP 503 and do not access PostgreSQL. This includes previews and missing, malformed, or custom environment metadata until a separate or read-only database path is configured.
content.persistent_seed_unavailableBounded persistent-fixture preparation could not obtain its seed-convergence serialization lock; return HTTP 503. Ordinary graph mutations retain their transaction and query budget, bound only the ordered advisory-lock acquisitions inside that budget, and return content.graph_writer_fence_required on contention.
content.forbiddenThe authenticated token is not authorized for the requested Content operation.
content.not_foundThe requested Content record was not found or is not available to the caller.
content.method_not_allowedThe request used an HTTP method that the Content endpoint does not support.
content.source_asset_unavailableContent could not safely obtain the declared immutable first-party Incept source asset before the bounded deadline; the request is retryable and no media mutation occurred.
content.server_errorContent could not complete the operation because of an unexpected server-side failure.

tb_markup_token

Content dictionary owns the tb-* value-space used in stored HTML bodies; the external renderer implementation consumes this contract but does not define Content meaning.

ValueMeaning
tb-instructional-contentOuter instructional content wrapper accepted by the sanctioned renderer.
tb-article-containerArticle/body container supplied directly to the renderer.
tb-segmentProgressive reveal segment in an instructional body.
tb-interactionInteractive block marker.
tb-qti-assessment-itemInteraction subtype that points at QTI item XML through the local catalog.
tb-appletInteraction subtype that points at an applet manifest through the local catalog.
tb-catalogHidden same-body catalog of XML, applet, glossary, narration, or media entries.
tb-qti-configCatalog entry whose link points at QTI XML; XML and scoring stay QTI-owned.
tb-applet-configCatalog entry whose JSON manifest describes an external applet.
data-catalog-idrefAttribute resolving an interaction or term to a same-body tb-catalog entry id.
practice-stepPractice step marker inside example/practice containers.
example-practice-containerWorked-example/practice layout container.
headers-rowExample/practice header row.
headerExample/practice header cell.
step-rowExample/practice row.
stepStep cell.
example-stepWorked-example step cell.
answer-boxBlank answer region in a practice layout.
tb-glossary-termGlossary term marker resolved through data-catalog-idref/title.
tb-glossary-definitionHidden or adjacent glossary definition entry.
tb-narrationNarration text marker.
tb-narration-audioNarration audio marker.

usage_scope

QTI identifies assessment resources but does not define TimeBack routine-routing eligibility, canary hold-out, or secure mock-form exposure. Alpha owns this routing contract as typed Content metadata.

ValueMeaning
practice_eligibleRoutine routing may select this item/reference for instruction, practice, next-task, and next-form flows.
held_out_canaryHeld-out transfer or canary content reserved for mastery measurement; explicit reads are allowed but routine practice/next-task/next-form routing must not select it.
secure_formSecure full-form assessment content reserved for protected mock or exam contexts; explicit reads are allowed but instruction and practice routing must not select it.

Alias map

Alpha nameKindChangeSourceMeaningOwner
Content modulemodulerenameQTI 1EdTech surfacePublic Alpha module name for things students touch.content-itd-001-module-boundary-and-alias-map
content_item.content_idfieldrenameqti.artifact.artifact_idcontent-itd-002-shared-qti-truth-no-content-fork
content_item.workspace_idfieldrenameplatform.tenant.tenant_idcontent-axis-009-tenant-routing
content_item.content_kindfieldrestrictView expression over qti.artifact.artifact_kind and qti.package_resource.resource_type, plus extension-only kind for QTI-anchored Content sidecarscontent-itd-003-content-kind-taxonomy
content_item.expected_xpfieldextendalpha.content_item_extension.expected_xpcontent-itd-015-expected-xp-content-config
questionobjectrenameqti.artifact where artifact_kind = itemcontent-itd-003-content-kind-taxonomy
testobjectrenameqti.artifact where artifact_kind = testcontent-itd-003-content-kind-taxonomy
articleobjectextendalpha.content_item_extensioncontent-itd-004-non-qti-media-extension
videoobjectextendalpha.content_item_extension plus alpha.media_asset_extensioncontent-itd-004-non-qti-media-extension
audioobjectextendalpha.content_item_extension plus alpha.media_asset_extensioncontent-itd-004-non-qti-media-extension
imageobjectextendalpha.content_item_extension plus alpha.media_asset_extensioncontent-itd-004-non-qti-media-extension
interactiveobjectextendalpha.content_item_extensioncontent-itd-004-non-qti-media-extension
media_assetobjectextendalpha.media_asset_extensioncontent-itd-004-non-qti-media-extension
external_linkobjectextendalpha.external_link_extensioncontent-itd-004-non-qti-media-extension
scriptobjectextendqti.artifact base identity plus alpha.content_item_extension content_kind_override=scriptFirst-class script Content row; produced audio/video links to it with content_reference relationship_kind=source_script_for.content-itd-004-non-qti-media-extension
content_item.titlefieldrenameqti.artifact.titlecontent-itd-001-module-boundary-and-alias-map
content_item.languagefieldrenameqti.artifact.languagecontent-itd-001-module-boundary-and-alias-map
content_item.source_identifierfieldrenameqti.artifact.qti_identifiercontent-itd-001-module-boundary-and-alias-map
content_item.latest_version_idfieldrenameqti.artifact.latest_version_idcontent-itd-007-versioned-authoring-and-student-view
content_version.version_idfieldrenameqti.artifact_version.artifact_version_idcontent-itd-007-versioned-authoring-and-student-view
content_version.version_numberfieldrenameqti.artifact_version.version_numbercontent-itd-007-versioned-authoring-and-student-view
content_version.student_viewfieldrenameqti.artifact_version.delivery_jsoncontent-itd-007-versioned-authoring-and-student-view
content_version.editing_draftfieldrenameqti.artifact_version.authoring_jsoncontent-itd-007-versioned-authoring-and-student-view
content_version.canonical_xmlfieldrenameqti.artifact_version.canonical_xmlcontent-itd-007-versioned-authoring-and-student-view
media_asset.media_idfieldrenameqti.package_file.package_file_idcontent-itd-004-non-qti-media-extension
media_asset.media_kindfieldextendalpha.media_asset_extension.media_kindcontent-itd-004-non-qti-media-extension
media_asset.media_typefieldrenameqti.package_file.media_typecontent-itd-004-non-qti-media-extension
media_asset.byte_lengthfieldrenameqti.package_file.byte_lengthcontent-itd-004-non-qti-media-extension
external_link.external_urlfieldextendalpha.external_link_extension.external_urlcontent-itd-004-non-qti-media-extension
answer_slot.identifierfieldrenameqti.variable_declaration.identifier where variable_kind = responsecontent-itd-008-answer-slots-not-student-answers
answer_slot.cardinalityfieldrenameqti.variable_declaration.cardinalitycontent-itd-008-answer-slots-not-student-answers
answer_slot.base_typefieldrenameqti.variable_declaration.base_typecontent-itd-008-answer-slots-not-student-answers
answer_key.correct_responsefieldrestrictqti.variable_declaration.correct_responseTeacher/authorized read only, never a student answer.content-itd-008-answer-slots-not-student-answers
assessment_component.component_rolefieldrename + restrictqti.component.element_name mapped to test/section/part/question/question_ref/distractor/rubric/preauthored_feedbackcontent-itd-008-answer-slots-not-student-answers
assessment_component.display_textfieldrename + restrictqti.component.text_valuecontent-itd-008-answer-slots-not-student-answers
assessment_test.test_typefieldextendalpha.assessment_test_extension.test_typecontent-itd-006-typed-content-and-test-fields
assessment_test.is_mastery_gatefieldextendalpha.assessment_test_extension.is_mastery_gatecontent-itd-006-typed-content-and-test-fields
assessment_test.test_family_idfieldextendalpha.assessment_test_extension.test_family_idOptional opaque adapter join key under the current API/database contract; no lexical grammar is enforced. It should remain stable across content versions, forms, and retakes and must not contain secrets.content-itd-010-external-test-family-identity
content_item.subject_idfieldextendalpha.content_item_extension.subject_idcontent-itd-006-typed-content-and-test-fields
content_item.target_grade_idfieldextendalpha.content_item_extension.target_grade_idcontent-itd-006-typed-content-and-test-fields
content_curriculum_link.curriculum_node_idfieldextendalpha.content_curriculum_link.curriculum_node_id referencing curriculum.nodecontent-itd-005-curriculum-links-are-relationships
content_ref.content_idreference-contract-fieldrenameqti.artifact.artifact_idcontent-itd-016-uniform-content-reference-contract
content_ref.content_version_idreference-contract-fieldrenameqti.artifact_version.artifact_version_idcontent-itd-016-uniform-content-reference-contract
content_ref.content_kindreference-contract-fieldrestrictView expression over qti.artifact.artifact_kind and qti.package_resource.resource_type plus extension sidecar kindcontent-itd-016-uniform-content-reference-contract
content_reference.parent_content_idreference-contract-fieldextendalpha.content_reference.parent_content_artifact_id -> alpha.content_reference_view.parent_content_idThe parent half of content_ref is three flat columns: id, optional version id, and kind.content-itd-016-uniform-content-reference-contract
content_reference.parent_version_idreference-contract-fieldextendalpha.content_reference.parent_content_version_id -> alpha.content_reference_view.parent_version_idNullable exact-version member of the parent content_ref shape.content-itd-016-uniform-content-reference-contract
content_reference.parent_content_kindreference-contract-fieldextendalpha.content_reference.parent_content_kindGoverned twelve-kind discriminator in the parent content_ref shape.content-itd-016-uniform-content-reference-contract
content_reference.referenced_content_idreference-contract-fieldextendalpha.content_reference.referenced_content_artifact_id -> alpha.content_reference_view.referenced_content_idThe referenced half of content_ref is three flat columns: id, optional version id, and kind.content-itd-016-uniform-content-reference-contract
content_reference.referenced_version_idreference-contract-fieldextendalpha.content_reference.referenced_content_version_id -> alpha.content_reference_view.referenced_version_idNullable exact-version member of the referenced content_ref shape.content-itd-016-uniform-content-reference-contract
content_reference.referenced_content_kindreference-contract-fieldderivealpha.content_reference_view.referenced_content_kind derived from referenced qti.artifact + alpha.content_item_extensionRead-only governed twelve-kind discriminator; no alpha.content_reference table column exists.content-itd-016-uniform-content-reference-contract
content_reference.relationship_kindfieldextendalpha.content_reference.relationship_kindcontent-itd-016-uniform-content-reference-contract
content_item.source_record_idfieldextendalpha.content_item_extension.source_record_idcontent-itd-018-source-shaped-production-ingest
content_item.source_activity_reffieldextendalpha.content_item_extension.source_activity_refcontent-itd-018-source-shaped-production-ingest
catalog_facet.subjectcatalog-facetextendalpha.content_catalog_facet_assignment value/ref for subjectcontent-itd-014-catalog-facets-sidecar
catalog_facet.grade_bandcatalog-facetextendalpha.content_catalog_facet_assignment value/ref for grade_bandcontent-itd-014-catalog-facets-sidecar
catalog_facet.languagecatalog-facetextendalpha.content_catalog_facet_assignment value/ref for languagecontent-itd-014-catalog-facets-sidecar
catalog_facet.accessibility_profilecatalog-facetextendalpha.content_catalog_facet_assignment value/ref for accessibility_profilecontent-itd-014-catalog-facets-sidecar
catalog_facet.rights_licensecatalog-facetextendalpha.content_catalog_facet_assignment value/ref for rights_licensecontent-itd-014-catalog-facets-sidecar
catalog_facet.provenancecatalog-facetextendalpha.content_catalog_facet_assignment value/ref for provenancecontent-itd-014-catalog-facets-sidecar
catalog_facet.quality_ratingcatalog-facetextendalpha.content_catalog_facet_assignment value/ref for quality_ratingcontent-itd-014-catalog-facets-sidecar
catalog_facet.kc_refscatalog-facetextendalpha.content_catalog_facet_assignment value/ref for kc_refscontent-itd-014-catalog-facets-sidecar
catalog_facet.standards_framework_refscatalog-facetextendalpha.content_catalog_facet_assignment value/ref for standards_framework_refscontent-itd-014-catalog-facets-sidecar
catalog_facet.content_kindcatalog-facetextendalpha.content_catalog_facet_assignment value/ref for content_kindcontent-itd-014-catalog-facets-sidecar
catalog_facet.expected_xp_bandcatalog-facetextendalpha.content_catalog_facet_assignment value/ref for expected_xp_bandcontent-itd-014-catalog-facets-sidecar
catalog_facet.modalitycatalog-facetextendalpha.content_catalog_facet_assignment value/ref for modalitycontent-itd-014-catalog-facets-sidecar
content_item.subtypefieldextendalpha.content_item_extension.subtypecontent-itd-019-governed-subtypes-within-ten-kinds
content_item.dokfieldextendalpha.content_item_extension.dokcontent-itd-020-test-spec-and-test-bank
decodable.phonics_constraintfieldextendalpha.decodable_extension.phonics_constraintcontent-itd-019-governed-subtypes-within-ten-kinds
content_reference.form_indexreference-contract-fieldextendalpha.content_reference.form_index where relationship_kind = bank_membercontent-itd-020-test-spec-and-test-bank
test.assessment_rolefieldextendalpha.assessment_test_extension.assessment_rolecontent-itd-020-test-spec-and-test-bank
test_specobjectextendqti.artifact where artifact_kind = test, assessment_role = spec, plus alpha.test_spec_extensioncontent-itd-020-test-spec-and-test-bank
test_spec.kc_coveragefieldextendalpha.test_spec_extension.kc_coveragecontent-itd-020-test-spec-and-test-bank
test_spec.passing_rulefieldextendalpha.test_spec_extension.passing_rulecontent-itd-020-test-spec-and-test-bank
test_spec.min_formsfieldextendalpha.test_spec_extension.min_formscontent-itd-020-test-spec-and-test-bank
test_spec.max_item_overlapfieldextendalpha.test_spec_extension.max_item_overlapcontent-itd-020-test-spec-and-test-bank
test_bankobjectextendqti.artifact where artifact_kind = test, assessment_role = bank, plus alpha.test_bank_extensioncontent-itd-020-test-spec-and-test-bank
test_bank.spec_idfieldextendalpha.test_bank_extension.spec_idcontent-itd-020-test-spec-and-test-bank
content_effectiveness.validated_by_countread-dependency-fieldrestrictResults-owned alpha.content_effectiveness.data ->> 'validated_by_count'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.failed_by_countread-dependency-fieldrestrictResults-owned alpha.content_effectiveness.data ->> 'failed_by_count'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.effectiveness_rateread-dependency-fieldrestrictResults-owned alpha.content_effectiveness.data ->> 'effectiveness_rate'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.last_recomputed_atread-dependency-fieldrestrictResults-owned alpha.content_effectiveness.data ->> 'last_recomputed_at'content-itd-009-content-effectiveness-derived-rollup
content_html_body_contractobjectextendVirtual Content value-space over qti.artifact_version authoring_json/delivery_json; no Alpha tableOwns stored tb-* HTML semantics while QTI, Curriculum, renderers, Events, and Results retain their named seams.content-itd-021-tb-markup-body-contract
content_html_body_contract.htmlfieldextendqti.artifact_version.authoring_json/delivery_json HTML projectionNo new Content storage table.content-itd-021-tb-markup-body-contract
content_html_body_contract.tb_markup_tokenfieldextendContent-owned value-space inside the version HTML bodyDictionary contract only; no standalone token table.content-itd-021-tb-markup-body-contract
content_html_body_contract.catalog_idreffieldextendContent HTML body data-catalog-idref attributeStored only inside the immutable version body, including TimeBack import versions.content-itd-021-tb-markup-body-contract
content_html_body_contract.catalog_entry_idfieldextendContent HTML body local catalog entry idLocal to one immutable version body, including TimeBack import versions.content-itd-021-tb-markup-body-contract
content_html_body_contract.qti_xml_reffieldextendReference from Content HTML catalog to QTI-owned XML/scoringReference only; QTI remains the storage owner.content-itd-021-tb-markup-body-contract
content_html_body_contract.renderer_reffieldextendCurriculum course_component_member.renderer_refCross-module reference; renderer selection is not stored on Content.content-itd-021-tb-markup-body-contract
content_html_body_contract.renderer_messagefieldextendSanctioned renderer integration runtime protocolRuntime protocol only; not Content storage.content-itd-021-tb-markup-body-contract
content_html_body_contract.progress_event_contractfieldextendEvents/Results learner-progress seam consumed by renderersNo renderer-private or Content progress store.content-itd-021-tb-markup-body-contract
interactive_compositionobjectextendContent publicInteractiveComposition aggregate over active alpha.interactive_composition rowsPublic API aggregate over the Content-owned extend-only sidecar; exact physical rows live only in the generated Physical DDL section.content-itd-022-interactive-composition
interactive_composition.content_idfieldextendpublicInteractiveComposition.content_id from active alpha.interactive_composition.content_artifact_id rowsBase Content identity; no copied artifact fields.content-itd-022-interactive-composition
interactive_composition.version_idfieldextendpublicInteractiveComposition.version_id from active alpha.interactive_composition.content_version_id rowscontent-itd-022-interactive-composition
interactive_composition.composition_typefieldextendpublicInteractiveComposition.composition_type from active alpha.interactive_composition rowscontent-itd-022-interactive-composition
interactive_composition.media_asset_reffieldextendpublicInteractiveComposition media_asset_ref built from active alpha.interactive_composition.media_package_file_id rowsReference only; media bytes remain upstream.content-itd-022-interactive-composition
interactive_composition.duration_secondsfieldextendpublicInteractiveComposition.duration_seconds from active alpha.interactive_composition rowscontent-itd-022-interactive-composition
interactive_composition.segmentsfieldextendpublicInteractiveComposition segments aggregate from active row sequence/segment/question-reference fieldsAPI aggregate only; row fields remain in exact Physical DDL.content-itd-022-interactive-composition
interactive_composition.cuesfieldextendpublicInteractiveComposition cues aggregate from active row timestamp/question-reference fieldsAPI aggregate only; referenced questions remain independent QTI-backed Content rows.content-itd-022-interactive-composition
interactive_composition.validation_contractfieldderivepublicInteractiveComposition derived validation contract from composition_type and content-itd-022Read-only derived projection; no physical JSON validation-contract column.content-itd-022-interactive-composition
interactive_composition.updated_atfieldderivepublicInteractiveComposition latest active row created_at or parent Content updated_atRead-only aggregate timestamp; not learner state.content-itd-022-interactive-composition
content_itemobjectrestrictQTI assessment-item and assessment-test identities feed public question, test, test_spec, and test_bank rows. QTI assessmentStimulus contributes question anatomy only and is filtered from public content_item rows. Articles, videos, audio, images, interactives, media assets, external links, and scripts are anchored to QTI/Common-Cartridge-compatible resource rows where one exists; Alpha stores only new classification and lifecycle facts in sidecars. diagram and decodable are governed subtype values. QTI sections and course/unit/chapter/lesson containers route to Curriculum.The catalog row for one student-touchable thing, across versions.content-itd-001-module-boundary-and-alias-map
content_item.usage_scopefieldextendalpha.content_item_extension.usage_scopecontent-itd-020-test-spec-and-test-bank
content_item.source_systemfieldextendsource_systemcontent-itd-001-module-boundary-and-alias-map
content_item.statusfieldextendstatuscontent-itd-007-versioned-authoring-and-student-view
content_item.created_atfieldrenameqti.artifact.created_atcontent-axis-007-eventing-model
content_item.updated_atfieldextendupdated_atcontent-axis-007-eventing-model
content_item.retired_atfieldextendretired_atcontent-axis-011-privacy-retention
content_versionobjectrestrictQTI-backed versions alias qti.artifact_version. Non-QTI authoring and TimeBack source ingest use the same append-only version target while keeping QTI-owned fields in QTI base rows.One immutable exact edition of a content item.content-itd-007-versioned-authoring-and-student-view
content_version.content_idfieldrenameqti.artifact_version.artifact_idcontent-itd-007-versioned-authoring-and-student-view
content_version.content_hashfieldrename + extendqti.artifact_version.xml_hashcontent-axis-004-concurrency-model
content_version.supersedes_version_idfieldrenameqti.artifact_version.supersedes_version_idcontent-itd-007-versioned-authoring-and-student-view
content_version.etagfieldextendetagcontent-axis-004-concurrency-model
content_version.created_atfieldrenameqti.artifact_version.created_atcontent-itd-007-versioned-authoring-and-student-view
content_version.created_byfieldrenameqti.artifact_version.created_bycontent-axis-011-privacy-retention
media_asset.content_idfieldextendcontent_idcontent-itd-004-non-qti-media-extension
media_asset.version_idfieldextendversion_idcontent-itd-007-versioned-authoring-and-student-view
media_asset.content_hashfieldrenameqti.package_file.content_hashcontent-itd-004-non-qti-media-extension
media_asset.storage_pathfieldrenameqti.package_file.package_pathcontent-itd-004-non-qti-media-extension
media_asset.delivery_urlfieldextenddelivery_urlcontent-itd-004-non-qti-media-extension
media_asset.metadatafieldrenameqti.package_file.metadatacontent-axis-011-privacy-retention
media_asset.created_atfieldrenameqti.package_file.created_atcontent-itd-004-non-qti-media-extension
external_link.content_idfieldextendcontent_idcontent-itd-004-non-qti-media-extension
external_link.display_urlfieldextenddisplay_urlcontent-itd-004-non-qti-media-extension
external_link.open_policyfieldextendopen_policycontent-itd-004-non-qti-media-extension
external_link.last_validated_atfieldextendlast_validated_atcontent-axis-010-conformance-evidence
decodableobjectextendQTI/Common Cartridge can store the article resource, but the phonics constraint set is an Alpha-owned fact needed to render and discover decodable text.Phonics-constraint sidecar for content_item rows where content_kind='article' and subtype='decodable'.content-itd-019-governed-subtypes-within-ten-kinds
decodable.content_idfieldextendcontent_idcontent-itd-019-governed-subtypes-within-ten-kinds
decodable.constraint_set_idfieldextendconstraint_set_idcontent-itd-019-governed-subtypes-within-ten-kinds
decodable.policy_versionfieldextendpolicy_versioncontent-itd-019-governed-subtypes-within-ten-kinds
decodable.updated_atfieldextendupdated_atcontent-axis-007-eventing-model
test.content_idfieldrenameqti.artifact.artifact_idcontent-itd-020-test-spec-and-test-bank
test.test_typefieldextendalpha.assessment_test_extension.test_typecontent-itd-006-typed-content-and-test-fields
assessment_testobjectextendQTI stores the assessment test XML; Alpha adds the typed fields teachers and LLMs need without parsing names or producer URLs. content-itd-020 adds first-class public test_spec/test_bank kinds with role-specific sidecars over this same QTI shape.Typed Alpha fields for QTI-backed test, test_spec, and test_bank rows.content-itd-019-governed-subtypes-within-ten-kinds
assessment_test.content_idfieldextendcontent_idcontent-itd-006-typed-content-and-test-fields
assessment_test.assessment_rolefieldextendassessment_rolecontent-itd-019-governed-subtypes-within-ten-kinds
test_spec.spec_idfieldextendalpha.test_spec_extension.spec_idcontent-itd-020-test-spec-and-test-bank
test_spec.assessment_rolefieldextendassessment_rolecontent-itd-019-governed-subtypes-within-ten-kinds
test_spec.item_type_mixfieldextendalpha.test_spec_extension.item_type_mixcontent-itd-020-test-spec-and-test-bank
test_spec.difficulty_constraintsfieldextendalpha.test_spec_extension.difficulty_constraintscontent-itd-020-test-spec-and-test-bank
test_spec.enemy_item_rulefieldextendalpha.test_spec_extension.enemy_item_rulecontent-itd-020-test-spec-and-test-bank
test_spec.updated_atfieldextendupdated_atcontent-axis-007-eventing-model
test_bank.bank_idfieldextendalpha.test_bank_extension.bank_idcontent-itd-020-test-spec-and-test-bank
test_bank.assessment_rolefieldextendassessment_rolecontent-itd-019-governed-subtypes-within-ten-kinds
test_bank.membership_rulefieldextendalpha.test_bank_extension.membership_rulecontent-itd-020-test-spec-and-test-bank
test_bank.updated_atfieldextendupdated_atcontent-axis-007-eventing-model
content_curriculum_linkobjectextendCASE/Content supplies curriculum node identity; Alpha Content owns only the coverage relationship.A real relationship from Content to the shared curriculum graph.content-itd-005-curriculum-links-are-relationships
content_curriculum_link.content_curriculum_link_idfieldextendcontent_curriculum_link_idcontent-itd-005-curriculum-links-are-relationships
content_curriculum_link.content_idfieldextendcontent_idcontent-itd-005-curriculum-links-are-relationships
content_curriculum_link.version_idfieldextendversion_idcontent-itd-007-versioned-authoring-and-student-view
content_curriculum_link.link_kindfieldextendlink_kindcontent-itd-005-curriculum-links-are-relationships
content_curriculum_link.active_fromfieldextendactive_fromcontent-itd-005-curriculum-links-are-relationships
content_curriculum_link.active_untilfieldextendactive_untilcontent-axis-011-privacy-retention
content_catalog_facetobjectextendQTI metadata is not used as Alpha extension storage. The facet sidecar follows the tag-vs-column rule: governed, low-cardinality discovery dimensions can live here until they deserve real columns.Governed catalog-facet definition for discovery metadata.content-itd-014-catalog-facets-sidecar
content_catalog_facet.facet_keyfieldextendfacet_keycontent-itd-014-catalog-facets-sidecar
content_catalog_facet.labelfieldextendlabelcontent-itd-014-catalog-facets-sidecar
content_catalog_facet.value_typefieldextendvalue_typecontent-itd-014-catalog-facets-sidecar
content_catalog_facet.grainfieldextendgraincontent-itd-014-catalog-facets-sidecar
content_catalog_facet.allowed_valuesfieldextendallowed_valuescontent-itd-014-catalog-facets-sidecar
content_catalog_facet.statusfieldextendstatuscontent-itd-014-catalog-facets-sidecar
content_catalog_facet.updated_atfieldextendupdated_atcontent-axis-007-eventing-model
content_catalog_facet_assignmentobjectextendThe assignment table is the Content-specific case of the governed tag registry. Relationships remain real columns; discovery-only facets live here until promotion.Assignment of one governed catalog facet value to Content.content-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.facet_assignment_idfieldextendfacet_assignment_idcontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.facet_keyfieldextendfacet_keycontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.content_idfieldextendcontent_idcontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.version_idfieldextendversion_idcontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.media_idfieldextendmedia_idcontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.facet_valuefieldextendfacet_valuecontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.provenancefieldextendprovenancecontent-itd-014-catalog-facets-sidecar
content_catalog_facet_assignment.retired_atfieldextendretired_atcontent-itd-014-catalog-facets-sidecar
content_refobjectextendContent exposes one reference shape so Curriculum course_component_member.target_ref and catalog/LOR workflows can point at any Content kind without special-casing.The one reference shape for every Content kind.content-itd-016-uniform-content-reference-contract
content_referenceobjectextendQTI package resources can depend on other resources, but Alpha pins one relationship row shape for every Content kind so renderers and Common Cartridge export do not special-case question, test, test_spec, test_bank, article, video, audio, image, interactive, media_asset, external_link, or script.A stored relationship from one Content row to another using the uniform content_ref contract.content-itd-016-uniform-content-reference-contract
content_reference.content_reference_idfieldextendcontent_reference_idcontent-itd-016-uniform-content-reference-contract
content_reference.display_orderfieldextenddisplay_ordercontent-itd-016-uniform-content-reference-contract
content_reference.usage_scopefieldextendalpha.content_reference.usage_scopecontent-itd-020-test-spec-and-test-bank
content_reference.referenced_usage_scopefieldderivealpha.content_reference_view.referenced_usage_scopecontent-itd-020-test-spec-and-test-bank
content_reference.created_atfieldextendcreated_atcontent-itd-016-uniform-content-reference-contract
content_reference.retired_atfieldextendretired_atcontent-itd-016-uniform-content-reference-contract
answer_slotobjectrestrictOnly QTI response declarations are exposed as answer slots; outcome/template/context declarations are internal unless used by scoring_plan provenance.QTI response declaration exposed in plain language.content-itd-008-answer-slots-not-student-answers
answer_slot.answer_slot_idfieldrenameqti.variable_declaration.variable_declaration_idcontent-itd-008-answer-slots-not-student-answers
answer_slot.content_idfieldextendcontent_idcontent-itd-008-answer-slots-not-student-answers
answer_slot.version_idfieldrenameqti.variable_declaration.artifact_version_idcontent-itd-008-answer-slots-not-student-answers
answer_slot.source_tracefieldrenameqti.variable_declaration.source_tracecontent-itd-008-answer-slots-not-student-answers
answer_keyobjectrestrictQTI correct_response is preserved but restricted to authorized reads. It is not exposed to ordinary student content reads.Teacher-only correct response and mapping for an answer slot.content-itd-008-answer-slots-not-student-answers
answer_key.answer_slot_idfieldextendanswer_slot_idcontent-itd-008-answer-slots-not-student-answers
answer_key.mappingfieldrestrictqti.variable_declaration.mappingcontent-itd-008-answer-slots-not-student-answers
answer_key.required_scopefieldextendrequired_scopecontent-axis-006-auth-shape
assessment_componentobjectrestrictQTI component elements remain the source. Alpha publishes school-language component_role values for the parts of the blank assessment that apps need to render or audit.Sections, parts, choices, rubrics, and pre-authored feedback from the QTI component tree.content-itd-008-answer-slots-not-student-answers
assessment_component.assessment_component_idfieldrenameqti.component.component_idcontent-itd-008-answer-slots-not-student-answers
assessment_component.content_idfieldextendcontent_idcontent-itd-008-answer-slots-not-student-answers
assessment_component.version_idfieldrenameqti.component.artifact_version_idcontent-itd-008-answer-slots-not-student-answers
assessment_component.parent_assessment_component_idfieldrenameqti.component.parent_component_idcontent-itd-008-answer-slots-not-student-answers
assessment_component.ordinalfieldrenameqti.component.ordinalcontent-itd-008-answer-slots-not-student-answers
assessment_component.element_namefieldrenameqti.component.element_namecontent-itd-008-answer-slots-not-student-answers
assessment_component.qti_identifierfieldrenameqti.component.qti_identifiercontent-itd-008-answer-slots-not-student-answers
assessment_component.response_identifierfieldextendresponse_identifiercontent-itd-008-answer-slots-not-student-answers
assessment_component.outcome_identifierfieldextendoutcome_identifiercontent-itd-008-answer-slots-not-student-answers
assessment_component.feedback_identifierfieldextendfeedback_identifiercontent-itd-008-answer-slots-not-student-answers
assessment_component.show_hidefieldextendshow_hidecontent-itd-008-answer-slots-not-student-answers
assessment_component.source_tracefieldrenameqti.component.source_tracecontent-itd-008-answer-slots-not-student-answers
scoring_planobjectrestrictQTI processing rules remain the source. Alpha exposes enough provenance to explain the blank scoring plan without becoming Results.QTI processing provenance for scoring a content version.content-itd-008-answer-slots-not-student-answers
scoring_plan.scoring_plan_idfieldrenameqti.processing_rule.processing_rule_idcontent-itd-008-answer-slots-not-student-answers
scoring_plan.content_idfieldextendcontent_idcontent-itd-008-answer-slots-not-student-answers
scoring_plan.version_idfieldrenameqti.processing_rule.artifact_version_idcontent-itd-008-answer-slots-not-student-answers
scoring_plan.parent_scoring_plan_idfieldrenameqti.processing_rule.parent_processing_rule_idcontent-itd-008-answer-slots-not-student-answers
scoring_plan.rule_scopefieldrenameqti.processing_rule.rule_scopecontent-itd-008-answer-slots-not-student-answers
scoring_plan.rule_namefieldrenameqti.processing_rule.rule_namecontent-itd-008-answer-slots-not-student-answers
scoring_plan.sequence_numberfieldrenameqti.processing_rule.sequence_numbercontent-itd-008-answer-slots-not-student-answers
scoring_plan.operandsfieldrenameqti.processing_rule.operandscontent-itd-008-answer-slots-not-student-answers
scoring_plan.source_tracefieldrenameqti.processing_rule.source_tracecontent-itd-008-answer-slots-not-student-answers
content_effectivenessobjectderiveContent-effectiveness fields are derived from settled Results evidence. Content exposes them beside the content item as a read dependency, not as Content-owned storage.Results-owned derived effectiveness read for one content item.content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.content_idread-dependency-fieldderivealpha.content_effectiveness.data ->> 'content_id'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.content_version_idread-dependency-fieldderivealpha.content_effectiveness.data ->> 'content_version_id'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.kc_idread-dependency-fieldderivealpha.content_effectiveness.data ->> 'kc_id'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.subject_idread-dependency-fieldderivealpha.content_effectiveness.data ->> 'subject_id'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.evidence_countread-dependency-fieldderivealpha.content_effectiveness.data ->> 'evidence_count'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.freshness_statusread-dependency-fieldderiveGET /items/{contentId}/effectiveness fallback over alpha.content_effectivenesscontent-itd-009-content-effectiveness-derived-rollup
content_effectiveness.policy_versionread-dependency-fieldderivealpha.content_effectiveness.data ->> 'policy_version'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.source_result_refsread-dependency-fieldderivealpha.content_effectiveness.data -> 'source_result_refs'content-itd-009-content-effectiveness-derived-rollup
content_effectiveness.provenanceread-dependency-fieldderivealpha.content_effectiveness.datacontent-itd-009-content-effectiveness-derived-rollup
content_trust_evidenceobjectextendCurrent runtime exposes generic producer/import trust metadata or unknown/null native trust. The accepted target binds QTI-backed content to an exact QTI conformance run and non-QTI media to a named Content validation check.Read-only trust status and validation provenance for Content.content-axis-010-conformance-evidence
content_trust_evidence.content_idfieldextendcontent_idcontent-axis-010-conformance-evidence
content_trust_evidence.trust_statusfieldextendtrust_statuscontent-axis-010-conformance-evidence
content_trust_evidence.evidence_urlfieldextendevidence_urlcontent-axis-010-conformance-evidence
content_trust_evidence.checked_atfieldextendchecked_atcontent-axis-010-conformance-evidence
content_trust_evidence.problem_codefieldextendproblem_codecontent-itd-012-plain-language-problems-and-provenance
content_policyobjectrestrictThe runtime exposes alpha.content_policy_view where rows exist, while source import executes a bundled JSON policy. A future shared alpha.policy authority must replace—not be inferred from—this current arrangement.Current Content policy projection, including module-local rows and the bundled versioned source-adapter policy.content-itd-009-content-effectiveness-derived-rollup
content_policy.policy_keyfieldextendpolicy_keycontent-itd-009-content-effectiveness-derived-rollup
content_policy.value_jsonfieldextendvalue_jsoncontent-itd-009-content-effectiveness-derived-rollup
content_policy.policy_versionfieldextendpolicy_versioncontent-itd-009-content-effectiveness-derived-rollup
content_policy.updated_atfieldextendupdated_atcontent-itd-009-content-effectiveness-derived-rollup
content_problemobjectrestrictThe envelope comes from Platform. Content adds the exact stable code and field contract emitted by implementation/impl/src/errors.mjs.Stable problem codes and field errors returned by Content APIs.content-itd-012-plain-language-problems-and-provenance
content_problem.typefieldextendtypecontent-axis-008-error-envelope
content_problem.titlefieldextendtitlecontent-axis-008-error-envelope
content_problem.statusfieldextendstatuscontent-axis-008-error-envelope
content_problem.codefieldextendcodecontent-itd-012-plain-language-problems-and-provenance
content_problem.detailfieldextenddetailcontent-axis-008-error-envelope
content_problem.requestIdfieldextendrequestIdcontent-axis-008-error-envelope
content_problem.traceIdfieldextendtraceIdcontent-axis-008-error-envelope
content_problem.causefieldextendcausecontent-axis-008-error-envelope
content_problem.docUrlfieldextenddocUrlcontent-axis-008-error-envelope
content_problem.fieldErrorsfieldextendfieldErrorscontent-axis-008-error-envelope
content_kc_tagobjectextendThe Curriculum registry supplies kc_id identity; Content owns only the mapping from its stable Content identity to that registry identity.The canonical weighted many-to-many Q-matrix row from Content to a governed registry KC.content-itd-005-curriculum-links-are-relationships
content_kc_tag.tenant_idfieldextendResolved from the authenticated route tenant.content-itd-005-curriculum-links-are-relationships
content_kc_tag.content_idfieldextendTaken from the Content item route after tenant-scoped resolution.content-itd-005-curriculum-links-are-relationships
content_kc_tag.kc_idfieldextendSupplied by an authorized Content/KC tagging workflow after registry resolution.content-itd-005-curriculum-links-are-relationships
content_kc_tag.weightfieldextendAsserted by the authorized tagging or review workflow.content-itd-005-curriculum-links-are-relationships
content_kc_tag.is_primaryfieldextendAsserted by the authorized tagging or review workflow.content-itd-005-curriculum-links-are-relationships
content_kc_tag.provenancefieldextendSupplied by the authorized tagging workflow.content-itd-005-curriculum-links-are-relationships
content_kc_tag.confidencefieldextendSupplied by the authorized tagging or review workflow.content-itd-005-curriculum-links-are-relationships
content_kc_tag.created_atfieldextendSet by PostgreSQL on initial insert.content-axis-011-privacy-retention
content_kc_tag.updated_atfieldextendSet by PostgreSQL insert/upsert.content-axis-011-privacy-retention
content_kc_tag.retired_atfieldextendSet by a governed retirement workflow; the initial public API writes null.content-axis-011-privacy-retention
content_item.source_tablefieldextendalpha.content_item_extension.source_tablecontent-itd-018-source-shaped-production-ingest
content_release_eligibilityobjectextendcontent-itd-023 trust-based exact-version eligibility under owner ruling #2534 (2026-08-05): publication plus integrity makes a version serveable; trust_status=failed is the single post-visibility revocation lever.Current lifecycle and item-revocation answer for one exact Content version.content-itd-023-trust-based-release-eligibility
content_release_eligibility.content_idfieldextendContent base identity.content-itd-023-trust-based-release-eligibility
content_release_eligibility.content_version_idfieldextendContent version identity.content-itd-023-trust-based-release-eligibility
content_release_eligibility.content_kindfieldrestrict + extendContent item kind taxonomy.content-itd-023-trust-based-release-eligibility
content_release_eligibility.usage_scopefieldextendContent item routing exposure contract.content-itd-023-trust-based-release-eligibility
content_release_eligibility.trust_statusfieldextendContent current item revocation state.content-itd-023-trust-based-release-eligibility
content_release_eligibility.serveablefieldextendContent lifecycle and item revocation state.content-itd-023-trust-based-release-eligibility
content_release_eligibility.release_eligiblefieldextendContent lifecycle and item revocation state.content-itd-023-trust-based-release-eligibility
content_release_eligibility.problem_codefieldextendContent problem envelope.content-itd-023-trust-based-release-eligibility
content_test_serve_grantobjectextendcontent-itd-024-governed-test-serveSoft-revocable demo authorization for one test/synthetic identity.content-itd-024-governed-test-serve
content_test_serve_grant.tenant_idreference-contract-fieldrestrictPlatform tenant identity.content-itd-024-governed-test-serve
content_test_serve_grant.test_serve_grant_idfieldextendContent test-serving policy.content-itd-024-governed-test-serve
content_test_serve_grant.test_identity_idreference-contract-fieldrestrictPeople & Orgs identity reference only; no person facts are copied.content-itd-024-governed-test-serve
content_test_serve_grant.producer_surfacefieldextendContent producer policy.content-itd-024-governed-test-serve
content_test_serve_grant.authorization_reffieldextendGovernance provenance.content-itd-024-governed-test-serve
content_test_serve_grant.expires_atfieldextendContent test-serving policy.content-itd-024-governed-test-serve
content_test_serve_grant.revoked_atfieldextendContent test-serving policy.content-itd-024-governed-test-serve
content_test_serve_grant.created_atfieldextendContent audit field.content-itd-024-governed-test-serve
content_test_serve_authorizationobjectextendcontent-itd-024-governed-test-serveImmutable exact bank/form test-serve receipt.content-itd-024-governed-test-serve
content_test_serve_authorization.tenant_idreference-contract-fieldrestrictPlatform tenant identity.content-itd-024-governed-test-serve
content_test_serve_authorization.test_serve_authorization_idfieldextendContent authorization evidence.content-itd-024-governed-test-serve
content_test_serve_authorization.test_serve_grant_idreference-contract-fieldrestrictContent grant reference.content-itd-024-governed-test-serve
content_test_serve_authorization.caller_subjectfieldextendVerified JWT subject.content-itd-024-governed-test-serve
content_test_serve_authorization.test_identity_idreference-contract-fieldrestrictPeople & Orgs identity reference.content-itd-024-governed-test-serve
content_test_serve_authorization.producer_surfacefieldextendContent producer policy.content-itd-024-governed-test-serve
content_test_serve_authorization.gate_component_idreference-contract-fieldrestrictCurriculum gate identity.content-itd-024-governed-test-serve
content_test_serve_authorization.bank_content_idreference-contract-fieldrestrictContent bank identity.content-itd-024-governed-test-serve
content_test_serve_authorization.bank_content_version_idreference-contract-fieldrestrictContent version identity.content-itd-024-governed-test-serve
content_test_serve_authorization.form_content_idreference-contract-fieldrestrictContent form identity.content-itd-024-governed-test-serve
content_test_serve_authorization.form_content_version_idreference-contract-fieldrestrictContent version identity.content-itd-024-governed-test-serve
content_test_serve_authorization.request_idfieldextendPlatform request tracing.content-itd-024-governed-test-serve
content_test_serve_authorization.trace_idfieldextendPlatform request tracing.content-itd-024-governed-test-serve
content_test_serve_authorization.authorized_atfieldextendContent audit field.content-itd-024-governed-test-serve
content_test_serve_eligibilityobjectrestrictcontent-itd-024-governed-test-serveCurrent fail-closed answer for one exact Content version and one test identity.content-itd-024-governed-test-serve
content_test_serve_eligibility.content_idread-dependency-fieldderiveContent identity.content-itd-024-governed-test-serve
content_test_serve_eligibility.content_version_idread-dependency-fieldderiveContent version identity.content-itd-024-governed-test-serve
content_test_serve_eligibility.content_kindread-dependency-fieldderiveContent kind.content-itd-024-governed-test-serve
content_test_serve_eligibility.usage_scoperead-dependency-fieldderiveContent usage policy.content-itd-024-governed-test-serve
content_test_serve_eligibility.producer_surfacefieldextendContent producer policy.content-itd-024-governed-test-serve
content_test_serve_eligibility.test_identity_idread-dependency-fieldderivePeople & Orgs identity reference.content-itd-024-governed-test-serve
content_test_serve_eligibility.test_serve_grant_idreference-contract-fieldrestrictContent grant.content-itd-024-governed-test-serve
content_test_serve_eligibility.test_serve_eligiblefieldextendContent test-serving policy.content-itd-024-governed-test-serve
content_test_serve_eligibility.problem_codefieldextendContent error contract.content-itd-024-governed-test-serve

Generated cut map

This is the complete public Alpha cut list. Every excluded upstream/runtime object has an audience-facing reason and a deep link to the decision that owns the tradeoff.

Excluded source/objectChangeAudience tradeoff / owning boundaryOwner ITD
qti.delivery_sessioncutA delivery session is a learner runtime moment/snapshot. It belongs to Events/Results runtime handling, not Content.content-itd-011-public-cuts-and-internal-provenance, content-itd-008-answer-slots-not-student-answers
qti.attemptcutAttempts contain student responses and processed outcomes. Content owns the blank answer slots and scoring plan only.content-itd-011-public-cuts-and-internal-provenance, content-itd-008-answer-slots-not-student-answers
oneroster.result / oneroster.lineItemcutDurable outcomes and gradebook rollups live in Results, not the blank Content module.content-itd-011-public-cuts-and-internal-provenance, content-itd-008-answer-slots-not-student-answers
QTI internal artifact kinds: result, usage-data, metadata, response-processing, outcome-declaration, manifest-resourcecutThey remain upstream provenance or generated processing evidence, but they are not ordinary student-touchable Content catalog objects.content-itd-011-public-cuts-and-internal-provenance, content-itd-003-content-kind-taxonomy
QTI sections and course/unit/chapter/lesson/lesson_section containerscutInstructional containers and sequence structure are Curriculum. Content owns only the student-touchable things referenced from those containers.content-itd-011-public-cuts-and-internal-provenance, content-itd-003-content-kind-taxonomy
question bank, playlist, library, course bundle, and collection membershipcutCollections are Curriculum-side organization of references to Content. Content exposes uniform content_id/version_id references and does not store kind-specific collection tables.content-itd-011-public-cuts-and-internal-provenance, content-itd-013-lossless-common-cartridge-round-trip
imscp_v1p1 / Common Cartridge bundlecutA bundle is transport output generated on demand from a Curriculum collection plus referenced Content. It is never a stored Content kind.content-itd-013-lossless-common-cartridge-round-trip, content-itd-011-public-cuts-and-internal-provenance
student mastery / student knowledge graphcutThe student's knowledge graph is a Results overlay on Curriculum. Content may carry weighted links to registry KCs but never stores learner mastery state.content-itd-011-public-cuts-and-internal-provenance, content-itd-005-curriculum-links-are-relationships
qti.assessmentStimulus as a standalone public Content rowcutStimulus remains question anatomy so student/app-builder consumers get one complete question instead of a second asset they must join and launch independently.content-itd-003-content-kind-taxonomy
raw QTI package bytescutRaw package bytes remain upstream transport/provenance; Alpha consumers receive governed Content assets and on-demand exports rather than a second stored package object.content-itd-011-public-cuts-and-internal-provenance, content-itd-013-lossless-common-cartridge-round-trip
generic qti.component / object-graph browsingcutAlpha exposes only the blank assessment-component roles renderers and teachers need; generic graph browsing would force app builders to reconstruct QTI internals and widen unsafe mutation scope.content-itd-008-answer-slots-not-student-answers, content-itd-011-public-cuts-and-internal-provenance
standalone qti.variable_declaration / qti.processing_rule row APIscutAuthorized consumers receive answer-slot and scoring-plan projections; standalone internals would leak QTI processing vocabulary without improving the blank-instrument job.content-itd-008-answer-slots-not-student-answers, content-itd-011-public-cuts-and-internal-provenance
qti.conformance_run mutation and controlcutThe accepted target lets Content consumers read exact-version trust evidence, but current runtime exposes only generic/unknown provenance. Starting or mutating conformance jobs stays with release/QTI tooling to avoid exposing an expensive control surface.content-axis-010-conformance-evidence, content-itd-011-public-cuts-and-internal-provenance
submissions, outcome_state, learner processing_trace, AI grading audit, and post-attempt feedbackcutThese are learner-specific runtime/outcome evidence; keeping them in Events/Results gives Content consumers reusable blanks without PII, attempt state, or private gradebook semantics.content-itd-008-answer-slots-not-student-answers
Merlot, OER Commons, Khan, IXL, provider library, playlist, and provider question-bank tablescutProvider adapters map onto ordinary Content, Curriculum, facets, references, and transport so customers can switch sources without adopting provider-specific platform storage.content-itd-017-lor-clones-no-specific-storage

Cross-cutting obligations

Tag registry vs. real column

Number: 1

ContentObligation: Content uses weighted content_kc_tag relationship rows for registry-KC alignment and typed content_reference rows for content-to-content relationships; content_curriculum_link remains a frozen archive. Typed view/extension columns hold content_kind, expected_xp, subject_id, target_grade_id, media_type, test_type, is_mastery_gate, test_family_id, usage_scope, source_system, and source_record_id. Catalog discovery dimensions live in named governed sidecars and promote to real columns only when they become join, constraint, or computed inputs.

Point-in-time default

Number: 2

ContentObligation: Content is not roster membership. Authoring and TimeBack ingest use immutable base QTI rows or extension rows keyed to exact versions, and list reads preserve version identity. Content must not expose a 'current only' shortcut that hides which version a student saw; changed source bytes append, and historical hash replay never rolls the served pointer backward.

Typed field, never parsed

Number: 3

ContentObligation: Content kind, expected_xp, curated expected_xp_band assignments, subject, grade band, modality, language, test type, mastery gate, usage scope, media kind, media type, source family, source record id, and source activity ref are set on base write-through, source ingest, extension write, or catalog curation and never inferred from titles, URLs, package paths, MIME type, or display text at read time. The documented expected_xp_band= convenience filter is a runtime-owned numeric projection over expected_xp, not evidence of a stored facet assignment.

Policy config

Number: 4

ContentObligation: Content thresholds and policy lists, including effectiveness freshness, display cutoffs, catalog facet value sets, speed-running calibration rules, and expected_xp banding, live under alpha.policy.* and are not duplicated in apps.

Event/result/gradebook separation

Number: 5

ContentObligation: Content holds blank instruments and media. Events holds interactions. Results holds answers, scores, mastery, and gradebook rollups.

Two graphs, two homes

Number: 6

ContentObligation: Content links to Curriculum's shared graph. It never stores the student's knowledge graph or mastery state.

NWEA account boundary

Number: 7

ContentObligation: Content does not carry brand/modality/NWEA account grouping. MAP-related content can carry subject/test family, while district account grouping remains People & Orgs/Results.

Secrets are not fields/tags

Number: 8

ContentObligation: Content metadata, media records, and tags cannot contain student app credentials, raw tokens, or secret values.

XP ledger separation

Number: 9

ContentObligation: expected_xp is student-independent Content configuration. Speed-running is the accepted calibration policy, but current publication/import paths do not require proof of a speed-run and may persist policy-derived or default values. Awarded XP, repeat-attempt discounts, effort signals, negative XP, and reward triggers live in the Results XP ledger and Policy, never in Content.

Content effectiveness rollup

Number: 10

ContentObligation: Results owns alpha.content_effectiveness as the derived rollup over settled result evidence. Content exposes a read endpoint that queries the Results-owned public view and safely returns insufficient_data when no Results evidence exists; apps never maintain counters.

Named ingest adapters

Number: 11

ContentObligation: Content owns the TimeBack production content ingest adapter for source-shaped content/activity-reference rows and stores nullable blank test_family_id. Current import does not populate/resolve that family id, Results has no Content family foreign key, and the importer neither appends frozen curriculum-link rows nor mints content_kc_tag rows without an authorized registry resolution workflow. Implemented import failures return HTTP 400 or 422 Problems, never HTTP 200 Problems.

Universal gate failure protocol

Number: 12

ContentObligation: Content owns the blank spec/bank/forms as the entity home (#72, content-itd-020): a mastery_gate gating member target_ref points at a Content test_bank (curriculum/alpha caitd-013), and 'equivalent form' resolves to the lowest-index unseen bank member whose content_reference.usage_scope and referenced content_item.usage_scope are both practice_eligible; held_out_canary and secure_form remain readable but excluded from routine retries/practice. Gate fields, passing_criteria, on_fail, retake cooldown, and the mastery-cutoff number stay on Curriculum course_component_member and alpha.policy; the spec's passing_rule is referenced, never restated as a number. A grade gate's bank must hold at least the spec's min_forms equivalent forms. Content tests remain reusable blank instruments that may be gated differently in different members.

Rewards and motivation are Policy

Number: 13

ContentObligation: 100for100 payouts, league promotions, streak bonuses, penalties, and reward amounts never live on Content rows or catalog facets.

Goal-to-effort conversion

Number: 14

ContentObligation: GOALS reads expected_xp through Content/Curriculum and Results/Policy. Content does not predict hours, calendar dates, RIT targets, or course progress.

LOR clone storage

Number: 15

ContentObligation: Merlot, OER Commons, Khan Academy library, IXL skill plans, question banks, playlists, and libraries add no clone-specific Content storage; they are recipes over one-row-per-asset Content, content_ref/content_reference rows, Curriculum, catalog facets, and Common Cartridge transport.

Locked vocabulary

Number: 16

ContentObligation: Content items are views or configuration. expected_xp is config. content_effectiveness is a Results-owned derived read. Awarded XP is a Results ledger entry. Course progress is a measure outside Content. Future GOALS output is a prediction outside Content.

Receipt-backed exact-version release eligibility

Number: 17

ContentObligation: Content computes release_eligible exactly equal to serveable from the owning item lifecycle, item revocation state, and the server-owned QC receipt for the requested immutable version: status=published, retired_at=null, item trust trusted/degraded, and the matching version receipt trusted/degraded. A later version cannot inherit an older receipt. Setting item trust_status=failed is the immediate all-version revocation lever. No producer release evidence, required quality-bar tuple, owner allowlist, or second attestation participates. Curriculum stores only its exact Content reference and asks Content at authoring and launch; consumers never copy or recompute serveable or release_eligible.

Bounded test-bank graph writes

Number: 18

ContentObligation: Every active test-bank graph writer budgets its complete post-write result inside the owning transaction under the tenant graph fence: public and repository/direct active embeds and bank_member writes, KC-tag upsert/revival, QTI package import, and TimeBack materialization. A cardinality-neutral active repository/materializer replay still executes this budget; a completed API idempotency replay returns its prior result without executing a graph writer. One write may affect at most 1,024 banks, and every affected bank may have at most 1,024 active bank-member facts and 4,096 joined form/question/active-KC facts. All three ceilings are inclusive. The 1,025th affected bank or active member and the 4,097th joined fact return HTTP 409 content.invalid_test_bank_member_contract; member overflow identifies fieldErrors.name=bank_members, while affected-bank and joined-fact overflow identify fieldErrors.name=form_graph. The rejected transaction leaves no lasting graph, parent timestamp/ETag, or fresh idempotency-ledger effect. Retirement remains available as remediation: retire active member/embed/KC-tag facts or split shared forms/questions/banks to reduce fanout, then retry.

Content owns the stored HTML body vocabulary; Curriculum selects renderer_ref per member; QTI owns XML/scoring; Events/Results own durable learner progress. The renderer and host must not create a private progress store.

Name: tb_markup_renderer_progress_seam

Owner: Content dictionary with Curriculum renderer_ref and Events/Results progress seams

Tokens: tb-instructional-content; tb-article-container; tb-segment; tb-interaction; tb-qti-assessment-item; tb-applet; tb-catalog; tb-qti-config; tb-applet-config; data-catalog-idref; practice-step; example-practice-container; headers-row; header; step-row; step; example-step; answer-box; tb-glossary-term; tb-glossary-definition; tb-narration; tb-narration-audio

Renderer: {"renderer_ref":"renderer:interactive-lesson","iframe_url":"https://platform3-andymontgomery-9773s-projects.vercel.app/player","playground_url":"https://platform3-andymontgomery-9773s-projects.vercel.app/player?demo=1","implementation_ref":"platform3:first-party-reference-player:/site/player","versioned_iframe_url":"https://platform3-andymontgomery-9773s-projects.vercel.app/player/versions/2026-08-05.issue-2501-article-html/","player_version":"2026-08-05.issue-2501-article-html","capability_matrix_url":"https://platform3-andymontgomery-9773s-projects.vercel.app/player/renderer-capabilities.json","registered_for_routing":true,"verified_rendering":true,"rendering_state":"verified_partial","content_load_fields":["html","qtiXml","testForm","title","contentId","contentRef","gateComponentId","studentId","interactiveComposition","contentState","config"],"host_messages":["CONTENT_LOAD","TTS_GENERATE_RESPONSE"],"renderer_messages":["CONTENT_READY","CONTENT_STATE_CHANGE","CONTENT_RESIZE","CONTENT_ERROR","TTS_GENERATE_REQUEST"],"preview_affordances":["ad_hoc_html","ad_hoc_qti_xml_a1_text_structural","exact_test_form_fixture"]}