TimeBack Platform

Platform Architecture

This document pins the cross-module substrate that QTI, OneRoster, Caliper, and future modules inherit. It lifts the patterns validated by the approved QTI loop into platform-wide ITDs so future modules do not re-decide tenant identity, auth, CORS, errors, hosted docs, privacy, evals, audit, observability, loop policy, or the standard API decision axes.

Surfaceplatform
Deliverablearchitecture
ITDs32
Canonical URLPatched by driver

QTI Inputs Promoted

QTI is the empirical input for this platform pass. The approved QTI artifacts are not copied wholesale; the cross-module patterns that held up under review are promoted, while QTI-specific standards content remains in qti.*.

QTI source patternPlatform promotionITD
qti.* schema ownershipModule schemas are mandatory for every standards module.PITD-002
qti.tenantPromoted to platform.tenant; QTI requires explicit reconciliation.PITD-003
Bearer JWT and tenant claim matchingShared platform auth and tenant scoping contract.PITD-005
Top-level Authentication and Errors sectionsRequired in every customer website.PITD-006
Route-scoped CORS correctionOpen-origin CORS advertises only matched route methods plus OPTIONS.PITD-019
Idempotency-Key and If-MatchShared retry and optimistic concurrency policy.PITD-007
candidate_ref / studentRef privacyGeneral student-data privacy policy for all modules.PITD-008
Conformance runner rollbackConformance claims require real evidence, not fabricated status.PITD-016
Alpha cut/restrict/rename/extend patternRequired divergence vocabulary for every Alpha surface.PITD-015
Vercel driver-deployed hosted docsShared documentation identity and master index policy.PITD-011
Customer eval plus scoring rubricPlatform-wide quality gate and rollback discipline.PITD-012

QTI 1EdTech Architecture

24 ITDs, including tenant boundary, security boundary, hosted docs, conformance evidence, and learner-data privacy.

QTI 1EdTech Data Dictionary

13 qti.* tables and 127 fields with provenance, invalid-value guidance, and stable anchors.

QTI 1EdTech Customer Website

Top-level Authentication and Errors, inline endpoint schemas, idempotency, ETag, If-Match, and Problem responses.

QTI 1EdTech Implementation

Runnable Node package, real conformance runner after rollback, self-contained OpenAPI refs, privacy tests, and migration comments.

QTI 1EdTech Surface QC

Release-gate report that caught the fake conformance-run path and required rollback to implementation.

QTI Alpha Architecture

14 Alpha ITDs requiring every cut, restriction, rename, and extension to map back to 1EdTech truth.

QTI Alpha Data Dictionary

9 public Alpha objects and 84 public fields over the same qti.* persistence model.

QTI Alpha Customer Website

Plain-language API docs for teachers, students, parents, and app-builder LLMs, including trust status and public cuts.

QTI Alpha Implementation

Facade over the approved 1EdTech implementation, with tests closing public response-shape drift.

QTI Alpha Surface QC

QC report proving Alpha stayed a facade, inherited privacy/conformance tests, and kept trust status read-only.

Shared Model

The platform substrate is small on purpose. Module-specific standards data stays in each module schema. Cross-module tenant identity, idempotency, and audit move into platform.*.

Shared tablePurposeDecisionQTI reconciliation
platform.tenantOne school, district, publisher, application, or workspace boundary shared by every module.PITD-003-SHARED-TENANT-MODELSupersedes qti.tenant as cross-module truth. The platform implementation must migrate or provide a compatibility view before future modules depend on it.
platform.idempotency_keyShared retry ledger for create, import, upload, export-job, and asynchronous command operations.PITD-007-IDEMPOTENCY-AND-CONCURRENCYPromotes qti.content_package.idempotency_key from a package field into a reusable platform ledger while QTI package rows keep their package-specific key copy or foreign key.
platform.audit_logAppend-only cross-module record for writes, privileged reads, deletions, denied authorization, and trust/conformance changes.PITD-009-AUDIT-LOGAdds a shared operational table that QTI did not have; QTI operations become audit emitters in the platform implementation.

Producer Surface Registry

Producer surfaces preserve upstream provenance and generation history while routing customer-facing answers through the normal Platform3 module model. They do not create a third consumer API surface and they do not replace Content, Results, Events, or Analytics.

Producer surfaceGoverned objectsConsumer contractDecision
incept incept.incept_event_ledger, incept.incept_loop_runs, incept.incept_event_artifacts, incept.incept_quality_bars, incept.incept_model_grid_evidence, incept.incept_customer_feedback, incept.incept_repair_attempts, incept.incept_promotion_decisions, incept.incept_external_issue_links, incept.incept_deployments, incept.incept_projection_checkpoints, and the seven incept.*_v projection views named in PITD-032. Platform3 API/view paths with normal auth, tenant scope, audit, data-dictionary coverage, and non-service-role readback. Direct SUPABASE_DB_URL reads are deprecated bootstrap only. PITD-032

HTTP Contract

The HTTP contract is intentionally conventional: typed success bodies, one Problem error shape, tenant-scoped auth, route-scoped CORS preflight, shared idempotency behavior, and optimistic concurrency for updates that can lose work.

Problem error shape

{
  "type": "https://platform3-andymontgomery-9773s-projects.vercel.app/problems/validation-error",
  "title": "Validation failed",
  "status": 400,
  "code": "validation_error",
  "detail": "Safe caller-facing detail",
  "requestId": "req_...",
  "traceId": "trace_...",
  "fieldErrors": [
    {"field": "studentRef", "message": "Use an opaque UUID"}
  ]
}

JWT tenant rule

{
  "iss": "timeback",
  "sub": "timeback:student:person_student_001",
  "tenant_id": "tenant uuid for tenant routes",
  "role": "student",
  "roles": ["student"],
  "scopes": ["people_orgs:read", "content:read", "qti:attempt", "events:write"],
  "personId": "person_student_001",
  "studentId": "person_student_001",
  "exp": 1780000000
}
StatusNamePlatform meaning
200OKSuccessful read or command that returns a completed resource.
201CreatedSynchronous create that returns the newly created resource.
202AcceptedImport, conformance, export-job, or other accepted work that may complete asynchronously.
204No ContentSuccessful deletion or command with no response body.
400Bad RequestMalformed JSON, invalid field shape, invalid pseudonymous learner ref, unsupported profile, or validation problem documented as caller-fixable.
401UnauthorizedMissing, malformed, expired, untrusted, or unsigned Bearer JWT.
403ForbiddenAuthenticated principal lacks tenant, role, scope, service-role, or operation authorization.
404Not FoundResource is absent or not visible inside the authenticated tenant scope.
409ConflictIdempotency conflict, stale version state, duplicate unique key, or conflicting lifecycle transition.
412Precondition FailedA documented conditional request precondition evaluates false.
428Precondition RequiredA mutation that requires If-Match or equivalent precondition omitted it.
5xxServer ErrorUnexpected platform, dependency, conformance-runner, or release-blocking server failure.

API Decision Axis Ledger

The loop requires every API surface architecture to pin these standard axes before downstream deliverables build on it. Each row is a SHIP or DEFER decision with alternatives, tradeoffs, downstream obligations, and a concrete re-open trigger for rejected or deferred options.

AxisStatusDecisionAlternatives and tradeoffsDownstream rulesRe-open triggerITD
write granularitySHIPPlatform administrative writes are per-resource commands only. Bulk import/export write flows belong to standards modules when their source spec requires them; the platform substrate does not add a second bulk-write primitive.
  • bulk-only: Works for OneRoster CSV-style module ingestion, but makes simple tenant administration unnatural and forces clients to manufacture files for single-resource changes.
  • per-resource only: Fits tenant, audit, idempotency, and module catalog administration while keeping standards bulk imports owned by their modules.
  • both bulk and per-resource on the platform surface: Adds a second way to perform the same administrative changes and makes idempotency, audit, and CORS method discovery harder.
  • Platform tenant creation, detail reads, audit inspection, idempotency inspection, and module catalog operations use resource endpoints.
  • A module may expose bulk endpoints only when its own architecture pins that standard-specific write model.
  • CORS Allow-Methods must reflect the actual per-resource or bulk route, not a platform-wide write superset.
Re-open only if three integrators in 90 days need a platform-level batch administrative operation that cannot be expressed as module-owned import/export jobs.PITD-020
read shapeSHIPPlatform administrative reads use list plus detail plus narrow sub-collections: module catalog list/detail, tenant detail, tenant audit-log sub-collection, and tenant idempotency-key detail.
  • list-only: Easy to cache, but clients cannot inspect a specific tenant, audit narrative, or idempotency result without reading source code.
  • list plus detail: Good for catalog resources, but audit and idempotency state are operational sub-collections tied to a tenant.
  • list plus detail plus sub-collections: Adds route count, but keeps operational reads discoverable without creating a general graph API.
  • Every list endpoint must document the matching detail endpoint unless the architecture explicitly defers detail reads with a trigger.
  • Sub-collections are allowed only for operational facts owned by the parent resource, such as tenant audit-log entries.
  • Customer websites must show list/detail/sub-collection examples in the same endpoint family.
Re-open for graph-style expansions only after three integrators in 90 days need the same cross-resource projection and the projection cannot be handled by linked detail URLs.PITD-021
query modelSHIPPlatform list and sub-collection endpoints support documented filters, stable sort keys, limit-based paging with opaque cursors when result size can exceed one page, and modifiedSince where the collection is an append-like operational log. Ad hoc query parameters are not accepted.
  • none: Simple handlers, but audit logs, idempotency records, and module catalogs become unscannable as tenants grow.
  • filter and sort only: Useful for small lists, but unstable for large or append-only collections without paging and cursors.
  • filter plus paging plus cursor, with modifiedSince on append-like logs: Requires cursor contract tests, but gives deterministic scans and supports poll-based integrations.
  • Every accepted query parameter must be named in the customer website and validated by implementation tests.
  • Cursor tokens are opaque to clients and scoped to tenant, route, filter, sort, and principal visibility.
  • modifiedSince is allowed only on collections whose ordering and clock semantics are documented.
Re-open for arbitrary expression filters only if three integrators in 90 days need the same unsupported predicate and it cannot be represented by a named filter.PITD-022
concurrency modelSHIPResource-changing updates that can overwrite customer work require per-resource validators, exposed as ETag and enforced with If-Match. Missing required validators return 428; stale validators return 412 or the documented 409 conflict shape.
  • none: Lowest friction, but silent last-write-wins bugs are unacceptable for learner, roster, and administrative state.
  • If-Match per resource: Requires clients to store validators, but it is standard HTTP and easy to test.
  • bulk-only concurrency tokens: Works for file import jobs, but does not protect resource edits outside the batch.
  • Every update endpoint must state whether If-Match is required, optional, or not applicable.
  • ETag values must change when the customer-visible resource representation changes.
  • Bulk/import jobs may use job-level validators only when the module architecture pins why per-resource validators do not apply.
Re-open for server-side locks only if optimistic validators cannot prevent a documented repeated lost-update workflow for three integrators in 90 days.PITD-023
idempotency modelSHIPRetryable writes use Idempotency-Key, persisted in platform.idempotency_key with request hash, response replay metadata, tenant, module, surface, method, route template, and operation id.
  • none: Easy to implement, but retrying a network timeout can create duplicate tenants, imports, or jobs.
  • Idempotency-Key on writes: Requires a shared ledger and request hashing, but makes retries safe and observable.
  • Natural unique constraints only: Prevents some duplicates, but cannot replay the original response or identify same-key different-body conflicts.
  • Same key and same canonical request hash returns the original outcome.
  • Same key and different canonical request hash returns 409 with a typed Problem.
  • Customer websites must identify which operations require Idempotency-Key and which do not.
Re-open for idempotency-less writes only when the operation is mathematically side-effect-free or the architecture proves duplicate execution is harmless.PITD-024
auth shapeSHIPPlatform APIs use Bearer JWTs with tenantId, role or roles, scopes, and allowlisted domain-scoped claims. Public /dev/mint is demo-only. Generic production end-user tokens use the protected tenant-token exchange. An explicitly allowlisted first-party bridge selects an exact same-origin redirect/post-login/logout tuple by canonical route tenant UUID before Host/Origin validation; multiple apps can share one Platform deployment while keeping host-only SameSite cookies. session-token keeps binding, session, and audit on the canonical UUID, then signs the tenant row's existing unique tenant_key for downstream People & Orgs and Results. Invalid, duplicate, mismatched, or unlisted configuration fails closed before storage. Human tokens carry exact person/student relationship claims only: personIds contains authorized students, never the parent or guide actor, and placeIds, schoolIds, classIds, and candidateRef are absent. Shared platform middleware enforces tenant/role/scope and passes exact claims through to the owning module.
  • role-only: Readable, but too coarse for service-role maintenance, audit reads, and future delegated operations.
  • role plus scopes: Requires explicit scope docs, but gives narrow authorization without importing module domain claims.
  • scoped domain claims on every token: Useful for SIS or assessment domains, but makes the platform token vocabulary depend on every standard.
  • public real-tenant token minting: Easy for cold demos, but it turns tenant provisioning into an unaudited self-service credential path.
  • tenantId is required for tenant-scoped routes and must match the route tenant.
  • Privileged operations must name the role or scope that authorizes them.
  • POST /dev/mint?tenantId=demo is the only public mint helper; non-demo tenant ids must be rejected.
  • Production end-user JWTs are issued through POST /platform/tenants/{tenantId}/token-exchanges by a same-tenant issuer or platform service token with platform:token:issue authority.
  • PLATFORM_TIMEBACK_TENANT_ROUTES_JSON lists each first-party tenant and exact URI tuple; the route tenant UUID selects it and Host/Origin only validate it.
  • Each app reverse-proxies only its exact auth paths on its own origin, keeping cookies same-origin without app secrets.
  • Legacy single-tenant URI variables retain their exact behavior only when the allowlist is absent.
  • A deployed consumer handoff is complete only when the consumer receives the stable module base URL, the matching real-tenant JWT, and the tenant header value when that module requires X-Timeback-Tenant; an operator or reviewer JWT that remains only in Platform3 local env is not a durable consumer path.
  • Module-specific domain claims must be documented by that module and cannot be required by shared platform middleware.
Re-open platform-wide domain claims only after two modules independently require the same claim with the same semantics.PITD-025
eventing modelSHIPThe platform eventing model is poll plus modifiedSince for append-like operational collections. Webhooks are explicitly deferred until repeated integrator demand proves polling is the blocker.
  • poll-only: Simple, but clients waste calls and cannot efficiently resume from a known freshness point.
  • poll plus modifiedSince: Requires timestamp semantics, but keeps event consumption replayable and browser-safe.
  • webhooks: Lower latency, but adds subscription state, delivery signatures, retries, and customer-operated receivers before the platform has demand.
  • Append-like collections that support modifiedSince must define clock source, inclusivity, and pagination interaction.
  • Modules must not add webhooks without an architecture ITD, data dictionary entries, customer website docs, implementation tests, and surface QC replay evidence.
  • Audit and conformance/trust collections are the first platform collections eligible for modifiedSince.
Re-open webhooks when three integrators in 90 days report that polling prevents their documented job or when p95 freshness above five minutes blocks a committed workflow.PITD-026
error envelopeSHIPEvery surface uses typed RFC 7807 Problem Details with stable, dereferenceable type URIs under the master Platform3 problem catalog at https://platform3-andymontgomery-9773s-projects.vercel.app/problems/*, a stable code, requestId, traceId, and optional fieldErrors.
  • none: Fast for handlers, but clients regex prose and support cannot correlate failures.
  • plain RFC 7807: Standard, but a free-text or unstable type value is not enough for reliable client behavior.
  • typed RFC 7807 with stable URIs: Requires a type registry, but gives predictable cross-module error handling.
  • Problem detail must be safe to show to the caller and must not include secrets or direct learner PII.
  • Every documented 4xx and 5xx path must name its Problem code and status.
  • requestId and traceId must be returned in the error body or headers and logged with the same values.
Re-open only if a required external standard mandates a conflicting error shape and the module architecture proves an adapter cannot preserve typed Problem semantics.PITD-027
tenant routingSHIPTenant scope is carried in the URL for tenant resources and independently enforced from the JWT tenantId claim. Tenant headers are not accepted as the routing source of truth.
  • tenant in URL: Visible and linkable, but requires every tenant route to enforce path-token matching.
  • tenant in header: Keeps paths shorter, but makes browser links, curl snippets, and audit evidence less self-contained.
  • tenant in JWT only: Reduces route parameters, but makes shared admin paths ambiguous and harder to deep-link.
  • Tenant-scoped paths must name the tenant or workspace segment and compare it to JWT tenantId.
  • Mismatched path and JWT tenant returns 403, not 404, unless the module architecture explicitly chooses not-found cloaking for a sensitive resource.
  • Public demo minting is restricted to tenantId=demo; real tenant end-user tokens are issued through the protected tenant token-exchange route after tenant provisioning.
Re-open tenant headers only if an external conformance suite requires them and an adapter cannot map them to URL plus JWT enforcement.PITD-028
conformance evidenceSHIPConformance and trust claims require executed evidence: vendored or local spec-runner output, recorded bundle/source hashes, runner version, assertion results, and release-gate links. External certification is a future supplement, not a substitute for local evidence.
  • none: Avoids setup, but turns conformance into a marketing claim.
  • spec-runner: Requires fixtures and assertion storage, but produces repeatable release evidence.
  • external certification only: Valuable for buyers, but too slow and too opaque to be the loop's day-to-day release gate.
  • Every passed conformance claim must link to executed evidence and the source bundle hash.
  • Missing runner, missing bundle, failed assertion, or unparseable output cannot produce passed status.
  • Surface QC must probe evidence, not just read a boolean trust field.
Re-open external certification as a required gate when a paying integrator or procurement process requires a named external certification before launch.PITD-029
privacy / retentionSHIPStudent and learner data follow GDPR-style minimization and deletion semantics: pseudonymous learner references at boundaries, redacted logs/problems/audit metadata, separate reusable-content versus learner-runtime lifecycle, and documented deletion paths for learner-derived state.
  • none: Easiest, but invites PII into logs, traces, generated XML, and support artifacts.
  • DELETE per spec only: Matches individual standards, but misses cross-module audit, logs, traces, and shared student outcomes.
  • GDPR-style minimization and retention: Requires validation and deletion design, but gives a single privacy bar across modules.
  • Learner reference fields must reject direct names, emails, phone numbers, SIS IDs, tokens, and raw auth subjects.
  • Deletion paths must distinguish reusable educational content from learner runtime or outcome state.
  • Audit and observability data must store redacted ids, hashes, or summaries instead of raw learner PII.
Re-open retention periods only when a legal, district, or standard-specific requirement imposes a concrete retention value the platform cannot satisfy with current minimization rules.PITD-030
list endpointsSHIPEvery platform collection that can be read by an integrator exposes a list endpoint with documented filters and paging. Write-and-remember is rejected for platform administrative resources.
  • one per collection: More endpoint docs, but clients can discover and reconcile state.
  • write-and-remember: Reduces server reads, but a client that loses local state cannot recover without support.
  • admin-only lists hidden from customer docs: Useful for operators, but fails the integrator's cold-build job.
  • Every data dictionary collection marked customer-readable must have a documented list endpoint unless architecture explicitly defers it.
  • List responses return typed JSON with data arrays and pagination links when more pages exist.
  • Write-only resources require an architecture deferral with a concrete repeat-customer trigger.
Re-open write-and-remember only for high-risk resources where listing itself would leak sensitive information and the architecture pins the support recovery path.PITD-031

ITD Index

Every later platform data dictionary entry, customer website section, implementation helper, and module architecture may link directly to these anchors.

PITD-001 Source Authority And Self-ContainmentRepository · active · 2026-05-21PITD-002 Module Schemas And Shared Platform SchemaPersistence · active · 2026-05-21PITD-003 Shared Tenant ModelPersistence · active · 2026-05-21PITD-004 Shared Supabase PostgreSQLPersistence · active · 2026-05-21PITD-005 Authentication, Authorization, And Tenant ScopeSecurity · active · 2026-05-21PITD-006 HTTP Envelope, Status, And Problem ErrorsAPI · active · 2026-05-21PITD-007 Idempotency And Optimistic ConcurrencyAPI · active · 2026-05-21PITD-008 Student Data Privacy And PII HandlingPrivacy · active · 2026-05-21PITD-009 Cross-Module Audit LogOperations · active · 2026-05-21PITD-010 Observability, Metrics, And SLOsOperations · active · 2026-05-21PITD-011 Hosted Documentation IdentityDocs · active · 2026-05-21PITD-012 Evals, Benchmarks, And Quality GatesLoop · active · 2026-05-21PITD-013 Sequential Loop Execution And Durable StateLoop · active · 2026-05-21PITD-014 Data Dictionary Provenance ContractDocs · active · 2026-05-21PITD-015 Surface Model And Derivation OrderProduct · active · 2026-05-21PITD-016 Conformance And Trust EvidenceRelease · active · 2026-05-21PITD-017 Migrations And DDL DisciplinePersistence · active · 2026-05-21PITD-018 AI-Maintainable Implementation ContractsImplementation · active · 2026-05-21PITD-019 Route-Scoped CORS PreflightAPI · active · 2026-05-27PITD-020 API Axis: Write GranularityAPI Axis · active · 2026-05-27PITD-021 API Axis: Read ShapeAPI Axis · active · 2026-05-27PITD-022 API Axis: Query ModelAPI Axis · active · 2026-05-27PITD-023 API Axis: Concurrency ModelAPI Axis · active · 2026-05-27PITD-024 API Axis: Idempotency ModelAPI Axis · active · 2026-05-27PITD-025 API Axis: Auth ShapeAPI Axis · active · 2026-05-27PITD-026 API Axis: Eventing ModelAPI Axis · active · 2026-05-27PITD-027 API Axis: Error EnvelopeAPI Axis · active · 2026-05-27PITD-028 API Axis: Tenant RoutingAPI Axis · active · 2026-05-27PITD-029 API Axis: Conformance EvidenceAPI Axis · active · 2026-05-27PITD-030 API Axis: Privacy / RetentionAPI Axis · active · 2026-05-27PITD-031 API Axis: List EndpointsAPI Axis · active · 2026-05-27PITD-032 Incept Producer SurfaceProducer Surface · active · 2026-06-25

Important Technical Decisions

Each ITD includes visible provenance metadata, the decision, the QTI evidence that motivated it, alternatives and tradeoffs, downstream rules, and trace links.

Repository

PITD-001: Source Authority And Self-Containment

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate a contract that depends on external standards or sibling checkouts they cannot fetch, so every normative input must be pinned in-repo or as a hosted canonical URL.

Decision. The platform3 working tree is the only product authority. Every third-party standard, SDK, example corpus, benchmark snapshot, generated trace, migration, loop state file, and approved artifact needed to regenerate or review the platform must live inside the repository or be recorded as a hosted canonical URL produced by the loop.

QTI evidence promoted. QTI succeeded only after the QTI 3.0 specification, schemas, response-processing templates, and example corpus were pinned under vendor/qti-spec-bundle and approved artifacts stopped depending on sibling workspaces.

Why this is simplest. The repository is being maintained by headless agents and reviewer loops. A self-contained tree is the simplest way to keep those agents from importing stale external context or fabricating unavailable evidence.

Alternatives and tradeoffs

Read live standards and sibling repos at build time This is convenient during exploration, but it makes a reviewer unable to reproduce the exact input and lets old sibling truth override platform3.
Vendor only generated summaries Smaller, but reviewers lose the normative source needed to catch drift in validation, enumerations, and conformance behavior.
Pin full relevant source bundles in vendor/<source> Larger repository, but it gives deterministic review, offline validation, and a clear read-only boundary.

Downstream rules

  • Every module architecture must list relevant vendor/<source> files read and explain what was adapted or rebuilt.
  • No implementation may import code or data from a sibling checkout, user home directory, or untracked symlink.
  • If a public standard is needed, pin it under vendor/<source> with a manifest, retrieval date, source URL, and validation notes.

Trace

loop/DECISIONS.md vendor/qti-spec-bundle/MANIFEST.md qti-1edtech-architecture

Persistence

PITD-002: Module Schemas And Shared Platform Schema

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate ambiguous ownership of cross-module concepts, so module-specific data must stay in the module schema while shared concepts live once in platform.*.

Decision. Each standards module owns a Postgres schema named for the module, such as qti.*, oneroster.*, and caliper.*. Cross-module platform concepts live in platform.* and are referenced by module tables rather than duplicated.

QTI evidence promoted. QTI used qti.* consistently and proved module-scoped persistence works. It also duplicated tenant metadata in qti.tenant, which is now promoted into a platform-wide model instead of repeated in future modules.

Why this is simplest. QTI already demonstrated the value of qti.* ownership. The only repeatable cross-module correction is to move concepts that every module needs into platform.* before OneRoster and Caliper copy them.

Alternatives and tradeoffs

One public schema for every table Simpler table names, but ownership, migrations, and rollback targets become unclear once multiple standards modules exist.
Every module duplicates every concept Fast for the first module, but tenant, idempotency, and audit semantics diverge across QTI, OneRoster, and Caliper.
Module schemas plus platform.* shared substrate Requires explicit foreign keys and migration ordering, but keeps module truth separate from shared truth.

Downstream rules

  • Module-specific content, runtime, conformance, and standards projection tables remain in the module schema.
  • Shared tenant, idempotency, and audit tables live in platform.*.
  • A module may create a compatibility view only when reconciling an earlier approved artifact such as qti.tenant.

Trace

qti-1edtech-data-dictionary qti-alpha-surface-qc PITD-003

Persistence

PITD-003: Shared Tenant Model

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate a school existing as several different tenant records per standard, so tenant identity must resolve to one shared platform.tenant.

Decision. platform.tenant is the platform-wide tenant table. Module tables that need tenant scope reference platform.tenant.tenant_id. The prior qti.tenant table is treated as the QTI predecessor pattern and must be reconciled by a later platform data dictionary and implementation step through migration, compatibility view, or documented rollback target.

QTI evidence promoted. QTI's qti.tenant proved tenant-scoped APIs and data are required, but the same tenant will also own OneRoster rosters, Caliper events, and future module data. Copying tenant tables per module would make a school exist in several places.

Why this is simplest. The platform goal is cross-module student outcomes. A student, family, teacher, and app-builder LLM should not have to reason about different tenant records per standard.

Alternatives and tradeoffs

Keep qti.tenant and create oneroster.tenant, caliper.tenant, and so on No QTI migration, but cross-module identity, audit, deletion, and access policy become join-by-convention instead of database truth.
Use auth provider tenants only Avoids a table, but the data dictionary cannot document school/workspace meaning, lifecycle, display keys, or references from module rows.
Promote a shared platform.tenant Requires a reconciliation path for QTI, but gives one durable school/workspace boundary for every module.

Downstream rules

  • platform.tenant fields must include tenant_id, tenant_key, display_name, status, metadata, created_at, and updated_at unless the data dictionary proves a simpler shape.
  • Every tenant-scoped route must carry a tenant or workspace path value that resolves to platform.tenant.
  • QTI reconciliation must be explicit: either migrate qti.tenant into platform.tenant, expose qti.tenant as a compatibility view, or recommend rollback to the earliest QTI deliverable that still hardcodes the old table.

Trace

qti-1edtech-architecture#itd-008-tenant-boundary qti-alpha-customer-website PITD-005

Persistence

PITD-004: Shared Supabase PostgreSQL

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate undocumented or per-module databases when they must write migrations and cross-module queries, so durable state lives in one shared Postgres documented before use.

Decision. The platform3 Supabase PostgreSQL database is the shared persistence substrate for every module and every surface. Module implementations may use repositories or facades, but durable state lives in Postgres and must be documented in the data dictionary before implementation depends on it.

QTI evidence promoted. QTI's architecture and implementation converged on a shared Supabase project named platform3, forward migrations, SQL comments, and tests that compare migration shape to the approved dictionary.

Why this is simplest. The brainlift says the persistence layer is the key. A single shared Postgres substrate with module schemas is the simplest durable truth.

Alternatives and tradeoffs

Separate database per module Strong isolation, but cross-module reporting, audit, learner deletion, and tenant identity become distributed-system problems too early.
Document first, defer persistence choice to implementation Keeps architecture abstract, but the data dictionary cannot be the platform truth if persistence is undecided.
One Supabase Postgres project with module schemas Requires careful migration boundaries, but keeps the platform queryable and reviewable end to end.

Downstream rules

  • Secrets stay in .env.local and never in loop artifacts, logs, prompts, summaries, or generated docs.
  • Service-role operations are implementation concerns and must not bypass architecture, dictionary, and customer-site contracts.
  • Shared platform.* tables are created before module tables that reference them.

Trace

loop/DECISIONS.md qti-1edtech-architecture#itd-003-shared-supabase-postgresql

Security

PITD-005: Authentication, Authorization, And Tenant Scope

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents, district integrators, and real-student apps cannot tolerate cross-tenant data exposure, public real-tenant mint helpers, app-local password capture, or an undocumented production handoff, so every customer API uses signed Bearer JWTs with route-versus-claim tenant matching and real-tenant end-user tokens come from the protected tenant token-exchange path fronted by Platform-owned login/session.

Decision. Every customer API uses signed Bearer JWTs. Tenant-scoped routes compare the route tenant or workspace value with the JWT tenant claim used by that owning API. Public /dev/mint only mints tenantId=demo tokens; generic production onboarding uses the audited protected token exchange. For each explicitly allowlisted first-party bridge, the canonical route tenant UUID selects one strict redirect/post-login/logout tuple before exact Host and Origin validation. Apps reverse-proxy only their exact auth paths on their own origin, keeping sessions host-only and SameSite without app secrets or cross-site cookies. session-token keeps binding, session, and audit on canonical platform.tenant.tenant_id, then signs that row's existing unique tenant_key for downstream People & Orgs and Results; there is no universal repository adapter or second mapping authority. An app that keeps that JWT opaque can call the tenant-bound token-context route; Platform reuses its verifier and returns only no-store verified end-user scope, without distributing the HS256 key or minting another token. Service-role authority is explicit, narrow, audited, and never inferred from a missing user token.

QTI evidence promoted. QTI customer websites required Bearer JWT, tenant claim matching, service-role-only learner deletion, and HTTPS-only handling. Alpha renamed tenant to workspace but kept the same boundary. Issue #114 added the missing production-positive path: protected token exchange rather than public real-tenant minting. Issue #108 clarified that a deployed consumer handoff also needs the module base URL, matching real-tenant JWT, and tenant header value wired into consumer config. Issues #407 and #445 pin the human front door for real-student apps: Platform-owned TimeBack Cognito/session, not app-owned login, not Google SSO as the alphatimeback3 source of truth, and not roster password capture.

Why this is simplest. This is the smallest rule that works for both standards experts and Alpha callers while keeping tenant isolation visible in tests, logs, and audit rows.

Alternatives and tradeoffs

Trust path tenant and skip token tenant matching Simple handler code, but one authorization bug exposes cross-tenant student data.
Use opaque sessions only Useful for browsers, but app-builder LLMs, integrations, and standards tooling need inspectable machine auth contracts.
Use JWT claims plus tenant path matching Slightly more boilerplate, but the rule is testable, portable, and matches QTI's approved contracts.

Downstream rules

  • Required JWT claims are iss, sub, iat, exp, the owning API's tenant field, and roles or scopes for privileged operations.
  • Generic real-tenant end-user tokens come from POST /platform/tenants/{tenantId}/token-exchanges, authorized by a same-tenant issuer or platform service token with platform:token:issue; /dev/mint remains demo-only.
  • PLATFORM_TIMEBACK_TENANT_ROUTES_JSON is a strict canonical-tenant UUID allowlist; invalid JSON, unknown fields, duplicate tenants, mixed origins, callback mismatches, and unlisted tenants fail before storage, and Host/Origin never select configuration.
  • Each allowlisted end-user JWT carries current student, parent/guardian, or guide roles, exact person/student relationship claims, iat, and exp; personIds contains authorized students only, and refresh/logout happen at the Platform session bridge.
  • Legacy single-tenant redirect/post-login/logout variables retain their behavior only when the allowlist variable is absent.
  • Deployed/Postgres TimeBack auth requires PLATFORM_JWT_SIGNING_SECRET and has no source-known fallback secret.
  • A real-tenant consumer handoff must include the stable module base URL, the matching JWT, and the tenant header value when the module requires X-Timeback-Tenant; Platform3-local operator tokens alone are not sufficient for a deployed consumer.
  • The service role may run cross-tenant maintenance only through named operations with audit rows and redacted logs.
  • 401 means missing or invalid authentication; 403 means authenticated but not authorized for the tenant, role, or operation.

Trace

qti-1edtech-customer-website qti-alpha-customer-website PITD-009

API

PITD-006: HTTP Envelope, Status, And Problem Errors

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate relearning status and error semantics per module or regexing prose, so success uses typed JSON and errors use one redacted Problem shape.

Decision. Every module uses a consistent HTTP contract: successful responses return typed JSON objects or no body for 204; asynchronous accepted work returns 202 with a trackable resource; errors use a redacted Problem object with stable code, status, title, detail, requestId, traceId, and optional fieldErrors.

QTI evidence promoted. QTI's first customer website failed until Authentication and Errors became top-level sections with inline endpoint schemas. The approved sites now use consistent status codes and Problem details that redact learner data and secrets.

Why this is simplest. QTI's reviewer feedback showed that implementers need endpoint-local schemas and one canonical error vocabulary. Typed success plus Problem errors is the simplest stable convention.

Alternatives and tradeoffs

Let each module design its own envelope Local flexibility, but app-builder LLMs and shared middleware must relearn status and error semantics per module.
Wrap every success in the same generic envelope Uniform, but noisy for simple GETs and unlike the Stripe-style endpoint pages the customer eval rewards.
Typed success bodies plus one Problem error shape Slightly more documentation work, but keeps success payloads natural and errors predictable.

Downstream rules

  • Document status codes 200, 201, 202, 204, 400, 401, 403, 404, 409, 412, 428, and 5xx when a module uses them.
  • Problem.detail must be safe for the caller and must not include JWTs, headers, access tokens, raw package bytes, direct learner PII, IP addresses, or user agents.
  • Every customer website must include top-level Authentication and Errors sections and inline request/response schemas per endpoint.

Trace

qti-1edtech-customer-website qti-alpha-customer-website PITD-008

API

PITD-007: Idempotency And Optimistic Concurrency

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate duplicate side effects on retry or silent lost updates, so retryable writes require Idempotency-Key and lost-update-sensitive writes require If-Match.

Decision. The platform owns idempotency in platform.idempotency_key for retryable create, upload, import, export-job, and asynchronous command operations. Resource-changing updates that can overwrite user work require validators such as ETag and If-Match.

QTI evidence promoted. QTI package ingest required Idempotency-Key, delivery JSON returned ETag, and authoring saves required If-Match. The pattern should not be rediscovered separately by OneRoster and Caliper.

Why this is simplest. The approved QTI surface already needed idempotency. Centralizing it avoids repeated middleware and makes cross-module client behavior predictable.

Alternatives and tradeoffs

Rely on natural unique constraints only Catches some duplicates, but cannot replay the original response or distinguish retry from conflict.
Keep idempotency tables per module Easy to ship module by module, but retry semantics, retention, and conflict behavior drift.
Use shared platform.idempotency_key with module operation metadata Adds one shared table, but gives one retry policy and one audit path across modules.

Downstream rules

  • Idempotency scope is tenant_id, module, surface, method, route template, operation id, idempotency key, and request hash.
  • Same key and same request returns the original outcome; same key and different request returns 409.
  • Missing If-Match on a required update returns 428; stale or conflicting state returns 409; failed preconditions may return 412 when the module documents that condition.

Trace

qti-1edtech-architecture#itd-010-idempotency qti-1edtech-customer-website platform.idempotency_key

Privacy

PITD-008: Student Data Privacy And PII Handling

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate learner PII leaking into references, logs, traces, generated XML, or Problems, so learner references stay pseudonymous and learner-derived state is protected.

Decision. Student-facing runtime data uses tenant-scoped pseudonymous learner references at API and persistence boundaries. Direct learner or parent PII is not accepted in learner reference fields, processing traces, logs, audit metadata, generated standards XML, or Problem details.

QTI evidence promoted. QTI architecture attempt 1 was rejected until ITD-024 made candidate_ref pseudonymous, redacted processing traces, and separated reusable content from learner runtime deletion.

Why this is simplest. The platform's primary customers are students and families. The simplest trustworthy rule is to keep identity references pseudonymous while still protecting legitimate learner work as learner data.

Alternatives and tradeoffs

Store whatever the upstream standard or client sends High fidelity, but standards payloads, traces, and logs can accidentally become identity stores.
Ban all free-text learner responses Privacy-safe, but impossible for assessments, feedback, and student work that legitimately include open responses.
Use pseudonymous references and protect learner-derived state Requires validation and deletion paths, but preserves learning workflows while reducing avoidable identity exposure.

Downstream rules

  • Learner reference fields must be UUID-shaped or a stricter platform-approved opaque identifier and must reject names, emails, phone numbers, SIS IDs, raw JWT subjects, auth tokens, and contact details.
  • Reusable content records and learner runtime records must have separate lifecycle and deletion semantics.
  • Logs, audit rows, traces, Problems, and conformance evidence must store hashes, ids, or summaries instead of raw learner PII.

Trace

qti-1edtech-architecture#itd-024-candidate-learner-data-privacy qti-alpha-architecture#alpha-itd-010-student-ref-privacy-language

Operations

PITD-009: Cross-Module Audit Log

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate having no cross-module, queryable record of high-risk actions for support and compliance, so platform.audit_log is the shared append-only narrative.

Decision. platform.audit_log is the shared append-only record of customer-visible writes, privileged reads, learner-runtime deletion, conformance/trust changes, authz denials, and administrative maintenance. Module tables remain source of record; the audit log is the platform's tamper-evident narrative of who did what, where, and with what outcome.

QTI evidence promoted. QTI needed import status, package hashes, conformance evidence, learner deletion, and service-role controls. Those are operational facts a support or compliance reviewer must inspect across modules, not just inside qti.*.

Why this is simplest. A shared audit log is the smallest durable mechanism that lets families, schools, support, and reviewers trace high-risk actions across standards modules.

Alternatives and tradeoffs

Only rely on application logs Cheap, but logs are noisy, retention-bound, and not shaped for customer or compliance queries.
Create audit tables per module Module-local, but support workflows and cross-module incident review require unions and inconsistent redaction rules.
Use a shared platform.audit_log with module resource references Requires every module write path to call shared middleware, but gives one query surface for platform accountability.

Downstream rules

  • Required fields include audit_log_id, tenant_id, module, surface, operation_id, actor_subject, actor_roles, resource_type, resource_id, action, outcome, http_status, request_id, trace_id, idempotency_key_id, occurred_at, and redacted_metadata.
  • Do not store raw request bodies, tokens, learner names, emails, or package bytes in audit metadata.
  • Every service-role operation must write audit rows whether it succeeds or fails authorization.

Trace

PITD-005 PITD-008 platform.audit_log

Operations

PITD-010: Observability, Metrics, And SLOs

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate incompatible signals or unstated reliability targets across modules, so structured logs, metrics, traces, and platform SLOs use shared field names.

Decision. Every module emits structured logs, metrics, traces, and release evidence using shared field names. Platform-level SLOs are defined for API availability, latency, error rates, conformance/trust freshness, and privacy/security incidents; module SLOs may be stricter but not looser without an ITD.

QTI evidence promoted. QTI's architecture eval surfaced observability as a gap. QTI surface QC later proved why: the fake conformance path only became obvious once release evidence was checked as a first-class artifact.

Why this is simplest. Observability is cheaper as a platform convention than as a retrofit after the customer website has already promised behavior.

Alternatives and tradeoffs

Leave observability to implementation teams Flexible, but future modules repeat QTI's late discovery pattern and reviewers cannot compare evidence.
Only store audit rows Durable for actions, but not enough for latency, error budget, dependency health, or incident triage.
Define platform log, metric, trace, and SLO conventions now Adds non-functional requirements early, but prevents every module from inventing incompatible signals.

Downstream rules

  • Structured logs must include timestamp, level, service, module, surface, operation_id, tenant_id or tenant hash, request_id, trace_id, actor_subject hash, status_code, latency_ms, outcome, error_code, and redaction_status.
  • Minimum metrics include request_count, request_latency, error_count by code, authz_denied_count, idempotency_replay_count, validation_reject_count, privacy_reject_count, audit_write_failure_count, and conformance_freshness_seconds where applicable.
  • Default SLO targets are 99.5 percent monthly availability for customer APIs, p95 read latency under 500 ms excluding large exports, p95 write latency under 2 s excluding documented asynchronous work, and zero tolerated confirmed PII leaks in logs or Problems.

Trace

qti-1edtech-surface-qc PITD-009 PITD-016

Docs

PITD-011: Hosted Documentation Identity

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate documentation links that churn on every redeploy, so deliverables have stable hierarchical canonical URLs with deploy_url recorded separately.

Decision. Documentation deliverables are static hosted HTML sites deployed by the driver to the Vercel project platform3. A deliverable's canonical URL is the hierarchical master-alias path /{module}/{surface}/{deliverable}/, and the underlying Vercel deploy URL is recorded separately as deploy_url in loop state.

QTI evidence promoted. QTI originally approved per-deploy URLs, then the platform loop migrated canonical links to hierarchical master-alias rewrites so downstream docs and integrators no longer depend on Vercel hash URLs. A prior summary inconsistency showed that the driver, not the doer, must own deploy verification.

Why this is simplest. Customers need stable URLs and the loop needs auditable deploy evidence. A hierarchical canonical path plus separate deploy_url gives both without asking consumers to track Vercel hashes.

Alternatives and tradeoffs

Use markdown files in git as the deliverable Reviewable by engineers, but not a single customer-facing URL for students, parents, teachers, or app-builder LLMs.
Use the root platform3 alias without hierarchical paths Easy to remember, but one mutable root cannot identify which module, surface, or deliverable the customer meant.
Use unique Vercel deployment URLs as canonical Immutable, but every redeploy churns the customer-facing URL and breaks docs that should point to the stable deliverable.
Use hierarchical master-alias canonical paths rewritten to current deploy URLs Requires the master site's rewrites table, but gives stable customer URLs while preserving deploy_url audit history.

Downstream rules

  • Doers build OUT_DIR/site and set canonical_url to null; the driver deploys, fetches unauthenticated 2xx, writes deploy_url, and patches canonical_url to the hierarchical master-alias URL.
  • Deployment Protection must remain off for public documentation deliverables.
  • Every section that downstream artifacts cite must have a stable hash anchor, and the master site's vercel.json must rewrite that canonical path to the current deploy URL.

Trace

loop/DECISIONS.md qti-1edtech-architecture#itd-023-hosted-docs qti-alpha-surface-qc

Loop

PITD-012: Evals, Benchmarks, And Quality Gates

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate deliverables that a discerning customer would still reject, so every deliverable must pass both a named customer eval and a binary scoring rubric.

Decision. Every deliverable is judged by two separate evals: a pass/fail customer eval against a named fetchable benchmark and a binary failure-named scoring rubric. The driver advances only after the reviewer returns approved with customer eval yes, rubric pass, and no cross-artifact contradiction.

QTI evidence promoted. QTI improved materially when the customer website compared itself to Stripe's API docs, when surface QC compared itself to CNCF conformance, and when implementation was rolled back for failing the promised conformance evidence.

Why this is simplest. QTI's failures were useful because they were both customer-specific and repairable. The same evaluation policy must apply to every future module.

Alternatives and tradeoffs

Use a checklist rubric only Actionable, but it can rubber-stamp a deliverable that a discerning customer would still reject.
Use customer taste only High bar, but failure feedback is too vague for headless repair loops.
Use decoupled customer eval plus rubric More review work, but it keeps standards high and fixes concrete.

Downstream rules

  • The customer eval prompt must name one persona, one job-to-be-done, and one live or pinned benchmark.
  • Rubrics must have 3 to 10 non-overlapping binary failure categories, one critical category, and quote-anchored applied failures.
  • If a benchmark is missing from loop/context/benchmarks/index.json, the reviewer proposes a fetchable benchmark and the supervisor promotes it once.

Trace

loop/context/evals.md loop/context/benchmarks/index.json qti-1edtech-customer-website qti-1edtech-surface-qc

Loop

PITD-013: Sequential Loop Execution And Durable State

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate implementation drifting ahead of unresolved architecture or customer-site flaws, so one sequential driver with durable loop-file state owns ordering and rollback.

Decision. The loop uses one sequential driver per module. Codex does the build, the driver deploys documentation sites, Claude reviews, and the driver advances, retries, rolls back, regenerates the master site, and commits approval state. Durable memory lives in loop files, not live chat context.

QTI evidence promoted. QTI's approved chain required multiple attempts, driver-managed deployment, reviewer-created evals, issue tracking, rollback to implementation, and a generated master index. Independent cron-like agents would not have preserved that order.

Why this is simplest. Deliverables are derivational. A single ordered driver is the simplest way to prevent implementation from running ahead of unresolved architecture or customer-site flaws.

Alternatives and tradeoffs

Independent agents per deliverable Parallel, but architecture, dictionary, website, and implementation can drift before review catches them.
One human-managed checklist Simple, but loses the headless durable-memory property and creates manual deploy/review gaps.
Sequential driver with explicit state machine Less parallelism, but preserves causality, rollback discipline, and auditability.

Downstream rules

  • Commit loop context, state, transcript, issues, and eval definitions/results; do not commit runtime logs.
  • Doers may not fabricate canonical URLs or run Vercel deployment from inside the sandbox.
  • Reviewer rollback goes to the earliest flawed deliverable, including earlier QTI deliverables when platform truth intentionally supersedes them.

Trace

loop/driver.sh loop/platform/state.json qti-1edtech-surface-qc

Docs

PITD-014: Data Dictionary Provenance Contract

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate a database they cannot understand without reading source, so every field documents meaning, constraints, allowed/invalid values, examples, and provenance.

Decision. Every data dictionary entry documents meaning, shape, lifecycle, constraints, allowed values, invalid values, examples, relationships, and provenance. A field is labeled pass-through, gap fill, cut, restrict, rename, or extend and links to the ITD that authorizes that label.

QTI evidence promoted. QTI's data dictionaries passed because table and field rows carried meaning, not just SQL shape, and because Alpha mapped every public field back to a qti.* source path or Alpha ITD.

Why this is simplest. The brainlift says the persistence layer is the key. The data dictionary must let a staff engineer write migrations and queries without reading source code.

Alternatives and tradeoffs

Document schemas from DDL only Accurate shape, but not enough to identify invalid values or explain product meaning to LLMs and engineers.
Document only customer-facing fields Friendly, but implementation and migrations still need hidden/shared fields to be governed.
Document every shared and module field with provenance More work, but it makes the database the platform truth.

Downstream rules

  • Anchor format must be stable and predictable: table anchors for platform.tenant use table-platform-tenant; field anchors use field-platform-tenant-tenant-id.
  • Allowed values must explain behavior, not restate names.
  • Invalid-value guidance is required for IDs, references, enums, JSON objects, learner-data fields, and every status lifecycle.

Trace

qti-1edtech-data-dictionary qti-alpha-data-dictionary loop/context/benchmarks/data_dictionary.html

Product

PITD-015: Surface Model And Derivation Order

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate a customer surface that cannot trace back to standards truth, so the Alpha surface may only cut, restrict, rename, or extend over the approved expert surface.

Decision. Standards modules expose two API/documentation surfaces over shared persistence: an expert standards surface that follows the standard exactly, and an Alpha surface that may only cut, restrict, rename, or extend for students, parents, teachers, and app-builder LLMs. Architecture precedes data dictionary, customer website precedes implementation, and implementation derives from all three.

QTI evidence promoted. QTI proved the order: the Alpha surface stayed trustworthy because it was a facade over the approved 1EdTech persistence and every Alpha divergence linked to an Alpha ITD.

Why this is simplest. The platform needs both compliance and customer comprehension. Separate surfaces over one persistence model are the simplest way to serve both.

Alternatives and tradeoffs

Build Alpha first Faster customer language, but risks inventing a product model that cannot trace back to standards truth.
Merge expert and Alpha docs One site, but either students drown in standards detail or experts lose conformance detail.
Build expert surface first, then Alpha facade More deliverables, but gives both audiences a clean route to the same database truth.

Downstream rules

  • Alpha changes must be exactly one of cut, restrict, rename, or extend, with alternatives and tradeoffs.
  • The customer website is the implementation specification and must not be skipped.
  • Implementation may expose no behavior that lacks architecture, data dictionary, and customer website provenance.

Trace

loop/context/timeback-platform-brainlift.md qti-alpha-architecture qti-alpha-surface-qc

Release

PITD-016: Conformance And Trust Evidence

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate conformance asserted as prose or a boolean, so conformance claims require executed, reproducible evidence and read-only public trust status.

Decision. Standards modules that claim conformance must execute real local or vendored conformance evidence and persist granular results. Public Alpha surfaces expose trust status as read-only customer information; release tooling and expert surfaces own mutation of conformance runs.

QTI evidence promoted. QTI surface QC caught an implementation that fabricated passed conformance. The approved rollback required a real runner, real bundle hash, persisted assertion rows, and tests for failure states.

Why this is simplest. Conformance is a trust claim. It must be reproducible evidence, not a boolean field or a marketing statement.

Alternatives and tradeoffs

Treat conformance as prose in documentation Easy to publish, but customers cannot verify whether the implementation matches the promise.
Expose conformance mutation to every public caller Transparent, but lets ordinary users trigger expensive or release-gate jobs.
Run conformance through release/expert paths and expose read-only trust summaries Requires evidence plumbing, but it separates release control from customer visibility.

Downstream rules

  • Conformance runs must record profile, source bundle hash, runner version, started_at, finished_at, status, summary, and per-assertion details in the module schema unless platform data dictionary later promotes a shared shape.
  • A missing bundle, runner error, or failed assertion cannot produce a passed status.
  • Alpha trust-status endpoints are read-only and must link to the approved surface QC URL.

Trace

qti-1edtech-surface-qc qti-alpha-surface-qc PITD-012

Persistence

PITD-017: Migrations And DDL Discipline

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate schema drift between the documented dictionary and the live database, so changes use forward-only migrations with comments and contract tests against the dictionary.

Decision. Database changes use forward-only migrations with comments, indexes, foreign keys, check constraints, and tests that compare implementation DDL to the approved data dictionary. Destructive changes require an explicit rollback/re-delivery path through the earliest affected deliverable.

QTI evidence promoted. QTI's implementation approval depended on migration comments, schema contract tests, candidate_ref constraints, JSON object checks, conformance tables, and byte-identical Alpha persistence.

Why this is simplest. The database is shared across modules and surfaces. Schema drift is a platform bug, not a local implementation detail.

Alternatives and tradeoffs

Let implementation migrations define truth Fast, but the data dictionary becomes after-the-fact documentation and cannot guide implementation.
Use ORM models only Convenient in code, but hides Postgres constraints and comments that reviewers and database operators need.
Use dictionary-derived SQL migrations with contract tests Requires extra verification, but keeps persistence, docs, and implementation aligned.

Downstream rules

  • Every table and non-obvious field needs a SQL comment derived from the data dictionary.
  • Status values, type labels, learner reference shape, and redaction-sensitive JSON fields require check constraints or documented validation boundaries.
  • Implementation tests must fail when a published table, field, enum, or critical index is missing.

Trace

qti-1edtech-implementation qti-alpha-implementation PITD-014

Implementation

PITD-018: AI-Maintainable Implementation Contracts

#
Status
active
Date
2026-05-21
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate implementations that future headless agents cannot safely modify or verify, so shared libraries stay small, contract-tested, dependency-light, and example-backed.

Decision. Shared libraries and module implementations must be small, contract-tested, dependency-light, and accompanied by runnable examples so AI agents can safely extend them without rediscovering platform rules.

QTI evidence promoted. QTI implementation reviews failed when the README and OpenAPI refs were not self-contained, then passed after the artifact included a runnable quickstart, self-resolving contracts, tests, provenance, and examples.

Why this is simplest. The brainlift explicitly wants implementation written, tested, maintained, release-managed, and product-managed by AI. That requires clear contracts more than clever abstractions.

Alternatives and tradeoffs

Optimize only for production service code May run in deployment, but future headless agents cannot confidently modify or verify it.
Generate large framework-heavy SDKs Feature-rich, but dependency churn and hidden behavior make reviews harder.
Ship small shared libraries with examples and contract tests Less abstraction, but the behavior is inspectable, portable, and easier for agents to maintain.

Downstream rules

  • The platform implementation deliverable must include JWT verifier, tenant scoper, audit logger, Problem builder, idempotency middleware, and platform.* migration helper.
  • Every shared library must include a consumer example showing a mock module importing it.
  • Tests must cover customer website promises, not just internal helper behavior.

Trace

qti-1edtech-implementation qti-alpha-implementation PITD-005 PITD-006

API

PITD-019: Route-Scoped CORS Preflight

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators making browser-direct calls cannot tolerate preflight that advertises methods a route does not serve, so Allow-Methods reflects only the matched route's served methods plus OPTIONS.

Decision. The platform CORS contract is open-origin and route-scoped: responses set Access-Control-Allow-Origin: *, and OPTIONS preflight returns Access-Control-Allow-Methods containing only the methods served by the matched route plus OPTIONS. A route that serves only GET advertises GET, OPTIONS; a route that serves only POST advertises POST, OPTIONS.

QTI evidence promoted. Triage decision 2026-05-26-008 showed that broad preflight advertising made a browser-direct OneRoster integrator write POST, PUT, PATCH, and DELETE calls against collection routes that the surface did not serve. Platform implementation attempt 2 corrected the shared helper with routeCorsMethods and deployed smoke evidence.

Why this is simplest. The negative-complexity fix is to make the existing CORS primitive say less and mean more: open origin stays, but method advertising becomes the route's actual contract.

Alternatives and tradeoffs

Advertise GET, POST, PUT, PATCH, DELETE, OPTIONS on every route Simple default, but it lies on read-only and bulk-only routes and pushes method discovery failures into runtime 404 or 405 responses.
Use per-origin credentialed CORS allowlists Useful for cookie-based browser apps, but platform APIs use Bearer tokens and need cold integrator quickstarts without proxy setup.
Keep open origin and compute Allow-Methods from the matched route Requires route metadata in shared middleware, but makes preflight a truthful contract and lets every module inherit one implementation.

Downstream rules

  • Every implementation must define route metadata used by the shared routeCorsMethods helper or an equivalent platform-reviewed adapter.
  • OPTIONS for a matched route must include exactly the route's served methods plus OPTIONS, ordered GET, POST, PUT, PATCH, DELETE, OPTIONS where present.
  • Unknown routes may answer OPTIONS only, but must not advertise methods whose runtime handlers would return 404 or 405.

Trace

2026-05-26-008 loop/platform/artifacts/1edtech/implementation/impl/src/http/cors.mjs loop/platform/artifacts/1edtech/implementation/impl/README.md

API Axis

PITD-020: API Axis: Write Granularity

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate manufacturing files for single-resource administrative changes or a duplicate write primitive, so platform writes are per-resource and bulk stays module-owned.

Decision. SHIP: Platform administrative writes are per-resource commands only. Bulk import/export write flows belong to standards modules when their source spec requires them; the platform substrate does not add a second bulk-write primitive.

QTI evidence promoted. QTI proved that package ingest may need bulk/import semantics, while platform tenant management is a small administrative resource surface. OneRoster's bulk-only decision also showed why method shape must be explicit instead of inferred from platform defaults.

Why this is simplest. This avoids a duplicate primitive: modules keep their spec-specific bulk jobs, and the platform API stays the administrative control plane.

Alternatives and tradeoffs

bulk-only Works for OneRoster CSV-style module ingestion, but makes simple tenant administration unnatural and forces clients to manufacture files for single-resource changes.
per-resource only Fits tenant, audit, idempotency, and module catalog administration while keeping standards bulk imports owned by their modules.
both bulk and per-resource on the platform surface Adds a second way to perform the same administrative changes and makes idempotency, audit, and CORS method discovery harder.

Downstream rules

  • Platform tenant creation, detail reads, audit inspection, idempotency inspection, and module catalog operations use resource endpoints.
  • A module may expose bulk endpoints only when its own architecture pins that standard-specific write model.
  • CORS Allow-Methods must reflect the actual per-resource or bulk route, not a platform-wide write superset.
  • Rejected/deferred alternative re-open trigger: Re-open only if three integrators in 90 days need a platform-level batch administrative operation that cannot be expressed as module-owned import/export jobs.

Trace

PITD-002 PITD-007 PITD-019 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-021: API Axis: Read Shape

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate list-only APIs that hide the resource they must inspect or unbounded graph reads, so reads use list plus detail plus narrow sub-collections.

Decision. SHIP: Platform administrative reads use list plus detail plus narrow sub-collections: module catalog list/detail, tenant detail, tenant audit-log sub-collection, and tenant idempotency-key detail.

QTI evidence promoted. QTI and Alpha both needed endpoint-local schemas and customer-visible trust/audit facts. Platform implementation already exposes module list/detail and tenant-scoped audit/idempotency inspection as the reusable substrate.

Why this is simplest. List-only APIs hide the resource a customer needs to inspect; unrestricted nested graphs make every module relearn projection rules. Narrow sub-collections are the smallest useful read surface.

Alternatives and tradeoffs

list-only Easy to cache, but clients cannot inspect a specific tenant, audit narrative, or idempotency result without reading source code.
list plus detail Good for catalog resources, but audit and idempotency state are operational sub-collections tied to a tenant.
list plus detail plus sub-collections Adds route count, but keeps operational reads discoverable without creating a general graph API.

Downstream rules

  • Every list endpoint must document the matching detail endpoint unless the architecture explicitly defers detail reads with a trigger.
  • Sub-collections are allowed only for operational facts owned by the parent resource, such as tenant audit-log entries.
  • Customer websites must show list/detail/sub-collection examples in the same endpoint family.
  • Rejected/deferred alternative re-open trigger: Re-open for graph-style expansions only after three integrators in 90 days need the same cross-resource projection and the projection cannot be handled by linked detail URLs.

Trace

PITD-006 PITD-009 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-022: API Axis: Query Model

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate unscannable collections or non-replayable ad hoc query parameters, so endpoints support documented filters, stable sort, cursor paging, and modifiedSince on append-like logs.

Decision. SHIP: Platform list and sub-collection endpoints support documented filters, stable sort keys, limit-based paging with opaque cursors when result size can exceed one page, and modifiedSince where the collection is an append-like operational log. Ad hoc query parameters are not accepted.

QTI evidence promoted. QTI customer docs passed only after endpoint schemas were inline and precise. Audit and conformance evidence need repeatable scans; accepting undocumented parameters would make those scans non-replayable.

Why this is simplest. Filter plus paging plus cursor is the smallest query model that supports real integration work without turning every endpoint into custom SQL over HTTP.

Alternatives and tradeoffs

none Simple handlers, but audit logs, idempotency records, and module catalogs become unscannable as tenants grow.
filter and sort only Useful for small lists, but unstable for large or append-only collections without paging and cursors.
filter plus paging plus cursor, with modifiedSince on append-like logs Requires cursor contract tests, but gives deterministic scans and supports poll-based integrations.

Downstream rules

  • Every accepted query parameter must be named in the customer website and validated by implementation tests.
  • Cursor tokens are opaque to clients and scoped to tenant, route, filter, sort, and principal visibility.
  • modifiedSince is allowed only on collections whose ordering and clock semantics are documented.
  • Rejected/deferred alternative re-open trigger: Re-open for arbitrary expression filters only if three integrators in 90 days need the same unsupported predicate and it cannot be represented by a named filter.

Trace

PITD-006 PITD-010 PITD-014 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-023: API Axis: Concurrency Model

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate silent last-write-wins on administrative or learner state, so resource-changing updates expose ETag and enforce If-Match with documented 428/412/409 responses.

Decision. SHIP: Resource-changing updates that can overwrite customer work require per-resource validators, exposed as ETag and enforced with If-Match. Missing required validators return 428; stale validators return 412 or the documented 409 conflict shape.

QTI evidence promoted. QTI authoring saves required If-Match to prevent lost updates. That is a cross-module rule, not a QTI-only special case.

Why this is simplest. Per-resource validators make lost-update protection explicit at the HTTP boundary and avoid inventing a separate lock service.

Alternatives and tradeoffs

none Lowest friction, but silent last-write-wins bugs are unacceptable for learner, roster, and administrative state.
If-Match per resource Requires clients to store validators, but it is standard HTTP and easy to test.
bulk-only concurrency tokens Works for file import jobs, but does not protect resource edits outside the batch.

Downstream rules

  • Every update endpoint must state whether If-Match is required, optional, or not applicable.
  • ETag values must change when the customer-visible resource representation changes.
  • Bulk/import jobs may use job-level validators only when the module architecture pins why per-resource validators do not apply.
  • Rejected/deferred alternative re-open trigger: Re-open for server-side locks only if optimistic validators cannot prevent a documented repeated lost-update workflow for three integrators in 90 days.

Trace

PITD-007 qti-1edtech-customer-website loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-024: API Axis: Idempotency Model

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate a retried timeout creating duplicate tenants, imports, or jobs, so retryable writes use Idempotency-Key persisted in the shared ledger.

Decision. SHIP: Retryable writes use Idempotency-Key, persisted in platform.idempotency_key with request hash, response replay metadata, tenant, module, surface, method, route template, and operation id.

QTI evidence promoted. QTI package ingest and the approved platform implementation both needed replay versus conflict behavior. The platform table prevents each module from redefining retry semantics.

Why this is simplest. A shared idempotency ledger removes ambiguity and makes browser, CLI, and server clients follow one rule.

Alternatives and tradeoffs

none Easy to implement, but retrying a network timeout can create duplicate tenants, imports, or jobs.
Idempotency-Key on writes Requires a shared ledger and request hashing, but makes retries safe and observable.
Natural unique constraints only Prevents some duplicates, but cannot replay the original response or identify same-key different-body conflicts.

Downstream rules

  • Same key and same canonical request hash returns the original outcome.
  • Same key and different canonical request hash returns 409 with a typed Problem.
  • Customer websites must identify which operations require Idempotency-Key and which do not.
  • Rejected/deferred alternative re-open trigger: Re-open for idempotency-less writes only when the operation is mathematically side-effect-free or the architecture proves duplicate execution is harmless.

Trace

PITD-007 platform.idempotency_key loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-025: API Axis: Auth Shape

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents, district integrators, and real-student apps cannot tolerate a platform token vocabulary that depends on every standard's domain claims or a login/session bridge invented by each app, so tokens carry tenantId, role/roles, scopes, and allowlisted domain claims while Platform owns the student SSO front door.

Decision. SHIP: Platform APIs use Bearer JWTs with tenantId, role or roles, scopes, and allowlisted domain-scoped claims. Public /dev/mint is demo-only. Generic production end-user tokens use the protected tenant-token exchange. An explicitly allowlisted first-party bridge selects an exact same-origin redirect/post-login/logout tuple by canonical route tenant UUID before Host/Origin validation; multiple apps can therefore share one Platform deployment while reverse-proxying only their exact auth paths and keeping host-only SameSite cookies. session-token keeps binding, session, and audit records on the canonical UUID, then signs the tenant row's existing unique tenant_key for downstream People & Orgs and Results. POST /platform/tenants/{canonicalTenantUuid}/token-context verifies that opaque token against the same active UUID/key boundary and returns only a no-store end-user context; invalid, expired, machine, inconsistent-scope, and wrong-tenant tokens fail closed, and no app receives a signing key. Invalid, duplicate, mismatched, or unlisted configuration fails closed before storage; no Host-derived routing, cross-site cookie, app secret, or second deployment is introduced. Human tokens carry exact person/student relationship claims only: personIds contains authorized students, never the parent or guide actor, and placeIds, schoolIds, classIds, and candidateRef are absent. Shared platform middleware enforces tenant/role/scope and passes exact claims through to the owning module.

QTI evidence promoted. QTI and Alpha both validated Bearer JWT plus tenant/workspace scoping. Issue #114 showed that real integrators also need a documented production replacement for the demo mint: tenant provisioning plus scoped per-end-user token issuance without opening a public real-tenant mint helper. Issue #108 then showed that a deployed consumer handoff is incomplete if it has operator-only reviewer tokens but no durable module base URL, real-tenant JWT, and tenant header wiring in the consumer's deployed config. Issue #407 adds the missing real-student front door: Platform-owned TimeBack SSO/session maps the human to People & Orgs identity before token exchange.

Why this is simplest. Role plus scopes plus tenantId is enough for platform administration, while a protected token exchange with explicit student identity claims gives production integrators a reachable handoff path and still leaves domain-specific authorization to the module that owns the domain model.

Alternatives and tradeoffs

role-only Readable, but too coarse for service-role maintenance, audit reads, and future delegated operations.
role plus scopes Requires explicit scope docs, but gives narrow authorization without importing module domain claims.
scoped domain claims on every token Useful for SIS or assessment domains, but makes the platform token vocabulary depend on every standard.
public real-tenant token minting Easy for cold demos, but it turns tenant provisioning into an unaudited self-service credential path.
app-owned student login or refresh tokens Makes every student app invent an IdP/session bridge and bypasses the People & Orgs password-cut decision.

Downstream rules

  • tenantId is required for tenant-scoped routes and must match the route tenant value used by that owning API.
  • Privileged operations must name the role or scope that authorizes them.
  • POST /dev/mint?tenantId=demo is the only public mint helper; non-demo tenant ids must be rejected.
  • Generic production end-user JWTs are issued through POST /platform/tenants/{tenantId}/token-exchanges by a same-tenant issuer or platform service token with platform:token:issue authority.
  • PLATFORM_TIMEBACK_TENANT_ROUTES_JSON lists each first-party tenant and exact URI tuple; the route tenant UUID selects the tuple and Host/Origin only validate it.
  • Each app reverse-proxies only its own tenant's exact auth paths so cookies remain same-origin; the app receives no Platform signing secret.
  • Legacy single-tenant redirect/post-login/logout variables retain their exact behavior only when the allowlist is absent.
  • A deployed consumer handoff is complete only when the consumer receives the stable module base URL, the matching real-tenant JWT, and the tenant header value when that module requires X-Timeback-Tenant; an operator or reviewer JWT that remains only in Platform3 local env is not a durable consumer path.
  • Module-specific domain claims must be documented by that module and cannot be required by shared platform middleware.
  • Rejected/deferred alternative re-open trigger: Re-open platform-wide domain claims only after two modules independently require the same claim with the same semantics.

Trace

PITD-005 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-026: API Axis: Eventing Model

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate building against webhook delivery the platform has not committed to, so eventing is poll plus modifiedSince with webhooks explicitly deferred.

Decision. SHIP: The platform eventing model is poll plus modifiedSince for append-like operational collections. Webhooks are explicitly deferred until repeated integrator demand proves polling is the blocker.

QTI evidence promoted. QTI and platform surface QC both rely on replayable pull evidence. No approved customer website currently commits to inbound webhook delivery or webhook secret rotation.

Why this is simplest. Poll plus modifiedSince is enough for cold integrators to build reliable sync without adding delivery retries, signatures, subscriptions, and dead-letter handling as a duplicate event primitive.

Alternatives and tradeoffs

poll-only Simple, but clients waste calls and cannot efficiently resume from a known freshness point.
poll plus modifiedSince Requires timestamp semantics, but keeps event consumption replayable and browser-safe.
webhooks Lower latency, but adds subscription state, delivery signatures, retries, and customer-operated receivers before the platform has demand.

Downstream rules

  • Append-like collections that support modifiedSince must define clock source, inclusivity, and pagination interaction.
  • Modules must not add webhooks without an architecture ITD, data dictionary entries, customer website docs, implementation tests, and surface QC replay evidence.
  • Audit and conformance/trust collections are the first platform collections eligible for modifiedSince.
  • Rejected/deferred alternative re-open trigger: Re-open webhooks when three integrators in 90 days report that polling prevents their documented job or when p95 freshness above five minutes blocks a committed workflow.

Trace

PITD-009 PITD-010 PITD-016 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-027: API Axis: Error Envelope

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate branching on free-text or unstable error values, so every surface returns typed RFC 7807 Problems with stable type URIs, stable code, requestId, and traceId.

Decision. SHIP: Every surface uses typed RFC 7807 Problem Details with stable, dereferenceable type URIs under the master Platform3 problem catalog at https://platform3-andymontgomery-9773s-projects.vercel.app/problems/*, a stable code, requestId, traceId, and optional fieldErrors.

QTI evidence promoted. QTI customer website attempts failed until Authentication and Errors were top-level and inline. Typed Problems are now shared platform truth.

Why this is simplest. Typed RFC 7807 keeps the standard shape and adds the stable machine fields integrators need for branching and support.

Alternatives and tradeoffs

none Fast for handlers, but clients regex prose and support cannot correlate failures.
plain RFC 7807 Standard, but a free-text or unstable type value is not enough for reliable client behavior.
typed RFC 7807 with stable URIs Requires a type registry, but gives predictable cross-module error handling.

Downstream rules

  • Problem detail must be safe to show to the caller and must not include secrets or direct learner PII.
  • Every documented 4xx and 5xx path must name its Problem code and status.
  • requestId and traceId must be returned in the error body or headers and logged with the same values.
  • Rejected/deferred alternative re-open trigger: Re-open only if a required external standard mandates a conflicting error shape and the module architecture proves an adapter cannot preserve typed Problem semantics.

Trace

PITD-006 PITD-008 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-028: API Axis: Tenant Routing

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate non-inspectable tenant scope in links, curl, and audit, so tenant scope is carried in the URL and independently enforced against the JWT tenantId.

Decision. SHIP: Tenant scope is carried in the URL for tenant resources and independently enforced from the JWT tenantId claim. Tenant headers are not accepted as the routing source of truth.

QTI evidence promoted. QTI and Alpha both converged on visible tenant/workspace boundaries plus token matching. The platform implementation asserts tenant scope before tenant audit and idempotency reads.

Why this is simplest. Putting tenant in the URL makes links, audit rows, and support repros inspectable; matching it against JWT tenantId prevents cross-tenant access.

Alternatives and tradeoffs

tenant in URL Visible and linkable, but requires every tenant route to enforce path-token matching.
tenant in header Keeps paths shorter, but makes browser links, curl snippets, and audit evidence less self-contained.
tenant in JWT only Reduces route parameters, but makes shared admin paths ambiguous and harder to deep-link.

Downstream rules

  • Tenant-scoped paths must name the tenant or workspace segment and compare it to JWT tenantId.
  • Mismatched path and JWT tenant returns 403, not 404, unless the module architecture explicitly chooses not-found cloaking for a sensitive resource.
  • Public demo minting is restricted to tenantId=demo; real tenant end-user tokens are issued through the protected tenant token-exchange route after tenant provisioning.
  • Rejected/deferred alternative re-open trigger: Re-open tenant headers only if an external conformance suite requires them and an adapter cannot map them to URL plus JWT enforcement.

Trace

PITD-003 PITD-005 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-029: API Axis: Conformance Evidence

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate conformance claims they cannot replay, so trust claims require executed spec-runner evidence with recorded hashes, runner version, and assertion results.

Decision. SHIP: Conformance and trust claims require executed evidence: vendored or local spec-runner output, recorded bundle/source hashes, runner version, assertion results, and release-gate links. External certification is a future supplement, not a substitute for local evidence.

QTI evidence promoted. QTI surface QC caught a fabricated conformance path and approved only after real runner evidence existed. Caliper and OneRoster inherit that trust rule.

Why this is simplest. A local spec-runner or equivalent evidence path is the smallest auditable proof the loop can replay without depending on an external registry.

Alternatives and tradeoffs

none Avoids setup, but turns conformance into a marketing claim.
spec-runner Requires fixtures and assertion storage, but produces repeatable release evidence.
external certification only Valuable for buyers, but too slow and too opaque to be the loop's day-to-day release gate.

Downstream rules

  • Every passed conformance claim must link to executed evidence and the source bundle hash.
  • Missing runner, missing bundle, failed assertion, or unparseable output cannot produce passed status.
  • Surface QC must probe evidence, not just read a boolean trust field.
  • Rejected/deferred alternative re-open trigger: Re-open external certification as a required gate when a paying integrator or procurement process requires a named external certification before launch.

Trace

PITD-016 qti-1edtech-surface-qc loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-030: API Axis: Privacy / Retention

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate learner PII surfacing in logs, problems, audit metadata, or undocumented retention, so student data follows GDPR-style minimization and documented deletion semantics.

Decision. SHIP: Student and learner data follow GDPR-style minimization and deletion semantics: pseudonymous learner references at boundaries, redacted logs/problems/audit metadata, separate reusable-content versus learner-runtime lifecycle, and documented deletion paths for learner-derived state.

QTI evidence promoted. QTI ITD-024 was required after privacy gaps appeared. Alpha's studentRef language proved the same rule must be understandable outside standards vocabulary.

Why this is simplest. The platform's primary customers are students and families; privacy cannot be a module-local afterthought.

Alternatives and tradeoffs

none Easiest, but invites PII into logs, traces, generated XML, and support artifacts.
DELETE per spec only Matches individual standards, but misses cross-module audit, logs, traces, and shared student outcomes.
GDPR-style minimization and retention Requires validation and deletion design, but gives a single privacy bar across modules.

Downstream rules

  • Learner reference fields must reject direct names, emails, phone numbers, SIS IDs, tokens, and raw auth subjects.
  • Deletion paths must distinguish reusable educational content from learner runtime or outcome state.
  • Audit and observability data must store redacted ids, hashes, or summaries instead of raw learner PII.
  • Rejected/deferred alternative re-open trigger: Re-open retention periods only when a legal, district, or standard-specific requirement imposes a concrete retention value the platform cannot satisfy with current minimization rules.

Trace

PITD-008 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

API Axis

PITD-031: API Axis: List Endpoints

#
Status
active
Date
2026-05-27
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-05-29
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. 1EdTech-compliant AI agents and district integrators cannot tolerate write-and-remember resources that they cannot recover after losing local state, so every integrator-readable collection exposes a documented list endpoint.

Decision. SHIP: Every platform collection that can be read by an integrator exposes a list endpoint with documented filters and paging. Write-and-remember is rejected for platform administrative resources.

QTI evidence promoted. QTI and platform implementation customer flows rely on cold integrators discovering modules, tenants, audit rows, and idempotency state from docs and live endpoints.

Why this is simplest. A list endpoint is the simplest way for a cold integrator and an app-builder LLM to recover state without private memory.

Alternatives and tradeoffs

one per collection More endpoint docs, but clients can discover and reconcile state.
write-and-remember Reduces server reads, but a client that loses local state cannot recover without support.
admin-only lists hidden from customer docs Useful for operators, but fails the integrator's cold-build job.

Downstream rules

  • Every data dictionary collection marked customer-readable must have a documented list endpoint unless architecture explicitly defers it.
  • List responses return typed JSON with data arrays and pagination links when more pages exist.
  • Write-only resources require an architecture deferral with a concrete repeat-customer trigger.
  • Rejected/deferred alternative re-open trigger: Re-open write-and-remember only for high-risk resources where listing itself would leak sensitive information and the architecture pins the support recovery path.

Trace

PITD-006 PITD-014 loop/context/loop-brainlift.md#decision-axes-per-deliverable-type

Producer Surface

PITD-032: Incept Producer Surface

#
Status
active
Date
2026-06-25
Author
platform3-loop
supersedes
none
superseded_by
none
Status
Accepted
Date
2026-06-25
Owner
TimeBack Platform Architecture (AI-maintained)

Audience constraint. The Platform3 operator, Incept app integrator, and cold skill-pack agents cannot tolerate a production app reading Incept progress through raw SUPABASE_DB_URL access, because that bypasses Platform3 auth, tenant scope, audit, data-dictionary semantics, and non-service-role readback.

Decision. SHIP: Incept is a first-class Platform3 upstream producer surface. Its governed incept schema preserves generation, evaluation, model, source, quality, repair, promotion, deployment, and issue-link provenance; generated student-facing artifacts materialize as canonical Content/QTI rows or explicit reconciliation errors; consumer-facing progress/status reads are exposed through Platform3 API/view paths with normal auth, tenant scope, audit, data-dictionary coverage, and non-service-role readback.

QTI evidence promoted. QTI proved that generated artifacts and trust evidence need canonical rows plus replayable provenance. Incept extends that platform pattern to generation/progress provenance without creating an alternate Content or Results model.

Why this is simplest. A governed producer surface keeps the useful Incept ledger, removes direct database access from the product path, and reuses existing Platform3 primitives for auth, tenant scope, audit, data dictionary, list/detail reads, and convergence. A third consumer API or ledger-only JSON model would duplicate module ownership and leak platform work back to apps.

Alternatives and tradeoffs

direct database reads Fast to wire, but makes a Vercel app depend on service-level Postgres access and bypasses the Platform3 product contract.
third consumer API surface Could hide tables, but duplicates the 1EdTech/Alpha split and creates a competing place for Content, Results, Events, and Analytics answers.
governed producer surface Requires data dictionary and readback work, but preserves provenance while routing customer-facing answers through existing Platform3 owners.

Downstream rules

  • The Platform3 data dictionary must cover every field and projection rule for incept.incept_event_ledger, incept.incept_loop_runs, incept.incept_event_artifacts, incept.incept_quality_bars, incept.incept_model_grid_evidence, incept.incept_customer_feedback, incept.incept_repair_attempts, incept.incept_promotion_decisions, incept.incept_external_issue_links, incept.incept_deployments, incept.incept_projection_checkpoints, incept.incept_regeneration_event_timeline_v, incept.incept_progress_projection_input_v, incept.incept_quality_grid_fact_v, incept.incept_model_grid_latest_v, incept.incept_customer_feedback_status_v, incept.incept_layer_health_v, and incept.incept_promotion_timeline_v.
  • Implementation must expose or read-register those objects through Platform3-native API/view paths with tenant enforcement, normal JWT/scopes, audit rows for privileged reads and writes, documented idempotency on write paths, and a non-service-role consumer credential path.
  • No generated student-facing artifact may exist only as Incept ledger JSON; it must have canonical Content/QTI materialization or an explicit reconciliation error.
  • Incept progress projections must be reproducible from ledger rows and projection checkpoints, and the raw DB plus data dictionary path must reach the same answer as the API/view path.
  • Incept producer events must expose governed trafficClass values: customer, goal-run, and self-test. Headline Accuracy counts only customer; owner-directed materialization and repair traffic writes goal-run; loop, reviewer, CI, and smoke-test traffic writes self-test.
  • Incept docs and skill packs must name the Platform3 API/view path as the preferred read path and direct database access as deprecated bootstrap only.
  • The Incept app's /api/customer-progress path must switch off direct SUPABASE_DB_URL access or have a verified single-adapter handoff PR ready before the issue closes.
  • public.incept_generation_runs is legacy/bootstrap compatibility only; no additional durable public.incept_* tables may be added.
  • PostgREST schema exposure alone is not the product contract if used; it must sit behind Platform3 auth, tenant, audit, and data-dictionary rules.

Trace

loop/context/incept-platform3-surface-decision.md loop/triage/inbound/2026-06-25-issue-148.md loop/triage/decisions.yaml#2026-06-25-012 platform_incept_producer_surface GitHub #148

Module Conformance Checklist

Future modules use this list to prove they inherit platform-wide truth before their own surface QC can pass.

  1. Use platform.tenant for tenant scope and never create a new per-module tenant table unless a rollback-approved compatibility bridge requires it.
  2. Keep module-specific standards data in the module schema and shared operational facts in platform.*.
  3. Register producer schemas such as incept as governed producer surfaces before any consumer app treats their rows as a product contract.
  4. Include top-level Authentication and Errors sections in every customer website.
  5. Use Problem errors and redact learner PII, secrets, raw package bytes, headers, IP addresses, and user agents.
  6. Require Idempotency-Key for documented retryable create/import/upload/async operations.
  7. Require If-Match or equivalent validators for lost-update-sensitive writes.
  8. Compute Access-Control-Allow-Methods from the matched route and advertise only the served methods plus OPTIONS.
  9. Pin the 12 API decision axes in architecture before downstream data dictionaries, customer websites, implementations, or surface QC claim conformance.
  10. Write platform.audit_log rows for writes, privileged reads, service-role operations, learner-runtime deletion, conformance/trust mutations, and authz denials.
  11. For deployed consumer handoffs, provide the stable <MODULE>_BASE_URL, matching <MODULE>_REVIEWER_JWT or consumer JWT, and <MODULE>_REVIEWER_TENANT when a module requires X-Timeback-Tenant; verify from the consumer side before closing cutover issues.
  12. Emit structured logs and metrics using platform field names and SLO dimensions.
  13. Run customer eval and rubric before advancing; roll back to the earliest flawed deliverable when a later artifact exposes a real contradiction.
  14. Build static hosted docs under OUT_DIR/site and let the driver deploy and patch canonical_url.

Design Intent And Constraints

Intent

Make the platform substrate explicit before OneRoster, Caliper, and later modules copy QTI's first-module patterns. The platform architecture is narrow: it defines shared truth, not every module's standards model.

Known reconciliation

qti.tenant predates this platform pass. The platform decision is platform.tenant; the platform data dictionary and implementation must define the migration or compatibility bridge before full surface QC.

Non-goals

This architecture does not redefine QTI XML, QTI runtime semantics, Alpha's QTI vocabulary, or conformance assertion details. Those remain owned by the approved QTI artifacts unless a reviewer orders rollback.

Benchmark bar

This attempt targets the registered architecture benchmark at loop/context/benchmarks/architecture.html, MADR's decision-record structure, and the approved QTI architecture eval's requirement for complete, traceable ITDs.