diff --git a/.rusuban/locks.json b/.rusuban/locks.json new file mode 100644 index 000000000..d351a260c --- /dev/null +++ b/.rusuban/locks.json @@ -0,0 +1,52 @@ +{ + "mergeMethod": "rebase", + "lockedPaths": [ + ".github/**", + "scripts/**", + "nix/**", + "flake.*", + "package.json", + "package-lock.json", + "Cargo.toml", + "Cargo.lock", + "electron-builder.*", + ".npmrc" + ], + "maxLines": 300, + "maxFiles": 15, + "sizeExempt": [ + "*.test.*", + "*.spec.*", + "**/tests/**", + "**/test/**", + "**/__tests__/**", + "**/fixtures/**", + "*.md", + "technical-documentation/**", + "docs/**" + ], + "requiredChecks": ["CodeRabbit"], + "ignoredChecks": [ + "nix build .#openscreen", + "Sync PR activity to Discord", + "Sync ROADMAP.md to Discord", + "Mark linked issues fixed in main" + ], + "evidence": [ + { + "paths": [ + "crates/compositor/**", + "electron/native/**", + "electron/native-bridge/**", + "electron/recording/**", + "src/native/**", + "src/lib/exporter/**", + "*Preview*.js", + "*Preview*.jsx", + "*Preview*.ts", + "*Preview*.tsx" + ], + "what": "a pixel-identical export of the reference project; export time and preview frame rate within ±5 % of the base; a preview and an export of the same instant that show the same effects, composition and timing at the preview's size" + } + ] +} diff --git a/.rusuban/rules/01-autonomy.md b/.rusuban/rules/01-autonomy.md new file mode 100644 index 000000000..ece892392 --- /dev/null +++ b/.rusuban/rules/01-autonomy.md @@ -0,0 +1,82 @@ +# What the agents do alone, and what comes to the owner + +The owner is @EtienneLescot. Every card goes to the owner. + +## Alone + +The agents act alone on everything that is not a product or architecture decision: + +- fix a bug, and merge a PR that is not a feature once its gates are green (see 02-merging); +- approve a fork's CI after reading the diff; +- ask for a rebase, a fix or missing information; +- close a duplicate, an item that was replaced, or one that came due. + +## To the owner, always with a card + +- A feature, issue or PR. +- A change of UI or UX: visible English text, style, layout, a default value, a setting. +- An architecture choice: a new module, a new dependency, a new IPC or API surface, a data format. +- An impact on pixels, rendering or performance that no proof has ruled out. +- A refusal: declining a PR, closing a feature request, or answering a product question. + +## Issues + +- **A bug that can be reproduced and is documented enough**: the agents own it, and a worker fixes it. +- **A bug without enough information**: it waits on its reporter (`owner: "third"`, `waits: "@login"`). + Post one factual question. +- **A product, UI or architecture request**: to the owner, with a card. +- **A duplicate**: set `links.duplicateOf`, post a factual comment and close it. + +## Waiting on a third party: two days at most + +An item that waits on someone (a reporter, an author, a contributor, a merge, a release) comes back +two days later (`revisitAt`). Read the thread first: if they answered in the last two days, take the +answer in and judge again. Otherwise, move on without them. + +- **A bug fix or a consolidation** (bug, maintenance, cleanup, robustness, translation): the agents + own it, and a worker moves it forward. + - An issue: fix it from what is known (the thread, logs, the code, a reproduction on a machine the + agents can reach) and open the PR. + - A contributor's PR: finish it in their place, on their fork's branch, without closing their PR + (rebase, fixes, review threads). They keep the credit. + - If their fork refuses maintainer edits, ask them to allow them. Without an answer in two days, + carry their commits to a new PR from a fork under your account whose Actions stay disabled, + never from a branch of this repo: a branch here runs its workflows in the repo's trusted + context, where secrets can reach them; a fork's PR never runs its code with secrets or a + write token. Their name stays on their commits: + - read every commit first. One that touches `.github/`, `scripts/` or the build goes to the + owner on a card; + - link the two PRs, and say so on theirs. When theirs would close an issue, the new PR's + description carries its closing reference; + - before the new PR merges, read their PR's head again and bring in what they pushed since. + Once it merged, compare their head with the last one you carried: anything newer goes into + a follow-up PR. If the issue the new PR closed is not complete without it, reopen it. The + follow-up's description carries its closing reference only when it completes the issue, and + `Refs #N` otherwise, `Refs owner/repo#N` for an issue in another repo. + - A wait on a merge or a release: check whether it happened, then close the item or push what + blocks it. + - Close only when the code gives no lead and no machine reproduces it, with a factual comment that + invites a reopen with the missing information. +- **A new feature**, issue or PR: to the owner, with a card that presents it as it is: what is done, + what is missing. Offer actions you will take: merge it as it is, finish it yourself, keep it open as + "help wanted", or close it. + +Never hand a two-day wait back to the third party without a recent answer from them: that would be a +silent wait. + +## Nothing stays with the agents without work + +An item the agents own comes back after one day at most (`revisitAt`). With no work in progress, +delegate it to a worker, hand it to a named third party, or bring it to the owner with a card. + +## Priority + +- **P0**: a crash, lost data, or a recording or an export that fails, in a released version. +- **P1**: a core flow degraded (capture, preview, editing, export), or a regression. +- **P2**: any other bug, and maintenance. +- **P3**: cosmetic, and nice to have. + +## Areas + +`capture`, `preview`, `export`, `editor`, `ai`, `mcp`, `i18n`, `packaging`, `tooling`, `storage`, +`webcam`, `audio`. diff --git a/.rusuban/rules/02-merging.md b/.rusuban/rules/02-merging.md new file mode 100644 index 000000000..499da8dc4 --- /dev/null +++ b/.rusuban/rules/02-merging.md @@ -0,0 +1,82 @@ +# What merges alone, and how this repo merges + +## A PR may merge alone (`pr.auto: true`) + +It applies to every author, contributors included, judged on the head you read. A PR merges alone +only when it is one of these: + +- a bug fix; +- a translation into a language other than English; +- documentation; +- tests; +- maintenance. + +It never merges alone when it is: + +- a feature; +- a change of UI or UX; +- an architecture choice; +- an impact on pixels, rendering or performance that a proof has not ruled out. + +**A bug** is behavior that contradicts what is expected or documented: a crash, a desync, a wrong +export. A new setting, an interface text, a default value or a new visible behavior is a feature. + +The locks file adds what the server checks alone: + +- the supply-chain paths (CI, scripts, dependencies, packaging) never merge alone; +- at most 300 changed lines and 15 files, tests and documentation excluded. + +## Rendering and performance need a proof + +Preview and export share one source of truth for rendering: what you see is what you export. + +A change to capture, preview, compositor, export or rendering needs a proof of no impact: + +- a pixel-identical export of the reference project; +- export time and preview frame rate within ±5 % of the base, measured in the real app, heavy case + included; +- a preview and an export of the same instant, compared at the preview's size: they show the same + effects, with the same composition and the same timing. They need not match pixel for pixel. + +The locks file names the zones. Elsewhere, set `pr.evidence.needed: true` yourself when the change can +reach the picture or its timing. A worker other than the judge makes the proof and records it. + +Performance comes first. A correctness fix that costs latency is split in two: + +- the part that costs nothing goes on its own; +- the rest goes to the owner as an explicit trade-off, on a card. + +## Rebase only + +- **This repo merges by rebase only, with no merge commits and no squash.** +- **Conflicts are fixed by rebasing on the base, never by a merge commit.** With a merge commit, GitHub + still calls the PR mergeable, but it cannot rebase it. Check the REST field `rebaseable`, not + `mergeable`. +- **During a train of merges, `rebaseable` can be stale.** Rebase on main, push, and wait for CI. +- **Merge first the PRs that touch shared files**, such as the end-to-end checklist and the locales. + +## No closing keyword in a commit + +- **A rebase merge replays every commit.** A `Fixes #N` in a commit closes the issue, even when the PR + only says "Part of #N". +- **Closing keywords** (`Fixes`, `Closes`, `Resolves`) belong in the PR's description only, and only + when the PR completes the issue. Agents write `Refs #N`. +- **Before a partial fix merges**, read its commit messages. + +## Checks + +- **The Nix build is not a merge gate**: the locks file ignores it. +- **CodeRabbit is required.** When its review is cancelled or skipped (it reviews at most 8 PRs an + hour here), comment `@coderabbitai review` on the PR, then wait for its review. If that request is + skipped too, ask once more an hour later; if the second one is skipped as well, the PR goes to the + owner on a card. Never more than two requests per head. +- **Do not trust the CI rollup on a fork's PR.** Its workflows wait for an approval, while the Discord + sync and CodeRabbit pass without one, so the rollup can read green when no real job ran. Judge from + the CI workflow's own run on the head. + +## Features run on the three systems + +- **A feature must work on macOS, Windows and Linux.** A feature PR limited to one system is not merged. +- **Before you propose to merge a feature, check the three systems.** If one is missing, comment to + ask the contributor for the port and a short end-to-end video per system (a real capture and an + export). diff --git a/.rusuban/rules/03-review.md b/.rusuban/rules/03-review.md new file mode 100644 index 000000000..3851adbd3 --- /dev/null +++ b/.rusuban/rules/03-review.md @@ -0,0 +1,56 @@ +# Reviewing + +These are what the owner has turned down after CI was green. Check them before you recommend a merge. + +## Interface + +- **Every control has a visible effect in every reasonable state, not only at the edges.** If what it + changes is invisible, show it on the canvas or drop the control. +- **One control, one axis.** Two controls never fight over the same visible result, and a control + never moves an axis it does not name. +- **No raw internal values shown to the user**, such as signed percentages for a position. +- **One style per row**: never text buttons and icon buttons mixed in the same panel. +- **No explanatory sentence under a setting.** The label says it. +- **An option that does nothing in the current context is hidden**, not greyed out with a reason. +- **The one exception is a warning that prevents a real surprise.** +- **An automatic mode is available only on homogeneous inputs.** On mixed inputs it is not offered. +- **Prefer fixing the model underneath** to adding presets or controls over a broken one. + +## Translations + +- **Every new text key exists in the locale files.** A key missing everywhere shows raw in the app. +- **The locale check is not enough.** It only compares the locales with one another, and the tests mock + the translation function. + +## Rendering + +- **Every effect goes through the one source of rendering that preview and export share**: what you + see is what you export. A PR that renders an effect in only one of the two paths, or differently + in each, is not merged. + +## Performance + +**A PR on preview, capture, compositor or export carries before-and-after numbers**, measured in the +real app, heavy case included: + +- frame rate; +- time per frame; +- seek latency; +- CPU and GPU; +- frames dropped. + +No numbers, no merge. + +## PRs that meet + +- **Two PRs green on their own can break main together.** When a PR changes what a shared function does, + for example it no longer throws, look at every caller, including those another open PR adds. +- **When two open PRs touch the same files**, set `links.before` so the order is explicit. + +## Fixes made by workers + +- **A fix of an issue is made in the worker's own worktree**, on a new branch, and its PR is opened + with `Refs #N`. +- **Finishing a contributor's PR happens on their branch**, never in a competing PR (see + 01-autonomy). +- **The repo's AGENTS.md applies before the PR**: targeted tests, both typechecks, and lint. diff --git a/.rusuban/rules/04-github.md b/.rusuban/rules/04-github.md new file mode 100644 index 000000000..a8bb1ac0e --- /dev/null +++ b/.rusuban/rules/04-github.md @@ -0,0 +1,16 @@ +# Writing on GitHub + +- **Every message on GitHub is in English**: short, warm and factual. +- **What agents may post on their own is factual.** + - Allowed: fixed in a version, a request for information, a duplicate, a reminder, a review of a + bug fix, a request to rebase. + - Never on your own, always a card first: a refusal, closing a feature, a product answer. +- **Thank contributors.** When you finish a contributor's PR, it stays theirs: + - push to their fork's branch, as the maintainer can; + - keep their PR open; + - rebase it, never merge main into it; + - their name stays on their commits. +- **Approve a fork's CI only after reading the head's diff.** + - The diff must hold no secret, no network access, no install hook, and no doubtful dependency. + - Read any change under `.github/` or `scripts/` line by line. If in doubt, write a card. + - Approving one contributor's runs also releases their other open PRs: read those diffs too.