Contributing to Kshana
Thanks for your interest. Kshana aims to be a neutral, reproducible, honestly- validated reference for hybrid quantum/classical PNT. Contributions are held to that bar: correctness, citations, and reproducibility over breadth.
How the project is governed — who decides, the technical bar, and the open/closed
boundary — is documented in GOVERNANCE.md.
Development#
cargo build
cargo test # all tests must pass
cargo clippy # keep it warning-clean
cargo fmt
The optional language bindings are feature-gated and off by default (so the build above and the dependency-audit gate never touch them). To work on them:
maturin develop --features python # Python extension (needs maturin)
wasm-pack build --target web -- --features wasm # WebAssembly module
cargo clippy --features python --features wasm # lint the binding modules
Before every commit — the fast loop#
These take seconds. They are a subset of ci.yml's check job, in the same order, so
a failure here is a failure there:
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
./scripts/check-reproducible.sh # reference scenario is byte-identical across runs
./scripts/check-no-attribution.sh # repo hygiene (see below)
./scripts/check-version-sync.sh # every version surface agrees with Cargo.toml
./scripts/check-doc-coverage.sh # missing-docs ratchet: the count may fall, never rise
- Reproducibility is a hard invariant. A change that makes
(scenario, seed, version)non-deterministic is a bug. Randomness must flow through the seeded RNG; quantum and classical runs use independent, deterministically-derived seeds. - Repository hygiene. Commits and content must carry no automated-tool attribution trailers or footers, and must not name an AI assistant as an author anywhere in content, file names, or history. The guard enforces this.
Before you push — the full gate#
scripts/gate.sh is the canonical gate: it runs cargo test --all unabridged, then
scripts/check-repeatability.sh to re-run the library suite a few more times, because a
thread-interleaving race is invisible to a single run. Only on success does it write
.gate-receipt.json (untracked — machine state about one run, not content).
scripts/gate.sh
REPEAT=0 scripts/gate.sh # canonical suite only, no repeatability loop — a LOCAL
# shortcut: the pre-push gate refuses its receipt unless
# KSHANA_MIN_REPEAT_RUNS=0 is also set on the push
TEST_THREADS=6 scripts/gate.sh # cap per-binary concurrency if the run is memory-starved
scripts/check-gate-receipt.sh # is there a valid receipt for the commit being pushed?
scripts/install-gate-hook.sh --check # is the pre-push hook installed on this clone?
It is slow on purpose — 62-79 minutes in the healthy steady state, per the header of
scripts/gate.sh, which carries the current figure — and there is no timeout, because
a timeout short enough to be useful would kill a healthy run. A subset run that came
back green is not a gate: both of the defects this mechanism exists for reached it
that way.
Contributors working from a fork do not need the receipt hook — it is a local
maintainer gate, and CI is what actually gates a pull request. Running gate.sh
before you open one simply means CI tells you nothing you did not already know.
Adding or changing a sensor model#
- Every numeric parameter needs provenance. Put the citation in the model's
provenancestring and the scenario file. No anonymous constants. - Validate against the standard relation, not just internal consistency — e.g. Allan deviation for clocks, Groves' dead-reckoning error growth for inertial, the timing→ranging conversion for time transfer. Add a test that the simulated output reproduces the published/relation value within a stated tolerance.
- Be honest about maturity. The status registry is
src/verification.rs::verification_matrix()— add or amend the row there, name its external oracle (or say plainly that there is none, which makes itModelled), then regenerate the published artifacts withcargo run --bin gen_validation_artifacts.docs/VERIFICATION-MATRIX.md,docs/MODELLED-RATIONALE.mdandweb/data/verification-matrix.jsonare all generated from that function and say "do not edit by hand" for a reason. Update thedocs/VALIDATION.mdnarrative as well when the prose needs it, and label figures that are targets or ground- demonstrator results as such.
Tests#
- Test-driven: write the failing test first, with the expected value derived by hand from the physics/relation before implementing.
- Deterministic tests assert exact (hand-derived) values; statistical tests assert a stated tolerance and, ideally, average over seeds to control scatter.
Commits and versioning#
- Conventional Commits (
feat:,fix:,docs:,test:,chore:…). - Semantic Versioning. Pre-1.0, the scenario/result schema may change; call out breaking changes.
- Releases are cut by pushing a
vX.Y.Ztag, and publishing is automatic but ordered. The Release workflow runs the full verification on the tagged commit, and only when it passes does it publish to crates.io, the Python Package Index (PyPI), npm, ghcr.io, the Model Context Protocol (MCP) registry and the JetBrains Marketplace; it then checks every channel serves the version and rebuilds kshana.dev from the tag. Nobody runscargo publishby hand. The steps, and how to retry a failed publish, are indocs/RELEASING.md.
Changelog maintenance (required)#
Every user-visible change updates CHANGELOG.md:
- Add an entry under the
[Unreleased]section, in the right group (Added/Changed/Fixed/Removed/Documented/Planned). - On release, rename
[Unreleased]to the new[x.y.z] - YYYY-MM-DD, start a fresh[Unreleased], bump theversioninCargo.toml(soengine_versionin result JSON matches), update the compare links at the bottom, and tagvx.y.z. - Keep entries terse and user-facing; link issues/PRs where useful.
A pull request that changes behaviour without a changelog entry is incomplete.
Export control#
PNT resilience and quantum sensing can touch dual-use export controls. Keep the public repository to generic, published models and methods. Anything resembling export-sensitive resilience/anti-spoof depth belongs in the private overlay, not here. If unsure, ask before contributing it.
License#
Kshana is dual-licensed (AGPL-3.0 or a commercial licence from Ashforde OÜ — see
LICENSING.md). For that to keep working, contributions must be
usable under both licences. So, by contributing, you agree that:
- your contribution is licensed inbound under the AGPL-3.0-only; and
- you also grant Ashforde OÜ a perpetual, worldwide, royalty-free, irrevocable licence to use, modify, and relicense your contribution as part of Kshana's commercially-licensed edition (i.e. to also distribute it under non-AGPL commercial terms). You retain copyright in your contribution.
This lightweight dual-licence grant — not a copyright assignment — is what lets the project stay open and offer a commercial edition. If you cannot grant (2) (for example, employer-owned code), say so in your pull request before contributing.
Sign off each commit to certify the Developer Certificate of Origin:
git commit -s (adds a Signed-off-by line).