Contributing¶
Thank you for considering it. This page is about what a change has to satisfy before it can be merged, and most of it is unusual only because of what this software is for.
Written down before anybody needed it. What follows is the process the maintainers already hold themselves to, so that it is not invented under pressure later — and it applies to their own commits:
main.jsonin.github/rulesets/grants no bypass actors, so once those rules are installed a maintainer's change reachesmainthrough a pull request like anybody else's. That directory'sREADME.mdsays what is and is not in force today.
Before a large change¶
Open an issue first for anything that adds a dependency, changes the
evidence format, adds a rule to the baseline pack, or touches qed.core. Not
bureaucracy: several of those have consequences that are easy to miss, and it
is kinder to say so before you have written the code than after.
Small fixes — a bug, a docstring, a test that was missing — need no issue. Send the pull request.
Developer Certificate of Origin¶
Every commit must be signed off (SPEC §25.1). This is the DCO, not a CLA: you keep your copyright, and you assert that you have the right to contribute the code under Apache-2.0.
which appends:
Use your real name and a real address. git config --global user.name and
user.email once, and -s does the rest. The dco CI job checks every commit
a pull request adds, and a missing line is fixable with
git rebase --signoff <base>.
The check runs on pull requests only, which is what a DCO is for: contributions from people who are not the maintainer. The requirement predated the check by sixty-four commits, none of which carried the line. There is no cutoff now — the pre-publication history rewrite signed off every commit, because a governance document that documents its own exception is the shape of failure this project exists to remove.
(qed-ui is AGPL-3.0 and uses a CLA instead. Different repository, different
rule.)
What a change has to pass¶
All three, on your machine, before you push. CI runs the same things on Linux
and Windows across Python 3.12 and 3.13, plus PostgreSQL, the container on two
architectures, pip-audit, gitleaks, and a strict docs build.
The definition of done (SPEC §23)¶
- Tests, not just code. A fix needs a test that fails without it. A feature needs the test that would have caught its absence.
mypy --strictclean, and noAnyinqed.core.- Docstrings that say why. The house style is to explain the reasoning a reader cannot reconstruct from the code — especially a decision that looks arbitrary. If a line exists because of a bug, name the bug.
- A
CHANGELOG.mdentry for anything a user would notice. - An ADR in
docs/adr/for anything the spec does not settle. "The spec was silent so I picked one" is fine; "the spec was silent so nobody knows why it works this way" is not. - No new dependency without a spec update. Amend SPEC §20.3 in the same pull request.
Things that will be refused¶
Not to be unwelcoming — each of these is load-bearing, and it is better to know in advance.
| Change | Why |
|---|---|
| An LLM, or any model SDK, in the decision path | A verdict must be a deterministic function of its inputs. tests/core/test_no_llm.py fails the build. |
A network client, socket, or asyncio import in qed.core |
The kernel decides offline; adapters and qed.remote do I/O. AST-checked. |
| An HMAC or symmetric signing path | A verifier must not need a secret the producer holds. Ed25519 only. |
| A development fallback signing key | A missing key is a hard failure, always. |
| Making a decision depend on rule file order, locale or clock skew | Determinism is the product. |
Proprietary code, or code ported from valqore-engine with its history |
Git history is irreversible; see GOVERNANCE.md. |
| An ORM, Alembic, OPA/Rego, Cedar, or a React build chain | SPEC §26 lists these as explicitly not used. |
A change to hashing or record fields without a schema_version bump |
A record written today must verify in seven years. |
Writing a rule for the baseline pack¶
The pack ships in front of other people's agents, so a rule that is wrong costs an operator their trust in the whole thing.
- Ship a noisy rule in
mode: shadow. A rule that blocks real traffic on day one is the first one an operator turns off, and then they turn off the pack. - A
fix:an operator can actually follow. "Narrow the scope" is not one. compliance:mappings only where the control genuinely covers it. An invented mapping becomes an untraceable line in somebody's OSCAL export. A control id nothing defines is a lint error.- A golden case per rule, in
tests/policy/golden/cases.yaml. Runqed policy test <cases> --coverageto see what you missed. - Watch the verb boundaries.
\bdoes not work the way you expect onsnake_casetool names, and aBLOCKwith no approval path gets disabled.
Documentation¶
- Commands in a document must have been run.
docs/validation.mdis the page about why: this project has a documented history of green builds shipping broken artifacts, and a quoted command that was never executed is the same category of claim. - Cite a test by path when you claim something is enforced.
tests/docs/test_claims.pychecks those paths resolve. - A new page goes in
mkdocs.yml's nav in the same commit.tests/docs/test_site.pyfails otherwise, because a page nobody links is a page nobody reads.
Commit messages¶
Conventional commits for the subject (fix:, feat:, docs:). The body
should explain why, and it can be long — the repository's history is part
of its documentation, and a commit that says what the diff already says is a
wasted opportunity. If the change came from a bug, describe the bug and how it
got past whatever should have caught it.
Reporting a security bug¶
Not here. SECURITY.md has the private channels, and a security
bug in a public issue is a disclosure.
Code of conduct¶
Be civil and assume good faith. Technical disagreement is welcome and personal remarks are not. The maintainers will remove comments and, if necessary, contributors; that decision is theirs and is not up for debate in the thread it concerns.
CODE_OF_CONDUCT.md is the full version: what the rule means in practice, where
to report a problem, and what happens when the report concerns a maintainer.