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.
Metadata
Release files for snapgate 0.1.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 | |
|---|---|---|---|
| snapgate-0.1.0.tar.gz | 29.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| snapgate-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.2 kB
Release files / snapgate-0.1.0.tar.gz
| Download URL | snapgate-0.1.0.tar.gz |
|---|---|
| Size | 29.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0445295e9160465c44b49570f81a6f8dc2a44ea1d6cac7b5de9aa809ae6ff265
|
|
BLAKE2b-256 checksum How to use checksums |
743d98283d262d6352f1faf430c1f570d1c423ea47b16f104a1270ffe54f2d84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / snapgate-0.1.0-py3-none-any.whl
| Download URL | snapgate-0.1.0-py3-none-any.whl |
|---|---|
| Size | 20.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bdde91945346db4f9d529f5b5379c96899ffe053ecca67794edce827b3b51139
|
|
BLAKE2b-256 checksum How to use checksums |
4b9ae2268ddbd4f979254a85ff607bc45a839a821f6fba8f59b66840164c87a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|