Correct-by-construction generation: one projection bottleneck, content-addressed recipes, and an exhaustive sweep that proves the invariant holds everywhere.
Project description
snapgate
Correct-by-construction generation. Write sloppy generators; get provably-correct output — one projection function makes every artifact valid by construction, one recipe hash makes it reproducible forever, one exhaustive sweep proves the invariant holds across the whole parameter space.
Zero dependencies. Python ≥ 3.10. Apache-2.0.
pip install snapgate
The pattern
Most constrained-generation code tries to make every generator perfect, then samples the output space with tests and hopes. snapgate inverts both moves:
-
Project, don't perfect. Generators are allowed to be approximate. Every artifact passes through one total projection —
project(x, constraint)— at a single emission chokepoint. The domain suppliescontains(x)andnearest(x); the framework guarantees totality, idempotence, and that an already-valid artifact is never disturbed. Holding aProjected[T]is the proof the value crossed the chokepoint; nothing else can construct one. -
Hash the recipe, not the artifact. An artifact's identity is the content hash of the recipe that produces it. The
Ledgerstores recipes — never artifacts — andrecall(id)re-generates the exact artifact and verifies its content hash. A good result can never be lost, because the description of how it was made is the result. -
Sweep, don't sample.
sweep(axes, generate, gates)enumerates the full Cartesian product of your parameter space and classifies every case per gate:PASS/LEAK(invariant violated) /SKIP(gate not applicable) /ERROR. Fail-closed exit code, JSON report, per-axis pass-rate breakdown. Not a sample — the whole surface.
This pattern was extracted from a private production generation system where it has held a hard domain invariant over an exhaustive combinatorial sweep of several hundred thousand cases, in CI, at zero leaks. snapgate is the pattern with the domain removed.
Sixty seconds
from snapgate import Gate, project, sweep
# 1. Your domain constraint: membership + your own notion of "nearest valid".
class MultipleOf:
def __init__(self, k): self.k = k
def contains(self, x): return x % self.k == 0
def nearest(self, x): return round(x / self.k) * self.k
# 2. A sloppy generator, made correct at the chokepoint.
def generate(case):
raw = case["a"] * 7 + case["b"] # no attempt to stay valid
return project(raw, MultipleOf(12)).value # valid by construction
# 3. Prove it over the WHOLE space, not a sample.
report = sweep(
axes={"a": range(100), "b": range(100)}, # all 10,000 cases
generate=generate,
gates=[Gate("multiple-of-12", lambda case, x: x % 12 == 0)],
)
assert not report.failed
print(report.summary())
And reproducibility:
from snapgate import Ledger, Recipe, rng_for
def generate(recipe):
rng = rng_for(recipe) # ONLY source of randomness
return [rng.randint(0, 127) for _ in range(recipe.config["n"])]
ledger = Ledger("ledger.jsonl", generate=generate)
entry = ledger.record(Recipe("root", {"n": 8, "mood": "bright"}))
# ...months later, artifact long deleted:
artifact = ledger.recall(entry["id"]) # exact reconstruction, hash-verified
The laws
All normative, all executable (tests/test_laws.py, property-based via Hypothesis):
| # | Law | Statement |
|---|---|---|
| 1 | Totality | Projection against a satisfiable constraint always yields a valid value |
| 2 | Identity | An already-valid candidate is returned unchanged |
| 3 | Idempotence | Projecting twice equals projecting once |
| 4 | Determinism | Equal recipes ⇒ equal ids ⇒ equal artifact content hashes |
| 5 | Recall integrity | A ledger recall reproduces the exact artifact or raises |
| 6 | Sensitivity | A constraint-violating artifact reaching its gate is LEAK, never PASS |
Law 6 matters most: a proof harness you never saw catch anything proves nothing. Both
shipped examples include a deliberately-broken generator variant that the sweep must
catch, run in CI (tests/test_sensitivity.py).
Examples (two domains, same three primitives)
-
examples/palette— WCAG-contrast-safe color palettes. Constraint: every text/background pair meets its WCAG 2.x contrast ratio (4.5:1 normal, 3:1 large), computed, never eyeballed.nearestwalks lightness to the closest compliant color. The sweep enumerates hue × lightness × role combinations and proves 0 violations. -
examples/budget— conservation-constrained budget allocation. Constraint: channel allocations sum exactly to the total and respect per-channel min/max.nearestis a bounded redistribution. The sweep enumerates budget levels × channel mixes × bound profiles and proves conservation everywhere.
Run either:
snapgate sweep examples/palette/spec.py --json palette-report.json
snapgate sweep examples/budget/spec.py
Exit code is non-zero on any LEAK or ERROR — a sweep drops into CI as-is.
CLI
snapgate sweep <module-or-file> [--json PATH] [--progress N] [--breakdown GATE:AXIS]
A spec module declares AXES (mapping of axis name → values), GATES (list of
snapgate.Gate), and generate(case) -> artifact.
When to reach for this
- Generated output must satisfy a hard validity rule (schema, range, physical constraint, style rule, legal window) with zero tolerance for leaks.
- You need generated artifacts to be exactly reproducible months later without storing them.
- Your parameter space is finite and enumerable, and "we tested some of it" isn't good enough.
What this is not
- Not a solver:
nearestcomes from your domain knowledge, snapgate just makes its application total, witnessed, and proven. - Not property-based testing: Hypothesis samples cleverly; a sweep enumerates exhaustively. Use both (snapgate's own laws are Hypothesis-tested).
Spec
The full normative specification, RFC-2119 style: SPEC.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file snapgate-0.1.0.tar.gz.
File metadata
- Download URL: snapgate-0.1.0.tar.gz
- Upload date:
- Size: 29.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0445295e9160465c44b49570f81a6f8dc2a44ea1d6cac7b5de9aa809ae6ff265
|
|
| MD5 |
4728fd4fe0626a52f31c203ded38e1df
|
|
| BLAKE2b-256 |
743d98283d262d6352f1faf430c1f570d1c423ea47b16f104a1270ffe54f2d84
|
File details
Details for the file snapgate-0.1.0-py3-none-any.whl.
File metadata
- Download URL: snapgate-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdde91945346db4f9d529f5b5379c96899ffe053ecca67794edce827b3b51139
|
|
| MD5 |
f718dd696653beebc632826fa390388f
|
|
| BLAKE2b-256 |
4b9ae2268ddbd4f979254a85ff607bc45a839a821f6fba8f59b66840164c87a7
|