Contributing¶
Thanks for considering a contribution to LDTC. This page summarizes
what changes are most welcome and how to get a patch through CI. The
canonical guide lives in CONTRIBUTING.md at the repository root and
is included verbatim below; the rest of this page covers conventions
that are specific to the documentation site.
What changes are welcome¶
LDTC is a research harness, so contributions that strengthen the guarantees printed onto the verifier's terminal are especially valuable:
- New estimators or metrics in
ldtc.lmeaswith bootstrap confidence intervals and tests against synthetic ground truth. - New
Ωperturbations inldtc.omegathat exercise novel failure modes (intermittent power, noisy actuators, multi-agent coordination). - Hardware adapters in
ldtc.plantfor real devices: a small, well-documented adapter is more useful than a large one. - Reporting / verification tooling that consumes the signed indicators and audit log without ever reaching back into the LREG.
- Docs: clarifications, additional examples, and tighter prose are always welcome. Run the style guide by your changes before submitting.
What we cannot accept:
- Anything that reads, mutates, or bypasses the LREG outside the
guard's
derive()path. This is a hard rule; PRs that touch this surface will be rejected on principle. - Changes that weaken the audit chain, the indicator schema, or the
Δtgovernance loop without an explicit migration story.
Quick start for contributors¶
git clone https://github.com/<your-fork>/ldtc.git
cd ldtc
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,docs]"
make lint typecheck test
make docs # builds docs in --strict mode
If make docs fails locally with a Cairo error, see
Troubleshooting.
What to put in a PR¶
A typical good PR contains:
- The smallest set of code changes that solves one problem.
- New or updated tests that fail before the change and pass after.
- Updates to the relevant docstrings (Google style; see style guide).
- If the public surface changed, an updated entry in the matching
docs/api/*.mdpage ordocs/concepts/*.mdpage. - A clear, present-tense title and body describing why the change matters, not just what it does.
Conventional Commits (feat:, fix:, docs:, refactor:, test:,
chore:) are appreciated but not required.
CI gates¶
Every push runs:
make lint(Black, Ruff with Google docstring rules).make typecheck(MyPy in strict mode).make test(Pytest, including property tests over the partition algebra and the LREG monotonicity invariant).make docs(mkdocs build --strict; broken cross-references and missing pages fail the build).
Run all four locally before opening a PR.
Repository contributing guide¶
The following section is the project-wide contributing guide. It is
embedded verbatim from CONTRIBUTING.md so that the source of truth
stays a single file.
Contributing to LDTC¶
Thanks for your interest in contributing. This repository is a verification harness for the Loop-Dominance (NC1/SC1) pipeline described in the manuscript. Contributions should keep the code reproducible, auditable, and consistent with the paper's symbols and assumptions (Δt, M, ε, τmax, σ, C/Ex partition, Ω battery, LREG/attestation).
Quick start¶
Development uses Python ≥ 3.9.
# install runtime deps (editable)
make install
# install dev tooling (pytest, ruff, black, mypy)
make dev
# run tests, lint, type-check, and format
make test
make lint
make typecheck
make fmt
# smoke runs
make run # baseline NC1
make omega-power-sag # Ω power-sag demo
Project layout (high-level)¶
src/ldtc/arbiter/– policy and refusal semanticsattest/– indicators, exporter, keys (LREG-derived)cli/– command-line interface and entrypointsguardrails/– audit, Δt guards, smell-testslmeas/– estimators, metrics, partitioningomega/– perturbation generators (power sag, ingress flood, command conflict)plant/– sim/hw adapters and modelsreporting/– artifacts, tables, timelinesruntime/– scheduler and windowsconfigs/– R₀ defaults, negative controls, example R* profilescripts/– calibration, indicator verification, batch helperstests/– unit testsdocs/– method notes and figures
Coding guidelines¶
- Style: Black; lint: Ruff (with the Google docstring convention enabled); typing: MyPy (settings in
pyproject.toml). - Docstrings: Google-style throughout. See the project documentation style guide for the full conventions and examples, and the Google Python Style Guide §3.8 Comments and Docstrings for the upstream reference.
- Prose follows the Chicago Manual of Style (17th ed.): no em dashes, straight ASCII quotes, serial commas, sentence-case headings. Keep Greek and mathematical symbols (Δt, 𝓛, M, ε, τ, σ, Ω) as Unicode.
- Prefer explicit, descriptive names; follow repository symbol mapping to the paper.
- Add or extend tests in
tests/for new behavior; keep fast unit tests (no network or large IO). - Keep artifacts under
artifacts/only; do not commit generated files.
Common commands:
make test # pytest -q
make lint # ruff check . (includes Google-style docstring rules on src/ldtc)
make typecheck # mypy src tests scripts
make fmt # black src tests examples scripts
make docs # mkdocs build --strict
make docs-serve # mkdocs serve (live preview at http://127.0.0.1:8000)
Conventional Commits¶
This project uses Conventional Commits. Use the form:
Commit message character set¶
- Encoding: UTF‑8 is allowed and preferred across subjects and bodies.
- Subjects may include UTF‑8 symbols (e.g., Δ, 𝓛, λ/θ/κ) when they add clarity; keep the subject ≤ 72 chars and avoid emoji.
- If maximum legacy compatibility is needed, prefer ASCII in the subject and use UTF‑8 in the body.
Example (UTF‑8 subject):
Accepted types (stick to the standard):
build– build system or external dependencies (e.g., requirements, packaging)chore– maintenance (no src/ behavior change)ci– continuous integration configuration (workflows, pipelines)docs– documentation onlyfeat– user-facing feature or capabilityfix– bug fixperf– performance improvementsrefactor– code change that neither fixes a bug nor adds a featurerevert– revert of a previous commitstyle– formatting/whitespace (no code behavior)test– add/adjust tests only
Recommended scopes (choose the smallest, most accurate unit; prefer module/directory names):
- Module/directory scopes:
arbiter– policy and refusal semanticsattest– indicators, exporter, keys (LREG-derived)cli– command-line interface and entrypointsguardrails– audit, Δt guards, smell-testslmeas– estimators, metrics, partitioningomega– perturbation generators (power sag, ingress flood, command conflict)plant– sim/hw adapters and modelsreporting– artifacts, tables, timelines-
runtime– scheduler and windows -
Other scopes:
configs– configuration files (R₀ defaults, negative controls, example R* profile)deps– dependency updates and version pins (e.g., requirements files)docker– containerization (e.g.,Dockerfile, image build/runtime settings)examples– example scripts and minimal demos underexamples/makefile–Makefiletargets and build helpersnotebooks– Jupyter notebooks undernotebooks/paper– LaTeX manuscript sources underpaper/(e.g.,main.tex,macros.tex,refs.bib,Makefile,scripts/)pyproject–pyproject.tomlpackaging/build metadata and tool configrepo– repository metadata and top-level files (e.g.,README.md,CONTRIBUTING.md,LICENSE,CITATION.cff,.gitignore); also docs assets like images underdocs/assets/mkdocs– documentation site (MkDocs/Material) configuration and content underdocs/scripts– utility/CLI scripts underscripts/tests– unit/integration tests undertests/workflows– CI pipelines under.github/workflows/
Note: Avoid redundant type==scope pairs (e.g., docs(docs)). Prefer a module scope (e.g., docs(attest)) or docs(repo) for top-level repository updates.
Examples:
build(deps): refresh pinned versions
chore(makefile): add figures target for paper assets
chore(pyproject): bump version to 0.2.0
ci(workflows): add indicator verification job
docs(attest): clarify Mq bit width and signing scheme
docs(notebooks): clarify demo parameters in 02_sc1_omega.ipynb
docs(repo): update LDTC logo asset in docs/assets
feat(lmeas): add Kraskov kNN MI path with configurable k
fix(omega): correct power-sag duration units to seconds
perf(plant): reduce allocation in sim step to lower GC pauses
refactor(runtime): extract jitter accounting from scheduler loop
revert(cli): revert omega ingress flag rename
test(guardrails): add Δt governance invalidation cases
Examples (no scope):
build: update packaging metadata
chore: update .gitignore patterns
docs: add Zenodo DOI
revert: revert "refactor(runtime): extract jitter accounting from scheduler loop"
style: format code with Black
Breaking changes:
- Use
!after the type/scope or aBREAKING CHANGE:footer.
feat(lmeas)!: change default Mmin from 1 dB to 3 dB
BREAKING CHANGE: Default NC1 threshold raised to 3 dB; update configs.
Multiple scopes (optional)¶
- Comma-separate scopes without spaces:
type(scope1,scope2): ... - Prefer a single scope when possible; use multiple only when the change genuinely spans tightly related areas.
Scope ordering (house style):
- Put the most impacted scope first (e.g.,
repo), then any secondary scopes. - For extra consistency, alphabetize the remaining scopes after the primary.
- Keep it to 1–3 scopes max.
Example:
Primary = reporting (new figure generation and bundling). Secondary = cli (exposes/wires the subcommand).
Examples:
feat(cli,reporting): add figures subcommand and timeline export
fix(guardrails,attest): block raw LREG reads and enforce indicator-only exports
refactor(runtime,lmeas): decouple scheduler tick from windowing logic
Pull requests and squash merges¶
- PR title: use Conventional Commit format.
- Example:
feat(cli): add figures subcommand - Imperative mood; no trailing period; aim for ≤ 72 chars; use
!for breaking changes. - Prefer one primary scope; use comma-separated scopes only when necessary.
- PR description: include brief sections: What, Why, How (brief), Testing, Risks/Impact, Docs/Follow-ups.
- Link issues with keywords (e.g.,
Closes #123). - Merging: use "Squash and merge" with "Pull request title and description".
- Keep PRs focused; avoid unrelated changes in the same PR.
Conventional Commits applies to the subject line (your PR title) and optional footers. The PR body is free-form; when squashing, it becomes the commit body. Place any footers at the bottom of the description.
Recommended PR template:
What
- Short summary of the change
Why
- Motivation/user value
How (brief)
- Key implementation notes or decisions
Testing
- Local/CI coverage; links to tests if relevant
Risks/Impact
- Compat, rollout, perf, security; mitigations
Docs/Follow-ups
- Docs updated or TODO next steps
Closes #123
BREAKING CHANGE: <details if any>
Co-authored-by: Name <email>
Pull request checklist¶
- PR title: Conventional Commits format (CI-enforced by
pr-lint.yml). - Tests: added/updated;
make testpasses. - Lint/format/type-check:
make lint,make fmt,make typecheckpass. - Docs: update
docs/andREADME.mdif behavior, symbols, or indicators change. - Configs: update
configs/profile_r0.ymland example R* mapping if thresholds/symbols move. - Artifacts: none committed; runs write to
artifacts/only.
Adding a new Ω perturbation or estimator (quick recipe)¶
- Ω: implement under
src/ldtc/omega/, add CLI wiring incli/, add tests intests/test_omega.py. - Estimator: implement in
src/ldtc/lmeas/, expose config flags, and extend tests intests/test_estimators.py. - Update indicators/reporting if exported fields change; update docs.
Versioning and releases¶
- The version is tracked in
pyproject.toml(project.version) and mirrored insrc/ldtc/__init__.pyas__version__. Both files are updated automatically by python-semantic-release. - Automated release pipeline (on every merge to
main): python-semantic-releasescans Conventional Commit messages since the last tag.- It determines the next SemVer bump:
feat→ minor,fix/perf→ patch,BREAKING CHANGE→ major. - Version files are updated,
CHANGELOG.mdis generated, and a tagged release commit (chore(release): vX.Y.Z) is pushed. - A GitHub Release is created with auto-generated release notes and the built sdist/wheel attached.
- When drafts are disabled, the package is also published to PyPI via Trusted Publishing.
- Draft / published toggle: the
DRAFT_RELEASEvariable at the top of.github/workflows/release.ymlcontrols release mode. Set to"true"(the default) for draft GitHub Releases with PyPI publishing skipped; flip to"false"to publish releases and upload to PyPI immediately. - Commit types that trigger a release:
feat(minor),fixandperf(patch),BREAKING CHANGE(major). All other types (build,chore,ci,docs,refactor,revert,style,test) are recorded in the changelog but do not trigger a release on their own. - Tag format:
v-prefixed (e.g.,v1.1.0). - Manual version bumps are no longer needed; just merge PRs with valid Conventional Commit titles. For ad-hoc runs, use the workflow's Run workflow button (
workflow_dispatch).
Branching rules¶
main: default branch; protected; mirrors PyPI.- All work branches are created from
main.
Branch naming¶
- Use lowercase kebab-case; no spaces; keep names concise (aim ≤ 40 chars).
- Branch prefixes match Conventional Commit types:
feat/<scope>-<short-desc>fix/<issue-or-bug>-<short-desc>chore/<short-desc>docs/<short-desc>ci/<short-desc>refactor/<scope>-<short-desc>test/<short-desc>perf/<short-desc>build/<short-desc>- Optionally append an issue ID at the end (e.g.,
feat/cli-figures-123). - Delete remote and local branches after merge.
Examples:
feat/cli-figures
fix/omega-duration-units-123
docs/contributing-branch-naming
ci/mplbackend-agg-headless
build/lock-filters-ldtc
refactor/runtime-jitter-accounting
test/omega-suite
fix/attest-sig-verify
CI¶
- CI (
ci.yml): runs Black, Ruff, MyPy, pytest, and indicator verification on pushes tomainand PRs. - PR Lint (
pr-lint.yml): validates the PR title against Conventional Commits format (protects squash merges) and checks individual commit messages via commitlint (protects rebase merges). Recommended: add the PR title job as a required status check in branch-protection settings. - Release (
release.yml): runs on merge tomain; computes version, generates changelog, tags, creates GitHub Release, and (whenDRAFT_RELEASEis"false") publishes to PyPI. - Docs (
docs.yml): deploys documentation to GitHub Pages on push tomain. - Build Paper (
build-paper.yml): compiles the LaTeX manuscript.
Security and provenance¶
- LREG/attestation paths are measurement-only; do not expose raw LREG contents outside enclave abstractions in code or docs.
- Δt governance and audit rules must not be bypassed in contributions; changes require tests and documentation.
License¶
By contributing, you agree that your contributions are licensed under the repository's MIT License.