mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
docs: rewrite CONTRIBUTING.md, add docs/branching.md
The previous CONTRIBUTING.md read like a stock Rust contributing template that mentioned FIPS. Replace it with an entry-point doc that gives new contributors the FIPS-specific mental model they need to make a useful first PR: the FMP/FSP layering and why mesh-level changes need multi-node testing, the three-branch release model and how to choose a target branch, structured bug reporting expectations, and PR submission requirements (scope discipline, the local-CI ladder, separate requirements for feature PRs vs bug-fix PRs, squash-merge mechanics). Add a contributor-facing AI coding assistant policy: use is welcome, but the contributor must do a thorough manual review and editorial pass before submission. The agent is a tool; the contributor is accountable for the submission. Review effort scales with submission effort -- unreviewed agent output will receive an agent reply in turn, without human review. Add docs/branching.md as the long-form companion covering the release workflow, version conventions, and merge-direction rationale. The new CONTRIBUTING.md is the day-to-day entry point; docs/branching.md is the reference. All cross-references resolve against current HEAD. Previous stale links to fips-intro.md, fips-wire-formats.md, and fips-configuration.md are gone; the doc points at the current docs/design/ layout, docs/getting-started.md, docs/tutorials/join-the-test-mesh.md, and testing/README.md. No code changes.
This commit is contained in:
285
CONTRIBUTING.md
285
CONTRIBUTING.md
@@ -1,94 +1,243 @@
|
||||
# Contributing to FIPS
|
||||
|
||||
## Getting Started
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
Clone the repo:
|
||||
FIPS is a mesh routing protocol for Nostr identities over arbitrary
|
||||
transports. The architecture is layered, top to bottom:
|
||||
|
||||
```
|
||||
- **IPv6 TUN compatibility layer** — presents the mesh as a local
|
||||
network interface (`fips0`) so unmodified applications can use it.
|
||||
Applications send IPv6 packets to `fd::/8` addresses derived from
|
||||
Nostr pubkeys; the daemon converts between IPv6 packets and FSP
|
||||
datagrams.
|
||||
- **FSP** (FIPS Session Protocol) — end-to-end encrypted sessions
|
||||
between identities, with periodic rekey.
|
||||
- **FMP** (FIPS Mesh Protocol) — peer management, spanning tree,
|
||||
bloom filters, routing and forwarding, and link encryption.
|
||||
- **Transport** — the actual wire: UDP, TCP, Tor, Bluetooth LE,
|
||||
Ethernet, and so on. Each transport plugs into FMP via a trait.
|
||||
|
||||
Most non-trivial changes affect behavior visible across the mesh —
|
||||
how nodes find each other, how packets route, how sessions rekey, how
|
||||
peers recover from failure. A single-node `cargo test` run is
|
||||
necessary but not sufficient for that class of change; the integration
|
||||
harness in [testing/](testing/) is where regressions actually surface.
|
||||
This document covers the workflow assuming that context. Protocol
|
||||
depth lives in [docs/design/](docs/design/).
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
git clone https://github.com/jmcorgan/fips.git
|
||||
cd fips
|
||||
```
|
||||
|
||||
Before changing code, read the protocol docs in this order:
|
||||
|
||||
- [docs/design/README.md](docs/design/README.md)
|
||||
- [docs/design/fips-intro.md](docs/design/fips-intro.md)
|
||||
- the specific design doc for the behavior you are touching
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Rust 1.94.1 and Linux with TUN support
|
||||
- Use the pinned toolchain from [rust-toolchain.toml](rust-toolchain.toml) for deterministic builds
|
||||
- For the default BLE-enabled build on Debian/Ubuntu:
|
||||
`sudo apt install bluez libdbus-1-dev pkg-config`
|
||||
- Docker is required for the integration harnesses under [testing/](testing/)
|
||||
|
||||
If you do not want BLE locally, build and test without default features:
|
||||
|
||||
```bash
|
||||
cargo build --no-default-features --features tui
|
||||
cargo test --no-default-features --features tui
|
||||
```
|
||||
|
||||
## Local Verification
|
||||
|
||||
Choose the narrowest check that matches your change:
|
||||
|
||||
- Docs-only changes:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
|
||||
- Normal code changes:
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
cargo test
|
||||
cargo clippy --all -- -D warnings
|
||||
```
|
||||
|
||||
- Local CI-style unit test run:
|
||||
The pinned toolchain in [rust-toolchain.toml](rust-toolchain.toml) is
|
||||
used for deterministic builds. On Debian/Ubuntu, BLE-capable builds
|
||||
need `bluez`, `libdbus-1-dev`, and `pkg-config` installed; the default
|
||||
build picks up BLE if those are present and skips it cleanly if not.
|
||||
|
||||
For multi-node integration runs, Docker is required. The harness
|
||||
under [testing/](testing/) starts containerized topologies and
|
||||
exercises real mesh behavior; see [testing/README.md](testing/README.md)
|
||||
for the suite catalog.
|
||||
|
||||
For a guided first-run that joins the public test mesh, see
|
||||
[docs/tutorials/join-the-test-mesh.md](docs/tutorials/join-the-test-mesh.md).
|
||||
Pointing your local daemon at a `test-*` node is the cheapest way to
|
||||
dogfood a change end-to-end before opening a PR.
|
||||
|
||||
## Choosing a branch to target
|
||||
|
||||
FIPS uses three long-lived branches, each a superset of the previous:
|
||||
|
||||
- **`maint`** — bug fixes for the latest released version.
|
||||
- **`master`** — compatible work for the next feature release.
|
||||
- **`next`** — wire-format-breaking and API-breaking work, staged for
|
||||
the next forklift release.
|
||||
|
||||
Pick the branch that matches the scope of your change:
|
||||
|
||||
| Your change | Target |
|
||||
| --- | --- |
|
||||
| Bug fix in a feature that shipped in the latest release | `maint` |
|
||||
| Bug fix in code added on `master` since the last release | `master` |
|
||||
| Bug fix in `next`-only code (wire-format-breaking work) | `next` |
|
||||
| New feature, no wire-format or API break | `master` |
|
||||
| Wire-format-breaking or API-breaking change | `next` |
|
||||
| Documentation, CI, contributor-facing changes | `maint` if they apply to released material, else `master` |
|
||||
|
||||
When in doubt, ask in the issue. The maintainer can retarget if
|
||||
needed. The full release workflow, version conventions, and
|
||||
merge-direction rationale are in [docs/branching.md](docs/branching.md).
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Search [open issues](https://github.com/jmcorgan/fips/issues) before
|
||||
filing a new one — duplicates are common in a young project.
|
||||
|
||||
When you open a bug report, please include:
|
||||
|
||||
- **FIPS version** (`fipsctl --version`)
|
||||
- **Rust toolchain version** (`rustc --version`)
|
||||
- **OS / distro** (Linux distro + kernel, or macOS / Windows version)
|
||||
- **What you expected to happen** — your mental model of the
|
||||
behavior, ideally referencing the relevant docs or config field.
|
||||
- **What actually happened** — the observed behavior, including the
|
||||
surprise.
|
||||
- **Reproduction steps** — minimal and deterministic if you can.
|
||||
Multi-node bugs should include the topology and per-node config
|
||||
excerpts.
|
||||
- **Evidence** — relevant log excerpts (`journalctl -u fips` or stdout
|
||||
with `RUST_LOG=info` or `debug`), `fipsctl show` output if relevant
|
||||
(`peers`, `links`, `status`), and any visible mesh state.
|
||||
|
||||
One issue per bug. Don't bundle unrelated symptoms even if you
|
||||
suspect they share a root cause — the maintainer will link them if
|
||||
they turn out to be related.
|
||||
|
||||
## Submitting pull requests
|
||||
|
||||
### Scope discipline
|
||||
|
||||
Every PR should make one logical change. The reviewer should be able
|
||||
to read the whole diff and trace every line back to the PR's stated
|
||||
purpose.
|
||||
|
||||
- No drive-by reformatting of unrelated files.
|
||||
- No unrelated refactors folded into a bug fix or a feature PR.
|
||||
- No "while I was in there" cleanups in files outside the change's
|
||||
natural footprint. Send them as separate PRs; they'll usually land
|
||||
faster on their own.
|
||||
- Pre-existing lint warnings in files you didn't touch are not yours
|
||||
to fix in this PR.
|
||||
|
||||
### Required before opening any PR
|
||||
|
||||
Run these locally and confirm they all pass:
|
||||
|
||||
```bash
|
||||
./testing/ci-local.sh --test-only
|
||||
cargo fmt --check
|
||||
cargo build
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo test
|
||||
```
|
||||
|
||||
- Narrow integration run for transport, routing, Docker, or packaging-sensitive changes:
|
||||
`fmt` and `clippy -D warnings` are CI gates — PRs with formatting
|
||||
drift or new clippy warnings will fail CI and be sent back.
|
||||
|
||||
Then run the integration suite that exercises your change:
|
||||
|
||||
```bash
|
||||
./testing/ci-local.sh --only static-mesh
|
||||
./testing/ci-local.sh --only <suite>
|
||||
```
|
||||
|
||||
See [testing/README.md](testing/README.md) for the available integration and chaos harnesses.
|
||||
See [testing/README.md](testing/README.md) for the available suites
|
||||
and what each covers. Routing, discovery, rekey, NAT, gateway, and
|
||||
transport changes all have specific suites; pick the narrowest one
|
||||
that touches your code path.
|
||||
|
||||
## Filing Issues
|
||||
**Recommended before opening**: the full local CI run.
|
||||
|
||||
- Search existing issues before opening a new one.
|
||||
- Include FIPS version, Rust version, and OS.
|
||||
- For bugs: steps to reproduce, expected vs actual behavior.
|
||||
```bash
|
||||
./testing/ci-local.sh
|
||||
```
|
||||
|
||||
## Pull Requests
|
||||
This is the same matrix that runs on GitHub Actions. Catching a
|
||||
regression locally is much cheaper than catching it in CI.
|
||||
|
||||
- All PRs must pass `cargo build`, `cargo test`, and `cargo clippy --all -- -D warnings`.
|
||||
- Keep commits focused — one logical change per commit.
|
||||
- Add tests for new functionality.
|
||||
- Reference relevant design docs if the change touches protocol behavior.
|
||||
- Pull requests are merged via squash-merge.
|
||||
- Update docs in the same change when you modify:
|
||||
- protocol or routing behavior
|
||||
- wire formats
|
||||
- configuration shape or defaults
|
||||
- operational workflows or testing instructions
|
||||
### Additional requirements for feature PRs
|
||||
|
||||
In practice this usually means updating one or more of:
|
||||
- **New CI coverage.** Features added without a test that exercises
|
||||
them won't be reviewed. Either extend an existing integration
|
||||
suite or add a new one under `testing/`. Coverage of just the
|
||||
happy path is fine for an initial PR; edge cases can land as
|
||||
follow-ups.
|
||||
- **Documentation updated alongside the code.** Protocol changes
|
||||
update the relevant [docs/design/](docs/design/) page. Config
|
||||
changes update the operator-facing docs in [docs/](docs/) and the
|
||||
reference config. Behavior visible to operators updates
|
||||
[README.md](README.md) and any tutorial it touches.
|
||||
|
||||
- [docs/design/fips-mesh-operation.md](docs/design/fips-mesh-operation.md)
|
||||
- [docs/design/fips-wire-formats.md](docs/design/fips-wire-formats.md)
|
||||
- [docs/design/fips-configuration.md](docs/design/fips-configuration.md)
|
||||
- [README.md](README.md)
|
||||
- [testing/README.md](testing/README.md)
|
||||
### Additional requirements for bug-fix PRs
|
||||
|
||||
## Questions
|
||||
- **A regression test** where practical. If a regression test isn't
|
||||
tractable (some bugs only surface under timing or scale that's hard
|
||||
to encode), say so in the PR description with a one-paragraph
|
||||
explanation.
|
||||
- **Commit message references the bug**: the symptom, the root cause
|
||||
in one sentence, and the fix shape.
|
||||
|
||||
Open a GitHub issue for design or implementation questions.
|
||||
### Merge mechanics
|
||||
|
||||
PRs are merged via **squash-merge**. One logical change per PR
|
||||
becomes one commit on the destination branch, which keeps `git
|
||||
bisect` useful across the integration suite. Your in-PR commit
|
||||
history doesn't matter for the final landed history — the maintainer
|
||||
rewrites the commit message at merge time.
|
||||
|
||||
## AI coding assistant policy
|
||||
|
||||
Use of AI coding assistants (Claude Code, Copilot, Cursor, Aider, and
|
||||
similar) in preparing a contribution is welcome. These tools are
|
||||
force multipliers and we have no objection in principle to their use
|
||||
in writing code, tests, documentation, or PR descriptions.
|
||||
|
||||
What we require is that the contributor does a thorough manual review
|
||||
and editorial pass over the output before submission. Concretely:
|
||||
|
||||
- Verify that the code does what it claims, not just that it
|
||||
compiles.
|
||||
- Verify that any tests the agent wrote actually test something
|
||||
useful, not just that they pass.
|
||||
- Verify that any documentation matches the behavior.
|
||||
- Spot-check the diff for nothing-surprising: no unrelated files
|
||||
modified, no fabricated APIs, no references to symbols that don't
|
||||
exist, no version bumps you didn't intend, no churn outside the
|
||||
change's natural footprint.
|
||||
- Be ready to discuss the design choices in the PR as if you wrote
|
||||
every line, because for the purposes of accountability you did.
|
||||
|
||||
The coding agent is a tool. The contributor is the author of record
|
||||
and is accountable for whatever they submit. PRs are reviewed on
|
||||
what they contain, not on who or what wrote them.
|
||||
|
||||
**Review effort scales with submission effort.** A submission that
|
||||
shows signs of being unreviewed agent output — irrelevant edits
|
||||
scattered across the tree, hallucinated function names, mismatched
|
||||
test/behavior pairs, fabricated API references, ChatGPT-style summary
|
||||
prose in comments — will receive an AI-coding-agent reply in turn,
|
||||
without human review. If you want a human reviewer's attention, do
|
||||
the editorial pass yourself first.
|
||||
|
||||
Repeated submissions of unreviewed AI output will result in the
|
||||
contributor being asked to step back and may result in account
|
||||
restrictions.
|
||||
|
||||
## Where the conversation happens
|
||||
|
||||
- **GitHub issues** — bugs, feature requests, design discussions
|
||||
that don't fit on a specific PR.
|
||||
- **GitHub PRs** — design discussion specific to a change in
|
||||
flight. Comment threads on the diff are the right place to push
|
||||
back on a decision.
|
||||
- **[fips.network](https://fips.network)** — community page, podcast,
|
||||
and the project's Nostr account. Broader project conversation and
|
||||
announcements happen here.
|
||||
|
||||
For implementation questions specific to your PR, ask in the PR
|
||||
itself. For design or roadmap questions that don't have a clear PR
|
||||
home yet, file a GitHub issue with the `design` label.
|
||||
|
||||
## Further reading
|
||||
|
||||
- [docs/design/README.md](docs/design/README.md) — protocol design tree.
|
||||
- [docs/branching.md](docs/branching.md) — full release workflow and
|
||||
merge-direction rationale.
|
||||
- [docs/getting-started.md](docs/getting-started.md) — operator
|
||||
walkthrough for a new node.
|
||||
- [docs/tutorials/join-the-test-mesh.md](docs/tutorials/join-the-test-mesh.md)
|
||||
— how to dogfood your change against the public test mesh.
|
||||
- [testing/README.md](testing/README.md) — integration suite catalog.
|
||||
|
||||
143
docs/branching.md
Normal file
143
docs/branching.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# FIPS Branching and Merging Strategy
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
This document explains how the three long-lived branches relate, when
|
||||
to target each one, and how merges propagate fixes and features. For
|
||||
the day-to-day "how do I send a PR" workflow, see
|
||||
[CONTRIBUTING.md](../CONTRIBUTING.md).
|
||||
|
||||
## Branch Structure
|
||||
|
||||
Three long-lived branches track parallel development streams:
|
||||
|
||||
```text
|
||||
next ──●──●──●──●──●──────────────●──●── (wire-format-breaking work)
|
||||
\ /
|
||||
master ────●──●──●──●──●──●──────●──●──●── (compatible features, latest release line)
|
||||
\ /
|
||||
maint ────────●──●──●──●──●────────────── (bug fixes for the latest release)
|
||||
```
|
||||
|
||||
### maint
|
||||
|
||||
- Reset to each minor release tag at release time
|
||||
- Accepts only bug fixes for functionality that shipped in the
|
||||
latest release
|
||||
- No new features, no API changes, no wire-format changes
|
||||
- Patch releases tag from here (e.g., `v0.3.1`, `v0.3.2`)
|
||||
- Periodically merged forward into `master` so fixes propagate
|
||||
|
||||
### master
|
||||
|
||||
- Compatible development for the next feature release
|
||||
- Multiple feature releases may ship from master (`v0.4.0`, `v0.5.0`)
|
||||
before `next` promotes
|
||||
- No wire-format breaking changes; no API breaks
|
||||
- Receives merges from `maint` so released-line fixes flow forward
|
||||
- Periodically merged forward into `next`
|
||||
|
||||
### next
|
||||
|
||||
- Accumulates work that breaks wire format, API, or compatibility
|
||||
- Receives merges from `master` so it stays current with bug fixes
|
||||
and compatible feature work
|
||||
- Cargo version on `next` is the expected release version with a
|
||||
`-dev` suffix, updated if `master` ships additional minor
|
||||
releases first
|
||||
- Becomes the new `master` at the next breaking release; at the same
|
||||
point the old `master` becomes the new `maint`
|
||||
|
||||
## Versioning
|
||||
|
||||
While the project is in the `0.x` era, semver treats minor bumps as
|
||||
potentially breaking. Both `master` and `next` bump the minor version;
|
||||
the distinction between compatible and breaking is captured in the
|
||||
changelog and in which branch the work landed on.
|
||||
|
||||
The `-dev` suffix in `Cargo.toml` indicates an unreleased development
|
||||
state on the branch.
|
||||
|
||||
## Merge Direction
|
||||
|
||||
Fixes and features flow in **one direction only**: `maint → master → next`.
|
||||
Never merge backward (`next` into `master`, or `master` into `maint`).
|
||||
|
||||
```text
|
||||
maint ──→ master ──→ next
|
||||
```
|
||||
|
||||
This guarantees:
|
||||
|
||||
- Bug fixes shipped in a release reach all subsequent branches
|
||||
- Compatible features reach `next`
|
||||
- Wire-format-breaking work stays isolated on `next` until release
|
||||
|
||||
If you submit a PR on `next` that should also be on master or maint
|
||||
(rare, since the criteria for needing it on multiple branches are
|
||||
usually mutually exclusive), the PR stays on its target; the
|
||||
maintainer either backports as a separate commit on the upstream
|
||||
branch or asks you to.
|
||||
|
||||
## Choosing a Branch for Your PR
|
||||
|
||||
Pick the branch that matches the scope of your change:
|
||||
|
||||
| Your change | Target branch | Why |
|
||||
| --- | --- | --- |
|
||||
| Bug fix in a feature that shipped in the latest release | `maint` | Fix forward-merges to `master` and `next` |
|
||||
| Bug fix in code added on `master` since the last release (not in any released version) | `master` | The released v0.x.y line is unaffected, so `maint` does not need the change |
|
||||
| Bug fix in code added on `next` (wire-format-breaking work) | `next` | The bug only exists where the breaking work exists |
|
||||
| New feature that does not break wire format or API | `master` | Becomes part of the next compatible release |
|
||||
| Wire-format breaking change, API break, or fundamental protocol shape change | `next` | Stays isolated until the next forklift release |
|
||||
| Documentation, CI, or contributor-facing changes | `maint` if they apply to released material, else `master` | Forward-merges propagate naturally |
|
||||
|
||||
If you are not sure, ask in the related issue. The safest defaults
|
||||
are `master` for new features and `maint` for bug fixes; the
|
||||
maintainer will retarget the PR if needed.
|
||||
|
||||
## Release Workflow
|
||||
|
||||
### Bug fix release (from `maint`)
|
||||
|
||||
1. Fix on `maint`
|
||||
2. Bump patch version, tag (e.g., `v0.3.1`)
|
||||
3. Merge `maint` into `master`
|
||||
4. Merge `master` into `next`
|
||||
|
||||
### Compatible feature release (from `master`)
|
||||
|
||||
1. Finalize features on `master`
|
||||
2. Merge `maint` into `master` to pick up any pending fixes
|
||||
3. Set version, tag (e.g., `v0.4.0`)
|
||||
4. Reset `maint` to the new tag
|
||||
5. Bump `master` to the next `-dev` version
|
||||
6. Merge `master` into `next`
|
||||
|
||||
### Breaking release (from `next`)
|
||||
|
||||
1. Finalize features on `next`
|
||||
2. Merge `master` into `next` to pick up pending fixes and features
|
||||
3. Assign version as the next minor after `master`'s last release, tag
|
||||
4. `master` becomes the new `maint`
|
||||
5. `next` becomes the new `master`
|
||||
6. Create a new `next` branch from `master`
|
||||
|
||||
## Practical Guidelines
|
||||
|
||||
- **Commit to the appropriate branch for the scope of the change.**
|
||||
Do not commit bug fixes to `master` when they apply to the latest
|
||||
release — put them on `maint` and let the forward-merge propagate.
|
||||
- **Feature branches base off the long-lived branch they target.**
|
||||
Create with `git checkout -b my-feature maint` (or `master` or
|
||||
`next`), not `git checkout -b my-feature origin/maint`. The
|
||||
`origin/`-prefixed form auto-sets the new branch's upstream to
|
||||
the source ref, which can cause `git push` to land on the wrong
|
||||
ref under some configurations.
|
||||
- **When in doubt about whether a change is compatible**, target
|
||||
`next`. The maintainer can advise on retargeting.
|
||||
- **Resolve merge conflicts on the receiving branch**, preserving
|
||||
both the inherited fix and the new development.
|
||||
- **PRs are merged via squash-merge.** One logical change per PR
|
||||
becomes one commit on the destination branch, making bisect
|
||||
clean across the integration suite.
|
||||
Reference in New Issue
Block a user