easy-cheese-schemas
The machine-readable artifact contracts of easy-cheese, published as an installable package: run manifests, decompositions, curd blocks, PR plans, and the readiness gate, as attrs types with cattrs structuring and explicit schema-version tolerance.
pip install easy-cheese-schemas
Requires Python 3.11 or newer. cattrs floors at 3.10; 3.11+ skips the exceptiongroup dependency, and 3.10 reaches end of life in October 2026.
Package boundary
easy_cheese_schemas defines shared contracts, not workflow execution.
It owns types, invariants, pure normalization, validation, canonical serialization, and schema generation.
Pure planner materialization stays here because it transforms supplied values without dispatch or artifact access.
Runtime consumers depend on schemas; schemas must not depend on runtime consumers.
| Responsibility | Owner |
|---|---|
| Planner, Cook, Cure, and callback execution | easy_cheese.shared.workflow |
| Artifact resolution, verification, and local retention | easy_cheese.shared.artifacts |
| Artifact publication and handoff acceptance | easy_cheese.shared.publication |
| Repository benchmarks and build compilers | scripts/ |
Import runtime functions from their owning module.
The schema package does not provide compatibility re-exports. Runtime callback records and exceptions stay with their runtime module. Persisted semantic contracts stay in schemas.
Mold-to-Cook boundary values
Mold hands bound work to Cook through direct references, not a published
schema. A ready finalization carries request_id, spec_ref,
planner_result_ref, plan_ref, and exact MoldCookCoverage. The host
validates every reference before any writer runs. CookSetupAuthorization is
limited to its named prerequisite curd, authorized paths, and authorized
commands; setup evidence does not clear unrelated holds. Partial coverage
preserves the acknowledged unresolved work until it is completed or explicitly
disposed.
What this is, and what it is not
It is the artifact vocabulary: the types an external producer or consumer needs to write or read an easy-cheese document without reimplementing its field rules.
The schema package is the canonical enforcement path for the structural and collection invariants listed above. load and validate_contract structure and validate versioned values before a producer or consumer can treat them as contracts. Runtime modules still own checks that require artifact resolution, execution context, or phase state; those remain listed below. A successful Loaded is necessary but does not by itself grant execution authority.
These are versioned canonical models, not derivatives of older hand-rolled validators. The package has no compatibility re-exports; callers use explicit runtime boundary validators when artifact or phase evidence is required.
Also not published: easy-cheese's corpus and layout assumptions (paths.py) and the findings report grammar. Those are repo-internal and stay unversioned on purpose.
Runtime-owned checks
The types check field shape and the collection invariants below, while runtime validators retain checks that need resolved evidence or current phase state.
Enforced here: required fields and their types, enum membership, curd file-disjointness, wiring DAG acyclicity and unknown W<n> references, wave size and curd surface floors, and the PR-plan shape rules.
Not enforced here, and checked only by the runtime validators:
agent_resolutionconsistency — exactly one accepted attempt; the resolved agent matching that attempt; attempt and resolved power meeting the request'sminimum_power; prompt-only permission enforcement implyingdegradedand a read-only request; an unknown resolved power implyingdegraded; a preferred-exact acceptance carrying a nullfallback_reason(and a non-preferred one carrying a reason).- Phase-dependent requirements —
phaseofpost_review_completeorpr_publish_completerequiringcurrent_review/post_review. - Curd lifecycle — a curd with
status: completedrequiringreview_context.
These checks intentionally remain with runtime modules because they require resolved evidence or current phase state; they are not a temporary migration gap.
Usage
load structures a raw mapping into one of the artifact types. It never raises: it returns a Loaded carrying the value (or None), the payload's provenance, and every problem it found, in the same where.key must be ... format easy-cheese's validators emit.
from easy_cheese_schemas import PrGroup, load
plan = {
"schema_version": 1,
"branch": "feat/publish",
"title": "Publish the schemas package",
"base": "main",
"commits": ["9f2c1ab"],
}
strict = load(plan, PrGroup, strict=True)
print(strict.provenance, strict.problems)
print(strict.value)
# Written by a newer producer: unknown fields are ignored, the rest still parses.
newer = load(plan | {"schema_version": 2, "reviewers": ["ada"]}, PrGroup, strict=True)
print(newer.provenance, newer.value.branch)
# Lenient: gaps are reported, not raised, and the value is still usable.
lenient = load(plan | {"depends_on": None}, PrGroup, strict=False)
print(lenient.provenance, lenient.problems)
print(lenient.value)
Provenance.CURRENT ()
PrGroup(branch='feat/publish', title='Publish the schemas package', base='main', commits=['9f2c1ab'], body=None, depends_on=[])
Provenance.FUTURE feat/publish
Provenance.CURRENT ('PrGroup.body must be present; using default', 'PrGroup.depends_on must be a list, not NoneType')
PrGroup(branch='feat/publish', title='Publish the schemas package', base='main', commits=['9f2c1ab'], body=None, depends_on=[])
Problems accumulate; load reports every one it found in a single pass rather than stopping at the first, because the callers reporting them to a human need the whole list. problems is a tuple[str, ...] — Loaded is frozen, and a mutable list on a frozen carrier is an invitation to edit the evidence.
Values are not type-coerced. A str where a list[str] belongs is a problem, not eight one-character paths; "no" where a bool belongs is a problem, not True. Reading a document is how you find out whether to trust it, so this layer reports the mismatch rather than papering over it.
One case returns a value and problems: a schema_version stamp that is not an integer is recorded as a problem and the payload is treated as UNSTAMPED, because an untrustworthy stamp is not a reason to discard an otherwise readable document. Callers that gate on value is not None should check problems too.
The schema_version contract
SCHEMA_VERSION = 4 # what this package writes and fully understands
MIN_READABLE = 1 # oldest stamp still readable; widens as the schema evolves
STAMP_KEY = "schema_version"
The real coupling is the data boundary, not the code boundary. A vendored bundle is internally consistent by construction — it ships its own copy of these types — but persisted artifacts in the durable corpus outlive the upgrade that rewrote the reader, and external producers are the entire point of publishing. So every payload carries its vintage, and a reader can tell what it is holding before it acts on it.
classify_stamp maps the stamp to one of five outcomes:
| Provenance | Stamp condition | Meaning |
|---|---|---|
CURRENT |
stamp == SCHEMA_VERSION |
Written against this exact schema. |
PRIOR |
MIN_READABLE <= stamp < SCHEMA_VERSION |
One or more versions behind, still readable — the N-1 tolerance. |
UNSTAMPED |
key absent (or present but not an int, which is also reported as a problem) |
No stamp. Normal for a hand-authored document, foreign for a manifest. |
STALE |
stamp < MIN_READABLE |
Older than this reader supports. |
FUTURE |
stamp > SCHEMA_VERSION |
Written by a newer easy-cheese. |
FUTURE is not a rejection. Recognized fields parse, unknown fields are ignored, and the caller gets provenance=FUTURE so it can decide whether to act, warn, or refuse. Provenance is orthogonal to validity: a FUTURE payload can still be structurally invalid, and a CURRENT one can still collect problems.
Two-tier strictness by artifact class
load does not decide strictness — strict is the caller's keyword argument. The tiers are a convention about which default each artifact class deserves:
- Markdown documents (specs, findings, handoffs) are hand-authored and hand-edited. A missing stamp is normal, so they are read lenient: documented defaults are filled in, every gap is recorded in
problems, and the caller still gets a usable value. - JSON/YAML manifests are machine-written. A missing stamp means the payload is foreign, so they are read strict: full cattrs validation, with the raised exception group flattened into
problemsandvalue=Noneon failure. An explicit--laxescape exists at the CLI boundary for the case where a human is knowingly hand-repairing a manifest.
Stability policy
The package is semver'd, and the version governs the artifact contracts, not just the Python API. SCHEMA_VERSION and the package version move independently: a schema bump is always a major bump, but not every major bump is a schema bump.
- Patch — no contract change. Bug fixes, problem-message wording, documentation.
- Minor — additive only. New optional fields, new types, new exports. Every artifact a previous minor could write is still read as
CURRENT, and every artifact a previous minor could read still parses. - Major — a breaking contract change: a removed or renamed field, a narrowed type, a field made required, or a raised
MIN_READABLE. Accompanied by aSCHEMA_VERSIONbump, so previously-written artifacts becomePRIORorSTALErather than silently misparsing.
The additive-only discipline is what makes FUTURE provenance safe, and it is a hard rule, not a preference. Because unknown fields are ignored, an older reader handed a newer artifact will silently drop anything it does not recognize. That is correct behavior when new fields are additive and optional, and it is data loss when they are not — the older reader would produce a value that looks complete and is not. So within a SCHEMA_VERSION, new fields must be additive and optional. Anything else waits for the major bump.
Pre-1.0 caveat: while the version is 0.x, minor bumps may break. The policy above binds from 1.0.
Releasing (repo owner)
A pending publisher must exist on PyPI before the first publish. Publishing uses PyPI Trusted Publishing (OIDC), so no long-lived token is stored in the repository — but that means PyPI has to be told, in advance, which workflow in which repository is allowed to publish. Create the pending publisher on PyPI with the project name, the repository, and the publishing workflow's filename. This is a one-time manual step and it cannot be automated: without it, the first release run fails at upload.
After that, releases are automatic — a version bump to pyproject.toml landing on main triggers the publish.
License
MIT.
Metadata
Release files for easy-cheese-schemas 3.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| easy_cheese_schemas-3.0.0.tar.gz | 82.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| easy_cheese_schemas-3.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 171.8 kB
Release files / easy_cheese_schemas-3.0.0.tar.gz
| Download URL | easy_cheese_schemas-3.0.0.tar.gz |
|---|---|
| Size | 82.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
29e5d8b384db715613e7aaa069079db68678707d121140ba9ae600c78a39e076
|
|
BLAKE2b-256 checksum How to use checksums |
7a59724bd141a28bb1d7dfda195011637f18c0551f88a0663929872fdd59ca95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / easy_cheese_schemas-3.0.0-py3-none-any.whl
| Download URL | easy_cheese_schemas-3.0.0-py3-none-any.whl |
|---|---|
| Size | 89.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f76190e6b0d7b71a6f975f12afbcd19416a9bca9ef8869dc3d99a6cc137bb5bf
|
|
BLAKE2b-256 checksum How to use checksums |
8ed817a514f282d493a7a01dc9d4925045a1f5fbfb42ffabbab91bb8dcd4d7c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logSecurity for easy-cheese-schemas 3.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for easy_cheese_schemas-3.0.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.