@deterministic-code/deterministic-specifications
v0.3.0
Published
Canonical YAML contract (JSON Schema) for the deterministic code generator: the specs consumers author against and emitters read.
Maintainers
Readme
deterministic-specifications
The canonical YAML contract for the deterministic code generator. Files under backend/ and frontend/ named *.spec.yaml are strict JSON Schema (draft 2020-12, authored in YAML) that define the shape of one authored deterministic/*.yaml file. backend/types.yaml is the language-agnostic field-type catalog (default-value tokens and numeric ranges), not a schema.
The specs
| Spec | Governs | Purpose |
| --- | --- | --- |
| backend/datasource-types.spec.yaml | datasource_types.yaml | The physical data model — tables, fields, indexes, FKs. |
| backend/types.yaml | field default_value tokens and ranges | Language-agnostic field-type catalog. Shape locked by backend/types.spec.yaml. |
| backend/datasource-seeds.spec.yaml | datasource_seeds.yaml | Seed rows for datasource tables. Validated against datasource_types.yaml. |
| backend/view-types.spec.yaml | view_types.yaml | View shapes composed from datasource tables and other views. |
| backend/routes.spec.yaml | routes.yaml | The authored HTTP route surface. |
| backend/routes-api.spec.yaml | routes-api IR | Flattened API catalog from expandRoutes (OpenAPI / GraphQL / proto source). |
| backend/services.spec.yaml | services.yaml | Service classes resolved via DI at app bootstrap. |
| backend/app.spec.yaml | backend-app.yaml | Express app bootstrap — middleware, statics, tail handlers. |
| frontend/bindings.spec.yaml | frontend_bindings.yaml | External datasources a frontend binds to (REST/GraphQL). |
Samples
Kitchen-sink documents under samples/valid/ exercise every property, enum, const, oneOf branch, and pattern in the live specs. samples/invalid/ holds one document per independently observable schema constraint; together they must fail validate(). Both suites live in validators/typescript/test/samples.integration.test.ts.
Readable apps live under examples/: examples/minimal/ (required keys only) and examples/tasks/ (a small user/project/task contract). examples/errors/ is a human-curated gallery of typical authoring mistakes — one per file — not the exhaustive mutant dump.
Conventions
- Every authored document must declare a
versionsemver (today:1.0.0). Unknown keys are rejected (additionalProperties: false) so typos fail loudly rather than being silently ignored. - Shared identifier patterns (
^[a-z_][a-z0-9_]*$), thefile:/id:/uuid:/user_id+nameinclude machinery, and thecombine_optionsmerge transforms recur across several specs. - Schema shape is only the first gate; several specs pair with a semantic layer (cross-document reference checks, merged-settings validation) in the consuming generator.
Versioning
The live contract is 1.0.0. It lives at the repo root as three sibling folders:
backend/ # live specs
frontend/
validators/typescript/src/validators/ # live engines + testsEvery authored deterministic/*.yaml document must declare an exact semver. There is no floating alias:
version: 1.0.01.0.0(the live version) binds to the root specs and the livevalidators/typescript/src/validators/engines.- Any other published semver binds to
versions/<semver>/, which containsbackend/,frontend/, andvalidators/engines.ts. After a bump,1.0.0falls back to that archive if the live tree is gone.
Validators require version and pin to it: a 1.0.0 engine rejects any other value. A missing or non-semver version is a validation error before an engine is loaded.
Root spec files start with version: 1.0.0. Each frozen copy is stamped with version: <semver> and a versioned $id. Each frozen engine is pinned to that semver.
Archive a new version by moving the live specs and engine file:
npm run bump-version -- 1.1.0That relocates backend/, frontend/, and validators/typescript/src/validators/engines.ts into versions/1.1.0/, stamps the specs, and rewrites the engine so it stays pinned to 1.1.0. Live tests stay at repo root and keep covering every archived version. After a bump, set LIVE_VERSION to the next unpublished semver when re-authoring the live tree. Bumps are infrequent and take an explicit semver — no auto-increment.
The TypeScript validator suite enumerates every folder under versions/ and fails if any published version is missing specs or validators/engines.ts.
These are contract files: adding a field, key, x- extension, or op annotation is a deliberate contract change. Freeze a new semver before changing the live specs so existing documents stay valid against their pinned snapshot.
