Contributing to EIS
EIS is maintained by LZX Industries and takes proposals from any maker or user of Eurorack hardware. Open an issue or a pull request at git.lzxindustries.net/lzx/eurorack-specification.
What belongs in EIS
A requirement is a shall only where, without it, a conforming product from one maker could fail to fit, power up, or work with one from another (Scope 1.1). Construction choices, product features, and factory procedures do not belong. A proposal for a new shall says which two products would stop working together without it.
How a change is made
- Edit the model first. Every requirement lives in
data/requirements.json, with the role or interface it binds and how it is verified; the document's structure (clauses, pages, prefixes, roles, interfaces, features, annexes, data files) lives indata/document.json; numbers live in the otherdata/*.jsonfiles.tools/model.pyreads them all, and nothing else lists the document's structure. Clause prose inspec/states the requirement and cites its identifier. A changed requirement gets a new identifier:data/register.lock.jsonholds the identifiers and text as last locked, andpython tools/model.py --lockrewrites it deliberately. - Run the generators and checks with
eis check(orpython -m pytest tests). The generators rewrite the register, the injected tables, and the figure cards; commit what they write. - If you touched prose, build the PDF and the site with
eis build all(needs thebuildextra andplaywright install chromium). Neither is committed; CI builds them. - A product's claim is best kept as a claim file:
eis claim eis-claim.yamlvalidates it and prints the claim line (Conformance 4.2).
Identifiers are frozen. A new requirement takes the next free number of its prefix, whatever its place in the clause; a removed requirement leaves its number unused, and the gap stays; a requirement whose meaning changes gets a new identifier. data/register.lock.json records the identifiers and their text, and eis check fails on any other change; python tools/model.py --lock rewrites it when an editor changes wording deliberately.
Editions
An edition is a tag on this repository. pyproject.toml carries the version being drafted, and every claim example names it. A claim names one edition and stays valid for it. The foreword carries the edition, its status and date, what each edition changed, and the errata; a release updates the foreword and nothing else narrates the change.
| Edition | What a later one may change |
|---|---|
vX.Y.Z |
A later vX.Y.Z+1 corrects errata only; nothing that conformed stops conforming. |
vX.Y+1.0 |
Adds requirements, features, or formats; nothing that conformed to vX.Y stops conforming. |
vX+1.0.0 |
May remove or tighten a shall. |
Identifiers are never reused, in a draft or a released edition: a removed requirement leaves its number unused, and a changed requirement keeps its identifier only when every product that met the old text meets the new one; otherwise it gets a new identifier.
Repository layout
| Folder | Holds |
|---|---|
spec/ |
The normative clauses, chapter 9 for the installer, and the front matter; requirements.md is generated |
annex/ |
The annexes; annex/README.md indexes them and says which are normative |
figures/ |
Figure cards, 1920 px wide SVG, drawn by tools/ (and by the reference repository) in the house style of tools/card.py |
data/ |
Machine-readable models and the register |
tools/ |
Generators, the builders, and eis.py, the one entry point; tools/brand/ holds the fonts and mark the PDF embeds |
tests/ |
Checks against external publications and repository hygiene; fixtures/ holds the reduced timing contract |
pyproject.toml |
The version, pinned tooling, and the eis command (pip install -e ".[build,test]") |
standard.json |
Metadata for LZX Industries' standards registry; not part of the specification |
Third-party PDFs, drawings, and solid models are not stored here; data/sources.json records where each was retrieved and its checksum. The module survey and the catalog rail sections are in the eis-reference repository. This repository keeps a copy of the survey in data/survey/, with the commit it was copied at, and tools/survey.py writes Annex F and the depth card from that copy, so eis check and eis build run with nothing else checked out. python tools/survey.py --pull refreshes the copy from an eis-reference checkout (a path, EIS_REFERENCE, or the sibling folder); the survey is edited there, never here.
Publishing
CI (.forgejo/workflows/checks.yml) runs eis check and eis build all on every push and pull request and keeps the PDFs and the site as artifacts. A tag v* is an edition: the same workflow then rebuilds the site with root-absolute links under /eis/ and uploads it, with the PDFs and design references, to web/v1/media/eis/ on the web CDN bucket, which the storefront serves at lzxindustries.net/eis. The deploy job reads four repository secrets, named as the monorepo's web CDN environment variables: LZX_WEB_CDN_S3_ENDPOINT_HOSTNAME, LZX_WEB_CDN_S3_BUCKET, LZX_WEB_CDN_S3_ACCESS_KEY_ID, and LZX_WEB_CDN_S3_SECRET_ACCESS_KEY. Nothing on a desk publishes an edition; lzx eis.publish.site in the monorepo is for previewing a draft at the same address between editions.
Style
- Plain English in short sentences. Numbers carry units, with a space before the unit and before %.
- A shall sentence names its identifier in parentheses, without the
EIS-prefix (PANEL-009); the register and the JSON carry the prefix. - There are no shoulds: a recommendation is written "EIS recommends …" and carries no identifier.
- The text describes EIS as it is. It does not narrate how the text changed, or compare EIS with standards it does not reference. Change is narrated in one place, the foreword: the edition, its status and date, a change summary per edition, and the errata. A clause never says what it used to say; the VOICE lint allows the words of change on the foreword alone.
- Tables that mirror a
data/file are generated between marker comments, not typed. - One voice: Eurorack, American spelling (catalog, color, center, aluminum, analog), and the Ω sign (75 Ω). The
VOICElist intests/links.pyis the rule and the test.