# Source Contract

Canonical docs:

- Architecture: https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/architecture
- Data dictionary: https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/data_dictionary
- Customer website: https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/customer_website
- Customer website operation contract: https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/customer_website/contract.json
- Implementation API: https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/implementation/api
- Surface QC: https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/surface_qc

Vendored source material used to build the approved surface:

- `vendor/oneroster-prior-workspace/spec_bundle/source/oneroster-csv-binding-1.2.1.html`
- `vendor/oneroster-prior-workspace/spec_bundle/source/oneroster-1.2-index.html`
- `vendor/oneroster-prior-workspace/generated/spec/oneroster-csv-tables.json`
- `vendor/oneroster-prior-workspace/contracts/oneroster-boundary.openapi.yaml`
- `vendor/oneroster-prior-workspace/docs/adr/0001-official-source-bundle.md`
- `vendor/oneroster-prior-workspace/docs/adr/0003-rest-json-is-a-projection.md`
- `vendor/oneroster-prior-workspace/docs/adr/0005-validation-and-rest-projection.md`

## Route Guidance

The customer website contract is the operation source. Fetch it when you need a full list:

```bash
curl -fsS https://platform3-andymontgomery-9773s-projects.vercel.app/oneroster/1edtech/customer_website/contract.json
```

Route families the contract currently includes:

- public demo token minting: `POST /dev/mint?tenantId=demo` and `POST /demo-token?tenantId=demo`;
- CSV evidence: `POST /imports/csv`, `GET /imports/{batch_id}`, and `POST /exports/csv`;
- list and detail reads for supported OneRoster collections;
- relationship sub-collections for classes, schools/orgs, students, and users;
- per-resource `POST`, `PUT`, `PATCH`, and `DELETE` with idempotency and ETag preconditions.

Keep the exact operation list in `contract.json`, not in this skill.

## Problem Handling

The surface returns typed RFC 7807 Problems with stable `oneroster:` codes. Branch on `code`, preserve `type`, `requestId`, and `traceId`, and show `fieldErrors[]` when present.

Examples of behavior the surface owns:

- unsupported query controls return `oneroster:unsupported_parameter`;
- invalid inputs return `oneroster:validation_failed`;
- missing `Idempotency-Key` or `If-Match` returns a precondition Problem;
- unknown records return `oneroster:not_found`.

Do not parse `detail` text as control flow.

## Write Guidance

Use idempotency for retries:

```bash
curl -fsS -X POST "$BASE_URL/categories" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-category-$(date +%s)" \
  -d '{"sourcedId":"category-demo","title":"Demo category","weight":"10"}'
```

Use `ETag` plus `If-Match` for replace, patch, and delete:

```bash
curl -i -fsS "$BASE_URL/categories/category-demo" \
  -H "Authorization: Bearer $TOKEN"

curl -fsS -X PATCH "$BASE_URL/categories/category-demo" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: patch-category-$(date +%s)" \
  -H "If-Match: <etag from detail read>" \
  -d '{"title":"Demo category patched"}'
```

The surface decides validation, duplicate behavior, audit capture, and replay semantics.

## Leak Check

Before you ship an app or report, answer these checks:

- Did I fetch the canonical docs or `contract.json` instead of inventing route coverage?
- Did all domain data come from API calls, not local seed files or copied schema tables?
- Did I avoid copying allowed-value tables and score-scale rules into app code?
- Did I let the surface handle validation, idempotency, ETags, tenant scoping, import/export evidence, Problems, and PII redaction?
- Did my output cite the customer website or data dictionary for every field or behavior claim?

If any answer is no, stop and narrow the output to surface calls and canonical docs.
