Skip to content

Commit 8da0c3c

Browse files
committed
docs(agents): address review feedback on the release-flow docs
The manual fallback was the only real defect. It bumped `package.json` with a `sed` while `set-release-version.mjs` — which prerelease.yml and promote.yml both call — also writes `package-lock.json`. A fallback release cut by hand therefore shipped a lockfile disagreeing with the package it locks, the exact drift that script was written to stop. It now calls the script, and hoists the RC version into `$RC` so rc.2+ does not need three edits kept in sync. Also: "promote.yml is the only writer" now says *automated* writer, so it stops contradicting the manual fallback three sections below; the cherry-pick rule points at `git log release/vX.Y.Z..main` for seeing what is not in the RC; the product constraint distinguishes gating on readiness from gating on the user, so an unfinished capture backend can still hide behind a flag; and `.harness/memory/MEMORY.md` no longer describes the pre-#90 `release/vX.Y.Z-rc.N` naming.
1 parent 9d08f34 commit 8da0c3c

3 files changed

Lines changed: 14 additions & 10 deletions

File tree

.harness/docs/git-workflow.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Tier 3 (homebrew/winget/nix/aur) does **not** run on pre-releases — they're al
6767

6868
Pin the pre-release link in `#rc-testing`. Get the maintainer team + a few early adopters to install and smoke-test.
6969

70-
**Between RC cut and promote**, the only thing that may happen on `release/vX.Y.Z` is **cherry-picks of bugfixes** that address problems discovered in the RC. Features, refactors, and CI/docs changes are **not** applied to the release branch — they live on `main` and ship in the next release cycle.
70+
**Between RC cut and promote**, the only thing that may happen on `release/vX.Y.Z` is **cherry-picks of bugfixes** that address problems discovered in the RC. Features, refactors, and CI/docs changes are **not** applied to the release branch — they live on `main` and ship in the next release cycle. `git log release/vX.Y.Z..main --oneline` lists exactly what is *not* in the RC.
7171

7272
If the RC has a regression, fix forward on `main`, then **cherry-pick the fix commit onto the release branch** with `git cherry-pick <sha>`, then re-cut as `vX.Y.Z-rc.(N+1)` (the rerun of `prerelease.yml` reuses the frozen branch and re-tags its tip; no rebase required). The previous RC is auto-superseded by GitHub.
7373

@@ -103,7 +103,7 @@ The name carries **no `-rc.N` suffix**. `prerelease.yml` and `promote.yml` must
103103
Key rules:
104104

105105
1. **`prerelease.yml` creates the branch at rc.1 and reuses it for later RCs.** It must never delete or recreate it: that would drop the cherry-picks and silently re-cut from `main`, which defeats the freeze this contract exists to guarantee.
106-
2. **`promote.yml` is the only writer** that turns `-rc.N` into the stable version on the branch.
106+
2. **`promote.yml` is the only automated writer** that turns `-rc.N` into the stable version on the branch. A maintainer doing that by hand means the dispatch failed — see § Manual fallback.
107107
3. **`main` is never frozen.** Develop as usual. The release branch is the freeze.
108108
4. **Cherry-picks during the RC window** are committed manually by a maintainer (`git checkout release/vX.Y.Z && git cherry-pick <sha>`), then rerun `prerelease.yml` with the next `rc_number` to re-tag the branch tip.
109109

@@ -113,17 +113,21 @@ This exists because of the v1.6.0 incident (2026-07-05): the original `promote.y
113113

114114
If the dispatch UI is unavailable, the workflow still works from a shell:
115115

116+
Use `set-release-version.mjs`, not a hand-rolled `sed`: it writes the version to **`package-lock.json` too**, and a release commit that bumps only `package.json` ships a lockfile disagreeing with the package it locks (`npm ci` never catches it).
117+
116118
```bash
119+
RC=1.5.0-rc.1 # bump the rc.N for every later candidate
120+
117121
# Cut RC (skips milestone migration and Discord announce)
118122
git checkout -b release/v1.5.0 main # rc.2+: git checkout release/v1.5.0 instead
119-
sed -i -E 's|("version"[[:space:]]*:[[:space:]]*")[^"]*(")|\11.5.0-rc.1\2|' package.json
120-
git add package.json && git commit -m "chore(release): bump to 1.5.0-rc.1 [skip ci]"
123+
node .github/scripts/set-release-version.mjs "$RC"
124+
git commit -am "chore(release): bump to $RC [skip ci]"
121125
git push origin release/v1.5.0
122-
git tag v1.5.0-rc.1 && git push origin v1.5.0-rc.1
126+
git tag "v$RC" && git push origin "v$RC"
123127

124128
# Promote (skips milestone close and Discord announce)
125129
git checkout release/v1.5.0
126-
sed -i -E 's|("version"[[:space:]]*:[[:space:]]*")[^"]*(")|\11.5.0\2|' package.json
130+
node .github/scripts/set-release-version.mjs 1.5.0
127131
git commit -am "chore(release): bump to 1.5.0 [skip ci]"
128132
git push origin release/v1.5.0
129133
git tag v1.5.0 && git push origin v1.5.0

.harness/memory/MEMORY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ There's no Prettier/ESLint — Biome 2.4 does both. Config in `biome.json`: tabs
2323
`npm run build` runs tsc + vite build + electron-builder packaging. For renderer-only iteration use `npm run build-vite` (tsc + vite only, no packaging). Only run the full `build` when verifying a release artifact.
2424

2525
## Release tag must point at the release branch, not main (2026-07-05)
26-
On 2026-07-05 the original `promote.yml` did `git checkout main && git tag vX.Y.Z`, which captured the post-RC tip of `main` (23 commits after the RC cut) as the "stable" v1.6.0. The fix landed the same day: both `prerelease.yml` and `promote.yml` now use a frozen `release/vX.Y.Z-rc.N` branch and tag its tip — see `.github/workflows/prerelease.yml` § Push RC tag and `.github/workflows/promote.yml` § Push stable tag. When reviewing release-related changes, **always verify the tag is being applied to the release branch tip, not to main.** The build.yml `release_tag` input is the SHA, not a branch name; if you set it to a tag the GitHub Release check will look for the source ref — pass the release branch name when smoke-testing without a tag.
26+
On 2026-07-05 the original `promote.yml` did `git checkout main && git tag vX.Y.Z`, which captured the post-RC tip of `main` (23 commits after the RC cut) as the "stable" v1.6.0. The fix landed the same day: both `prerelease.yml` and `promote.yml` now use a frozen `release/vX.Y.Z` branch — one per stable version, named without the `-rc.N` suffix so both workflows resolve the same ref — and tag its tip, then dispatch `build.yml` pinned to that tag. See `.github/workflows/prerelease.yml` § Push RC tag and `.github/workflows/promote.yml` § Push stable tag. When reviewing release-related changes, **always verify the tag is being applied to the release branch tip, not to main.** The build.yml `release_tag` input is the SHA, not a branch name; if you set it to a tag the GitHub Release check will look for the source ref — pass the release branch name when smoke-testing without a tag.

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ OpenScreen is a free, open-source screen recorder and video editor (Electron + R
1414
- Format: `npm run format` (Biome, tabs, double quotes, 100-col)
1515
- i18n check: `npm run i18n:check` (validates the 13 locale files)
1616

17-
**Use npm, not bun/pnpm/yarn/Deno.** Not a style preference: the native Swift (macOS) and C++ (Windows) capture helpers are rebuilt against Electron's ABI by electron-builder + `@electron/rebuild` resolving `package-lock.json`, and other package managers break that path. `packageManager` + `engines` in `package.json` pin the versions; CI installs with `npm ci`.
17+
**Use npm, not bun/pnpm/yarn/Deno.** Not a style preference. The native Swift (macOS) and C++ (Windows) capture helpers are rebuilt against Electron's ABI by electron-builder + `@electron/rebuild`, which resolve the tree through `package-lock.json`. Another package manager writes a different lockfile, so that rebuild breaks. `packageManager` + `engines` in `package.json` pin the versions; CI installs with `npm ci`.
1818

1919
## Development principles
2020

21-
- Prefer the simplest solution that stays readable. No abstraction for hypothetical needs (YAGNI).
21+
- Prefer the simplest solution that stays readable — no abstraction for hypothetical needs (YAGNI).
2222
- **No mandated app-stack choice yet.** Contributors pick their own state/data library. Don't impose one across the codebase and don't refactor existing code onto a different one — keep each addition self-contained and consistent within its own module. A single choice may be enforced later.
2323
- Don't optimize for line count. A dense one-liner that hides control flow is worse than the explicit version.
2424
- Match the surrounding code's idiom rather than introducing a new pattern next to it.
@@ -147,4 +147,4 @@ Both workflows need the `OPENSCREEN_RELEASE_TOKEN` secret (see `technical-docume
147147
- **Pixi.js v8** is the rendering engine. Filters come from `pixi-filters` and `@pixi/filter-drop-shadow`. GSAP + `motion` for animation.
148148
- **i18n**: 13 locales in `src/i18n/locales/<locale>/` (e.g. `src/i18n/locales/en/settings.json`). The `i18n:check` script validates them — run it after touching translation files.
149149
- **Build pipeline**: `npm run build` is full electron-builder. For iterating on renderer only, use `npm run build-vite` (Vite + tsc, no packaging).
150-
- **Product constraints**: the project is free forever and explicitly "not production-grade". Don't add paywalls, premium tiers, or feature-gating logic, and don't add upsell language to the README or UI copy. This is a hard constraint, not a judgement call.
150+
- **Product constraints**: the project is free forever and explicitly "not production-grade". Don't add paywalls, premium tiers, or logic that gates a feature on who the user is, and don't add upsell language to the README or UI copy. This is a hard constraint, not a judgement call. (A flag that hides an unfinished capture backend is fine — it gates on readiness, not on the user.)

0 commit comments

Comments
 (0)