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.
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 pattern | Platform promotion | ITD |
|---|---|---|
| qti.* schema ownership | Module schemas are mandatory for every standards module. | PITD-002 |
| qti.tenant | Promoted to platform.tenant; QTI requires explicit reconciliation. | PITD-003 |
| Bearer JWT and tenant claim matching | Shared platform auth and tenant scoping contract. | PITD-005 |
| Top-level Authentication and Errors sections | Required in every customer website. | PITD-006 |
| Route-scoped CORS correction | Open-origin CORS advertises only matched route methods plus OPTIONS. | PITD-019 |
| Idempotency-Key and If-Match | Shared retry and optimistic concurrency policy. | PITD-007 |
| candidate_ref / studentRef privacy | General student-data privacy policy for all modules. | PITD-008 |
| Conformance runner rollback | Conformance claims require real evidence, not fabricated status. | PITD-016 |
| Alpha cut/restrict/rename/extend pattern | Required divergence vocabulary for every Alpha surface. | PITD-015 |
| Vercel driver-deployed hosted docs | Shared documentation identity and master index policy. | PITD-011 |
| Customer eval plus scoring rubric | Platform-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.
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 surface | Governed objects | Consumer contract | Decision |
|---|---|---|---|
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
}
| Status | Name | Platform meaning |
|---|---|---|
200 | OK | Successful read or command that returns a completed resource. |
201 | Created | Synchronous create that returns the newly created resource. |
202 | Accepted | Import, conformance, export-job, or other accepted work that may complete asynchronously. |
204 | No Content | Successful deletion or command with no response body. |
400 | Bad Request | Malformed JSON, invalid field shape, invalid pseudonymous learner ref, unsupported profile, or validation problem documented as caller-fixable. |
401 | Unauthorized | Missing, malformed, expired, untrusted, or unsigned Bearer JWT. |
403 | Forbidden | Authenticated principal lacks tenant, role, scope, service-role, or operation authorization. |
404 | Not Found | Resource is absent or not visible inside the authenticated tenant scope. |
409 | Conflict | Idempotency conflict, stale version state, duplicate unique key, or conflicting lifecycle transition. |
412 | Precondition Failed | A documented conditional request precondition evaluates false. |
428 | Precondition Required | A mutation that requires If-Match or equivalent precondition omitted it. |
5xx | Server Error | Unexpected 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.
| Axis | Status | Decision | Alternatives and tradeoffs | Downstream rules | Re-open trigger | ITD |
|---|---|---|---|---|---|---|
| write granularity | 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. |
|
| 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 shape | 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. |
|
| 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 model | 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. |
|
| 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 model | 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. |
|
| 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 model | 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. |
|
| 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 shape | 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 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. |
|
| Re-open platform-wide domain claims only after two modules independently require the same claim with the same semantics. | PITD-025 |
| eventing model | 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. |
|
| 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 envelope | 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. |
|
| 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 routing | 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. |
|
| 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 evidence | 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. |
|
| 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 / retention | 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. |
|
| 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 endpoints | 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. |
|
| 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.
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
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
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
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
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
Security
PITD-005: Authentication, Authorization, And Tenant Scope
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
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_JSONis 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, andexp;personIdscontains 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_SECRETand 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
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
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
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
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
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
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
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
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
Operations
PITD-010: Observability, Metrics, And SLOs
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
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
Docs
PITD-011: Hosted Documentation Identity
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
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
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
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
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
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
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
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
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
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
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
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
Persistence
PITD-017: Migrations And DDL Discipline
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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_JSONlists 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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, andincept.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
trafficClassvalues:customer,goal-run, andself-test. Headline Accuracy counts onlycustomer; owner-directed materialization and repair traffic writesgoal-run; loop, reviewer, CI, and smoke-test traffic writesself-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-progresspath must switch off directSUPABASE_DB_URLaccess or have a verified single-adapter handoff PR ready before the issue closes. public.incept_generation_runsis legacy/bootstrap compatibility only; no additional durablepublic.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.
- Use platform.tenant for tenant scope and never create a new per-module tenant table unless a rollback-approved compatibility bridge requires it.
- Keep module-specific standards data in the module schema and shared operational facts in platform.*.
- Register producer schemas such as
inceptas governed producer surfaces before any consumer app treats their rows as a product contract. - Include top-level Authentication and Errors sections in every customer website.
- Use Problem errors and redact learner PII, secrets, raw package bytes, headers, IP addresses, and user agents.
- Require Idempotency-Key for documented retryable create/import/upload/async operations.
- Require If-Match or equivalent validators for lost-update-sensitive writes.
- Compute Access-Control-Allow-Methods from the matched route and advertise only the served methods plus OPTIONS.
- Pin the 12 API decision axes in architecture before downstream data dictionaries, customer websites, implementations, or surface QC claim conformance.
- Write platform.audit_log rows for writes, privileged reads, service-role operations, learner-runtime deletion, conformance/trust mutations, and authz denials.
- 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.
- Emit structured logs and metrics using platform field names and SLO dimensions.
- Run customer eval and rubric before advancing; roll back to the earliest flawed deliverable when a later artifact exposes a real contradiction.
- 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.