Standards/framework source text
case.cf_document + case.cf_item + case.cf_association
One field-level authority for immutable standards releases, governed KCs, reusable course structure, ordered members, and exact-version Content references. A cold builder should need no Incept documentation or source code.
Target: The four-store model in this dictionary is the accepted authority after verified cutover.
Compatibility: The deployed Curriculum API currently reads CASE-backed components. Component GET fails closed rather than selecting one edge when storage has multiple active parents. POST /components creates initial placement; an isolated PATCH /components/{componentId} with parent_component_id + position atomically replaces the component's one active containment parent while preserving component/edge identity and every non-containment reference. Generic association POST and TimeBack ingest cannot add a second active parent; ingest also cannot replace a parent. A one-object lesson may carry one direct target. A producer-authoritative no-KC lesson is represented only by kind=lesson with an exact eligible target_ref, a compatible registered renderer_ref, scope_kc_refs=[], and kc_scope_decision=authoritative_no_kc; detail, tree, and next-lesson repeat that exact decision, and the lesson contributes no KC-version snapshot or mastery evidence. Missing or unresolved KC scope still fails closed. For a many-item lesson, create one stable ordered child practice/review component per Content item with parent_component_id=lesson, matching KC scope, target_ref, and renderer_ref; discover all targets through the lesson tree or GET /components?parentId=lesson. This is a one-for-one compatibility adapter to future member rows, not authority to add another member store. curriculum.component_sample remains only so deployed conformance probes can verify that compatibility read.
Cutover: The #707 KC registry cutover is complete. This pending-cutover rule applies only to still-unshipped course/component/member targets: do not advertise them as deployed until migrations, reconciliation, parity, and live readback pass.
Dual authority: Forbidden. Legacy CASE KC rows and source crosswalks are immutable migration evidence only; active KC identity, versions, graph, standards links, scope, remediation, reads, and lifecycle operations use the registry-native stores.
Curriculum owns student-independent scope, sequence, KC identity, reusable course structure, and ordered teaching delivery. It references but never stores Content bodies, Results state, Events, People and Orgs facts, Policy numbers, or Incept steward behavior.
case.cf_document + case.cf_item + case.cf_association
alpha.standards_source_* records
alpha.knowledge_component* + alpha.kc_*
alpha.course + alpha.course_component
alpha.course_component_member
Content exact-version contract
Results
Incept
Every public name resolves to exactly one authoritative store, derived view, compatibility read, or surface command. Aliases never move/copy data, and a view is never a second authority.
loop/curriculum/artifacts/alpha/architecture/site/alias-map.json
Generate owning Curriculum artifacts from the machine-readable registry, but consume the deployed descriptor at runtime; do not copy this list into clients or confuse it with the six-subject Results/HMG reporting subset. Economics, history, geography, and civics remain course-grain disciplines rather than subject ids.
Deployed: mathreadinglanguagesciencecomputer_sciencevocabularywritingsocial_studies
Only course_component_member selects renderer_ref. Writes reject missing, unknown, inactive, or content-kind-incompatible capabilities; renderer_kind is compatibility only when it resolves to the same registry row.
renderer_refaccepted_content_kindsintegration_endpointintegration_protocolplayground_urlimplementation_pointerlifecycle_stateverified_capability_evidence
Every value is a versioned alpha.policy row. Curriculum identity rows store references only, never thresholds, weights, rewards, calendars, cut scores, or retake numbers.
Curriculum creates: alpha.policy.mastery_cutoff · alpha.policy.placement_weights · alpha.policy.xp_award_formula · alpha.policy.spaced_repetition_model · alpha.policy.gate_retake_cooldown
Results creates: alpha.policy.reward_rules · alpha.policy.stuck_attempt_threshold · alpha.policy.growth_x_target · alpha.policy.proxy_subject_rules · alpha.policy.school_year_boundaries · alpha.policy.school_day · alpha.policy.rit_calculator · alpha.policy.99_level_thresholds · alpha.policy.tenure_buckets
Only green may proceed. CASE transport is never content-use permission.
source Selection Owner: The producer selects a source and supplies evidence under its runbook; Platform3 does not infer a source or silently broaden scope.
acquisition Rule: Acquisition records what was retrieved and from where. Acquisition alone never admits rows for generation, publication, or customer use.
transport Rights Rule: Successful CASE transport proves syntax/interchange only. It is not permission to copy, transform, generate from, publish, or redistribute source content.
scope Rule: Every admission names an exact authority + subject/grade/jurisdiction/version row scope. A partial source must be named as a partial scope; it may not use the unqualified authority/framework name.
rights Precedence: The most-specific material-grain rights record effective at evaluation time wins. A missing, expired, conflicting, or unknown record resolves to unknown and cannot inherit a broader permitted record.
counsel Rule: Counsel owns disputed ownership, contract interpretation, permissions, and risk exceptions. A technical operator cannot turn yellow/red into green; the counsel decision is stored as a new effective-dated rights record with evidence_ref and counsel_decision_ref.
fail Closed Rule: Only green may enter an active standards/KC/course workflow. Yellow and red return typed Problems and never degrade to warnings.
GREEN: All in-scope rows are bound to one immutable release; readback is lossless; effective material rights are permitted or public_domain; required attribution exists; the declared row scope is non-empty and exact. Generation/adoption may proceed for that scope only.
YELLOW: Evidence, scope, rights, attribution, or readback is incomplete/disputed but not conclusively prohibited. Quarantine: no generation, publication, or customer use until a new decision resolves every finding.
RED: Any effective material is prohibited, the source/scope is misrepresented, lossless evidence is irrecoverable, or counsel rejects use. Reject the release for adoption; preserve audit evidence.
API: Per-resource KC, version, relation, review, course, component, member, approval, firming, crosswalk, and import writes under /alpha/curriculum/v1
Author into the owning table; semantic KC edits append immutable versions, optional source_kc_id remains provenance only, and every graph/scope/remediation reference uses an exact active tenant-owned registry kc_id validated before any write. A direct POST /components with a caller-supplied component_id that matches a soft-retired CASE component reactivates that same identity only as draft: preserve its original created_at, advance its CASE version, clear retired_at, and reactivate a supplied same-id retired containment edge transactionally. If a surviving active child is reattached to the recreated parent through a new edge id, the active exact child/parent pair supersedes retired same-pair history for current tree, routing, and publication validation while the tombstone remains immutable audit history. An isolated component PATCH with parent_component_id + position locks and replaces exactly one active containment edge, preserves stable component/edge identity plus every other incident reference, and rejects zero/multiple parents, cycles, cross-tenant parents, or an occupied target position without partial writes; generic association POST refuses a second active parent, and TimeBack ingest may replay initial placement but cannot replace or add a parent. It never returns 201 without durable active readback. KC clustering remains producer/learning-scientist-owned and non-empty multi-KC lesson scope is preserved. The only sanctioned empty lesson scope is direct kind=lesson authoring with an exact eligible target_ref, compatible renderer_ref, scope_kc_refs=[], and kc_scope_decision=authoritative_no_kc; Curriculum echoes that decision and never synthesizes a KC.
curriculum:validation_failedcurriculum:reference_unresolvedcurriculum:kc_semantics_conflictcurriculum:precondition_requiredcurriculum:precondition_failed
API: GET /alpha/curriculum/v1/tracks/{trackId}/placement-candidates?studentId=…&subjectId=…
Resolve the track entry_policy_ref. PowerPath starts at the lowest or screener-selected likely-mastered grade, tests upward, and returns the first grade below the Policy mastery threshold. MAP/RIT may choose only the starting point, never final placement.
API: GET /alpha/curriculum/v1/courses/{courseId}/next-lesson?studentId=…&subjectId=…
Choose the first ordered lesson/review/practice/mastery-gate frontier before applying publication filters; require the course root, that candidate, and every containment ancestor to be published; require the exact current graph to have an immutable approval with a complete firm, active KC-version snapshot; and revalidate the candidate's exact Content version through Content-owned release eligibility. Draft, retired, changed, unapproved, incomplete, unavailable, malformed, mismatched, or ineligible state fails closed and never exposes a later node. Read student state from Results; Curriculum never stores or recomputes the student's realized path.
curriculum:not_foundcurriculum:lesson_structure_missingcurriculum:course_not_routablecurriculum:content_not_eligiblecurriculum:content_unavailablecurriculum:content_version_mismatchcurriculum:invalid_content_bank_member_contract
API: GET /alpha/curriculum/v1/gates/{gateId}/status?studentId=…
Read Results evidence and the member's passing_criteria_ref. Curriculum returns the resolved contract/status and never recomputes or stores Policy cut values or Results outcomes.
API: GET /alpha/curriculum/v1/gates/{gateId}/remediation?studentId=…&resultRecordId=…
Return typed shared choices never_learned→lesson, forgot→review, careless→practice. Results owns any per-student inserted sequence; clients never classify the miss.
API: POST Content /tenants/{tenantId}/alpha/content/imports/qti-package; for one primary object GET then PATCH /alpha/curriculum/v1/components/{lessonId}; for multiple items POST /alpha/curriculum/v1/components once per targeted child practice/review component; GET /alpha/curriculum/v1/components/{lessonId}/tree or GET /alpha/curriculum/v1/components?parentId={lessonId}
Provision a new course in owner order: import/admit its standards framework and use the returned framework identity in course standards_framework_refs; have the owning author create each missing governed registry KC with POST /alpha/curriculum/v1/kcs using stored_as=alpha.knowledge_component, definition, and optional provenance-only source_kc_id; retry only with the original Idempotency-Key or exact canonical kc_id, because source_kc_id never resolves an identity; capture and verify the returned canonical kc_id through GET /alpha/curriculum/v1/kcs/{kcId}; use only that exact UUID in prerequisite, scope, remediation, standards-map, and Content-attribution references. Write prerequisite ordering through POST /alpha/curriculum/v1/kc-prerequisites; write other typed graph semantics to alpha.kc_relation and standards links to alpha.standard_kc_map; never create KC containment. Import Content, then route each returned exact Content tuple {content_id, content_version_id, content_kind} from Curriculum after Content-owned release-eligibility succeeds. stored_as is a governed-authority assertion, not a physical-store selector. Migrated CASE/source ids are immutable evidence, never active read/retire aliases or UUID reference values. An ordinary scoped lesson preserves the producer-authored non-empty KC cluster and may carry many scope_kc_refs. When the producer explicitly decides that one content-bearing lesson has no authored KC attribution, POST /alpha/curriculum/v1/components sanctions only kind=lesson with the exact eligible target_ref, compatible renderer_ref, scope_kc_refs=[], and kc_scope_decision=authoritative_no_kc; Curriculum never substitutes a similarity, course-root, standards, or Content-tag binding. The accepted target cardinality is one course_component_member per ordered Content use. Until member routes are deployed, the CASE component compatibility adapter uses one stable targeted child practice/review component per additional item under the lesson; repeatedly PATCHing the lesson target replaces the prior direct target and is forbidden for many-item attachment. Standards import never mints KCs, Content kc-tags never encode lesson membership, and the frozen Content curriculum_node_id archive is not a current routing index.
Readback: The deployed compatibility BFF reads every targeted child from the lesson tree or parent-filtered component list; the target BFF reads member rows after verified cutover. Content /kc-tags may independently prove weighted item-to-KC attribution. GET Content items?curriculum_node_id=… remains historical archive compatibility only, has no automatic TTL, and receives no new placements.
API: POST /alpha/curriculum/v1/ingest/timeback-course-refs
Normalize only the courses → course_components → component_resources → resources boundary into course, reusable component, and ordered member rows. Resources pass through Content first, whose handoff must supply content_id, content_version_id, and content_kind; missing, malformed, mismatched, or ineligible exact versions fail closed and Curriculum never infers latest. Every lesson preserves its authored non-empty active kc_id cluster, including multi-KC scope; learning_objectives, standards, standard, and other standards-shaped evidence return curriculum:adapter_rejected and must use POST /alpha/curriculum/v1/standards-frameworks/import; course ingest never writes CASE standards or fabricates KCs; a source quiz is not a gate without explicit member gate fields.
Readback: Assembly writes deterministic identities as draft, verifies the exact intended tree, publishes components bottom-up, and publishes the course root last. Same-run retry upserts the same identities. Successful complete imports materialize readable course/component/member rows and become structurally routable only after root-last publication; launch still requires a matching immutable course approval, a complete firm active KC-version snapshot, and fresh exact Content eligibility. Source-empty or KC-unscoped known anchors return 409 curriculum:lesson_structure_missing; draft, retired, partially published, unapproved, or snapshot-incomplete graphs return 409 curriculum:course_not_routable and never skip forward.
API: POST /alpha/curriculum/v1/transports/common-cartridge/import and POST /alpha/curriculum/v1/transports/common-cartridge/preview
Import/export is transport over CASE standards, the course/component/member graph, and exact-version Content references. Produce bundles on demand and never store a cartridge as Curriculum authority.
A PP100 gate binds one exact Content adaptive bank and this exact versioned policy. Curriculum owns placement and remediation routing but does not select a fixed form, choose a question, store a score, or decide mastery. Results freezes the exact eligible Content pool at attempt start, deterministically selects an unseen question from the current score band, applies the governed score walk, pauses the same attempt for remediation after 30 responses in one session, and resumes with score and history intact. Mastery and spaced-retrieval eligibility occur only at exactly 100; errors can set the score back but can never make mastery mathematically unreachable. At scores 90–99 only Content-calibrated hard questions at standardized-test rigor are eligible, with no downward fallback unless the owning blueprint marks the lesson prerequisite.
This fixed-form route remains for non-PP100 gates and immutable historical PP100 v1 attempts. PP100 v2 never calls it: Results resolves the gate's exact pp100_adaptive_shards bank directly through the governed Content pool contract. Ordinary fixed-form learners launch only a published, complete gate whose exact bank and candidate form versions pass Content-owned release eligibility. Published gates always try that ordinary path first, and only an authoritative ineligible answer may enter Content's governed test-serve lane; timeouts, network errors, malformed answers, and target mismatches fail closed. Content's typed invalid-bank graph answers (content.invalid_test_bank_member_contract or content.bank_kc_attribution_incomplete) map immediately to HTTP 409 curriculum:invalid_content_bank_member_contract and can never enter test-serve, be treated as empty membership, or skip to a later form. A targetless draft rejects before Content reads, but a draft gate with a complete exact test_bank target may launch only when the exact student person_id is authorized by Content's demo-only grant plus live People & Orgs test/synthetic reality. Both fixed-form lanes evaluate at most 50 immutable exact members, require practice_eligible relationship and referenced-item scopes, and choose the same lowest-index unseen form. Test-serve additionally requires Content to atomically revalidate the exact bank/form membership and append an immutable authorization receipt before Curriculum returns serve_mode=test plus receipt/grant ids. A denied real identity keeps curriculum:invalid_gate_contract for a draft gate. Empty/oversized membership remains curriculum:invalid_gate_contract, no eligible forms remains curriculum:content_not_eligible, and only an eligible set with zero unseen forms is curriculum:bank_exhausted. Curriculum never substitutes latest, accepts a preview flag, or caches the test authorization.
curriculum_mastery_gate_test_bank_reference · curriculum_governed_test_identity_draft_gate_launch
Each blueprint item counts toward exactly one primary KC; secondary Q-matrix tags do not count twice. Standards breadth resolves the primary KC through alpha.standard_kc_map, never by substituting a standard for KC identity.
Fixed forms are comparable only when every hard blueprint constraint matches and item overlap is zero. passing_rule carries per-KC/gateway loss assumptions and defaults strict for prerequisite gates; numeric cuts stay in alpha.policy and the source corpus says 90%, not 89.5%.
curriculum_ls_pin_comparable_forms · curriculum_ls_pin_passing_rule_loss
rights_statusunknownpermittedrestrictedprohibitedpublic_domain
admission_outcomegreenyellowred
standards_material_grainreleaseframeworkstandardstatementattachment
readback_mismatch_codenonemissing_source_rowunexpected_source_rowtext_changedidentifier_changedorder_changedrelationship_changedrights_scope_changedraw_checksum_mismatchnormalized_checksum_mismatchparser_version_mismatch
kc_kindsubstantivedisciplinaryapplicationintegrative
kc_write_stored_as_assertionalpha.knowledge_component
kc_version_statusdraftfirm
kc_relation_typeapplies_toinstantiatesintegratesinterferes_withsplit_frommerged_intosupersedes
kc_source_identity_mapping_kindpreserved_uuiddeterministic_uuid_v5adopted_registry_source_kc_id
kc_case_migration_entity_typeknowledge_componentprerequisitestandard_kc_maplineage
kc_case_migration_dispositionacceptedrejected
kc_case_migration_rejection_reasonsource_retiredunresolved_tenantduplicate_source_identitymissing_definitionmissing_subject_idinvalid_kc_kindtarget_identity_collisionunresolved_kc_endpointself_loopcycle_sccnot_kc_standard_pairunresolved_standard_bindingambiguous_standard_binding
kc_review_decisionaccept-as-newmap-to-existingeditsplitmergereject/relocatedefer
firming_reasoncourse_approvalfirst_genuine_response
standard_kc_relationshipexactbroadernarrowersupports
course_rolemainhole_fillingremediationcatalog
component_kindtrackgradecourseunitmodulechaptersectiontopiclessonpracticereviewquiztestmastery_gateremediation_pocketplaceholder
kc_scope_decisionauthoritative_no_kc
target_kindcourse_componentcontent_version
component_target_repoint_operationrepointattach
publication_statusdraftpublishedretired
gate_remediation_reasonnever_learnedforgotcareless
alpha.subjectmathreadinglanguagesciencecomputer_sciencevocabularywritingsocial_studies
25 tables/views and 280 explicit fields. Each Alpha rule traces to architecture; CASE bodies trace to the upstream spec.
Immutable checksum-addressed evidence for one retrieved source scope.
curriculum_immutable_standards_source_release
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
source_release_id | UUIDrequired | Platform3-minted immutable release identity derived from the canonical source scope, checksums, parser, and release evidence. Constraint: Primary key with tenant_id; never derived solely from a mutable publisher URL. An exact replay reuses this id without writing; changed evidence mints a new id. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
source_system | TEXTrequired | Stable importing/source-system namespace used with source_framework_id to serialize one release lineage. | incept |
source_framework_id | TEXTrequired | Publisher/source identity shared by every immutable release in one framework lineage. | TX-TEKS-MATH-G3 |
source_authority | TEXTrequired | Publisher or authority responsible for the source. | Texas Education Agency |
official_source_url | URIrequired | Official retrieval origin. | https://tea.texas.gov/academics/curriculum-standards/teks |
declared_scope | JSONBrequired | Exact jurisdiction, subject, grade, edition, and row-membership scope admitted by this release. Constraint: Canonical object requires jurisdiction, subject, non-empty grades, edition, rowFilter, expectedRowCount, sourceRowKeysSha256, isPartial, and officialFrameworkName. expectedRowCount and the sorted source-row-key hash cover every binding, including the framework binding. Both must match exactly; partial scopes require an honest partial_display_name distinct from officialFrameworkName. | {"jurisdiction":"TX","subject":"math","grades":[3],"edition":"2024","rowFilter":"strand=3.4","expectedRowCount":130,"sourceRowKeysSha256":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","isPartial":true,"officialFrameworkName":"Texas Essential Knowledge and Skills for Mathematics"} |
partial_display_name | TEXTnullable | Honest customer-visible name for a partial source. Invalid when: Null when declared_scope is narrower than the official source, or equal to the unqualified authority/framework name for a partial scope. | Texas Math Grade 3 — Strand 3.4 only |
license_url | URInullable | Publisher license or terms location; null never means permission. | https://tea.texas.gov/terms |
release_rights_status | TEXT enumrequired enum: rights_status | Release-level default rights classification. Constraint: unknown is explicit; material overrides are resolved separately. | unknown |
required_attribution | TEXTnullable | Exact attribution required when use is permitted. | Source: Texas Education Agency |
retrieved_at | TIMESTAMPTZrequired | Timestamp of raw retrieval. | 2026-07-16T12:00:00Z |
raw_artifact_sha256 | TEXTrequired | Lowercase SHA-256 of the immutable raw artifact at raw_checksum_grain. Constraint: Exactly 64 lowercase hex characters. | 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef |
raw_checksum_grain | TEXTrequired | What exact bytes the raw checksum covers. | downloaded_zip_bytes |
parser_name | TEXTrequired | Named parser used for normalization. | tea-teks-json |
parser_version | TEXTrequired | Immutable parser version. | 2.1.0 |
normalized_artifact_ref | URI or opaque refrequired | Immutable normalized artifact location/reference. | artifact://standards/8a17f30a/normalized.json |
normalized_artifact_sha256 | TEXTrequired | SHA-256 of normalized bytes under normalization_profile. Constraint: Exactly 64 lowercase hex characters. | abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 |
normalization_profile | TEXTrequired | Versioned, lossless normalization rules used for readback. | case-lossless-v1 |
source_policy_ref | URIrequired | Versioned source-selection/admission policy evidence used for this release. | https://github.com/andymontgomery-byte/incept-skill-pack/blob/main/docs/standards-source-acquisition.md#v1 |
imported_by | TEXTrequired | Authenticated actor/application reference. | app:incept |
imported_at | TIMESTAMPTZrequired | Server-assigned immutable insert time. | 2026-07-16T12:01:00Z |
supersedes_source_release_id | UUIDnullable | Immediately prior immutable release in this source_system + source_framework_id lineage. Relationship: Self-FK alpha.standards_source_release within tenant; null only for the first known release or an exact historical replay response. | c30e0884-40a8-42e0-a969-c6fe8bdb1767 |
is_frozen | BOOLEANrequired | Storage guard proving this release and its bound CASE rows are append-only. Constraint: Always true. UPDATE and DELETE fail; changed reimport inserts a new superseding release. | true |
Lossless, one-release binding from each admitted source row/material to its CASE row.
curriculum_immutable_standards_source_release
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
binding_id | UUIDrequired | Immutable binding identity. Constraint: Primary key with tenant_id. | f1ad17e0-2508-4e7a-95df-93ffb5aa3399 |
source_release_id | UUIDrequired | Owning immutable release. Relationship: Many-to-one alpha.standards_source_release. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
source_row_key | TEXTrequired | Stable locator inside the raw artifact. Constraint: Unique with tenant_id + source_release_id. | sheet=Grade3,row=142 |
material_grain | TEXT enumrequired enum: standards_material_grain | Rights/readback evaluation grain. | standard |
source_locator | JSONBrequired | Lossless file/page/sheet/row/path locator. | {"file":"math-g3.xlsx","sheet":"Grade3","row":142} |
source_identifier | TEXTrequired | Publisher identifier exactly as supplied. | 3.4A |
case_resource_type | TEXTrequired | Bound CASE type. Constraint: cf_document, cf_item, or cf_association. | cf_item |
case_resource_id | UUIDrequired | Tenant-scoped CASE row id. Relationship: Polymorphic FK validated against case_resource_type. | 657b306e-4bd8-4938-bf1f-0951334e6a67 |
raw_statement | TEXTrequired | Exact source statement before normalization. | Represent multiplication facts by using arrays. |
normalized_statement | TEXTrequired | Normalized CASE statement under normalization_profile. | Represent multiplication facts by using arrays. |
ordinal_path | INTEGER[]required | Source order path preserved for lossless replay. | [3,4,1] |
binding_sha256 | TEXTrequired | Hash over release id, locator, identifiers, statements, order, and CASE target. Constraint: 64 lowercase hex characters. | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
created_at | TIMESTAMPTZrequired | Immutable insert time. | 2026-07-16T12:01:00Z |
Effective-dated material-level permission/admission decision with counsel provenance.
curriculum_immutable_standards_source_release
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
rights_record_id | UUIDrequired | Append-only rights decision identity. Constraint: Primary key with tenant_id. | 08d93f35-c236-4c26-a147-d86e04007cf5 |
source_release_id | UUIDrequired | Release whose material is evaluated. Relationship: Many-to-one alpha.standards_source_release. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
material_grain | TEXT enumrequired enum: standards_material_grain | Specificity of this decision. | statement |
material_ref | TEXTrequired | Release id or source_row_key at the declared grain. Constraint: Must resolve inside source_release_id. | sheet=Grade3,row=142 |
rights_status | TEXT enumrequired enum: rights_status | Permission classification; unknown is explicit and fail-closed. | permitted |
admission_outcome | TEXT enumrequired enum: admission_outcome | Deterministic operational result. Constraint: Only green permits adoption/generation. | green |
permission_basis | TEXTrequired | Plain-language legal/contract/public-domain basis. | Official public standards with attribution permitted by publisher terms. |
allowed_uses | TEXT[]required | Explicit permitted uses; absence never implies use. | ["store","display","generate"] |
required_attribution | TEXTnullable | Material-specific attribution overriding release default. | Source: Texas Education Agency |
effective_from | TIMESTAMPTZrequired | Inclusive decision start. | 2026-07-16T12:00:00Z |
effective_to | TIMESTAMPTZnullable | Exclusive decision end; null is open-ended. Constraint: Must be later than effective_from; overlapping records at the same grain are rejected. | null |
source_policy_ref | URIrequired | Versioned admission policy applied. | https://platform3-andymontgomery-9773s-projects.vercel.app/curriculum/alpha/architecture/#caitd-019-standards-source-release |
evidence_ref | URI or opaque refrequired | Immutable terms/license/evidence reference. | artifact://rights/tea-terms-2026-07-16.pdf |
decided_by_role | TEXTrequired | Role accountable for the decision. Constraint: operator or counsel; operator cannot grant an exception. | counsel |
counsel_decision_ref | URI or opaque refnullable | Required for disputed rights, contracts, or risk exceptions. Invalid when: Null when permission_basis depends on counsel interpretation or an exception. | legal://decision/2026-184 |
created_at | TIMESTAMPTZrequired | Immutable decision time. | 2026-07-16T12:10:00Z |
Immutable comparison proving release-bound CASE rows reproduce the source losslessly.
curriculum_immutable_standards_source_release
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
evidence_id | UUIDrequired | Immutable check identity. Constraint: Primary key with tenant_id. | 25f4d781-aa71-4605-9288-53e9a6b8cf2f |
source_release_id | UUIDrequired | Checked release. Relationship: Many-to-one alpha.standards_source_release. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
binding_id | UUIDnullable | Specific row binding; null only for release aggregate evidence. Relationship: Nullable FK alpha.standards_source_row_binding. | f1ad17e0-2508-4e7a-95df-93ffb5aa3399 |
raw_sha256 | TEXTrequired | Recomputed raw bytes hash. | 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef |
normalized_sha256 | TEXTrequired | Recomputed normalized bytes hash. | abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 |
readback_sha256 | TEXTrequired | Hash of canonical source-shaped readback. | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
mismatch_code | TEXT enumrequired enum: readback_mismatch_code | Typed result; none is the only passing value. | none |
mismatch_detail | JSONBnullable | Expected/actual locator and bounded redacted diff for failures. Constraint: Required when mismatch_code != none; no secrets or unrestricted source dumps. | null |
checked_at | TIMESTAMPTZrequired | Check execution time. | 2026-07-16T12:20:00Z |
checker_version | TEXTrequired | Deterministic readback checker version. | standards-readback-v1 |
Verbatim CASE framework identity and body; Curriculum adds no alternate standards text store.
curriculum_kc_registry_standard_separation
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
id | UUIDrequired | Tenant-scoped internal row identity. Constraint: Primary key with tenant_id. | 91a39ab0-82b7-45f4-98fc-a1f6405a93f9 |
identifier | TEXTrequired | Release-scoped CASE identifier; publisher identity remains in the source release and row binding. Constraint: Derived with source_release_id, so a changed reimport cannot collide with or overwrite the prior framework. | 91a39ab0-82b7-45f4-98fc-a1f6405a93f9 |
source_release_id | UUIDrequired | Immutable standards release owning this framework row. Relationship: FK alpha.standards_source_release within the tenant mapping. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
supersedes_source_release_id | UUIDnullable | Prior release named by the owning release; exposed beside the CASE body for historical readback. Relationship: FK alpha.standards_source_release; null on the first release. | c30e0884-40a8-42e0-a969-c6fe8bdb1767 |
is_frozen | BOOLEANrequired | Prevents UPDATE or DELETE of a release-bound framework. Constraint: True for standards frameworks; changed packages must use a new release-scoped identifier. | true |
body | JSONBrequired | Lossless CASE CFDocument JSON. | {"title":"Texas Math Grade 3","creator":"TEA"} |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; a new source release does not mutate the prior body. | null |
Verbatim CASE standard statement. KCs and course components must never be stored here after cutover.
curriculum_kc_registry_standard_separation
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
id | UUIDrequired | Tenant-scoped internal standard row identity. Constraint: Primary key with tenant_id. | 657b306e-4bd8-4938-bf1f-0951334e6a67 |
identifier | TEXTrequired | Release-scoped CASE standard identifier; publisher code and source identifier remain losslessly bound as source evidence. Constraint: Derived with source_release_id, so the same publisher code in a changed release creates a new row. | 657b306e-4bd8-4938-bf1f-0951334e6a67 |
cf_document_id | UUIDrequired | Owning release-specific CASE framework row. Relationship: Many-to-one case.cf_document within tenant. | 91a39ab0-82b7-45f4-98fc-a1f6405a93f9 |
source_release_id | UUIDrequired | Immutable release shared with the owning CASE framework and exact source-row binding. Relationship: FK alpha.standards_source_release within the tenant mapping. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
is_frozen | BOOLEANrequired | Prevents UPDATE or DELETE of the historical standard row. Constraint: True for imported standards; removal from a later release does not mutate or retire this historical row. | true |
body | JSONBrequired | Lossless CASE CFItem JSON containing the publisher statement. | {"fullStatement":"Represent multiplication facts by using arrays."} |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp. | null |
Within-framework containment and standard-to-standard alignment only.
curriculum_kc_registry_standard_separation
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
id | UUIDrequired | Tenant-scoped association identity. Constraint: Primary key with tenant_id. | e490c62a-a421-452e-b947-ef683875ec0b |
association_type | TEXTrequired | CASE relationship for standards only. Constraint: May express standards containment/alignment; must not represent KC prerequisites, KC lineage, KC-standard maps, course structure, or members. | isChildOf |
origin_node_id | UUIDrequired | Origin CASE standard/framework row. Relationship: Typed CASE endpoint. | 657b306e-4bd8-4938-bf1f-0951334e6a67 |
destination_node_id | UUIDrequired | Destination CASE standard/framework row. Relationship: Typed CASE endpoint. | 91a39ab0-82b7-45f4-98fc-a1f6405a93f9 |
body | JSONBrequired | Lossless CASE CFAssociation JSON. | {"associationType":"isChildOf"} |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp. | null |
Persistent, course-independent masterable identity; meaning lives in immutable versions.
curriculum_kc_registry_standard_separation · curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
kc_id | UUIDrequired | Persistent KC identity. Constraint: Primary key with tenant_id; never a CASE, lesson, standard, or course id. | 49371a30-9796-4bbd-a523-bd38a876e415 |
source_kc_id | TEXTnullable | Optional producer semantic identity retained as creation provenance and migration evidence. Constraint: Unique with tenant_id among active rows when present; 1–512 characters (at most 2048 UTF-8 bytes). Never accepted as an identity resolver by create, read, version, retire, graph, scope, remediation, or Content-attribution operations; callers capture and use the returned canonical kc_id UUID. A retry uses the original Idempotency-Key or exact canonical kc_id, never source_kc_id. | kc:math:3:oa:ccss.math.content.3.oa.1 |
lineage_id | UUIDrequired | Stable family grouping across splits/merges/supersession. Constraint: Does not replace typed lineage edges. | a0f70fc9-3a25-4537-a0ed-a05078774032 |
kc_kind | TEXT enumrequired for authored KCs; nullable only for #707 legacy adoption enum: kc_kind | Governed performance kind. Constraint: NULL means only unclassified legacy adoption pending #898; it requires publication_status=draft and is never publishable or accepted from an authoring API. | substantive |
subject_id | TEXTrequired | Live Platform authoring subject-registry value. Constraint: Resolve from the owning descriptor; current deployed values are documented but consumers must not copy the enum. | math |
current_version_id | UUIDrequired for governed KCs; nullable only for the retained unclassified #707 legacy row | Latest appended semantic version, draft or firm. Relationship: DEFERRABLE INITIALLY DEFERRED composite FK (tenant_id, kc_id, current_version_id) to alpha.knowledge_component_version (tenant_id, kc_id, version_id), so a KC cannot select another KC's version and the identity plus first immutable version can be created atomically. | 7c3f9e18-d244-41b2-9727-79fb4c97f11a |
publication_status | TEXT enumrequired enum: publication_status | Identity discovery lifecycle, separate from version firming. | draft |
Immutable authored KC meaning and reviewable definition quality.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
version_id | UUIDrequired | Immutable version identity. Constraint: Primary key with tenant_id; unique with tenant_id + kc_id as the composite current-version FK target. | 7c3f9e18-d244-41b2-9727-79fb4c97f11a |
kc_id | UUIDrequired | Persistent KC identity. Relationship: DEFERRABLE INITIALLY DEFERRED many-to-one FK alpha.knowledge_component; paired with knowledge_component.current_version_id for atomic first-version creation. | 49371a30-9796-4bbd-a523-bd38a876e415 |
version_number | INTEGERrequired | Monotonic per-KC version number. Constraint: >=1; unique with tenant_id + kc_id. | 1 |
status | TEXT enumrequired enum: kc_version_status | Draft/firm semantic lifecycle. Constraint: Only a firming event may change draft to firm; all other fields remain immutable. | draft |
definition | TEXTrequired | Verb-first observable performance definition, independent of any course. | Represent multiplication facts using equal-size arrays. |
positive_examples | JSONBrequired | Examples that satisfy the boundary. | ["Build 4 rows of 6 and state 4 × 6 = 24."] |
negative_examples | JSONBrequired | Near misses/non-examples. | ["Count objects without representing equal groups."] |
boundary_statement | TEXTnullable | What is deliberately excluded from this KC. | Does not require interpreting division remainders. |
misconceptions | JSONBnullable | Known course-independent misconceptions. | ["Swaps number of groups and group size without preserving the model."] |
instructional_classification | JSONBnullable | Course-independent instructional metadata; never pace/order/cluster fields. | {"knowledgeType":"procedure"} |
provenance | JSONBrequired | Sources and authoring chain for the definition. | {"source":"review:math-owner-42"} |
confidence | NUMERIC(4,3)required | Confidence in [0,1]. Constraint: 0 <= confidence <= 1. | 0.94 |
author_ref | TEXTrequired | Authenticated human/application author. | person:math-owner |
created_at | TIMESTAMPTZrequired | Immutable authored time. | 2026-07-16T13:00:00Z |
Immutable named source snapshot and reconciliation proof for the one-time #707 cutover.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
snapshot_id | UUIDrequired | Deterministic identity for the captured source hash. Constraint: Primary key. | 114bc4fb-6ac4-5be8-b93e-e3e96687d245 |
migration_key | TEXTrequired | Single idempotency key for this operator migration. Constraint: Unique; issue-707-case-kc-registry-v1. | issue-707-case-kc-registry-v1 |
snapshot_name | TEXTrequired | Human-readable immutable name including the capture time. Constraint: Unique. | issue-707-case-kc-registry-v1@2026-07-20T12:00:00.000Z |
source_system | TEXTrequired | Exact copied authority at cutover. | case.cf_item |
captured_at | TIMESTAMPTZrequired | Database capture time inside the SERIALIZABLE transaction. | 2026-07-20T12:00:00Z |
source_txid | BIGINTrequired | PostgreSQL transaction id that captured and applied the source snapshot. | 123456 |
source_hash_sha256 | TEXTrequired | SHA-256 over the sorted entity/source-key/source-row hashes. Constraint: 64 lowercase hex. | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
code_commit_sha | TEXTrequired | Merged, gated repository commit that executed the operator. Constraint: 40 lowercase hex and reachable from origin/main at apply time. | 0123456789abcdef0123456789abcdef01234567 |
discovered_counts | JSONBrequired | Per-entity discovered counts from this snapshot. | {"knowledge_component":6290,"prerequisite":3565} |
accepted_counts | JSONBrequired | Per-entity accepted counts. | {"knowledge_component":6280,"prerequisite":3559} |
rejected_counts | JSONBrequired | Per-entity totals and typed-reason counts. | {"knowledge_component":{"total":10,"reasons":{"source_retired":9,"missing_subject_id":1}}} |
reference_proof | JSONBrequired | Source-row retention, scope/evidence resolution, current-version, and DAG proof. | {"source_case_rows_retained":true,"prerequisite_dag":true,"new_orphaned_kc_references":0} |
status | TEXTrequired | Atomic run state. Constraint: applying or completed; only applying→completed is legal. | completed |
completed_at | TIMESTAMPTZnullable | Commit-bound completion timestamp. | 2026-07-20T12:03:00Z |
Immutable #707 migration evidence mapping a captured source id to the canonical registry UUID.
curriculum_kc_registry_standard_separation · curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
source_system | TEXTrequired | Source namespace. | case.cf_item |
source_tenant_ref | TEXTrequired | CASE tenant reference exactly as captured. | demo |
source_kc_id | TEXTrequired | CASE KC id exactly as captured, including semantic ids. Constraint: Unique with tenant_id + source_system. | kc:math:3:equal-groups |
kc_id | UUIDrequired | Canonical registry identity. Relationship: FK alpha.knowledge_component. | 49371a30-9796-4bbd-a523-bd38a876e415 |
mapping_kind | TEXT enumrequired enum: kc_source_identity_mapping_kind | Whether the source id was preserved, deterministically remapped, or adopted from an existing operational source_kc_id crosswalk. | adopted_registry_source_kc_id |
source_snapshot_id | UUIDrequired | Snapshot that admitted this mapping. Relationship: FK alpha.kc_case_migration_snapshot. | 114bc4fb-6ac4-5be8-b93e-e3e96687d245 |
source_row_sha256 | TEXTrequired | Hash of the exact migration payload for this KC. Constraint: 64 lowercase hex. | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
One immutable accepted/rejected disposition for every discovered #707 source object.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
snapshot_id | UUIDrequired | Owning named snapshot. Relationship: FK alpha.kc_case_migration_snapshot. | 114bc4fb-6ac4-5be8-b93e-e3e96687d245 |
entity_type | TEXT enumrequired enum: kc_case_migration_entity_type | Reconciled population. | prerequisite |
source_tenant_ref | TEXTrequired | Source CASE tenant reference. | demo |
source_id | TEXTrequired | Source CFItem/CFAssociation id. | 0a77d011-0f33-4e2e-8aac-5b59860e1fc1 |
tenant_id | UUIDnullable | Resolved target tenant; null only for unresolved_tenant rejection. | 11111111-1111-4111-8111-111111111111 |
source_row_sha256 | TEXTrequired | Hash of source_payload. Constraint: 64 lowercase hex. | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
source_payload | JSONBrequired | Minimal exact migration fields, not an unrestricted copyrighted source dump. | {"association_type":"precedes","origin_id":"kc-a","destination_id":"kc-b"} |
disposition | TEXT enumrequired enum: kc_case_migration_disposition | Accepted or rejected. | rejected |
rejection_reason | TEXT enumnullable enum: kc_case_migration_rejection_reason | Typed reason; required exactly when disposition=rejected. | cycle_scc |
target_refs | JSONBrequired | Canonical ids or deterministic rejection evidence such as SCC membership. | {"prerequisite_kc_id":"49371a30-9796-4bbd-a523-bd38a876e415"} |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
Canonical directed acyclic prerequisite graph.
curriculum_kc_registry_standard_separation
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
prerequisite_id | UUIDrequired | Edge identity. Constraint: Primary key with tenant_id. | 76d63c09-4090-4f90-939f-fe46d83d7d18 |
prerequisite_kc_id | UUIDrequired | KC that must come first. Relationship: FK active alpha.knowledge_component. | 92b2eaf0-8ff1-42ea-a352-3ac08b9d5951 |
dependent_kc_id | UUIDrequired | KC enabled by the prerequisite. Constraint: Must differ from prerequisite_kc_id; insert/update must preserve DAG acyclicity. Relationship: FK active alpha.knowledge_component. | 49371a30-9796-4bbd-a523-bd38a876e415 |
provenance | JSONBrequired | Why/source for the edge. | {"reviewDecisionId":"review-71"} |
confidence | NUMERIC(4,3)required | Edge confidence in [0,1]. | 0.9 |
Governed non-prerequisite semantic and lineage edges.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
relation_id | UUIDrequired | Edge identity. Constraint: Primary key with tenant_id. | d02a4eb7-44ce-407c-a42d-0b4b5e96b0e2 |
origin_kc_id | UUIDrequired | Typed relation origin. Relationship: FK active alpha.knowledge_component. | 49371a30-9796-4bbd-a523-bd38a876e415 |
destination_kc_id | UUIDrequired | Typed relation destination. Constraint: Must differ from origin_kc_id. Relationship: FK active alpha.knowledge_component. | b2cbd2ff-42ce-421b-a18c-07c488931ceb |
relation_type | TEXT enumrequired enum: kc_relation_type | Semantic or lineage relation. Constraint: Prerequisite is forbidden here; split/merge/supersede endpoints share lineage_id after transition. | applies_to |
provenance | JSONBrequired | Source/review evidence. | {"reviewDecisionId":"review-72"} |
confidence | NUMERIC(4,3)required | Relation confidence in [0,1]. | 0.86 |
Immutable structured review audit for one KC version.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
review_decision_id | UUIDrequired | Immutable audit identity. Constraint: Primary key with tenant_id. | 217b17b7-8f32-4901-a534-660593822932 |
version_id | UUIDrequired | Reviewed KC version. Relationship: FK alpha.knowledge_component_version. | 7c3f9e18-d244-41b2-9727-79fb4c97f11a |
decision | TEXT enumrequired enum: kc_review_decision | Structured review outcome. | edit |
edit_diff | JSONBnullable | Captured before/after or JSON Patch when decision edits/splits/merges. Invalid when: Null for edit, split, or merge without an explicit no-change explanation in rationale. | [{"op":"replace","path":"/definition","value":"Represent multiplication facts using equal-size arrays."}] |
rationale | TEXTrequired | Review reasoning. | Separates array representation from later division interpretation. |
provenance | JSONBrequired | Inputs/evidence considered. | {"sourceRefs":["TEKS:3.4A"]} |
actor_ref | TEXTrequired | Authenticated reviewer. | person:math-owner |
decided_at | TIMESTAMPTZrequired | Immutable decision time. | 2026-07-16T13:15:00Z |
Stable reusable course identity, role, scope, lifecycle, and approval reference.
curriculum_reusable_component_member_model
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
course_id | UUIDrequired | Stable course identity. Constraint: Primary key with tenant_id. | d7eb3c5c-5051-4860-bc8d-25919be371dd |
subject_id | TEXTrequired | Live authoring subject-registry value. | math |
grade_scope | JSONBrequired | Exact grade/band scope. | {"min":3,"max":3} |
course_role | TEXT enumrequired enum: course_role | Progress-denominator role. Constraint: Only main contributes to grade-level expected-XP denominator. | main |
name | TEXTrequired | Customer-visible course name. | Grade 3 Core Math |
description | TEXTnullable | Course purpose, not student state. | Core grade-three mathematics sequence. |
lineage_id | UUIDrequired | Course-family lineage identity. | a20513bf-6a4c-424f-b714-32eb3d68f2ed |
publication_status | TEXT enumrequired enum: publication_status | Course authoring lifecycle and learner-routing release boundary. Constraint: Create as draft. Publish only after the complete intended member/component tree is read back, every descendant is published bottom-up, and this course root is published last. | draft |
current_approval_id | UUIDnullable | Latest approved immutable course snapshot. Relationship: FK alpha.course_approval. | null |
entry_policy_ref | TEXTnullable | Versioned alpha.policy placement reference; no copied numbers. | alpha.policy.placement_weights:v3 |
exit_policy_ref | TEXTnullable | Versioned alpha.policy exit reference; no copied numbers. | alpha.policy.mastery_cutoff:v5 |
Reusable student-independent structure/KC scope decision and expected-effort leaf/fallback.
curriculum_reusable_component_member_model
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
component_id | UUIDrequired | Stable reusable component identity. Constraint: Primary key with tenant_id. | 5579cb54-e751-4eed-bc8e-95ab00b2f47e |
kind | TEXT enumrequired enum: component_kind | Governed component kind. | lesson |
scope_kc_ids | UUID[]required | Active KC identities in scope, or the explicit empty factual scope paired with authoritative_no_kc. Constraint: Non-empty for ordinary lesson/acquisition components. An empty array is valid only for a kind=lesson exact Content target whose kc_scope_decision is authoritative_no_kc. Producer or learning-scientist clustering grain is preserved, so a scoped lesson may carry many KCs. Never use semantic source ids, standards, similarity, course roots, or lesson ids as KC UUIDs. Relationship: Each non-empty element FK active alpha.knowledge_component; an authoritative_no_kc empty array creates no KC relationship. | ["49371a30-9796-4bbd-a523-bd38a876e415","92b2eaf0-8ff1-42ea-a352-3ac08b9d5951"] |
kc_scope_decision | TEXT enumnullable enum: kc_scope_decision | Producer-authoritative decision that this exact content-bearing lesson intentionally has no KC attribution. Constraint: Only authoritative_no_kc is accepted; valid only for kind=lesson with scope_kc_ids=[], an exact immutable Content target, and a compatible renderer. Null means the ordinary non-empty scope rule applies. The decision is factual absence, not permission to infer or synthesize a KC. | authoritative_no_kc |
name | TEXTrequired | Reusable component name. | Arrays for multiplication |
description | TEXTnullable | Reusable course-independent description. | Initial acquisition of equal-group array representation. |
expected_xp | NUMERICnullable | Student-independent expected effort as a leaf value or container fallback. Constraint: >=0; units xp_eq_expected_minutes; ignored at aggregate time whenever an active descendant carries expected_xp. | 18 |
lineage_id | UUIDrequired | Reusable component-family lineage. | 62b5cc63-8cd8-4ce8-af53-07a74b08ef63 |
publication_status | TEXT enumrequired enum: publication_status | Reusable component lifecycle and learner-routing eligibility state. Constraint: Course assembly creates draft rows and publishes bottom-up. A draft, retired, or missing status on the selected frontier or any containment ancestor makes the course non-routable. | published |
One ordered course-local use of a reusable component or exact Content version.
curriculum_reusable_component_member_model · curriculum_member_content_reference_gate_placement
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
member_id | UUIDrequired | Stable ordered-use identity. Constraint: Primary key with tenant_id. | c11c31b8-aef5-499d-874d-cd8dc435e920 |
course_id | UUIDrequired | Owning course. Relationship: FK active alpha.course. | d7eb3c5c-5051-4860-bc8d-25919be371dd |
parent_component_id | UUIDnullable | Reusable parent container; null means course root. Relationship: Nullable FK active alpha.course_component. | null |
position | INTEGERrequired | Stable sibling order. Constraint: >=0; unique with tenant_id + course_id + parent_component_id among active rows. | 4 |
target_kind | TEXT enumrequired enum: target_kind | Discriminator for exactly one target shape. | course_component |
target_component_id | UUIDnullable | Reusable component target when target_kind=course_component. Relationship: FK active alpha.course_component. Invalid when: Null for course_component or non-null for content_version. | 5579cb54-e751-4eed-bc8e-95ab00b2f47e |
content_id | UUIDnullable | Content identity when target_kind=content_version. Relationship: Opaque Content-owned id resolved through the Content API. Invalid when: Present without content_version_id or for course_component. | null |
content_version_id | UUIDnullable | Exact immutable Content version; never a floating latest pointer. Relationship: Content exact-version contract. Invalid when: Null when target_kind=content_version, or not owned by content_id. | null |
content_kind | TEXTnullable | Typed Content kind echoed only for reference validation/routing. Constraint: Must equal Content exact-version readback; enum remains Content-owned and is not copied into Curriculum's enumSets. | null |
renderer_ref | TEXTnullable | Active renderer capability accepting content_kind. Relationship: Platform renderer capability registry. Invalid when: Missing/unknown/inactive/incompatible for a Content target. | null |
gates | BOOLEANrequired | Whether this course-local member enforces a gate. | false |
passing_criteria_ref | TEXTnullable | Versioned alpha.policy reference for a gating member. Invalid when: Missing when gates=true or present when gates=false; never stores a threshold number. | null |
on_fail | JSONBnullable | Typed remediation protocol for a gating member. Constraint: Entries use never_learned→lesson, forgot→review, careless→practice. alpha.policy.pp100_lesson_mastery.v2 requires retry=resume_same_score_walk; every other current gate policy requires retry=same_or_equivalent_form. | null |
Immutable audit row for every accepted producer self-service repoint/attach of a component's exact Content pin.
curriculum_member_content_reference_gate_placement
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | TEXTrequired | Verified JWT tenant scope of the repointed component. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | demo |
repoint_audit_id | UUIDrequired | Immutable audit identity, one per accepted repoint or attach. Constraint: Primary key. | 0d1f5f6a-64f7-4a5e-8f8f-3a2b1c0d9e8f |
component_id | TEXTrequired | Repointed CASE-backed component identity. Relationship: Deployed compatibility FK to the active case.cf_item component; the accepted target model records the analogous member repoint. | 3d5e5eb4-fefe-59e0-ba33-0397203b51f1 |
operation | TEXT enumrequired enum: component_target_repoint_operation | Whether an existing exact pin moved within one Content identity (repoint) or a first pin was attached to an unpinned component (attach). | repoint |
previous_target_ref | JSONBnullable | Exact pin the compare-and-set premise matched; null exactly for attach. Constraint: repoint requires the full previous exact tuple; attach requires null. | {"module":"content","content_kind":"article","content_id":"41639afc-c1d1-952a-f579-ecb870428386","content_version_id":"6641dfed-3323-4cde-a8b3-19058caf5f77"} |
new_target_ref | JSONBrequired | Exact eligible tuple now pinned by the component. Constraint: Must have passed Content-owned exact-version release eligibility with practice_eligible usage scope inside the accepting request. | {"module":"content","content_kind":"article","content_id":"41639afc-c1d1-952a-f579-ecb870428386","content_version_id":"fa0933dc-d3b2-4956-957d-e2fd0b9892f5"} |
actor_ref | TEXTrequired | Authenticated producer/integrator subject that performed the operation. | integrator:ap-one |
request_id | TEXTnullable | Originating request id for support correlation. | req_4f518591-06b4-44e1-bfbe-aab60c598bdd |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
Immutable approval boundary pinning one reviewed course graph.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
approval_id | UUIDrequired | Immutable approval identity. Constraint: Primary key with tenant_id. | 3810e51f-e4e3-45c9-9169-593cf6c1a5f7 |
course_id | UUIDrequired | Approved course. Relationship: FK alpha.course. | d7eb3c5c-5051-4860-bc8d-25919be371dd |
course_graph_sha256 | TEXTrequired | Hash of active course/component/member graph at approval. | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
approved_by | TEXTrequired | Authenticated approver. | person:math-owner |
approved_at | TIMESTAMPTZrequired | Immutable approval time. | 2026-07-16T14:00:00Z |
provenance | JSONBrequired | Approval evidence/review references. | {"reviewId":"course-review-12"} |
Immutable exact KC-version set referenced by an approved course.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
approval_id | UUIDrequired | Owning immutable approval. Relationship: FK alpha.course_approval. | 3810e51f-e4e3-45c9-9169-593cf6c1a5f7 |
kc_id | UUIDrequired | Referenced KC identity. Relationship: FK alpha.knowledge_component. | 49371a30-9796-4bbd-a523-bd38a876e415 |
version_id | UUIDrequired | Exact version approved, whether already firm or firmed in this transaction. Relationship: FK alpha.knowledge_component_version for kc_id. | 7c3f9e18-d244-41b2-9727-79fb4c97f11a |
snapshot_source | TEXTrequired | Where the course graph referenced this KC. | course_component:5579cb54-e751-4eed-bc8e-95ab00b2f47e |
created_at | TIMESTAMPTZrequired | Immutable insert time. | 2026-07-16T14:00:00Z |
Immutable proof of the only two legal draft-to-firm transitions.
curriculum_kc_storage_governance
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
firming_event_id | UUIDrequired | Immutable event identity. Constraint: Primary key with tenant_id. | 62c6f3c7-d9ca-4d04-aa1b-a345332694b4 |
version_id | UUIDrequired | KC version made firm. Constraint: At most one effective firming event per version. Relationship: FK alpha.knowledge_component_version. | 7c3f9e18-d244-41b2-9727-79fb4c97f11a |
firming_reason | TEXT enumrequired enum: firming_reason | Course approval or live-learning safety backstop. | course_approval |
source_ref | TEXTrequired | approval_id, or governed live_learning first-genuine-response evidence ref. Constraint: course_approval must resolve to a snapshot containing version_id; first_genuine_response requires an explicit live_learning signal and first response evidence. | approval:3810e51f-e4e3-45c9-9169-593cf6c1a5f7 |
actor_ref | TEXTrequired | Authenticated/system actor. | app:curriculum |
firmed_at | TIMESTAMPTZrequired | Immutable firming time. | 2026-07-16T14:00:00Z |
Release-pinned first-class standard-to-KC mapping with relationship, provenance, and confidence.
curriculum_kc_registry_standard_separation
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
created_at | TIMESTAMPTZrequired | Server-assigned creation time. Constraint: Immutable after insert. | 2026-07-16T12:00:00Z |
updated_at | TIMESTAMPTZrequired | Server-assigned last mutable-row update time. Constraint: Changes only through a successful If-Match write. | 2026-07-16T12:00:00Z |
retired_at | TIMESTAMPTZnullable | Soft-retire timestamp; null means active. Constraint: Ordinary reads and reference validation require retired_at IS NULL. | null |
map_id | UUIDrequired | Crosswalk identity. Constraint: Unique with tenant_id; the table primary key is tenant_id + standard_id + kc_id. | db37d14f-af1d-4df2-9047-3d18df32ee0d |
source_release_id | UUIDrequired | Immutable standards release pin. Relationship: FK alpha.standards_source_release. | 8a17f30a-2a39-4a4c-b44e-643c3342756d |
standard_binding_id | UUIDrequired | Exact bound standard row in that release. Relationship: FK alpha.standards_source_row_binding where case_resource_type=cf_item. | f1ad17e0-2508-4e7a-95df-93ffb5aa3399 |
standard_id | UUIDrequired | Release-specific frozen CASE standard identity pinned by standard_binding_id. Relationship: FK release-scoped case.cf_item; must equal the bound row's case_resource_id. | 0f0eb990-7692-4bac-a0d0-aecb1cdd53ae |
kc_id | UUIDrequired | Mapped active KC identity. Relationship: FK alpha.knowledge_component. | 49371a30-9796-4bbd-a523-bd38a876e415 |
relationship | TEXT enumrequired enum: standard_kc_relationship | Direction/grain of the mapping. | supports |
provenance | JSONBrequired | Mapping source/reviewer/method. Constraint: Must be a non-empty JSON object. A guarded forward migration converts an existing TEXT column only when information_schema reports TEXT, wrapping every exact legacy string as {legacy: <exact stored string>}; arrays, null, empty objects, and new scalar writes are rejected. | {"reviewer":"person:math-owner","method":"manual"} |
confidence | NUMERIC(4,3)required | Mapping confidence in [0,1]. | 0.92 |
Read-only named projection without a stored KC containment tree.
curriculum_kc_registry_standard_separation
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
tenant_id | UUIDrequired | Verified JWT tenant scope; part of every key and join. Constraint: Must equal the authenticated tenant; never accepted from a URL or request body. | 11111111-1111-4111-8111-111111111111 |
set_id | TEXTrequired | Deterministic projection id. | course-approval:3810e51f-e4e3-45c9-9169-593cf6c1a5f7 |
set_kind | TEXTrequired | Projection source: course_approval, standards_release, or lineage_family. | course_approval |
name | TEXTrequired | Deterministic human-readable set name. | Grade 3 Core Math approved KC set |
kc_id | UUIDrequired | KC member. Relationship: FK active alpha.knowledge_component. | 49371a30-9796-4bbd-a523-bd38a876e415 |
version_id | UUIDnullable | Exact version when projection source pins one. | 7c3f9e18-d244-41b2-9727-79fb4c97f11a |
ordinal | INTEGERnullable | Deterministic display order; not a prerequisite or containment edge. | 1 |
source_ref | TEXTrequired | Approval/release/lineage row that mechanically produces membership. | approval:3810e51f-e4e3-45c9-9169-593cf6c1a5f7 |
Non-authoritative sample contract retained only for the deployed CASE-backed conformance probe.
Do not generate target migrations, KC storage, course storage, or authoring guidance from this table.
curriculum_shared_supabase_migration_gate
| Field | Type / null | Meaning and constraints | Example |
|---|---|---|---|
component_id | TEXTrequired | Legacy CASE-backed component identifier. | component-correction-live-58a7658fb35e |
kind | TEXT enumrequired enum: component_kind | Legacy served kind. | lesson |
subject_id | TEXTnullable | Legacy served subject. | math |
grade_level | INTEGERnullable | Legacy served grade. | 3 |
course_grade_mode | TEXTnullable | Legacy compatibility value. | single_grade |
expected_xp | NUMERICnullable | Legacy served expected effort. | 18 |
kc_scope_decision | TEXT enumnullable enum: kc_scope_decision | Explicit producer-authoritative no-KC lesson decision echoed by deployed compatibility reads. | authoritative_no_kc |
created_at | TIMESTAMPTZrequired | Legacy created time. | 2026-07-09T13:23:39Z |
updated_at | TIMESTAMPTZrequired | Legacy updated time. | 2026-07-09T13:23:39Z |
unit: xp_eq_expected_minutes
leaf Rule: An active expected-XP-bearing component with no active expected-XP-bearing descendant contributes its own expected_xp.
fallback Rule: A container expected_xp contributes only when its active subtree has no descendant with expected_xp.
aggregate Rule: Course/grade/track totals sum contributing leaves/fallbacks once per active member path. Reuse in two courses contributes once to each course, not once globally.
role Rule: Only course_role=main contributes to the Results grade-level denominator; hole_filling, remediation, and catalog remain separately queryable.
forbidden: Never average student actuals, add a container to descendant values, or read awarded/remaining XP from Curriculum.
No copied producer decision. Curriculum stores only content_id, content_version_id, and the typed content_kind needed for reference validation/routing. It stores no producer verdict, quality-bar id/version, release status, evidence ref, policy field, Content body, answer, or eligibility cache.
Reference: {"content_id":"UUID","content_version_id":"UUID","content_kind":"Content-owned TEXT"}
Eligibility read: GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions/{contentVersionId}/release-eligibility
At member write and again at launch, Curriculum reads the exact Content version and Content-owned release-eligibility response. The version must belong to content_id, be serveable, and be eligible. An authoritative missing, blocked, revoked, malformed, or otherwise non-green response fails closed as curriculum:content_not_eligible, while a target tuple mismatch becomes curriculum:content_version_mismatch. Network failure, request/operation timeout, or an upstream HTTP 5xx is HTTP 503 curriculum:content_unavailable with bounded Retry-After and is never mistaken for semantic ineligibility. Only component create, component update/publish, and TimeBack ingest prove that this check precedes their mutation; those exact boundaries may finalize an evidence-free failed_transient receipt and reclaim the identical Idempotency-Key after Content recovers. Reads and any unmarked or post-mutation 503 remain non-retry-authoritative. Content's content.invalid_test_bank_member_contract and content.bank_kc_attribution_incomplete responses are never flattened into eligibility, transport, skip, or fallback behavior: both map losslessly to HTTP 409 curriculum:invalid_content_bank_member_contract with the safe upstream code exposed in the public RFC 7807 cause field.
Accepted Content target; callers must treat 404/unsupported eligibility read as target-not-deployed, not as permission. The Curriculum target route cannot claim ready until exact-version Content eligibility is live.
API: POST /alpha/curriculum/v1/standards-frameworks/import with Idempotency-Key; GET /alpha/curriculum/v1/standards-source-releases/{sourceReleaseId}/readback
-- The API resolves platform.idempotency_key before this transaction: an exact active request hash/protocol/server lease token owns mutation and finalization; terminal rows replay exact status/body/headers; live same-hash contenders return curriculum:idempotency_in_progress; different hashes return curriculum:idempotency_conflict.
BEGIN ISOLATION LEVEL SERIALIZABLE;
INSERT INTO alpha.standards_source_release (tenant_id,source_release_id,source_authority,official_source_url,declared_scope,partial_display_name,license_url,release_rights_status,required_attribution,retrieved_at,raw_artifact_sha256,raw_checksum_grain,parser_name,parser_version,normalized_artifact_ref,normalized_artifact_sha256,normalization_profile,source_policy_ref,imported_by,imported_at)
VALUES (:tenant_id,:release_id,:source_authority,:official_source_url,:declared_scope,:partial_display_name,:license_url,:release_rights_status,:required_attribution,:retrieved_at,:raw_sha256,:raw_checksum_grain,:parser_name,:parser_version,:normalized_artifact_ref,:normalized_sha256,:normalization_profile,:source_policy_ref,:imported_by,now())
;
INSERT INTO case.cf_document (tenant_id,id,identifier,body,retired_at) VALUES (:tenant_id,:document_id,:document_identifier,:document_body,NULL);
INSERT INTO case.cf_item (tenant_id,id,identifier,cf_document_id,body,retired_at) VALUES (:tenant_id,:item_id,:item_identifier,:document_id,:item_body,NULL);
INSERT INTO alpha.standards_source_row_binding (tenant_id,binding_id,source_release_id,source_row_key,material_grain,source_locator,source_identifier,case_resource_type,case_resource_id,raw_statement,normalized_statement,ordinal_path,binding_sha256,created_at) VALUES
(:tenant_id,:document_binding_id,:release_id,:document_source_row_key,'framework',:document_source_locator,:document_identifier,'cf_document',:document_id,:document_raw_title,:document_normalized_title,:document_ordinal_path,:document_binding_sha256,now()),
(:tenant_id,:item_binding_id,:release_id,:item_source_row_key,'statement',:item_source_locator,:item_identifier,'cf_item',:item_id,:item_raw_statement,:item_normalized_statement,:item_ordinal_path,:item_binding_sha256,now());
INSERT INTO alpha.standards_rights_record (tenant_id,rights_record_id,source_release_id,material_grain,material_ref,rights_status,admission_outcome,permission_basis,allowed_uses,required_attribution,effective_from,effective_to,source_policy_ref,evidence_ref,decided_by_role,counsel_decision_ref,created_at) VALUES
(:tenant_id,:release_rights_record_id,:release_id,'release',:release_id::text,:release_rights_status,:release_admission_outcome,:release_permission_basis,:release_allowed_uses,:release_required_attribution,:rights_effective_from,:rights_effective_to,:source_policy_ref,:release_evidence_ref,:release_decided_by_role,:release_counsel_decision_ref,now()),
(:tenant_id,:item_rights_record_id,:release_id,'statement',:item_source_row_key,:item_rights_status,:item_admission_outcome,:item_permission_basis,:item_allowed_uses,:item_required_attribution,:rights_effective_from,:rights_effective_to,:source_policy_ref,:item_evidence_ref,:item_decided_by_role,:item_counsel_decision_ref,now());
INSERT INTO alpha.standards_readback_evidence (tenant_id,evidence_id,source_release_id,binding_id,raw_sha256,normalized_sha256,readback_sha256,mismatch_code,mismatch_detail,checked_at,checker_version) VALUES
(:tenant_id,:document_evidence_id,:release_id,:document_binding_id,:raw_sha256,:normalized_sha256,:document_readback_sha256,:document_mismatch_code,:document_mismatch_detail,now(),:checker_version),
(:tenant_id,:item_evidence_id,:release_id,:item_binding_id,:raw_sha256,:normalized_sha256,:item_readback_sha256,:item_mismatch_code,:item_mismatch_detail,now(),:checker_version);
WITH scope_check AS (
SELECT release.source_release_id,count(binding.binding_id) AS binding_count,
jsonb_typeof(release.declared_scope)='object'
AND NULLIF(release.declared_scope->>'jurisdiction','') IS NOT NULL
AND NULLIF(release.declared_scope->>'subject','') IS NOT NULL
AND NULLIF(release.declared_scope->>'edition','') IS NOT NULL
AND jsonb_typeof(release.declared_scope->'grades')='array' AND jsonb_array_length(release.declared_scope->'grades')>0
AND jsonb_typeof(release.declared_scope->'rowFilter')='string' AND NULLIF(release.declared_scope->>'rowFilter','') IS NOT NULL
AND (release.declared_scope->>'expectedRowCount') ~ '^[1-9][0-9]*$'
AND (release.declared_scope->>'sourceRowKeysSha256') ~ '^[0-9a-f]{64}$'
AND (release.declared_scope->>'isPartial') IN ('true','false')
AND NULLIF(release.declared_scope->>'officialFrameworkName','') IS NOT NULL
AND CASE WHEN (release.declared_scope->>'expectedRowCount') ~ '^[1-9][0-9]*$' THEN (release.declared_scope->>'expectedRowCount')::bigint=count(binding.binding_id) ELSE false END
AND release.declared_scope->>'sourceRowKeysSha256'=encode(digest(COALESCE(string_agg(binding.source_row_key,E'
' ORDER BY binding.source_row_key),''),'sha256'),'hex')
AND ((release.declared_scope->>'isPartial')='false' AND release.partial_display_name IS NULL OR (release.declared_scope->>'isPartial')='true' AND NULLIF(release.partial_display_name,'') IS NOT NULL AND release.partial_display_name<>release.declared_scope->>'officialFrameworkName') AS scope_exact
FROM alpha.standards_source_release release LEFT JOIN alpha.standards_source_row_binding binding ON binding.tenant_id=release.tenant_id AND binding.source_release_id=release.source_release_id
WHERE release.tenant_id=:tenant_id AND release.source_release_id=:release_id
GROUP BY release.source_release_id,release.declared_scope,release.partial_display_name
), ranked_rights AS (
SELECT binding.binding_id,rights.rights_status,rights.admission_outcome,(rights.rights_status='public_domain' OR COALESCE(rights.required_attribution,release.required_attribution) IS NOT NULL) AS attribution_satisfied,count(*) OVER (PARTITION BY binding.binding_id,CASE WHEN rights.material_grain='release' THEN 'release' ELSE 'specific' END) AS active_at_specificity,row_number() OVER (PARTITION BY binding.binding_id ORDER BY CASE WHEN rights.material_grain='release' THEN 1 ELSE 2 END DESC,rights.effective_from DESC,rights.created_at DESC) AS precedence
FROM alpha.standards_source_row_binding binding JOIN alpha.standards_source_release release ON release.tenant_id=binding.tenant_id AND release.source_release_id=binding.source_release_id JOIN alpha.standards_rights_record rights ON rights.tenant_id=binding.tenant_id AND rights.source_release_id=binding.source_release_id AND ((rights.material_grain=binding.material_grain AND rights.material_ref=binding.source_row_key) OR (rights.material_grain='release' AND rights.material_ref=binding.source_release_id::text)) AND rights.effective_from<=:evaluation_time AND (rights.effective_to IS NULL OR rights.effective_to>:evaluation_time)
WHERE binding.tenant_id=:tenant_id AND binding.source_release_id=:release_id
), evidence_status AS (
SELECT binding_id,count(*) AS evidence_count,bool_and(mismatch_code='none') AS all_pass,bool_or(mismatch_code<>'none') AS has_mismatch
FROM alpha.standards_readback_evidence WHERE tenant_id=:tenant_id AND source_release_id=:release_id AND binding_id IS NOT NULL GROUP BY binding_id
), release_check AS (
SELECT scope.binding_count,scope.scope_exact,count(DISTINCT evidence.binding_id) FILTER (WHERE evidence.evidence_count>0 AND evidence.all_pass) AS passing_readbacks,count(DISTINCT rights.binding_id) FILTER (WHERE rights.precedence=1 AND rights.active_at_specificity=1 AND rights.admission_outcome='green' AND rights.rights_status IN ('permitted','public_domain') AND rights.attribution_satisfied) AS green_rights,COALESCE(bool_or(rights.precedence=1 AND rights.active_at_specificity>1),false) AS has_rights_conflict,COALESCE(bool_or(rights.precedence=1 AND (rights.admission_outcome='red' OR rights.rights_status='prohibited')),false) AS has_red,COALESCE(bool_or(evidence.has_mismatch),false) AS has_any_mismatch
FROM scope_check scope LEFT JOIN alpha.standards_source_row_binding binding ON binding.tenant_id=:tenant_id AND binding.source_release_id=scope.source_release_id LEFT JOIN evidence_status evidence ON evidence.binding_id=binding.binding_id LEFT JOIN ranked_rights rights ON rights.binding_id=binding.binding_id
GROUP BY scope.binding_count,scope.scope_exact
)
SELECT CASE WHEN binding_count=0 OR NOT scope_exact OR has_any_mismatch OR has_red THEN 'red' WHEN has_rights_conflict THEN 'yellow' WHEN binding_count=passing_readbacks AND binding_count=green_rights THEN 'green' ELSE 'yellow' END AS admission_outcome,binding_count,scope_exact,passing_readbacks,green_rights,has_any_mismatch FROM release_check;
COMMIT;Guardrails: Tenant predicate on every read/writeBounded serializationIdempotency replay happens before the transaction; every release-id collision abortsCanonical declared scope count + sorted row-key hash must equal every bindingEvery CASE row has one bindingEvery evidence row for every binding must passMost-specific effective rights winsOnly green becomes adoptable
Problems: curriculum:standards_scope_invalidcurriculum:rights_unresolvedcurriculum:standards_readback_mismatchcurriculum:idempotency_conflict
API: POST /alpha/curriculum/v1/kcs; POST /alpha/curriculum/v1/kcs/{kcId}/versions; POST /alpha/curriculum/v1/kc-prerequisites; POST /alpha/curriculum/v1/kc-relations; POST /alpha/curriculum/v1/kc-review-decisions; POST /alpha/curriculum/v1/standard-kc-maps
BEGIN ISOLATION LEVEL SERIALIZABLE;
SET CONSTRAINTS ALL DEFERRED;
-- Every prerequisite create, correction, and retirement acquires this same tenant-scoped transaction lock; serialization failures are retried with the same Idempotency-Key.
SELECT pg_advisory_xact_lock(hashtextextended('curriculum:kc-prerequisite:'||:tenant_id::text,0));
INSERT INTO alpha.knowledge_component (tenant_id,kc_id,source_kc_id,lineage_id,kc_kind,subject_id,current_version_id,publication_status,created_at,updated_at) VALUES (:tenant_id,:kc_id,:source_kc_id,:lineage_id,:kc_kind,:subject_id,:version_id,'draft',now(),now());
INSERT INTO alpha.knowledge_component_version (tenant_id,version_id,kc_id,version_number,status,definition,positive_examples,negative_examples,boundary_statement,misconceptions,instructional_classification,provenance,confidence,author_ref,created_at) VALUES (:tenant_id,:version_id,:kc_id,1,'draft',:definition,:positive_examples,:negative_examples,:boundary_statement,:misconceptions,:instructional_classification,:provenance,:confidence,:author_ref,now());
INSERT INTO alpha.kc_prerequisite (tenant_id,from_kc_id,to_kc_id,version,prerequisite_id,prerequisite_kc_id,dependent_kc_id,provenance,confidence,created_at,updated_at) SELECT :tenant_id,:prerequisite_kc_id,:kc_id,1,:edge_id,:prerequisite_kc_id,:kc_id,:edge_provenance,:edge_confidence,now(),now() WHERE NOT EXISTS (WITH RECURSIVE reach(kc_id) AS (SELECT dependent_kc_id FROM alpha.kc_prerequisite WHERE tenant_id=:tenant_id AND prerequisite_kc_id=:kc_id AND retired_at IS NULL UNION SELECT p.dependent_kc_id FROM alpha.kc_prerequisite p JOIN reach r ON p.prerequisite_kc_id=r.kc_id WHERE p.tenant_id=:tenant_id AND p.retired_at IS NULL) SELECT 1 FROM reach WHERE kc_id=:prerequisite_kc_id);
DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM alpha.kc_prerequisite WHERE tenant_id=:tenant_id AND prerequisite_id=:edge_id) THEN RAISE EXCEPTION 'curriculum:prerequisite_cycle'; END IF; END $$;
INSERT INTO alpha.kc_relation (tenant_id,relation_id,origin_kc_id,destination_kc_id,relation_type,provenance,confidence,created_at,updated_at) VALUES (:tenant_id,:relation_id,:kc_id,:related_kc_id,'applies_to',:relation_provenance,:relation_confidence,now(),now());
INSERT INTO alpha.kc_review_decision (tenant_id,review_decision_id,version_id,decision,edit_diff,rationale,provenance,actor_ref,decided_at) VALUES (:tenant_id,:review_id,:version_id,:decision,:edit_diff,:rationale,:review_provenance,:actor_ref,now());
INSERT INTO alpha.standard_kc_map (tenant_id,map_id,source_release_id,standard_binding_id,standard_id,kc_id,relationship,provenance,confidence,created_at,updated_at) VALUES (:tenant_id,:map_id,:source_release_id,:standard_binding_id,:standard_id,:kc_id,:relationship,:map_provenance,:map_confidence,now(),now());
COMMIT;Guardrails: No CASE KC rowPOST /kcs is owner-only and accepts stored_as=alpha.knowledge_component only with definition, optional provenance-only source_kc_id, and no document_id, name, or containment field; create replay, GET, version, and retire accept the exact canonical kc_id onlysource_kc_id is never a create-or-resolve key: reusing it for a different or server-minted canonical kc_id returns a typed conflict without partial rows even when semantics match, and it never enables a later lookup/reference fallback; HTTP retries use the original Idempotency-KeySemantic source ids and the #707 crosswalk remain immutable evidence only and are never written into UUID reference fieldsEvery scope/remediation/graph reference is an active tenant registry UUIDSemantic edits appendEvery prerequisite mutation takes one tenant-scoped graph lock inside SERIALIZABLESerialization failures replay through Idempotency-Keyalpha.kc_prerequisite alone is acyclicalpha.kc_relation holds other typed non-DAG semanticsalpha.standard_kc_map pins release + bindingKCs have no containment treeSteward queues/monitoring are absent
Problems: curriculum:invalid_kc_kindcurriculum:kc_definition_qualitycurriculum:kc_semantics_conflictcurriculum:prerequisite_cyclecurriculum:invalid_kc_relationcurriculum:precondition_failed
API: POST /alpha/curriculum/v1/courses/{courseId}/approvals with Idempotency-Key
Integrator policy: An app integrator may invoke this workflow directly with its Platform-issued tenant-scoped credential. An ordinary course approval needs no per-course owner ruling.
Authorization: Bearer JWT with curriculum:write
Request body: {"approved_by":"integrator:ap-one","provenance":{"source":"ap-one:course-approval","course_ref":"{integratorCourseRef}"}}
Turnaround: The authorized approval transaction is synchronous. If the integrator lacks curriculum:write, request that narrow tenant credential through Platform tenant onboarding; this contract defines no credential-provisioning SLA and there is no per-course approval queue.
Preconditions:
Readback:
BEGIN ISOLATION LEVEL SERIALIZABLE; SELECT course_id FROM alpha.course WHERE tenant_id=:tenant_id AND course_id=:course_id AND retired_at IS NULL FOR UPDATE; CREATE TEMP TABLE _approval_scope (kc_id uuid PRIMARY KEY, version_id uuid NOT NULL, snapshot_source text NOT NULL) ON COMMIT DROP; INSERT INTO _approval_scope (kc_id,version_id,snapshot_source) SELECT kc.kc_id,kc.current_version_id,'course_component:'||min(component.component_id::text) FROM alpha.course_component_member member JOIN alpha.course_component component ON component.tenant_id=member.tenant_id AND component.component_id=member.target_component_id AND component.retired_at IS NULL CROSS JOIN LATERAL unnest(component.scope_kc_ids) scoped(kc_id) JOIN alpha.knowledge_component kc ON kc.tenant_id=component.tenant_id AND kc.kc_id=scoped.kc_id AND kc.retired_at IS NULL WHERE member.tenant_id=:tenant_id AND member.course_id=:course_id AND member.target_kind='course_component' AND member.retired_at IS NULL GROUP BY kc.kc_id,kc.current_version_id; DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM _approval_scope) OR (SELECT count(*) FROM _approval_scope) <> (SELECT count(DISTINCT scoped.kc_id) FROM alpha.course_component_member member JOIN alpha.course_component component ON component.tenant_id=member.tenant_id AND component.component_id=member.target_component_id AND component.retired_at IS NULL CROSS JOIN LATERAL unnest(component.scope_kc_ids) scoped(kc_id) WHERE member.tenant_id=:tenant_id AND member.course_id=:course_id AND member.target_kind='course_component' AND member.retired_at IS NULL) THEN RAISE EXCEPTION 'curriculum:approval_snapshot_incomplete'; END IF; END $$; INSERT INTO alpha.course_approval (tenant_id,approval_id,course_id,course_graph_sha256,approved_by,approved_at,provenance) VALUES (:tenant_id,:approval_id,:course_id,:course_graph_sha256,:approved_by,now(),:provenance); INSERT INTO alpha.course_approval_kc_snapshot (tenant_id,approval_id,kc_id,version_id,snapshot_source,created_at) SELECT :tenant_id,:approval_id,kc_id,version_id,snapshot_source,now() FROM _approval_scope; DO $$ BEGIN IF (SELECT count(*) FROM _approval_scope) <> (SELECT count(*) FROM alpha.course_approval_kc_snapshot WHERE tenant_id=:tenant_id AND approval_id=:approval_id) THEN RAISE EXCEPTION 'curriculum:approval_snapshot_incomplete'; END IF; END $$; INSERT INTO alpha.kc_firming_event (tenant_id,firming_event_id,version_id,firming_reason,source_ref,actor_ref,firmed_at) SELECT :tenant_id,gen_random_uuid(),snapshot.version_id,'course_approval','approval:'||:approval_id,:approved_by,now() FROM alpha.course_approval_kc_snapshot snapshot JOIN alpha.knowledge_component_version version ON version.tenant_id=snapshot.tenant_id AND version.version_id=snapshot.version_id WHERE snapshot.tenant_id=:tenant_id AND snapshot.approval_id=:approval_id AND version.status='draft' ON CONFLICT (tenant_id,version_id) DO NOTHING; UPDATE alpha.knowledge_component_version version SET status='firm' FROM alpha.course_approval_kc_snapshot snapshot WHERE snapshot.tenant_id=:tenant_id AND snapshot.approval_id=:approval_id AND version.tenant_id=snapshot.tenant_id AND version.version_id=snapshot.version_id AND version.status='draft'; UPDATE alpha.course SET current_approval_id=:approval_id,updated_at=now() WHERE tenant_id=:tenant_id AND course_id=:course_id; COMMIT;
Guardrails: Complete immutable snapshotFirm only exact snapshotted versionsNo publication/assignment firmingApproval and firming atomic
Problems: curriculum:approval_snapshot_incompletecurriculum:invalid_kc_lifecyclecurriculum:idempotency_conflict
API: POST /alpha/curriculum/v1/kc-firming-events with Idempotency-Key and body {version_id, firming_reason:'first_genuine_response', source_ref}
-- First obtain :validated_live_learning_evidence_ref from the Results/Events-owned contract; Curriculum rows cannot prove genuine traffic. BEGIN ISOLATION LEVEL SERIALIZABLE; SELECT status FROM alpha.knowledge_component_version WHERE tenant_id=:tenant_id AND version_id=:version_id FOR UPDATE; INSERT INTO alpha.kc_firming_event (tenant_id,firming_event_id,version_id,firming_reason,source_ref,actor_ref,firmed_at) VALUES (:tenant_id,:event_id,:version_id,'first_genuine_response',:validated_live_learning_evidence_ref,:actor_ref,now()) ON CONFLICT (tenant_id,version_id) DO NOTHING; UPDATE alpha.knowledge_component_version SET status='firm' WHERE tenant_id=:tenant_id AND version_id=:version_id AND status='draft' AND EXISTS (SELECT 1 FROM alpha.kc_firming_event WHERE tenant_id=:tenant_id AND version_id=:version_id AND firming_reason='first_genuine_response' AND source_ref=:validated_live_learning_evidence_ref); COMMIT;
Guardrails: Explicit live_learning=trueFirst genuine response evidencePreview/developer traffic rejectedAt most one effective firming eventIdempotent replay
Problems: curriculum:invalid_kc_lifecyclecurriculum:live_learning_evidence_requiredcurriculum:idempotency_conflict
API: POST /alpha/curriculum/v1/components; POST /alpha/curriculum/v1/courses/{courseId}/members (once per course)
BEGIN; INSERT INTO alpha.course_component (tenant_id,component_id,kind,scope_kc_ids,name,description,expected_xp,lineage_id,publication_status,created_at,updated_at) VALUES (:tenant_id,:component_id,'lesson',ARRAY[:kc_id]::uuid[],:component_name,:component_description,:expected_xp,:lineage_id,'published',now(),now()); INSERT INTO alpha.course_component_member (tenant_id,member_id,course_id,parent_component_id,position,target_kind,target_component_id,content_id,content_version_id,content_kind,renderer_ref,gates,passing_criteria_ref,on_fail,created_at,updated_at) VALUES (:tenant_id,:course_a_member_id,:course_a_id,:course_a_parent_id,:course_a_position,'course_component',:component_id,NULL,NULL,NULL,NULL,false,NULL,NULL,now(),now()), (:tenant_id,:course_b_member_id,:course_b_id,:course_b_parent_id,:course_b_position,'course_component',:component_id,NULL,NULL,NULL,NULL,false,NULL,NULL,now(),now()); COMMIT;
Guardrails: One component identityTwo member identitiesOrder/renderer/gate are member-localLesson preserves its non-empty active KC cluster
Problems: curriculum:unknown_kccurriculum:invalid_component_kindcurriculum:member_position_conflict
API: GET Content exact-version release-eligibility; POST /alpha/curriculum/v1/courses/{courseId}/members
-- First require a 200 eligible response from GET /tenants/{tenantId}/alpha/content/items/{contentId}/versions/{contentVersionId}/release-eligibility and verify renderer_ref against the live capability registry. Raw Curriculum rows cannot infer either verdict.
INSERT INTO alpha.course_component_member (tenant_id,member_id,course_id,parent_component_id,position,target_kind,target_component_id,content_id,content_version_id,content_kind,renderer_ref,gates,passing_criteria_ref,on_fail,created_at,updated_at)
VALUES (:tenant_id,:member_id,:course_id,:parent_component_id,:position,'content_version',NULL,:validated_content_id,:validated_content_version_id,:validated_content_kind,:validated_renderer_ref,:gates,:passing_criteria_ref,:on_fail,now(),now());Guardrails: Exact version, not latestContent owns eligibilityNo copied eligibility fieldsRenderer registry must accept content_kind404/unsupported fails closed
Problems: curriculum:content_not_eligiblecurriculum:content_unavailablecurriculum:content_version_mismatchcurriculum:invalid_content_bank_member_contractcurriculum:renderer_incompatible
API: POST /alpha/curriculum/v1/components/{componentId}/repoint with Idempotency-Key
Integrator policy: A producer whose course already pins a Content identity repoints that pin to its amended exact version directly with its Platform-issued tenant-scoped curriculum:write credential; a platform re-pin ticket is not the steady-state path. operation=attach pins newly published content onto a component without a current pin. This endpoint exposes the same governed exact-version target update the platform's own repin corridor executes; it is not a new storage primitive.
Request body: {"operation":"repoint","expected_target_ref":{"module":"content","content_kind":"article","content_id":"{contentId}","content_version_id":"{currentlyPinnedVersionId}"},"target_ref":{"module":"content","content_kind":"article","content_id":"{contentId}","content_version_id":"{amendedVersionId}"}}
Preconditions:
Readback:
BEGIN;
-- First require a 200 exact-version release-eligibility response with usage_scope='practice_eligible'
-- for :new_content_version_id from the owning Content API; raw Curriculum rows cannot infer that verdict.
SELECT member_id, content_id, content_version_id, content_kind, gates
FROM alpha.course_component_member
WHERE tenant_id=:tenant_id AND member_id=:member_id AND retired_at IS NULL
FOR UPDATE;
DO $$ BEGIN
IF NOT FOUND THEN RAISE EXCEPTION 'curriculum:not_found'; END IF;
END $$;
UPDATE alpha.course_component_member member
SET content_version_id=:new_content_version_id, updated_at=now()
WHERE member.tenant_id=:tenant_id AND member.member_id=:member_id AND member.retired_at IS NULL
AND member.target_kind='content_version'
AND member.gates=false
AND member.content_kind NOT IN ('test_bank','test','test_spec')
AND member.content_id=:expected_content_id
AND member.content_kind=:expected_content_kind
AND member.content_version_id IS NOT DISTINCT FROM :expected_content_version_id
AND member.content_id=:new_content_id;
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM alpha.course_component_member WHERE tenant_id=:tenant_id AND member_id=:member_id AND content_version_id=:new_content_version_id) THEN
RAISE EXCEPTION 'curriculum:repoint_pin_stale';
END IF;
END $$;
INSERT INTO alpha.component_target_repoint_audit (tenant_id, repoint_audit_id, component_id, operation, previous_target_ref, new_target_ref, actor_ref, request_id, created_at)
VALUES (:tenant_id, :repoint_audit_id, :member_id, :operation, :previous_target_ref, :new_target_ref, :actor_ref, :request_id, now());
COMMIT;
-- The deployed CASE compatibility adapter performs the identical operation on the component's
-- alpha.target_ref through the same normalized patch and CAS-guarded persistence as component PATCH.Guardrails: Compare-and-set on the exact current pin, never last-writer-winsOne Content identity per repoint; attach only onto an unpinned componentContent owns exact-version eligibility and the check happens server-side inside the accepting requestApproved assessment chains freeze to the reviewed-replacement manifest pathOne immutable audit row per accepted operation in the same transactionIdempotency-Key replay returns the stored response without a second audit rowRouting stays fail-closed until a new immutable course approval covers the changed graph
Problems: curriculum:not_foundcurriculum:repoint_pin_stalecurriculum:repoint_identity_mismatchcurriculum:repoint_target_not_serveablecurriculum:approved_chain_repoint_frozencurriculum:content_unavailablecurriculum:content_version_mismatchcurriculum:renderer_incompatiblecurriculum:idempotency_conflict
API: GET /alpha/curriculum/v1/courses/{courseId}/expected-xp
WITH RECURSIVE active_tree AS ( SELECT member.tenant_id,member.course_id,member.member_id,member.target_component_id,component.expected_xp,ARRAY[member.member_id]::uuid[] AS member_path FROM alpha.course_component_member member JOIN alpha.course_component component ON component.tenant_id=member.tenant_id AND component.component_id=member.target_component_id AND component.retired_at IS NULL WHERE member.tenant_id=:tenant_id AND member.course_id=:course_id AND member.parent_component_id IS NULL AND member.target_kind='course_component' AND member.retired_at IS NULL UNION ALL SELECT child.tenant_id,child.course_id,child.member_id,child.target_component_id,component.expected_xp,parent.member_path||child.member_id FROM active_tree parent JOIN alpha.course_component_member child ON child.tenant_id=parent.tenant_id AND child.course_id=parent.course_id AND child.parent_component_id=parent.target_component_id AND child.target_kind='course_component' AND child.retired_at IS NULL JOIN alpha.course_component component ON component.tenant_id=child.tenant_id AND component.component_id=child.target_component_id AND component.retired_at IS NULL WHERE NOT child.member_id=ANY(parent.member_path) ), contributing AS ( SELECT node.* FROM active_tree node WHERE node.expected_xp IS NOT NULL AND NOT EXISTS (SELECT 1 FROM active_tree descendant WHERE cardinality(descendant.member_path)>cardinality(node.member_path) AND descendant.member_path[1:cardinality(node.member_path)]=node.member_path AND descendant.expected_xp IS NOT NULL) ), cycle_check AS ( SELECT EXISTS (SELECT 1 FROM active_tree parent JOIN alpha.course_component_member child ON child.tenant_id=parent.tenant_id AND child.course_id=parent.course_id AND child.parent_component_id=parent.target_component_id AND child.retired_at IS NULL WHERE child.member_id=ANY(parent.member_path)) AS cycle_detected ) SELECT CASE WHEN cycle_check.cycle_detected THEN NULL ELSE COALESCE(sum(contributing.expected_xp),0) END AS expected_xp,course.course_role,(course.course_role='main') AS included_in_results_grade_denominator,cycle_check.cycle_detected FROM cycle_check JOIN alpha.course course ON course.tenant_id=:tenant_id AND course.course_id=:course_id AND course.retired_at IS NULL LEFT JOIN contributing ON true GROUP BY course.course_role,cycle_check.cycle_detected;
Guardrails: Every active course role returns its own totalContainer ignored when descendant has expected_xpFallback contributes only without valued descendantActive member paths onlyMain role only for the separate Results grade denominatorNo student actuals
Problems: curriculum:lesson_structure_missingcurriculum:expected_xp_ambiguous
API: POST /alpha/curriculum/v1/ingest/timeback-course-refs with Idempotency-Key
BEGIN;
CREATE TEMP TABLE _source_components (source_component_id uuid PRIMARY KEY,source_kind text NOT NULL,scope_kc_ids uuid[] NOT NULL,source_name text NOT NULL,expected_xp numeric,lineage_id uuid NOT NULL) ON COMMIT DROP;
INSERT INTO _source_components SELECT * FROM jsonb_to_recordset(:validated_source_components::jsonb) AS source(source_component_id uuid,source_kind text,scope_kc_ids uuid[],source_name text,expected_xp numeric,lineage_id uuid);
CREATE TEMP TABLE _ordered_members (member_id uuid PRIMARY KEY,parent_component_id uuid,source_position integer NOT NULL,target_kind text NOT NULL,target_component_id uuid,content_id uuid,content_version_id uuid,content_kind text,renderer_ref text,gates boolean NOT NULL,passing_criteria_ref text,on_fail jsonb) ON COMMIT DROP;
INSERT INTO _ordered_members SELECT * FROM jsonb_to_recordset(:validated_ordered_members::jsonb) AS member(member_id uuid,parent_component_id uuid,source_position integer,target_kind text,target_component_id uuid,content_id uuid,content_version_id uuid,content_kind text,renderer_ref text,gates boolean,passing_criteria_ref text,on_fail jsonb);
DO $$ BEGIN
IF EXISTS (SELECT 1 FROM _source_components WHERE source_kind='lesson' AND cardinality(scope_kc_ids)=0) OR EXISTS (SELECT 1 FROM _source_components source CROSS JOIN LATERAL unnest(source.scope_kc_ids) scoped(kc_id) LEFT JOIN alpha.knowledge_component kc ON kc.tenant_id=:tenant_id AND kc.kc_id=scoped.kc_id AND kc.retired_at IS NULL WHERE kc.kc_id IS NULL) THEN RAISE EXCEPTION 'curriculum:adapter_rejected'; END IF;
IF EXISTS (SELECT 1 FROM _ordered_members WHERE source_position<0 OR target_kind NOT IN ('course_component','content_version') OR (target_kind='course_component' AND (target_component_id IS NULL OR content_id IS NOT NULL OR content_version_id IS NOT NULL OR content_kind IS NOT NULL)) OR (target_kind='content_version' AND (target_component_id IS NOT NULL OR content_id IS NULL OR content_version_id IS NULL OR content_kind IS NULL OR renderer_ref IS NULL)) OR gates<>(passing_criteria_ref IS NOT NULL)) THEN RAISE EXCEPTION 'curriculum:adapter_rejected'; END IF;
END $$;
INSERT INTO alpha.course (tenant_id,course_id,subject_id,grade_scope,course_role,name,lineage_id,publication_status,created_at,updated_at) VALUES (:tenant_id,:course_id,:subject_id,:grade_scope,:course_role,:course_name,:course_lineage_id,'draft',now(),now()) ON CONFLICT (tenant_id,course_id) DO UPDATE SET subject_id=excluded.subject_id,grade_scope=excluded.grade_scope,course_role=excluded.course_role,name=excluded.name,lineage_id=excluded.lineage_id,publication_status='draft',updated_at=now();
INSERT INTO alpha.course_component (tenant_id,component_id,kind,scope_kc_ids,name,expected_xp,lineage_id,publication_status,created_at,updated_at) SELECT :tenant_id,source_component_id,source_kind,scope_kc_ids,source_name,expected_xp,lineage_id,'draft',now(),now() FROM _source_components ON CONFLICT (tenant_id,component_id) DO UPDATE SET kind=excluded.kind,scope_kc_ids=excluded.scope_kc_ids,name=excluded.name,expected_xp=excluded.expected_xp,lineage_id=excluded.lineage_id,publication_status='draft',updated_at=now();
INSERT INTO alpha.course_component_member (tenant_id,member_id,course_id,parent_component_id,position,target_kind,target_component_id,content_id,content_version_id,content_kind,renderer_ref,gates,passing_criteria_ref,on_fail,created_at,updated_at) SELECT :tenant_id,member_id,:course_id,parent_component_id,source_position,target_kind,target_component_id,content_id,content_version_id,content_kind,renderer_ref,gates,passing_criteria_ref,on_fail,now(),now() FROM _ordered_members ON CONFLICT (tenant_id,member_id) DO UPDATE SET course_id=excluded.course_id,parent_component_id=excluded.parent_component_id,position=excluded.position,target_kind=excluded.target_kind,target_component_id=excluded.target_component_id,content_id=excluded.content_id,content_version_id=excluded.content_version_id,content_kind=excluded.content_kind,renderer_ref=excluded.renderer_ref,gates=excluded.gates,passing_criteria_ref=excluded.passing_criteria_ref,on_fail=excluded.on_fail,updated_at=now();
DO $$ BEGIN
IF (SELECT count(*) FROM _source_components) <> (SELECT count(*) FROM alpha.course_component component JOIN _source_components source ON source.source_component_id=component.component_id WHERE component.tenant_id=:tenant_id AND component.publication_status='draft') OR (SELECT count(*) FROM _ordered_members) <> (SELECT count(*) FROM alpha.course_component_member member JOIN _ordered_members source ON source.member_id=member.member_id WHERE member.tenant_id=:tenant_id AND member.course_id=:course_id AND member.retired_at IS NULL) THEN RAISE EXCEPTION 'curriculum:publication_incomplete'; END IF;
END $$;
CREATE TEMP TABLE _intended_tree (component_id uuid PRIMARY KEY,depth integer NOT NULL) ON COMMIT DROP;
WITH RECURSIVE intended_tree AS (
SELECT component.component_id,0 AS depth FROM alpha.course_component component JOIN alpha.course_component_member member ON member.tenant_id=component.tenant_id AND member.target_component_id=component.component_id WHERE component.tenant_id=:tenant_id AND member.course_id=:course_id AND member.parent_component_id IS NULL AND member.target_kind='course_component' AND member.retired_at IS NULL
UNION ALL
SELECT child.component_id,parent.depth+1 FROM intended_tree parent JOIN alpha.course_component_member member ON member.tenant_id=:tenant_id AND member.course_id=:course_id AND member.parent_component_id=parent.component_id AND member.target_kind='course_component' AND member.retired_at IS NULL JOIN alpha.course_component child ON child.tenant_id=member.tenant_id AND child.component_id=member.target_component_id
)
INSERT INTO _intended_tree SELECT component_id,max(depth) FROM intended_tree GROUP BY component_id;
DO $$ DECLARE publish_depth integer; BEGIN
FOR publish_depth IN SELECT DISTINCT depth FROM _intended_tree ORDER BY depth DESC LOOP
UPDATE alpha.course_component component SET publication_status='published',updated_at=now() FROM _intended_tree tree WHERE component.tenant_id=:tenant_id AND component.component_id=tree.component_id AND tree.depth=publish_depth;
END LOOP;
END $$;
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM alpha.course_component_member member JOIN alpha.course_component component ON component.tenant_id=member.tenant_id AND component.component_id=member.target_component_id WHERE member.tenant_id=:tenant_id AND member.course_id=:course_id AND member.retired_at IS NULL AND component.kind IN ('lesson','review','practice','mastery_gate')) OR EXISTS (SELECT 1 FROM alpha.course_component_member member JOIN alpha.course_component component ON component.tenant_id=member.tenant_id AND component.component_id=member.target_component_id WHERE member.tenant_id=:tenant_id AND member.course_id=:course_id AND (member.retired_at IS NOT NULL OR component.retired_at IS NOT NULL OR component.publication_status<>'published')) THEN RAISE EXCEPTION 'curriculum:publication_incomplete'; END IF;
END $$;
UPDATE alpha.course SET publication_status='published',updated_at=now() WHERE tenant_id=:tenant_id AND course_id=:course_id;
COMMIT;Guardrails: Dry-run firstDeterministic same-run upsert identitiesEvery course/component is draft before assembly writesExact intended-tree readback precedes publicationPublish descendants bottom-up and the course root lastAny write/readback/publish failure rolls back or leaves the root draftPreserve source parentage and orderContent resolves resource bodies first and returns the exact versionNever infer latest or copy Content eligibility evidenceExact Content release eligibility is required at authoring and launchEvery lesson has a non-empty active KC cluster and multi-KC scope is preservedStandards evidence returns curriculum:adapter_rejected and never writes CASE rowsQuiz label alone does not create a gateSource-empty anchors stay non-routable
Problems: curriculum:validation_failedcurriculum:adapter_rejectedcurriculum:lesson_structure_missingcurriculum:publication_incompletecurriculum:content_not_eligiblecurriculum:content_unavailablecurriculum:content_version_mismatchcurriculum:invalid_content_bank_member_contractcurriculum:idempotency_conflict
API: GET /alpha/curriculum/v1/tracks/{trackId}/placement-candidates?studentId=:student_id&subjectId=:subject_id
SELECT m.member_id,m.position,m.target_component_id,c.entry_policy_ref FROM alpha.course c JOIN alpha.course_component_member m ON m.tenant_id=c.tenant_id AND m.course_id=c.course_id AND m.retired_at IS NULL WHERE c.tenant_id=:tenant_id AND c.course_id=:track_id AND c.retired_at IS NULL ORDER BY m.position,m.member_id; -- Apply the returned versioned entry_policy_ref through Policy/Results; MAP/RIT may seed the start only.
Guardrails: Tenant scopeActive ordered membersPolicy owns the algorithm/numbersMAP/RIT is not final placementStudent state stays in Results
Problems: curriculum:not_foundcurriculum:reference_unresolvedcurriculum:unsupported_query_parameter
API: GET /alpha/curriculum/v1/courses/{courseId}/next-lesson?studentId=:student_id&subjectId=:subject_id
WITH RECURSIVE course_root AS (
SELECT course_id,publication_status,retired_at FROM alpha.course WHERE tenant_id=:tenant_id AND course_id=:course_id
), tree AS (
SELECT m.tenant_id,m.course_id,m.member_id,m.parent_component_id,m.position,m.target_kind,m.target_component_id,ARRAY[m.position]::integer[] AS position_path,ARRAY[m.member_id]::uuid[] AS member_path,(m.retired_at IS NULL AND component.publication_status='published' AND component.retired_at IS NULL) AS ancestor_publication_safe
FROM alpha.course_component_member m JOIN alpha.course_component component ON component.tenant_id=m.tenant_id AND component.component_id=m.target_component_id
WHERE m.tenant_id=:tenant_id AND m.course_id=:course_id AND m.parent_component_id IS NULL AND m.target_kind='course_component'
UNION ALL
SELECT child.tenant_id,child.course_id,child.member_id,child.parent_component_id,child.position,child.target_kind,child.target_component_id,parent.position_path||child.position,parent.member_path||child.member_id,(parent.ancestor_publication_safe AND child.retired_at IS NULL AND component.publication_status='published' AND component.retired_at IS NULL)
FROM alpha.course_component_member child JOIN tree parent ON child.tenant_id=parent.tenant_id AND child.course_id=parent.course_id AND child.parent_component_id=parent.target_component_id JOIN alpha.course_component component ON component.tenant_id=child.tenant_id AND component.component_id=child.target_component_id
WHERE child.target_kind='course_component' AND NOT child.member_id=ANY(parent.member_path)
), first_frontier AS (
SELECT tree.member_id,tree.position,tree.position_path,tree.target_component_id,component.kind,component.scope_kc_ids,component.kc_scope_decision,tree.ancestor_publication_safe
FROM tree JOIN alpha.course_component component ON component.tenant_id=tree.tenant_id AND component.component_id=tree.target_component_id
WHERE component.kind IN ('lesson','review','practice','mastery_gate') ORDER BY tree.position_path,tree.member_id LIMIT 1
)
SELECT frontier.member_id,frontier.position,frontier.position_path,frontier.target_component_id,frontier.kind,frontier.scope_kc_ids,frontier.kc_scope_decision
FROM course_root root CROSS JOIN first_frontier frontier
WHERE root.publication_status='published' AND root.retired_at IS NULL AND frontier.ancestor_publication_safe;
-- Results supplies completed/current state; choose the first eligible row there, never in Curriculum storage.Guardrails: Tenant + active-row predicatesChoose the first frontier before publication filtering so an unpublished node is never skippedCourse root, selected frontier, and every containment ancestor must be published and not retiredCurrent graph must match an immutable approval with a complete exact firm KC-version snapshot for every scoped KCThe exact Content target is revalidated through Content-owned release eligibility at launch and latest is never substitutedDraft, retired, changed, unapproved, incomplete, unavailable, malformed, mismatched, or ineligible state fails closedLexicographic ancestor position_path preserves sibling-local hierarchy orderCycle paths are rejectedAn ordinary lesson has a non-empty active KC cluster and preserves multi-KC scope; an exact content-bearing lesson may instead echo scope_kc_ids=[] plus kc_scope_decision=authoritative_no_kc and contributes no KC snapshot or mastery evidenceResults supplies student stateMissing authoritative members fails closed
Problems: curriculum:not_foundcurriculum:lesson_structure_missingcurriculum:course_not_routablecurriculum:content_not_eligiblecurriculum:content_unavailablecurriculum:content_version_mismatchcurriculum:invalid_content_bank_member_contractcurriculum:unsupported_query_parameter
API: GET /alpha/curriculum/v1/gates/{gateId}/status?studentId=:student_id; GET /alpha/curriculum/v1/gates/{gateId}/remediation?studentId=:student_id&resultRecordId=:result_id
SELECT m.member_id,m.passing_criteria_ref,m.on_fail,m.content_id,m.content_version_id,m.content_kind FROM alpha.course_component_member m WHERE m.tenant_id=:tenant_id AND m.member_id=:gate_id AND m.gates=true AND m.retired_at IS NULL; -- Resolve passing_criteria_ref through Policy and result_id through Results. Return on_fail entries exactly; never persist the student's inserted remediation path in Curriculum.
Guardrails: Gate behavior is member-localPolicy numbers are referencedResults outcomes are read, not copiednever_learned→lessonforgot→reviewcareless→practice
Problems: curriculum:not_foundcurriculum:invalid_gate_contractcurriculum:reference_unresolved
API: GET /alpha/curriculum/v1/gates/{gateId}/next-form?studentId=:student_id
WITH base_gate AS (
SELECT content_id,content_version_id FROM alpha.course_component_member WHERE tenant_id=:tenant_id AND member_id=:gate_id AND gates=true AND content_kind='test_bank' AND retired_at IS NULL
), content_eligible_versions AS (
-- Populate from 200 ordinary exact-version release-eligibility responses, or for one Content-authorized
-- demo test identity from current test-serve eligibility responses. Test mode returns only after
-- Content appends the exact bank/form authorization receipt.
SELECT content_id,content_version_id FROM jsonb_to_recordset(:validated_content_eligible_versions::jsonb) AS eligible(content_id text,content_version_id text)
), eligible_gate AS (
SELECT gate.* FROM base_gate gate JOIN content_eligible_versions eligible ON eligible.content_id=gate.content_id::text AND eligible.content_version_id=gate.content_version_id::text
), raw_bank_members AS (
-- Read every active row for the exact bank version before applying scope or eligibility filters.
-- LEFT JOINs keep missing targets visible so malformed legacy rows cannot disappear.
SELECT r.content_reference_id,r.referenced_content_artifact_id AS referenced_content_id,
r.referenced_content_version_id AS referenced_version_id,r.form_index,r.usage_scope,
referenced_ext.usage_scope AS referenced_usage_scope,
CASE referenced_artifact.artifact_kind WHEN 'test' THEN 'test' WHEN 'item' THEN 'question' ELSE NULL END AS content_kind,
referenced_test.assessment_role
FROM alpha.content_reference r
JOIN platform.tenant tenant ON tenant.tenant_id=r.tenant_id
JOIN eligible_gate gate ON r.parent_content_artifact_id=gate.content_id AND r.parent_content_version_id=gate.content_version_id
LEFT JOIN qti.artifact referenced_artifact ON referenced_artifact.tenant_id=r.tenant_id AND referenced_artifact.artifact_id=r.referenced_content_artifact_id
LEFT JOIN alpha.content_item_extension referenced_ext ON referenced_ext.tenant_id=r.tenant_id AND referenced_ext.content_artifact_id=r.referenced_content_artifact_id
LEFT JOIN alpha.assessment_test_extension referenced_test ON referenced_test.tenant_id=r.tenant_id AND referenced_test.content_artifact_id=r.referenced_content_artifact_id
WHERE tenant.tenant_key=:tenant_key AND r.relationship_kind='bank_member' AND r.retired_at IS NULL
ORDER BY r.form_index ASC NULLS LAST,r.content_reference_id
LIMIT 51
), bank_member_contract AS (
SELECT count(*) AS member_count,
count(*) FILTER (WHERE content_kind IS DISTINCT FROM 'test' OR assessment_role IS DISTINCT FROM 'form' OR referenced_content_id IS NULL OR referenced_version_id IS NULL OR form_index IS NULL OR form_index<=0) AS malformed_count,
count(form_index)-count(DISTINCT form_index) AS duplicate_form_index_count
FROM raw_bank_members
), candidate_forms AS (
SELECT member.referenced_content_id,member.referenced_version_id,member.form_index
FROM raw_bank_members member CROSS JOIN bank_member_contract contract
WHERE contract.malformed_count=0 AND contract.duplicate_form_index_count=0
AND member.usage_scope='practice_eligible' AND member.referenced_usage_scope='practice_eligible'
), eligible_forms AS (
SELECT candidate.* FROM candidate_forms candidate JOIN content_eligible_versions eligible ON eligible.content_id=candidate.referenced_content_id AND eligible.content_version_id=candidate.referenced_version_id
), seen_forms AS (
SELECT data->>'content_id' AS content_id,data->>'content_version_id' AS content_version_id
FROM alpha.result_content_evidence
WHERE tenant_id=:tenant_key AND data->>'student_id'=:student_id
), unseen_forms AS (
SELECT form.* FROM eligible_forms form LEFT JOIN seen_forms seen ON seen.content_id=form.referenced_content_id AND seen.content_version_id=form.referenced_version_id WHERE seen.content_id IS NULL
), next_form AS (
SELECT * FROM unseen_forms ORDER BY form_index,referenced_content_id LIMIT 1
)
SELECT (SELECT count(*) FROM base_gate) AS gate_count,(SELECT count(*) FROM eligible_gate) AS eligible_gate_count,contract.member_count,contract.malformed_count,contract.duplicate_form_index_count,(SELECT count(*) FROM candidate_forms) AS candidate_count,(SELECT count(*) FROM eligible_forms) AS eligible_count,(SELECT count(*) FROM unseen_forms) AS unseen_count,next_form.referenced_content_id,next_form.referenced_version_id,next_form.form_index
FROM bank_member_contract contract LEFT JOIN next_form ON true;
-- Before scope filtering or form eligibility, map malformed_count>0 or duplicate_form_index_count>0 to curriculum:invalid_content_bank_member_contract. Map gate_count=0 to curriculum:not_found, eligible_gate_count=0 to curriculum:content_not_eligible, member_count=0 or >50 to curriculum:invalid_gate_contract, eligible_count=0 to curriculum:content_not_eligible, and eligible_count>0 plus unseen_count=0 to curriculum:bank_exhausted. Never synthesize form_index from display_order or row position, and never return an empty 200.Guardrails: PP100 v2 gates reject this fixed-form route because Results owns adaptive question selection from the exact pp100_adaptive_shards bankTargetless drafts fail before Content and membership readsA complete exact-bank draft is limited to Content's demo grant plus live People & Orgs test/synthetic realityPublished gates try ordinary release eligibility first; only authoritative ineligibility can enter test-serveContent invalid-bank contract answers map to the typed Curriculum 409 and never enter test-serve, appear empty, or skipTransport, timeout, malformed, and target-mismatch outcomes fail closedContent owns exact-version bank membershipRead and validate every active exact-bank row before applying usage-scope or eligibility filtersEach member must be an exact assessment_role=form test with a unique positive integer form_indexNever coalesce or synthesize form_index from display_order or row positionPin parent_content_id + parent_version_idThe bank version and every candidate form version must each pass the selected Content eligibility laneTest mode commits an immutable exact bank/form Content receipt before returnBoth Content usage scopes must be practice_eligibleResults owns seen-form evidenceStable ascending form_indexNever client-chosen or header-enabledMissing, ineligible, malformed, invalid-bank, and exhausted are distinct
Problems: curriculum:not_foundcurriculum:invalid_gate_contractcurriculum:content_not_eligiblecurriculum:content_unavailablecurriculum:invalid_content_bank_member_contractcurriculum:bank_exhausted
API: POST /alpha/curriculum/v1/transports/common-cartridge/preview; POST /alpha/curriculum/v1/transports/common-cartridge/import with Idempotency-Key
SELECT c.course_id,m.member_id,m.position,m.target_kind,m.target_component_id,m.content_id,m.content_version_id FROM alpha.course c JOIN alpha.course_component_member m ON m.tenant_id=c.tenant_id AND m.course_id=c.course_id AND m.retired_at IS NULL WHERE c.tenant_id=:tenant_id AND c.course_id=:course_id AND c.retired_at IS NULL ORDER BY m.position,m.member_id; -- Join CASE standards and Content package bytes through their owning dictionaries to build/validate the transport; do not INSERT a cartridge authority row.
Guardrails: Transport onlyNo stored cartridge authorityStable identifiersCASE/Curriculum/Content owners remain separateImport is idempotent
Problems: curriculum:transport_invalidcurriculum:reference_unresolvedcurriculum:idempotency_conflict
API: GET /alpha/curriculum/v1/kc-sets/{setId}
SELECT set_id,set_kind,name,kc_id,version_id,ordinal,source_ref FROM alpha.named_kc_set_v WHERE tenant_id=:tenant_id AND set_id=:set_id ORDER BY ordinal NULLS LAST,kc_id;
Guardrails: Read-onlyDeterministic source projectionNo stored KC parent/treeSet membership does not imply prerequisite order
Problems: curriculum:not_foundcurriculum:unsupported_query_parameter
API: GET /alpha/curriculum/v1/kcs; GET /alpha/curriculum/v1/kcs/{kcId}
SELECT kc.kc_id,kc.lineage_id,kc.kc_kind,kc.subject_id,kc.current_version_id,kc.publication_status,version.version_number,version.status,version.definition FROM alpha.knowledge_component kc JOIN alpha.knowledge_component_version version ON version.tenant_id=kc.tenant_id AND version.version_id=kc.current_version_id WHERE kc.tenant_id=:tenant_id AND kc.retired_at IS NULL AND kc.current_version_id IS NOT NULL ORDER BY kc.updated_at DESC,kc.kc_id LIMIT :limit;
Guardrails: The registry is the single KC owner: adaptive-diagnostics consumers (for example AlphaTest adaptive_diagnostic blueprints) discover Knowledge Components here, never from case.cf_item or a CASE package, and no KC row is ever copied or relabeled into the standards catalogAdaptive-eligible means an active owner-typed registry KC: retired rows and the retained unclassified #707 legacy adoption row (kc_kind NULL, no current version) are never discoverable and never adaptive-eligibleEvery returned identity is the canonical kc_id UUID and reads back through GET /alpha/curriculum/v1/kcs/{kcId}; superseded legacy CASE KC rows remain immutable migration evidence onlyCASE package/framework identity for standards remains the contained CFDocument.identifier per official CASE 1.1; KC discovery never mints a CASE package identityStable updated_at desc, kc_id asc order with an opaque server-issued cursor; unsupported query parameters and malformed cursors fail closed
Problems: curriculum:unsupported_query_parametercurriculum:validation_failed
| Method | Path | State | Write behavior |
|---|---|---|---|
POST | /alpha/curriculum/v1/standards-frameworks/import | authoritative target pending cutover | Idempotency-Key. bounded serializable import. Immutable. |
GET | /alpha/curriculum/v1/standards-frameworks | target contract; same path currently serves CASE-backed compatibility | stable list read with typed filters/cursor or inherited CASE offset. Immutable. |
GET | /alpha/curriculum/v1/standards-frameworks/{frameworkId} | target contract; same path currently serves CASE-backed compatibility | detail read with immutable source-release links. Immutable. |
GET | /alpha/curriculum/v1/standards-source-releases | authoritative target pending cutover | immutable created-at cursor list. Immutable. |
GET | /alpha/curriculum/v1/standards-source-releases/{sourceReleaseId} | authoritative target pending cutover | read. Immutable. |
GET | /alpha/curriculum/v1/standards-source-releases/{sourceReleaseId}/readback | authoritative target pending cutover | read. Immutable. |
POST | /alpha/curriculum/v1/kcs | authoritative governed implementation | Idempotency-Key. identity ETag after create; optional source_kc_id is tenant-unique provenance, never an active alias. |
GET | /alpha/curriculum/v1/kcs | authoritative governed implementation | tenant-isolated stable updated_at/kc_id cursor list of active registry KCs with their current immutable versions; typed subject_id/kc_kind/publication_status/updated_since filters; rows carry the same current-version readback as GET /kcs/{kcId}; retired rows and the retained unclassified #707 legacy row (no current version) are never listed. |
GET | /alpha/curriculum/v1/kcs/{kcId} | authoritative governed implementation | exact registry UUID read of current immutable version with ETag. |
POST | /alpha/curriculum/v1/kcs/{kcId}/versions | authoritative governed implementation | Idempotency-Key. append only. Immutable. |
GET | /alpha/curriculum/v1/kcs/{kcId}/versions | authoritative governed implementation | immutable version-number cursor list. Immutable. |
GET | /alpha/curriculum/v1/kcs/{kcId}/versions/{versionId} | authoritative governed implementation | read. Immutable. |
PATCH | /alpha/curriculum/v1/kcs/{kcId} | authoritative governed implementation | Idempotency-Key. If-Match required. |
DELETE | /alpha/curriculum/v1/kcs/{kcId} | authoritative governed implementation | Idempotency-Key. If-Match; soft retire only; friendly active-reference precheck plus native content_kc_tag_active_kc_fk commit invariant; active Curriculum references and active Content tags return curriculum:resource_referenced, while serialization conflicts retry. |
GET | /alpha/curriculum/v1/kc-prerequisites | authoritative governed implementation | stable cursor list; registry UUID endpoint filters. |
POST | /alpha/curriculum/v1/kc-prerequisites | authoritative governed implementation | Idempotency-Key. tenant graph lock inside SERIALIZABLE; registry UUID endpoints only. |
DELETE | /alpha/curriculum/v1/kc-prerequisites/{prerequisiteId} | authoritative target pending cutover | Idempotency-Key. If-Match; soft retire. |
GET | /alpha/curriculum/v1/kc-relations | authoritative target pending cutover | stable cursor list; kc/relation_type filters. |
POST | /alpha/curriculum/v1/kc-relations | authoritative target pending cutover | Idempotency-Key. If-Match on edge corrections. |
DELETE | /alpha/curriculum/v1/kc-relations/{relationId} | authoritative target pending cutover | Idempotency-Key. If-Match; soft retire. |
GET | /alpha/curriculum/v1/kc-review-decisions | authoritative governed implementation | immutable decided-at cursor list. Immutable. |
POST | /alpha/curriculum/v1/kc-review-decisions | authoritative governed implementation | Idempotency-Key. append only. Immutable. |
GET | /alpha/curriculum/v1/kc-firming-events | authoritative governed implementation | immutable firmed-at cursor list. Immutable. |
POST | /alpha/curriculum/v1/kc-firming-events | authoritative governed implementation | Idempotency-Key. append only after governed first-genuine-response evidence; course approval creates its own events atomically. Immutable. |
GET | /alpha/curriculum/v1/standard-kc-maps | authoritative governed implementation | tenant-isolated stable updated_at/map_id cursor list; typed source_release_id/standard_id/kc_id/relationship/updated_since filters; exact ten-field rows. |
POST | /alpha/curriculum/v1/standard-kc-maps | authoritative target pending cutover | Idempotency-Key. ETag after create. |
PATCH | /alpha/curriculum/v1/standard-kc-maps/{mapId} | authoritative target pending cutover | Idempotency-Key. If-Match required. |
DELETE | /alpha/curriculum/v1/standard-kc-maps/{mapId} | authoritative target pending cutover | Idempotency-Key. If-Match; soft retire. |
GET | /alpha/curriculum/v1/courses | authoritative target pending cutover | stable cursor list; role/subject/status/updated_since filters. |
POST | /alpha/curriculum/v1/courses/{courseId}/approvals | authoritative governed implementation over the current CASE-backed course graph | Idempotency-Key. serializable complete graph snapshot and firming transaction. Immutable. |
GET | /alpha/curriculum/v1/courses/{courseId}/approvals | authoritative governed implementation | immutable approved-at cursor list. Immutable. |
GET | /alpha/curriculum/v1/course-approvals/{approvalId}/kc-snapshot | authoritative target pending cutover | immutable list. Immutable. |
POST | /alpha/curriculum/v1/courses | authoritative target pending cutover | Idempotency-Key. ETag after create. |
GET | /alpha/curriculum/v1/courses/{courseId} | authoritative target pending cutover | read with ETag. |
PATCH | /alpha/curriculum/v1/courses/{courseId} | authoritative target pending cutover | Idempotency-Key. If-Match required. |
DELETE | /alpha/curriculum/v1/courses/{courseId} | authoritative target pending cutover | Idempotency-Key. If-Match; soft retire only. |
GET | /alpha/curriculum/v1/components | target contract; same path currently serves CASE-backed compatibility | stable cursor list; kind/subject/status/updated_since filters. |
POST | /alpha/curriculum/v1/components | deployed CASE compatibility; authoritative target pending cutover; kind=lesson permits scope_kc_refs=[] only with exact eligible Content target + compatible renderer + kc_scope_decision=authoritative_no_kc | Idempotency-Key. transactional insert-or-reactivate; same retired identity preserves created_at, advances CASE version, clears retired_at, returns active ETag. |
GET | /alpha/curriculum/v1/components/{componentId} | authoritative target pending cutover | read with ETag. |
PATCH | /alpha/curriculum/v1/components/{componentId} | deployed CASE compatibility plus authoritative target pending cutover | Idempotency-Key. If-Match required; isolated parent_component_id + position reparent is one locked transaction and requires exactly one active parent. |
POST | /alpha/curriculum/v1/components/{componentId}/repoint | authoritative governed implementation over the current CASE-backed component graph | Idempotency-Key. expected_target_ref is a mandatory compare-and-set premise over the exact current pin (optional If-Match additionally honored); the pin move and its immutable audit row commit in one CAS-guarded transaction. |
DELETE | /alpha/curriculum/v1/components/{componentId} | authoritative target pending cutover | Idempotency-Key. If-Match; active references block or atomically repoint. |
GET | /alpha/curriculum/v1/courses/{courseId}/members | authoritative target pending cutover | stable ordered cursor list. |
POST | /alpha/curriculum/v1/courses/{courseId}/members | authoritative target pending cutover | Idempotency-Key. If-Match course graph. |
PATCH | /alpha/curriculum/v1/courses/{courseId}/members/{memberId} | authoritative target pending cutover | Idempotency-Key. If-Match course graph. |
DELETE | /alpha/curriculum/v1/courses/{courseId}/members/{memberId} | authoritative target pending cutover | Idempotency-Key. If-Match; soft retire. |
GET | /alpha/curriculum/v1/courses/{courseId}/tree | target contract; same path currently serves CASE-backed compatibility | resolved identity-preserving read. |
GET | /alpha/curriculum/v1/courses/{courseId}/expected-xp | authoritative target pending cutover | read. |
GET | /alpha/curriculum/v1/courses/{courseId}/next-lesson | target contract; same path currently serves CASE-backed compatibility | Results-assisted read. |
GET | /alpha/curriculum/v1/tracks/{trackId}/placement-candidates | target contract; same path currently serves CASE-backed compatibility | Policy/Results-assisted read. |
GET | /alpha/curriculum/v1/gates | target contract pending cutover | stable cursor list over resolved active gate members; course/policy/content-kind filters. |
GET | /alpha/curriculum/v1/gates/{gateId} | target contract pending cutover | resolved gate contract detail without student state. |
GET | /alpha/curriculum/v1/gates/{gateId}/status | target contract; same path currently serves CASE-backed compatibility | Policy/Results-assisted read. |
GET | /alpha/curriculum/v1/gates/{gateId}/next-form | fixed-form gates only; PP100 v2 rejects because Results owns adaptive selection | Content/Results-assisted deterministic read; test mode commits one Content authorization receipt. |
GET | /alpha/curriculum/v1/gates/{gateId}/remediation | target contract; same path currently serves CASE-backed compatibility | Results-assisted read. |
GET | /alpha/curriculum/v1/kc-sets | authoritative target pending cutover | stable projection list. |
GET | /alpha/curriculum/v1/kc-sets/{setId} | authoritative target pending cutover | read-only projection. |
POST | /alpha/curriculum/v1/ingest/timeback-course-refs | target contract; same path currently writes CASE-backed compatibility | Idempotency-Key. bounded source-shaped import; shared containment lock rejects parent replacement or second-parent creation. |
POST | /alpha/curriculum/v1/transports/common-cartridge/preview | authoritative target pending cutover | Idempotency-Key. side-effect-free deterministic preview. Immutable. |
POST | /alpha/curriculum/v1/transports/common-cartridge/import | authoritative target pending cutover | Idempotency-Key. bounded transport import. |
GET | /alpha/curriculum/v1/import-jobs | authoritative target pending cutover | stable created-at cursor list. Immutable. |
GET | /alpha/curriculum/v1/import-jobs/{importJobId} | authoritative target pending cutover | read. Immutable. |
Per-resource target writes plus named bulk commands for standards release, Common Cartridge, and TimeBack ingest; no second KC representation or permanent dual write.
List, detail, and narrow sub-collection reads preserve identity/member separation and expose stored governed outputs without Incept computations.
Typed filters, stable sort, cursor paging, CASE offset only where inherited, updated_since polling, and 400 curriculum:unsupported_query_parameter for every unsupported parameter.
Mutable rows require ETag/If-Match (428 missing, 412 stale); immutable evidence/version/snapshot/event/audit rows have no PATCH route.
Every POST/PATCH/DELETE/import/remediation insertion uses Idempotency-Key in platform.idempotency_key with module=curriculum and surface=alpha. Exactly one server lease-token owner may mutate and finalize a canonical request hash; a live same-hash contender receives bounded Retry-After, a different hash conflicts, and only an explicitly rollback-safe failed_transient classification may be reclaimed. Curriculum Content eligibility may use failed_transient only when the typed 503 is marked at a proven pre-mutation create/update/TimeBack-ingest boundary and the owner finalizes no response, resource, header, or lock evidence; generic or post-mutation 5xx remains commit_uncertain.
Platform HS256 bearer JWT with tenantId, role(s), and curriculum:read/write/import/admin scopes; no school/class/student-scoped claims on shared Curriculum rows.
Poll list endpoints with updated_since. Webhooks remain deferred until three approved integrations in 90 days prove polling blocks a Curriculum workflow.
RFC 7807 with stable type URI, curriculum: code, requestId, traceId, fieldErrors, and rowErrors for bulk commands; Problems never use HTTP 200.
Tenant comes only from the verified JWT on flat /alpha/curriculum/v1 paths; never from URL or body.
Local and deployed evidence covers ownership, KC lifecycle/graphs, standards provenance/readback, reuse, source ingest, transport round-trip, auth/errors/idempotency/concurrency, and leak-free downstream consumers; no official certification claim.
Tenant scope, audit provenance, soft-retire semantics, immutable source history, redacted errors/logs/evidence, and no learner PII beyond typed personalization refs. An active exact isChildOf child/parent pair is the current containment projection and supersedes retired same-pair history without erasing its tombstone. Retention/erasure waits for Platform policy.
List every canonical collection named by the architecture. Derived per-kind/tree reads aid discovery but never become storage authority; no Incept queue/novelty/monitor/plan endpoints.
curriculum:validation_failedField/type/enum/reference validation fails.
Extra fields: type, title, status, detail, code, requestId, traceId, fieldErrors
curriculum:payload_too_largeAn authenticated JSON request exceeds the bounded request-body limit; reject before repository or idempotency work and never echo request bytes.
curriculum:unsupported_query_parameterA query parameter is not in the endpoint contract.
Extra fields: fieldErrors
curriculum:authentication_requiredBearer JWT is absent, invalid, expired, or not trusted.
curriculum:forbiddenJWT tenant/scope/role does not authorize the operation.
curriculum:not_foundTenant-scoped active identity is absent.
curriculum:precondition_failedIf-Match validator is stale.
curriculum:precondition_requiredA mutable write omits If-Match.
curriculum:idempotency_in_progressA live same-hash Curriculum lease already owns this retryable write; return Retry-After between 1 and 30 seconds and never enter the mutation callback.
curriculum:idempotency_conflictAn Idempotency-Key is replayed with a different canonical request hash.
curriculum:idempotency_key_expiredThe stored key is expired and cannot prove a safe single-owner retry; fail closed without mutation.
curriculum:idempotency_commit_uncertainA prior owner may have committed a side effect without a trustworthy terminal receipt, or the ledger is legacy/tokenless/corrupt; fail closed without reclaim or mutation.
curriculum:kc_semantics_conflictKC creation reuses a canonical kc_id with different governed semantics, or reuses provenance-only source_kc_id for a different or server-minted canonical kc_id even when semantics match.
Extra fields: fieldErrors
curriculum:standards_scope_invalidDeclared/partial scope is empty, dishonest, or inconsistent with bound rows.
Extra fields: fieldErrors, rowErrors
curriculum:rights_unresolvedEffective rights/admission is yellow, red, unknown, expired, missing, or conflicting.
Extra fields: rowErrors
curriculum:standards_readback_mismatchAny source row/readback checksum or typed comparison fails.
Extra fields: rowErrors
curriculum:invalid_kc_kindkc_kind is not substantive, disciplinary, application, or integrative.
Extra fields: fieldErrors
curriculum:kc_definition_qualityA KC version lacks the governed definition, examples, boundary, or provenance required for its lifecycle step.
Extra fields: fieldErrors
curriculum:invalid_kc_relationA relation type/endpoint is invalid, prerequisite is sent to the non-DAG relation store, or a lineage transition violates lineage_id rules.
Extra fields: fieldErrors
curriculum:unknown_kcA referenced KC is missing, retired, cross-tenant, or not an active registry identity.
Extra fields: fieldErrors
curriculum:prerequisite_cycleA prerequisite write would create a directed cycle.
Extra fields: fieldErrors
curriculum:invalid_kc_lifecycleA KC version is edited in place or firmed outside the two allowed paths.
Extra fields: fieldErrors
curriculum:live_learning_evidence_requiredA first_genuine_response firming write lacks validated first-response evidence with explicit live_learning=true.
Extra fields: fieldErrors
curriculum:approval_snapshot_incompleteAn approval cannot pin every distinct active KC to one exact version.
Extra fields: rowErrors
curriculum:course_not_routableThe current course graph is draft, retired, unapproved, changed since approval, or has a missing/non-firm KC snapshot.
Extra fields: fieldErrors
curriculum:invalid_component_kindkind is outside component_kind or violates its per-kind schema.
Extra fields: fieldErrors
curriculum:reference_unresolvedA KC, component, Content version, renderer, policy, standard binding, or parent reference is absent, retired, cross-tenant, cyclic, or incompatible.
Extra fields: fieldErrors
curriculum:content_not_eligibleContent authoritatively reports the exact version missing, blocked, revoked, otherwise non-green, malformed, or unresolved.
Extra fields: fieldErrors
curriculum:content_unavailableThe exact-version eligibility read fails by network error, bounded timeout, or upstream HTTP 5xx. Return bounded Retry-After; only a proven pre-mutation component create/update or TimeBack ingest may leave an evidence-free failed_transient receipt for identical-key recovery.
Extra fields: cause
curriculum:content_version_mismatchcontent_version_id does not belong to content_id or content_kind does not match Content readback.
Extra fields: fieldErrors
curriculum:invalid_content_bank_member_contractContent returns content.invalid_test_bank_member_contract or content.bank_kc_attribution_incomplete for the exact test-bank graph; expose the safe upstream code as the public RFC 7807 cause field and never convert this into generic ineligibility, transport failure, empty membership, fallback, or skip behavior.
Extra fields: fieldErrors, cause
curriculum:renderer_incompatiblerenderer_ref is missing, inactive, unknown, or rejects content_kind.
Extra fields: fieldErrors
curriculum:repoint_pin_staleA repoint/attach expected_target_ref compare-and-set premise does not equal the component's exact current pin — including attach against an already-pinned component and repoint against a superseded or legacy versionless pin. Nothing is written.
Extra fields: fieldErrors
curriculum:repoint_identity_mismatchA repoint attempts to change content_id or content_kind. A revision published under a new Content identity is a NEW identity: attach it to an unpinned placement instead of silently replacing an existing pin.
Extra fields: fieldErrors
curriculum:repoint_target_not_serveableContent authoritatively refuses the requested exact version for a repoint/attach — missing, not serveable, not release-eligible, or outside practice_eligible usage scope. The safe upstream cause is exposed as the RFC 7807 cause field; transient Content unavailability stays 503 curriculum:content_unavailable.
Extra fields: cause
curriculum:approved_chain_repoint_frozenProducer self-service repoint/attach targets a published component pinning an approved immutable assessment chain. The pin moves only through the reviewed-replacement manifest path: a committed reviewed manifest applied through the platform's dry-run-first ETag/CAS corridor.
Extra fields: fieldErrors
curriculum:member_position_conflictTwo active siblings claim one position.
Extra fields: fieldErrors
curriculum:relationship_cycleA component reparent or governed prerequisite mutation would make a node its own ancestor.
Extra fields: fieldErrors
curriculum:lesson_structure_missingA course anchor exists but has no active ordered, KC-scoped routable member structure.
Extra fields: rowErrors
curriculum:publication_incompleteA course/component publish is attempted before exact tree readback or before every descendant is published bottom-up; course roots must publish last.
Extra fields: fieldErrors, rowErrors
curriculum:expected_xp_ambiguousA graph/cycle/target error prevents deterministic leaf/fallback selection.
Extra fields: rowErrors
curriculum:invalid_gate_contractA gating member lacks valid Content target, passing criteria, remediation map, or test-bank/spec compatibility.
Extra fields: fieldErrors
curriculum:bank_exhaustedEvery eligible form in the gate's Content test_bank has already been seen by the student.
curriculum:adapter_rejectedA source-shaped TimeBack row cannot materialize without inventing order, KC scope, Content identity, or gate semantics.
Extra fields: rowErrors
curriculum:transport_invalidA Common Cartridge/CFPackage preview or import fails structure, reference, or round-trip validation.
Extra fields: rowErrors
authentication: Platform HS256 bearer JWT; tenantId plus curriculum:read/write/import/admin scopes. tenant_id is never caller-selected in path/body.
idempotency: Every POST/PATCH/DELETE/import uses Idempotency-Key stored in platform.idempotency_key with module=curriculum,surface=alpha. Claim, completion, and failure are conditional on the exact scope, canonical hash, curriculum-v2 protocol, and a server lease token; requestId is audit identity only. Exactly one token owner mutates. Terminal same-hash rows replay exact stored status/body/headers, live same-hash rows return 409 curriculum:idempotency_in_progress with bounded Retry-After, different hashes return 409 curriculum:idempotency_conflict, and reclaim requires an unexpired failed_transient row explicitly classified rollback-safe with no response, resource, header, or lock evidence. A typed curriculum:content_unavailable error qualifies only at the proven pre-mutation component create/update and TimeBack-ingest boundaries; any unmarked or post-mutation 5xx remains commit_uncertain. Expired, legacy/tokenless stale, corrupt, ordinary stale, and commit-uncertain rows fail closed.
concurrency: Mutable identities/edges use ETag and If-Match; missing is 428, stale is 412. Immutable releases, bindings, rights decisions, readback evidence, KC versions, review decisions, approvals, snapshots, and firming events have no PATCH route.
tenancy: Every PK/FK/unique query includes tenant_id from the verified JWT. Raw SQL examples use :tenant_id and must execute inside the same tenant-scoped transaction/RLS context.
polling: List endpoints use stable sort, cursor paging, and updated_since only where rows are mutable. Immutable evidence uses created-at cursors.
privacy: No learner PII, Content bodies/answers, producer credentials, source secrets, or unrestricted copyrighted source dumps in Problems/logs/evidence.