3. Quality
Context and Problem Statement
Quality is legible when every contributor can run the same small, deterministic gates. LychD needs correctness, style, static contracts, repeatable dependencies, and release-client checks without accumulating overlapping toolchains or treating a passing local command as host proof.
Decision Outcome
LychD uses uv to resolve, lock, and run Python tooling; Ruff for linting and formatting; and
BasedPyright in strict mode for src/lychd. pytest is the test engine specified by
ADR 04. The repository's Makefile is the shared command grammar.
The older Poetry + mypy + Flake8 + Black/isort stack remains a credible mature alternative, but it duplicates installation, configuration, and lint/format responsibility. The selected stack keeps those responsibilities explicit with fewer moving parts.
The Python Pillars
uvowns resolution, the committed lockfile, and tool execution.- Ruff owns linting and formatting, configured in
pyproject.toml. - BasedPyright checks
src/lychdunder its strict configuration. pytestsupplies regression evidence; its taxonomy and runtime limits belong to ADR 04.
uv.lock is the repository-managed environment's source of truth; project dependencies are not
managed with direct pip use. Ruff exceptions are deliberate, documented configuration rather
than reviewer folklore, and the same configured BasedPyright implementation serves local and CI
checks.
Cross-stack gates
The normal Python gates are non-mutating except the deliberate formatter command:
make lint RUFF_TARGETS="src/lychd tests"
make format-check FORMAT_TARGETS="src/lychd tests"
make type-check TYPECHECK_TARGETS="src/lychd"
make test PYTEST_TARGETS="tests/unit"
make check
make check is the non-mutating Python umbrella; it does not silently run frontend work. The
frontend has its own Node/npm boundary:
make frontend-check
make frontend-build
Both frontend gates regenerate the OpenAPI client contract. frontend-check then checks and tests
the Altar; frontend-build compiles its tracked projection beneath src/lychd/public/ so review can
see generated changes. Published documentation is checked separately with
uv run --locked --only-group docs zensical build --clean.
ADR 15 owns the exact Node/npm pins and the single frontend tool vocabulary. A quality or DX task may not introduce Bun, a second JavaScript lock/runtime, Tailwind, or another styling compiler without first satisfying that Covenant's product-shaped reopening gate.
Pull requests keep four independent lanes visible: make check, the disposable PostgreSQL
receipts, Altar check/build with a generated-projection diff guard, and the clean documentation
build. A main push repeats the first three while the Pages workflow's clean build supplies the
documentation gate and deployment artifact without running the same build twice. The tag/manual
release-candidate workflow remains separate because an ordinary green change is not an artifact or
host promotion receipt.
The editor configuration also routes Markdown through markdownlint and TOML, YAML, and JSON
through Prettier. The client uses strict TypeScript, svelte-check, and Vitest/jsdom; native CSS
is inspected directly. A production-factory browser receipt remains outside these gates and is
owned by ADR 15 and State of Work.
Consequences
Tool or configuration changes carry their lockfile and documentation consequences. Gates fail early and reproducibly, but a green gate is repository evidence, not evidence that a deployed host is healthy. Source, tests, locks, generated projections, and operational receipts retain their separate owners; delivery status belongs to State of Work.