Godstrument/test_factory.py
type-two 7e568d8323 ✦ revelation: CANON — factory dimensions (Stage 2C)
Four shipped patches on a read-only shelf: ✦ the heartbeat (boom-bap,
mpc 8-4, kick duck), ✦ the wheel within the wheel (WHEELS polymeter —
kick 16 / hat 12 / clap 10), ✦ the squeeze (GODSQUASH — the market &
quakes pump the master), ✦ quiet arrival (gentle earth-echo ambient,
no drums). git-tracked in factory/, authored in the client's
serializePatch shape.

Course-correction from the brief's stale anchor: the template select
reads /api/presets (account-based, auth.py), NOT the hub's legacy
patchList — so the factory shelf is injected there. list_factory() +
load_factory() prepend the ✦ patches for every signed-in player;
PUT/DELETE on a ✦ name → 403 (read-only); a missing factory/ degrades
to []. test_factory.py (deploy-excluded) validates shape.

Verified: HTTP dispatch serves the 4 ✦ names leading the list, loads
one, rejects writes (403), user saves still work, traversal/missing →
None, zero index.html changes. Taste disclaimer: these are structural
drafts — correct shape is the deliverable, beauty is the human's.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:13:38 +10:00

92 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""test_factory.py — validate the ✦ CANON factory patches' SHAPE.
Not a taste check (the human re-voices by ear) — this asserts every factory
patch loads cleanly through the client's migrateSeq expectations: 16-step seq
arrays, wlen in 1..16, sane bpm, valid route/groove/scale shape, and a
✦-prefixed name. Stdlib only; excluded from the deploy by the test_*.py filter.
python3 test_factory.py
"""
import json
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
FACTORY = os.path.join(HERE, "factory")
SCALES = {"chromatic", "major", "minor", "dorian", "phrygian", "lydian",
"mixolydian", "pentatonic", "minor_pent", "wholetone", "hirajoshi"}
SEQ_ARRAYS = ("steps", "vel", "chance", "rat", "lock", "len")
def check_seq(key, s, errs):
for a in SEQ_ARRAYS:
if a in s:
if not isinstance(s[a], list) or len(s[a]) != 16:
errs.append(f"{key}.{a} must be a 16-length array")
if "steps" not in s or not isinstance(s.get("steps"), list) or len(s["steps"]) != 16:
errs.append(f"{key}.steps missing/not-16 (migrateSeq would reject → dropped)")
if "wlen" in s and not (isinstance(s["wlen"], int) and 1 <= s["wlen"] <= 16):
errs.append(f"{key}.wlen must be an int 1..16, got {s.get('wlen')!r}")
if "on" in s and not isinstance(s["on"], (bool, int)):
errs.append(f"{key}.on must be boolean-ish")
def check_patch(name, p, errs):
if not isinstance(p.get("bpm"), (int, float)) or not (40 <= p["bpm"] <= 180):
errs.append(f"bpm must be 40..180, got {p.get('bpm')!r}")
for r in p.get("routes", []):
if not r.get("source") or not r.get("dest"):
errs.append("route missing source/dest")
if not isinstance(r.get("amount"), (int, float)):
errs.append(f"route {r.get('source')}{r.get('dest')} amount not numeric")
for key, s in (p.get("seqs") or {}).items():
check_seq(key, s, errs)
sc = p.get("scale") or {}
if sc and sc.get("name") not in SCALES:
errs.append(f"scale.name {sc.get('name')!r} not a known scale")
gr = p.get("groove") or {}
for k in ("swing", "humanize", "velo"):
if k in gr and not (0 <= gr[k] <= 1):
errs.append(f"groove.{k} out of 0..1")
def main():
if not os.path.isdir(FACTORY):
print("FAIL: no factory/ dir"); sys.exit(1)
files = sorted(f for f in os.listdir(FACTORY) if f.endswith(".json"))
if len(files) < 4:
print(f"FAIL: expected ≥4 factory patches, found {len(files)}"); sys.exit(1)
total_errs = 0
names = []
for fn in files:
with open(os.path.join(FACTORY, fn), encoding="utf-8") as f:
obj = json.load(f)
name, data = obj.get("name", ""), obj.get("data")
errs = []
if not name.startswith(""):
errs.append(f"name {name!r} must start with ''")
if not isinstance(data, dict):
errs.append("missing 'data' object")
else:
check_patch(name, data, errs)
names.append(name)
if errs:
total_errs += len(errs)
print(f"{fn}: " + "; ".join(errs))
else:
nseq = len(data.get("seqs") or {})
nroute = len(data.get("routes") or [])
print(f"{name} (bpm {data['bpm']}, {nseq} seqs, {nroute} routes)")
# the four the brief names
for want in ("✦ the heartbeat", "✦ the wheel within the wheel", "✦ the squeeze", "✦ quiet arrival"):
if want not in names:
print(f" ✗ missing canonical patch: {want}"); total_errs += 1
if total_errs:
print(f"\nFAIL: {total_errs} shape error(s)"); sys.exit(1)
print(f"\nALL {len(files)} FACTORY PATCHES VALID (shape only — beauty is the human's)")
if __name__ == "__main__":
main()