From 4bb9fb69198d33a30a24ab518194d83639ac805b Mon Sep 17 00:00:00 2001 From: Maksim Kramarenko Date: Mon, 11 May 2026 18:25:40 -0400 Subject: [PATCH 1/3] Add PR template and CONTRIBUTING.md for fork-vs-upstream policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit quiknode-labs/shredstream-proxy is a fork of jito-labs/shredstream-proxy. Changes here split into two buckets: 1. Generic improvements (bug fixes, features) that should also flow upstream — branch as `feature/*` or unprefixed, optionally PR upstream after merging here. 2. Fork-specific overrides (CI, deploy, infra) that should never go upstream — branch as `qn/*`. This PR introduces: - `.github/PULL_REQUEST_TEMPLATE.md` — checkbox that forces every PR author to consciously declare whether the change is upstreamable. GitHub renders it as the default body when opening a PR. - `CONTRIBUTING.md` — branch naming convention, examples, the right `gh pr create` invocations for each case, and a note on `gh repo sync` for pulling from upstream. The goal is to make accidental upstream contribution of fork-specific code unlikely without resorting to maintaining a separate vendor branch. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/PULL_REQUEST_TEMPLATE.md | 24 ++++++++++ CONTRIBUTING.md | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CONTRIBUTING.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..64ccc4a3 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,24 @@ + + +## Is this change upstreamable? + +- [ ] **Yes** — this is broadly useful and should be offered to + `jito-labs/shredstream-proxy` as well. Use an unprefixed or + `feature/*` branch name. After this PR merges here, open a separate + PR against `jito-labs/shredstream-proxy:master`. +- [ ] **No** — this is QuickNode-specific (CI runner, deploy paths, + operational tooling, OCI bucket paths, fleet-specific defaults, + etc.). Use a `qn/*` branch name. Do **not** open an upstream PR. + +## Summary + + + +## Test plan + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..622c5990 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,77 @@ +# Contributing + +This repository is a fork of [`jito-labs/shredstream-proxy`](https://github.com/jito-labs/shredstream-proxy) +maintained by QuickNode. Changes land here for two reasons: + +1. **Upstreamable improvements** — bug fixes, new features, or refactors + that are broadly useful and should eventually flow to + `jito-labs/shredstream-proxy`. +2. **Fork-specific overrides** — CI runners, deploy plumbing, operational + tooling, and other things tied to QuickNode's infrastructure that + don't belong upstream. + +To keep these straight and avoid accidentally proposing fork-specific +changes upstream, we use a branch-naming convention and a PR template +checkbox. + +## Branch naming + +| Prefix | Use for | Upstream-bound? | +|---|---|---| +| `qn/*` | Fork-specific changes — CI workflows, build pipeline shims, infra integration, fleet defaults | **No** — never open an upstream PR from these | +| `feature/*` or unprefixed | Generic improvements — bug fixes, new features, refactors | Yes, optionally | + +Examples: +- `qn/ci-make-runnable-on-fork` — CI runner switch from Jito's self-hosted + pool to GitHub-hosted runners. Fork-specific. +- `qn/oci-binary-path-update` — change OCI bucket layout the deploy + pipeline reads from. Fork-specific. +- `add-listen-port-device-metric-labels` (or `feature/...`) — new InfluxDB + tags on `receiver_stats`. Useful to anyone running the proxy → eligible + to upstream after merging here. + +If unsure, pick `qn/*`. It's safer to under-promote a generic change than +to accidentally surface a fork-specific one upstream. + +## Opening a PR + +Always specify the target repo explicitly when using `gh pr create`. The +fork's default for `gh` is the upstream repo, which can lead to mis-routed +PRs: + +```bash +# Fork-only (QN deploy depends on this PR): +gh pr create --repo quiknode-labs/shredstream-proxy --base master \ + --head qn/ + +# Upstream contribution (after the fork PR has merged): +gh pr create --repo jito-labs/shredstream-proxy --base master \ + --head +``` + +The PR template at `.github/PULL_REQUEST_TEMPLATE.md` includes a checkbox +to confirm the upstream/fork status at PR creation time — please tick the +right box. + +## Syncing with upstream + +To pull new commits from `jito-labs/shredstream-proxy:master`: + +```bash +gh repo sync quiknode-labs/shredstream-proxy --source jito-labs/shredstream-proxy +``` + +Or the GitHub UI's "Sync fork" button on the repo page. This only ever +pulls from upstream — it never pushes our `qn/*` changes anywhere. + +## Local development + +Standard Rust toolchain workflow (see `rust-toolchain.toml` for the pinned +version). Build deps: `protoc` (Protobuf compiler) and the submodule under +`jito_protos/protos/` initialized: + +```bash +git submodule update --init --recursive +cargo build --release +cargo test --all-features +``` From 5c2968c360f28084b0ab24a433a42d47bccf4e78 Mon Sep 17 00:00:00 2001 From: Maksim Kramarenko Date: Mon, 11 May 2026 18:40:35 -0400 Subject: [PATCH 2/3] Update PR template + CONTRIBUTING.md for main-qn / master split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that `main-qn` exists as the QN-side default branch and `master` is being repositioned as a clean mirror of jito-labs/shredstream-proxy, the policy docs need to reflect the new two-branch model. Changes: - PR template: target text now references `main-qn` (default) vs `master` (upstream mirror). The upstreamable workflow is described as "land on main-qn first, then cherry-pick to master and open upstream PR" — same pattern, just made explicit. - CONTRIBUTING.md: rewritten with a clear two-branch table at the top, branch-naming rules updated to specify branch-off and PR-target separately, full day-to-day workflow for both fork-only and upstreamable changes (with the cherry-pick step spelled out), and a section on `gh repo sync` for refreshing master from upstream. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/PULL_REQUEST_TEMPLATE.md | 29 +++--- CONTRIBUTING.md | 155 ++++++++++++++++++++++--------- 2 files changed, 127 insertions(+), 57 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 64ccc4a3..3722b1fb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,18 +1,25 @@ ## Is this change upstreamable? -- [ ] **Yes** — this is broadly useful and should be offered to - `jito-labs/shredstream-proxy` as well. Use an unprefixed or - `feature/*` branch name. After this PR merges here, open a separate - PR against `jito-labs/shredstream-proxy:master`. -- [ ] **No** — this is QuickNode-specific (CI runner, deploy paths, - operational tooling, OCI bucket paths, fleet-specific defaults, - etc.). Use a `qn/*` branch name. Do **not** open an upstream PR. +- [ ] **Yes** — broadly useful (bug fix, generic feature, refactor). After + this PR merges into `main-qn`, cherry-pick onto a branch off `master` + and open a PR against `jito-labs/shredstream-proxy:master`. +- [ ] **No** — QuickNode-specific (CI runner, deploy paths, OCI bucket, + fleet defaults, operational tooling). Use a `qn/*` branch name and + do **not** open an upstream PR. ## Summary @@ -20,5 +27,5 @@ submitting — it affects whether this change should also be offered upstream. ## Test plan - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 622c5990..a9ea044d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,74 +1,137 @@ # Contributing -This repository is a fork of [`jito-labs/shredstream-proxy`](https://github.com/jito-labs/shredstream-proxy) -maintained by QuickNode. Changes land here for two reasons: +This repository is QuickNode's fork of +[`jito-labs/shredstream-proxy`](https://github.com/jito-labs/shredstream-proxy). +We use a two-branch model to keep fork-specific overrides separated from +upstream-eligible work, so accidental upstream contribution of QN-only code +is unlikely. -1. **Upstreamable improvements** — bug fixes, new features, or refactors - that are broadly useful and should eventually flow to - `jito-labs/shredstream-proxy`. -2. **Fork-specific overrides** — CI runners, deploy plumbing, operational - tooling, and other things tied to QuickNode's infrastructure that - don't belong upstream. +## The two branches -To keep these straight and avoid accidentally proposing fork-specific -changes upstream, we use a branch-naming convention and a PR template -checkbox. +| Branch | Role | Where PRs target | What lives here | +|---|---|---|---| +| **`main-qn`** | Default branch on the fork. QN's working line. | All day-to-day PRs. | Everything in `master` + QN-specific patches (CI, deploy plumbing, fleet defaults). | +| **`master`** | Clean mirror of `jito-labs/shredstream-proxy:master`. | Only branches destined for upstream contribution. | Exactly what's upstream, nothing more. Refreshed via `gh repo sync`. | + +The deploy pipeline (`role_chain_build`) builds release tags. Tags are +created from `main-qn`, so the resulting binary always carries the QN +patches. ## Branch naming -| Prefix | Use for | Upstream-bound? | -|---|---|---| -| `qn/*` | Fork-specific changes — CI workflows, build pipeline shims, infra integration, fleet defaults | **No** — never open an upstream PR from these | -| `feature/*` or unprefixed | Generic improvements — bug fixes, new features, refactors | Yes, optionally | +| Prefix | Use for | Branch off | PR target | +|---|---|---|---| +| `qn/*` | Fork-specific changes — CI workflows, deploy paths, infra integration, operational tooling | `main-qn` | `main-qn` | +| `feature/*` or unprefixed | Generic improvements — bug fixes, generic features, refactors | `main-qn` (initially) | `main-qn` (initially); `master` later if upstreamed | + +If you're unsure whether a change is upstreamable, branch off `main-qn` +and target `main-qn`. The decision of whether to also send it upstream +can be made after review. + +## Day-to-day workflow (fork-only change) + +```bash +git checkout main-qn +git pull +git checkout -b qn/my-fork-only-change + +# ... make changes, commit ... -Examples: -- `qn/ci-make-runnable-on-fork` — CI runner switch from Jito's self-hosted - pool to GitHub-hosted runners. Fork-specific. -- `qn/oci-binary-path-update` — change OCI bucket layout the deploy - pipeline reads from. Fork-specific. -- `add-listen-port-device-metric-labels` (or `feature/...`) — new InfluxDB - tags on `receiver_stats`. Useful to anyone running the proxy → eligible - to upstream after merging here. +git push -u origin qn/my-fork-only-change +gh pr create \ + --repo quiknode-labs/shredstream-proxy \ + --base main-qn \ + --head qn/my-fork-only-change +``` -If unsure, pick `qn/*`. It's safer to under-promote a generic change than -to accidentally surface a fork-specific one upstream. +Always include `--repo` and `--base` explicitly. The default for `gh pr +create` is the upstream repo's default branch, which is wrong here. -## Opening a PR +## Workflow for an upstreamable change -Always specify the target repo explicitly when using `gh pr create`. The -fork's default for `gh` is the upstream repo, which can lead to mis-routed -PRs: +Do the work against `main-qn` first so the fleet can deploy it, then +mirror it upstream: ```bash -# Fork-only (QN deploy depends on this PR): -gh pr create --repo quiknode-labs/shredstream-proxy --base master \ - --head qn/ +# 1. Land it in our fork +git checkout main-qn +git pull +git checkout -b feature/my-improvement +# ... commits ... +git push -u origin feature/my-improvement +gh pr create \ + --repo quiknode-labs/shredstream-proxy \ + --base main-qn \ + --head feature/my-improvement +``` + +After that PR merges into `main-qn`: -# Upstream contribution (after the fork PR has merged): -gh pr create --repo jito-labs/shredstream-proxy --base master \ - --head +```bash +# 2. Cherry-pick the same change(s) onto a branch off the clean master +git checkout master +git pull +git checkout -b upstream/my-improvement +git cherry-pick +git push -u origin upstream/my-improvement + +# 3. Open the upstream PR +gh pr create \ + --repo jito-labs/shredstream-proxy \ + --base master \ + --head McSim85:upstream/my-improvement # or your GitHub user ``` -The PR template at `.github/PULL_REQUEST_TEMPLATE.md` includes a checkbox -to confirm the upstream/fork status at PR creation time — please tick the -right box. +After upstream merges your PR, the next `gh repo sync` pulls it back into +our `master`, and a routine merge of `master` into `main-qn` removes the +locally-applied version cleanly. -## Syncing with upstream +## Syncing `master` with upstream -To pull new commits from `jito-labs/shredstream-proxy:master`: +Periodically (or when there's something specific you want from upstream): ```bash -gh repo sync quiknode-labs/shredstream-proxy --source jito-labs/shredstream-proxy +gh repo sync quiknode-labs/shredstream-proxy \ + --source jito-labs/shredstream-proxy \ + --branch master ``` -Or the GitHub UI's "Sync fork" button on the repo page. This only ever -pulls from upstream — it never pushes our `qn/*` changes anywhere. +This is one-way: it only pulls from upstream, never pushes our changes +back. After sync, merge `master` into `main-qn` to bring upstream changes +into our working line: + +```bash +git checkout main-qn +git pull +git merge --no-ff origin/master +# resolve conflicts on overridden files (workflows, etc.) — keep our versions +git push +``` + +`git rerere` is helpful here if you keep getting the same conflicts. + +## Opening a PR — quick reference + +```bash +# Fork-only (most common case): +gh pr create --repo quiknode-labs/shredstream-proxy --base main-qn --head qn/ + +# Upstreamable, first land in fork: +gh pr create --repo quiknode-labs/shredstream-proxy --base main-qn --head feature/ + +# Upstreamable, mirror to upstream after fork-side merge: +gh pr create --repo jito-labs/shredstream-proxy --base master --head :upstream/ +``` + +The PR template at `.github/PULL_REQUEST_TEMPLATE.md` includes a checkbox +that asks whether a change is upstreamable. Tick the right box so reviewers +know whether to expect a follow-up upstream PR. ## Local development -Standard Rust toolchain workflow (see `rust-toolchain.toml` for the pinned -version). Build deps: `protoc` (Protobuf compiler) and the submodule under -`jito_protos/protos/` initialized: +Standard Rust workflow. Pinned toolchain in `rust-toolchain.toml`, +`protoc` required, and the submodule under `jito_protos/protos/` needs +to be initialized: ```bash git submodule update --init --recursive From d9545ec9ac30dfc4fc9537e93ffe2dd8802155d5 Mon Sep 17 00:00:00 2001 From: Maksim Kramarenko Date: Tue, 12 May 2026 14:07:12 -0400 Subject: [PATCH 3/3] Document current QN-specific patches and branch protection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two sections to CONTRIBUTING.md that became relevant after PR #4 (CI fixes) landed and branch protection rulesets were configured: - "What's currently QN-specific" — lists the three categories of changes on main-qn that diverge from upstream: the metric label patch (eligible for upstream), the CI workflow overrides (fork-specific), and the policy docs themselves. Future contributors can use this as a reference for what "broadly useful" looks like vs "QN-only". - "Branch protection" — explains the two rulesets (master-mirror-lock and main-qn-pr-review), why direct pushes to master fail, and which CI checks must pass on PRs to main-qn. No content changes elsewhere in the doc — the two-branch model and gh CLI invocations are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- CONTRIBUTING.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9ea044d..e321bf67 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,45 @@ The deploy pipeline (`role_chain_build`) builds release tags. Tags are created from `main-qn`, so the resulting binary always carries the QN patches. +## What's currently QN-specific + +As of this writing, the diff between `main-qn` and `master` is: + +| Change | What it does | +|---|---| +| `proxy/src/forwarder.rs` + `proxy/src/main.rs` (metric label patch) | Adds `listen_port` and `device` tags to the `shredstream_proxy-receiver_stats` metric so multicast (`device=doublezero1`) and unicast (`device=unicast`) traffic from the same source IP can be attributed separately. Originally needed to measure DoubleZero's marginal contribution to first-arrival shred throughput. Eligible for upstream contribution. | +| `.github/workflows/*.yml`, `.github/actions/setup-rust/action.yaml` | Switches CI from Jito's private self-hosted runners (`ubuntu-22.04-16c-64g-public`) to stock `ubuntu-22.04`. Replaces Docker Hub publish steps with direct `cargo build --release`. Uses `actions-rust-lang/setup-rust-toolchain` for the toolchain (reads `rust-toolchain.toml`). QN-specific — would not be appropriate upstream. | +| `.github/PULL_REQUEST_TEMPLATE.md`, `CONTRIBUTING.md` | Fork-management policy (this document). QN-specific. | + +When evaluating whether a new change is upstreamable, the metric label +patch is a useful reference for what "broadly useful" looks like. + +## Branch protection + +The fork has GitHub Rulesets configured to enforce the two-branch model: + +- **`master-mirror-lock`** ruleset on `master`: blocks direct pushes, + force-pushes, deletions, and non-fast-forward updates. Only repo + admins running `gh repo sync` (which uses the GitHub API, not git + push) can advance `master`. This guarantees `master` never diverges + from upstream. +- **`main-qn-pr-review`** ruleset on `main-qn`: requires a pull request + with at least one approval before merge. Blocks force-pushes and + deletions. CI status checks (`test`, `build`) are required to pass. + +If you try `git push origin master` directly, the push will be rejected +by the ruleset. That's intended — go through `gh repo sync` for upstream +updates, or open a PR against `main-qn` for QN-specific work. + +The active CI workflows on every PR to `main-qn`: + +| Workflow | What it runs | +|---|---| +| `test` | `cargo test --all-features --locked` | +| `build` | `cargo clippy --all-features --all-targets --tests -- -D warnings` and `cargo build --release --locked --bin jito-shredstream-proxy` | + +Both must pass before merge. The `release` workflow only runs on `v*` tag pushes — it produces a GitHub Release asset. + ## Branch naming | Prefix | Use for | Branch off | PR target |