docs: make origin dev the integration authority

This commit is contained in:
Bailey Dixon
2026-08-24 11:39:18 -04:00
parent 6a676beded
commit 4831f523df
6 changed files with 88 additions and 27 deletions
+18 -3
View File
@@ -21,6 +21,7 @@ not redefine the branch, release, or hotfix policy here and in `RELEASE.md`.
| Contract item | Canonical source or target |
|---|---|
| Integration branch | `dev`; normal feature, fix, docs, and chore PRs target `dev` |
| Integration authority | `origin/dev`; local `dev` is a fast-forward-only mirror, never a private staging queue |
| Release branch | `main`; release history and hotfix integration only |
| Production tag source | The new `main` tip after an approved `dev` → `main` release PR, or after an approved hotfix PR to `main` |
| Candidate tag source | An exact release-prepared and tested `dev` SHA; prerelease suffix required (`-alpha`, `-beta`, or `-rc.N`) |
@@ -36,6 +37,19 @@ open the `dev` → `main` release PR, tag the resulting `main` tip, publish the
surface artifacts, deploy or roll out, and verify the live result. Never create
a staging branch.
### Local integration discipline
- Fetch `origin/dev` before creating a task branch or worktree; do not base new
work on a stale local `dev` ref.
- Keep the primary local `dev` checkout tracked-clean and update it only with
`git merge --ff-only origin/dev`. Feature, fix, docs, release-prep, and
integration commits belong on their own branches and reach `dev` through PRs.
- When several reviewed branches must move together, combine them on a named
`integration/<batch>` branch in its own worktree, then open one PR to `dev`.
An integration branch is not a second `dev` and must not become a hidden queue.
- One coordinator owns final base refresh, required checks, and merges while
concurrent worktrees continue independently.
## Non-negotiables (the short list)
- **Vanilla Hermes path = upstream-only.** The standard (no-plugin) connection
@@ -56,9 +70,10 @@ a staging branch.
of these lanes are on demand; do not add scheduled execution without explicit
approval.
- **Conventional Commits + `main`/`dev` branching.** Normal branches start at
`dev` and PR back to `dev`; merge commits/no-ff are the repository policy.
Version bumps happen only during release preparation on `dev`, and production
tags are cut only from `main`.
current `origin/dev` and PR back to `dev`; merge commits/no-ff are the
repository policy.
Version bumps happen only on a release-prep branch targeting `dev`, and
production tags are cut only from `main`.
- **Android:** Jetpack Compose only (no XML), kotlinx.serialization (no Gson),
OkHttp (no Ktor), `wss://` only. Run `./gradlew lint` before pushing Kotlin.
- **Plugin (Python 3.11+):** aiohttp + asyncio (no threading), type hints
+15 -6
View File
@@ -139,18 +139,27 @@ After the plugin is in place, restart hermes and verify pairing with `hermes-pai
We follow [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`.
**Branching model: `main` + `dev`.** Feature branches — `feature/<name>`,
`fix/<name>`, `docs/<name>`, `chore/<name>` — branch off `dev` and merge back
into `dev` via merge-commit/no-ff PRs. This includes small documentation fixes.
`fix/<name>`, `docs/<name>`, `chore/<name>` — branch from current `origin/dev`
and merge back into `dev` via merge-commit/no-ff PRs. This includes small
documentation fixes.
`main` is release history, not the normal contribution target; it receives
approved release PRs from `dev` and focused hotfix PRs based on production tags.
`origin/dev` is the canonical integration ref. Keep local `dev` as a clean,
fast-forward-only mirror and create each task in its own branch/worktree from the
current `origin/dev`. Do not accumulate unpublished commits on local `dev`. If a
maintainer needs to combine several reviewed branches, use a temporary
`integration/<batch>` branch and merge that branch through a normal PR to `dev`.
See [docs/worktree-workflow.md](docs/worktree-workflow.md) for the concurrent
worktree procedure.
Feature completion means merged and verified on `dev`; it does not mean the
change has been released. A separate Forge release issue/session owns release
preparation, the `dev` → `main` release PR, tagging, artifacts, rollout or
deployment, and live verification. Release-prep commits land on `dev`; tags are
cut from the resulting `main` tip as `android-vX.Y.Z`, `server-vX.Y.Z`, or
`desktop-vX.Y.Z`. See [RELEASE.md](RELEASE.md) for the full release and hotfix
procedures.
deployment, and live verification. Release-prep commits use a dedicated branch
and PR into `dev`; tags are cut from the resulting `main` tip as
`android-vX.Y.Z`, `server-vX.Y.Z`, or `desktop-vX.Y.Z`. See
[RELEASE.md](RELEASE.md) for the full release and hotfix procedures.
## Stale PR salvage and contributor credit
+8
View File
@@ -1,5 +1,13 @@
# Hermes-Relay — Dev Log
## 2026-08-24 — Single dev integration authority
`origin/dev` is the sole integration authority. Primary local `dev` checkouts are
fast-forward-only mirrors, while feature, fix, docs, release-prep, and multi-branch
integration work stays in dedicated worktrees and reaches `dev` through PRs. This
keeps concurrent sessions from creating a second unpublished integration history
and makes exact-head CI the gate before release preparation.
## 2026-08-24 — Release surface naming
Future Android, Plugin, and CLI+UI GitHub Releases, Android Play submissions,
+17 -11
View File
@@ -137,8 +137,8 @@ optional Windows installer.
| `desktop/tray/package.json` | tray UI package version |
| `desktop/tray/package-lock.json` | locked tray UI package version |
Prepare a new CLI version on `dev` without creating a tag or npm-generated
commit:
Prepare a new CLI version on its release-prep branch targeting `dev`, without
creating a tag or npm-generated commit:
```powershell
cd desktop
@@ -185,14 +185,17 @@ never create a staging branch. Stable production tags are cut only from the new
### Normal contribution and release flow
1. Branch `feature/*`, `fix/*`, `docs/*`, or `chore/*` from `dev`.
1. Fetch `origin/dev` and branch `feature/*`, `fix/*`, `docs/*`, or `chore/*`
from that exact ref in a dedicated worktree.
2. Open the PR into `dev` and require CI to pass.
3. Merge with a merge commit/no-ff according to repository policy.
4. Accumulate user-facing work under `CHANGELOG.md` `[Unreleased]`.
5. Treat the feature as complete when it is merged and verified on `dev`.
6. Start a separate Forge release issue/session when a release train is approved.
7. Prepare the affected surface release on `dev`, including its version and notes.
8. Open and approve the release PR from `dev` into `main`.
7. Create `release/<surface-version>` from current `origin/dev`, prepare the
affected surface version and notes there, and merge its PR into `dev`.
8. Fast-forward local `dev` to the exact merged `origin/dev`, then open and
approve the release PR from `dev` into `main`.
9. Tag the new `main` tip with the affected surface prefix.
10. Build and publish that surface's artifacts, roll out or deploy from the
immutable tag, and verify the release and live environment.
@@ -205,10 +208,12 @@ never create a staging branch. Stable production tags are cut only from the new
| `fix/<name>` | Focused bug fix | `fix/media-projection-fgs` |
| `docs/<name>` | Docs-only changes larger than a typo | `docs/sideload-guide` |
| `chore/<name>` | Cleanup / refactor / tooling | `chore/sync-version-sources` |
| `integration/<batch>` | Maintainer-owned batch of reviewed branches | `integration/android-routing-batch` |
| `release/<surface-version>` | Surface release preparation targeting `dev` | `release/android-1.13.0` |
All of the above branch off `dev` and merge back to `dev`. There is no
straight-to-main exemption — even single-file typos go through a feature
branch and PR into `dev`.
All of the above branch from current `origin/dev` and merge back to `dev`.
There is no straight-to-main exemption — even single-file typos go through a
task branch and PR into `dev`.
### Merge style: `--no-ff`
@@ -226,7 +231,7 @@ preserves the branch context as a visible merge commit in
Squash merges lose that detail and are **not** the house style.
### Version bumps happen at release-prep on `dev`, NOT on feature branches
### Version bumps happen on release-prep branches, NOT feature branches
Feature branches **never** touch `gradle/libs.versions.toml`,
plugin-owned version metadata, or `desktop/package.json`.
@@ -234,8 +239,9 @@ If two feature branches both bumped a release version, they'd collide on
version files and, for Android, on `appVersionCode` (which must be
monotonic).
Version-bump commits live on `dev` as the last commit of release-prep
work. Android commits use `release(android): android-vX.Y.Z`; server commits
Version-bump commits land on `dev` through the release-prep PR as the final
release-preparation commit. Android commits use
`release(android): android-vX.Y.Z`; server commits
use `release(server): server-vX.Y.Z`; desktop commits use
`release(desktop): desktop-vX.Y.Z`. A release PR then merges `dev` →
`main` with `--no-ff`, and the matching tag is cut from the resulting
+4
View File
@@ -1042,6 +1042,10 @@ two operational frictions as it grew:
a release-merge from `dev`.
- `dev` = **integration branch**. Feature branches target `dev`; the
`[Unreleased]` CHANGELOG section lives there.
- `origin/dev` is the single integration authority. Local `dev` is a
fast-forward-only mirror; concurrent work stays on task worktrees, and any
multi-branch batch uses a named integration branch plus PR rather than a
private local-`dev` queue.
- Server pulls `dev` for staging. Users and `hermes-relay-update` track
`main` and tags.
- Releases are opened as PRs from `dev` into `main`, merged `--no-ff`,
+26 -7
View File
@@ -19,7 +19,7 @@ parallel. This is the entire reason per-feature worktrees feel fast.
```
main ──●──────────────────●───────── released only; tags cut HERE
\ /
dev ──●──●──●──●──●──●──●─────────── integration; [Unreleased] accumulates
origin/dev ──●──●──●──●──●──●──────────── canonical integration ref
/ / /
feat/a ──● worktree A ┐
feat/b ────● worktree B ├─ one worktree = one branch = one unit of work
@@ -29,10 +29,24 @@ feat/c ──────● worktree C ┘
## Four rules cover everything
1. **One worktree = one branch = one feature/fix**, in its own folder.
2. **Branch off `dev`, PR back to `dev`.** CI green → merge `--no-ff`.
2. **Branch from current `origin/dev`, PR back to `dev`.** CI green → merge
`--no-ff`.
3. **`main` only receives `dev`→`main` release merges.** Tag from `main`.
4. **Worktrees are disposable** — remove them once the PR merges.
The primary local `dev` checkout is a tracked-clean, fast-forward-only mirror of
`origin/dev`. It is not a staging area. Never commit, merge feature branches, or
queue release work there; update it with `git merge --ff-only origin/dev` after
fetching. This gives every session one integration authority even while several
worktrees are active.
When multiple reviewed branches must land as one batch, create
`integration/<batch>` from the latest `origin/dev` in a dedicated worktree, merge
the component branches there with `--no-ff`, and open one PR from that integration
branch to `dev`. One coordinator refreshes the batch against current `dev`, waits
for exact-head checks, and merges it. Other worktrees do not update local `dev` or
push directly to `origin/dev`.
## In Orca (the normal path here)
This repo is developed inside Orca, which has its own worktree manager. **Let Orca
@@ -54,8 +68,11 @@ the four rules above; gitflow is the merge discipline layered on top.
When you're not driving through Orca:
```bash
# Create a worktree for a new feature branch off dev
git worktree add ../hermes-feat-bridge-scroll -b feature/bridge-scroll dev
# Refresh the canonical integration ref without switching the primary checkout
git fetch origin dev
# Create a worktree for a new feature branch from exact origin/dev
git worktree add ../hermes-feat-bridge-scroll -b feature/bridge-scroll origin/dev
# ...work in that folder, commit, push, open a PR into dev...
@@ -74,8 +91,9 @@ git worktree remove <path> # delete a worktree (must be clean, or pass --force)
### Gotchas
- **A branch can be checked out in only one worktree at a time.** Trying to check
out `dev` in two worktrees errors — that's intentional. Keep `dev`/`main` in the
main checkout and feature branches in their own worktrees.
out `dev` in two worktrees errors — that's intentional. Keep local `dev`/`main`
as clean mirrors in the primary checkout and do all task work on worktree
branches.
- **Worktrees share the same `.git`**, so a `git fetch`/`git gc` in any worktree
affects all of them. Refs and stashes are shared; the *working tree* and
per-worktree `HEAD` are not.
@@ -98,4 +116,5 @@ git worktree remove <path> # delete a worktree (must be clean, or pass --force)
Worktrees change *nothing* about the release contract. Feature worktrees merge to
`dev`; releases are still cut by merging `dev` → `main` with `--no-ff` and tagging
from `main` (Android `android-v*`, Plugin `server-v*`, CLI+UI `desktop-v*`). Version bumps
happen on `dev` at release-prep, never on a feature branch — see RELEASE.md.
happen on a dedicated release-prep branch that merges through a PR to `dev` — see
RELEASE.md.