Contributingstable
Code conventions
- Python 3.11+, fully typed.
from __future__ import annotationsat the top of every module; annotate every public signature. Modern syntax —X | None, notOptional[X]. - pydantic v2 for every model that crosses a boundary (wire, API, config, record I/O). v1 APIs (
.dict(),.parse_obj(),@validator) are not used. - ruff is the formatter's judgement and the linter's: rule set
E,F,I,UP,B,SIMat a 100-column line length, configured once in the rootpyproject.tomland mirrored inservices/verd/pyproject.toml. Do not add per-file ignores to dodge a finding; the two that exist are documented at the point of the ignore and are about a deliberatesys.pathbootstrap. - Modules target ~300 lines. A module that outgrows that is usually two responsibilities that have not been separated yet. A handful here already run longer (
qd.py,recordio.py,schema_stage.py); that is a debt, not a licence to add more. - Complete files, never snippets. A change is submitted as the whole file it lands in.
- Comments explain why. The interesting comments in this repository record a decision and its alternative — a threshold that is not the obvious number, a probe written against
/dev/tcpbecause the image ships no curl. Do not write a comment that restates the line below it. - Idempotency is a requirement, not a nicety. Re-running an ingest, a publish or a migration over the same input must converge, not duplicate. Writes that a crash could interrupt are atomic: temp file plus
os.replace. - Honesty in claims. A record claims the conformance level its evidence supports, never the level you wish it supported. A federated record is well-formed and self-consistent — never described as "verified". If a detection is not actually performed, its availability is
unknown, andavailability_basissays how it was decided.
