# TreadleForge A pure standard-library Python compiler for constrained rising-shed shaft-loom drafts. Supply threading and a liftplan; receive a minimum-cardinality tie-up and exact treadling, with independent output reconstruction. The useful distinction is constrained synthesis and an explicit optimality result. Ordinary WIF conversion and viewing already have alternatives, including Bower and pixeLoom. ## Contract and input `products.treadleforge.engine.run(data)` returns `{"summary": dict, "files": dict[str, str], "warnings": list[str]}`. It does not read or write files, open a network connection, or mutate input. Invalid, unsupported, proven infeasible, or budget-exhausted requests raise `ValueError`; no partial result is returned. Required fields: | Field | Accepted value | |---|---| | `shafts` | Integer 1–8 | | `threading` | 1–256 integers, each 1–`shafts`; one shaft per warp end | | `liftplan` | 1–256 nonempty arrays of distinct integers 1–`shafts` | | `max_treadles` | Integer 1–8 | | `max_press` | Integer 1–8; the actual press count cannot exceed available treadles | | `loom` | Exactly `"rising-shed"` | Optional fields: | Field | Accepted value | |---|---| | `search_budget` | Integer 1–2,000,000; default 500,000 deterministic search steps | | `orientation` | Exactly `"warp-left-to-right,picks-top-to-bottom"`; also the default | The product of warp ends and picks must not exceed 16,384. Unknown fields, booleans masquerading as numbers, floats (including NaN/infinity), strings as numbers, empty lifts, repeated shafts within a lift, reversed orientations, and other loom types are refused. Repeated picks and repeated threading shafts are permitted. Lift order within a pick is immaterial; pick sequence is preserved. Shafts are numbered from one; threading index one is the leftmost end; pick one is the topmost row. No automatic reflection, rotation, or shed inversion occurs. Example: ```json {"shafts": 3, "threading": [1,2,3,1], "liftplan": [[1],[2],[1,2]], "max_treadles": 3, "max_press": 2, "loom": "rising-shed"} ``` This case needs two treadles, raising shaft one and shaft two separately, with both pressed on the final pick. ## Exact search Encode each shaft set as a positive bitmask. The candidate set contains every nonempty subset of any requested lift. This pruning is exhaustive: any used treadle in a rising-shed union solution must be contained in a lift where it is pressed. Empty and never-used treadles cannot improve the minimum. Enumerate treadle counts in increasing order. Skip a count only if the number of permitted nonempty press combinations is smaller than the number of distinct target lifts. For each remaining count, enumerate all candidate bases in ascending numeric bitmask order. For each basis, enumerate press combinations by increasing press count then lexicographic treadle index order; OR the corresponding shaft masks. A basis is feasible exactly when every target lift occurs. The first feasible basis is minimum in treadle count because every smaller count was excluded by a necessary lower bound or exhausted. Search need not exceed the number of distinct lifts, since assigning one treadle to each lift is always a logical solution when the treadle limit permits it. Tie-breaking is reproducible: the first numeric-bitmask basis wins, then each pick uses the fewest presses within that basis and the first lexicographic press tuple. The objective is minimum treadle count, not global treadle-force or foot-motion optimization. A search step is one candidate-submask visit, one basis visit, or one bitmask OR during press reconstruction. The next step beyond the budget raises `SEARCH_BUDGET_EXCEEDED`, explicitly reporting feasibility and optimality UNKNOWN. The bounded validation, candidate sorting and artifact rendering are outside that counter. Exhausting every admissible basis instead raises `INFEASIBLE`. No heuristic solution is labeled optimal and no nonoptimal artifact is silently returned. Worst-case search is combinatorial; larger valid inputs can be refused by budget. ## Outputs and independent check - `draft.wif`: WIF 1.1 tie-up/treadling draft with explicit rising shed and two colors. - `drawdown.svg`: dark warp-up cells, light weft-up cells, orientation text. - `threading.csv`, `tieup.csv`, `treadling.csv`: numbered setup and pick instructions. - `proof.json`: source and reconstructed matrices, lifted shafts for every pick, matrix and WIF SHA-256 digests, comparison counts and optimization search trace. - `report.txt`: human-readable minimum, press bound, comparison counts and limitations. `products.treadleforge.verifier.verify_wif(source, text)` reparses the emitted WIF with a strict INI parser and uses Python sets independently of the synthesis bitmasks. It checks required output sections, their CONTENTS declarations, identity, rising shed, dimensions, numbered structure rows, bounds, duplicates, exact threading, press bounds, and lifted shaft sets for every pick—including shafts absent from threading. It then compares every reconstructed cloth cell against the source. A mismatch raises `ValueError` before artifacts are returned. SHA-256 equality is supplementary evidence; it does not replace the explicit comparisons. This verifier accepts the emitted profile, not arbitrary WIF files. ## WIF source and scope Format reference fetched during implementation: [Bower's annotated WIF 1.1 reference](https://asunder.co/app/bower/articles/wif-file-specification). The exporter supplies the WIF identity, CONTENTS, dimensions, threading, tie-up, treadling and palette sections. Structural entries use one-based comma-separated indices, and `Rising Shed=true` states that listed shafts rise. Export omits LIFTPLAN to avoid ambiguous control paths. The reference reports core-section support in Bower; no consumer application was exercised here. The original Maple Hill page and its linked historical text could not be fetched by the browsing tool. No round-trip compatibility claim is made. ## Limits No arbitrary WIF import, falling-shed, counterbalance/countermarch mechanics, dobby/Jacquard control, multi-shaft threading, color input, floating-thread end, empty lift, yarn physics, fabric stability, treadle force, or ergonomic optimization. All-shafts-up picks are preserved with a warning. A logically exact draft can still be unsuitable for a particular physical loom or textile. Run `products/treadleforge/SMOKE.sh` from the repository. Its success marker is printed only after unittest exits successfully.