feat(forge): pull requests open as WIP until measured, with pr ready, wip, edit, update, status and a description check #48

Merged
HumanBean merged 2 commits from HumanBean/Longshot:pr-workflow into main 2026-11-13 00:53:19 +00:00
Owner

Why

Pull requests were opened for review before they were measured, and their descriptions went stale as they changed, so reviewers couldn't tell what was ready or what a PR does now. This makes a PR work in progress until it is measured, keeps its description current with a comment for each change, and gives the command line and a check to do it.

What changed

  • rules: CONTRIBUTING.md's Commits and pull requests (the steps 4 to 6: WIP until measured, the description kept current, a comment for each new thing, the label needs measurements) and Measurements (columns named main @ <hash> and this PR @ <hash>, never a bare Before/After; another baseline named exactly); one-line reminders in the template, docs/workflow.md's PR and review steps and AGENTS.md.
  • template: .forgejo/pull_request_template.md in the order Why, What changed, Flags and settings (a table, one row per switch, menu row, ini key or build flag, or "None"), Measurements (with How to reproduce), Not tested / Tested but not measured, Screenshots, Risk and rollback, Reviewer notes, Issues, the checklists; a line of guidance under each heading as a comment. The AI trailers box moved to If applicable, and a box for the Flags table and the switch reference joined it.
  • check: scripts/check_pr_description.py (from the local pr-description-check work, adapted): every required section filled in with no <...> stand-in left, a Measurements table whose columns each carry a label and a hash, one the change (this PR @ <hash>, or a named build that carries it) and one the baseline (main @ <hash>, or a named build), with a Baseline: <its column> line whenever it isn't main against this PR (no this PR, <anything> columns), and the main: / this PR: lines on their columns' commits, the Flags table or "None", every RX_*/HOS_*/LONGSHOT_* name the PR's diff adds listed there, every For everyone box ticked. Warnings only: a vk_menu.cpp change with Flags "None", and a PR rebased onto a newer main than the one measured. WIP PRs pass with a notice.
  • workflow: .forgejo/workflows/pr-description.yml runs it on pull_request_target (opened, edited, synchronize, reopened), reading only the description and the diff from the API, with #13's runner label and pinned checkout.
  • scripts/forge.py: pr create opens as WIP from the template with main's and the branch's commits filled in (--ready checks first); pr ready, pr wip, pr edit, pr update, pr status; pr comment --body-file as before.
  • tests: tests/test_check_pr_description.py (14), tests/test_forge_pr.py (18, the HTTP layer stood in, no network), the sample tests/pr_description/good.md.
  • docs: docs/forge.md documents the commands; docs/development.md's switches section points at the Flags table.

Flags and settings

Flag New or changed What it does Default now Goal: on by default? Helps on Doesn't help on Untested on Untested, but should help on
forge.py pr create --ready New Opens the PR ready for review, after the description check Off: PRs open as WIP No: WIP until measured is the rule PRs whose description is complete when opened - Windows -
forge.py pr create --draft Changed Now the default; still accepted, the same as --wip On Yes: it is the default Existing scripts and habits - Windows -
check_pr_description.py --wip (--draft), --diff New Treat a --file description as WIP; check it against a diff Off No: for local use Checking a description before opening - Windows -

Measurements

main: d4a69456 (2026-11-12)
this PR: pr-workflow @ bcaf516b
Hardware: Ryzen desktop, CachyOS (Linux 7.3), Python 3.13
Scene: no game run: the game-free checks only
Method: LONGSHOT_VULKAN_HEADERS=/usr/include python -I -B tests/run_all.py, two interleaved runs each (main, this PR, main, this PR), the whole run; the two new tests by themselves; forge.py pr status 18 and this PR, opened with forge.py pr create and filled with pr update, against git.magicbean.dev
How to reproduce: jj new main@forge (or this branch), then the command above; python -I -B tests/test_forge_pr.py; python -I scripts/forge.py pr status 48

main @ d4a69456 this PR @ bcaf516b Δ
tests/run_all.py: passed (run 1 / run 2) 489 / 489 491 / 491 +2 (the two new tests)
tests/run_all.py: failed 2 2 0 (the same two)
tests/run_all.py: skipped 38 38 0
tests/run_all.py: time (run 1 / run 2) 85 / 85 s 86 / 86 s +1 s
tests/test_check_pr_description.py absent 14 pass +14
tests/test_forge_pr.py absent 18 pass +18
main @ d4a69456:
FAIL       0.1s  tests/test_bake_portability.py
FAIL       0.1s  tests/test_builder_log_read_only.py
489 passed, 2 failed, 38 skipped in 85 s (linux, 24 at once)
489 passed, 2 failed, 38 skipped in 85 s (linux, 24 at once)

this PR @ bcaf516b:
FAIL       0.2s  tests/test_bake_portability.py
FAIL       0.1s  tests/test_builder_log_read_only.py
pass       0.2s  tests/test_check_pr_description.py
pass       0.4s  tests/test_forge_pr.py
491 passed, 2 failed, 38 skipped in 86 s (linux, 24 at once)
491 passed, 2 failed, 38 skipped in 86 s (linux, 24 at once)

The two failures are the known ones on main here (test_bake_portability: no zstandard; test_builder_log_read_only: no libtk).

Not tested

Not tested: Windows (forge.py and the check are standard library only, paths through pathlib/os.path); the workflow itself, since Actions are off and no runner serves the repository yet.
Tested but not measured: forge.py pr create, pr update, pr status and pr ready against git.magicbean.dev on this PR, and pr status 18 on a merged one.

Screenshots

Nothing on screen.

Risk and rollback

  • The workflow must merge with or after #13. Forgejo reads only the first of .forgejo/workflows, .gitea/workflows, .github/workflows that exists: merged before #13 moves the others, this PR's .forgejo/workflows would shadow .github/workflows. Actions are off on the repository, so nothing runs today either way; it takes effect with #13's move and the runner setup.
  • PRs opened with the old template fail the new check once marked ready; WIP ones only get a notice. Reverting the commit brings back the old template and commands.

Reviewer notes

Start with review() in scripts/check_pr_description.py, then cmd_pr_ready and fill_commits in scripts/forge.py. Left for a follow-up: #13's pr-title.yml strips only WIP: before checking the title, not [WIP]; menu rows and ini keys are only a warning (spotting them in a diff surely would need the menu's row table read).

Issues

See #13

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Not tested.
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags table filled in; README / docs/development.md switch reference updated.
  • Screenshots for a change that shows on screen.
  • A row in docs/tested-configurations.md for each measured run.
  • MKWVK_API_VERSION bumped (gpu/vk/vk_api.h's MkwVkHost or MkwVkRenderer changed).
  • The SPIR-V headers regenerated with glslang (a shader changed).
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths.
  • Docs updated.
## Why Pull requests were opened for review before they were measured, and their descriptions went stale as they changed, so reviewers couldn't tell what was ready or what a PR does now. This makes a PR work in progress until it is measured, keeps its description current with a comment for each change, and gives the command line and a check to do it. ## What changed - rules: CONTRIBUTING.md's *Commits and pull requests* (the steps 4 to 6: WIP until measured, the description kept current, a comment for each new thing, the label `needs measurements`) and *Measurements* (columns named `main @ <hash>` and `this PR @ <hash>`, never a bare Before/After; another baseline named exactly); one-line reminders in the template, `docs/workflow.md`'s PR and review steps and `AGENTS.md`. - template: `.forgejo/pull_request_template.md` in the order Why, What changed, Flags and settings (a table, one row per switch, menu row, ini key or build flag, or "None"), Measurements (with *How to reproduce*), Not tested / Tested but not measured, Screenshots, Risk and rollback, Reviewer notes, Issues, the checklists; a line of guidance under each heading as a comment. The AI trailers box moved to *If applicable*, and a box for the Flags table and the switch reference joined it. - check: `scripts/check_pr_description.py` (from the local `pr-description-check` work, adapted): every required section filled in with no `<...>` stand-in left, a Measurements table whose columns each carry a label and a hash, one the change (`this PR @ <hash>`, or a named build that carries it) and one the baseline (`main @ <hash>`, or a named build), with a `Baseline: <its column>` line whenever it isn't main against this PR (no `this PR, <anything>` columns), and the `main:` / `this PR:` lines on their columns' commits, the Flags table or "None", every `RX_*`/`HOS_*`/`LONGSHOT_*` name the PR's diff adds listed there, every *For everyone* box ticked. Warnings only: a `vk_menu.cpp` change with Flags "None", and a PR rebased onto a newer main than the one measured. WIP PRs pass with a notice. - workflow: `.forgejo/workflows/pr-description.yml` runs it on `pull_request_target` (opened, edited, synchronize, reopened), reading only the description and the diff from the API, with #13's runner label and pinned checkout. - `scripts/forge.py`: `pr create` opens as WIP from the template with main's and the branch's commits filled in (`--ready` checks first); `pr ready`, `pr wip`, `pr edit`, `pr update`, `pr status`; `pr comment --body-file` as before. - tests: `tests/test_check_pr_description.py` (14), `tests/test_forge_pr.py` (18, the HTTP layer stood in, no network), the sample `tests/pr_description/good.md`. - docs: `docs/forge.md` documents the commands; `docs/development.md`'s switches section points at the Flags table. ## Flags and settings | Flag | New or changed | What it does | Default now | Goal: on by default? | Helps on | Doesn't help on | Untested on | Untested, but should help on | |---|---|---|---|---|---|---|---|---| | `forge.py pr create --ready` | New | Opens the PR ready for review, after the description check | Off: PRs open as WIP | No: WIP until measured is the rule | PRs whose description is complete when opened | - | Windows | - | | `forge.py pr create --draft` | Changed | Now the default; still accepted, the same as `--wip` | On | Yes: it is the default | Existing scripts and habits | - | Windows | - | | `check_pr_description.py --wip` (`--draft`), `--diff` | New | Treat a `--file` description as WIP; check it against a diff | Off | No: for local use | Checking a description before opening | - | Windows | - | ## Measurements main: d4a69456 (2026-11-12) this PR: pr-workflow @ bcaf516b Hardware: Ryzen desktop, CachyOS (Linux 7.3), Python 3.13 Scene: no game run: the game-free checks only Method: `LONGSHOT_VULKAN_HEADERS=/usr/include python -I -B tests/run_all.py`, two interleaved runs each (main, this PR, main, this PR), the whole run; the two new tests by themselves; `forge.py pr status 18` and this PR, opened with `forge.py pr create` and filled with `pr update`, against git.magicbean.dev How to reproduce: `jj new main@forge` (or this branch), then the command above; `python -I -B tests/test_forge_pr.py`; `python -I scripts/forge.py pr status 48` | | main @ d4a69456 | this PR @ bcaf516b | Δ | |---|---|---|---| | tests/run_all.py: passed (run 1 / run 2) | 489 / 489 | 491 / 491 | +2 (the two new tests) | | tests/run_all.py: failed | 2 | 2 | 0 (the same two) | | tests/run_all.py: skipped | 38 | 38 | 0 | | tests/run_all.py: time (run 1 / run 2) | 85 / 85 s | 86 / 86 s | +1 s | | tests/test_check_pr_description.py | absent | 14 pass | +14 | | tests/test_forge_pr.py | absent | 18 pass | +18 | ``` main @ d4a69456: FAIL 0.1s tests/test_bake_portability.py FAIL 0.1s tests/test_builder_log_read_only.py 489 passed, 2 failed, 38 skipped in 85 s (linux, 24 at once) 489 passed, 2 failed, 38 skipped in 85 s (linux, 24 at once) this PR @ bcaf516b: FAIL 0.2s tests/test_bake_portability.py FAIL 0.1s tests/test_builder_log_read_only.py pass 0.2s tests/test_check_pr_description.py pass 0.4s tests/test_forge_pr.py 491 passed, 2 failed, 38 skipped in 86 s (linux, 24 at once) 491 passed, 2 failed, 38 skipped in 86 s (linux, 24 at once) ``` The two failures are the known ones on `main` here (`test_bake_portability`: no zstandard; `test_builder_log_read_only`: no libtk). ## Not tested Not tested: Windows (forge.py and the check are standard library only, paths through `pathlib`/`os.path`); the workflow itself, since Actions are off and no runner serves the repository yet. Tested but not measured: `forge.py pr create`, `pr update`, `pr status` and `pr ready` against git.magicbean.dev on this PR, and `pr status 18` on a merged one. ## Screenshots Nothing on screen. ## Risk and rollback - **The workflow must merge with or after #13.** Forgejo reads only the first of `.forgejo/workflows`, `.gitea/workflows`, `.github/workflows` that exists: merged before #13 moves the others, this PR's `.forgejo/workflows` would shadow `.github/workflows`. Actions are off on the repository, so nothing runs today either way; it takes effect with #13's move and the runner setup. - PRs opened with the old template fail the new check once marked ready; WIP ones only get a notice. Reverting the commit brings back the old template and commands. ## Reviewer notes Start with `review()` in `scripts/check_pr_description.py`, then `cmd_pr_ready` and `fill_commits` in `scripts/forge.py`. Left for a follow-up: #13's `pr-title.yml` strips only `WIP: ` before checking the title, not `[WIP]`; menu rows and ini keys are only a warning (spotting them in a diff surely would need the menu's row table read). ## Issues See #13 ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Not tested. - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [ ] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags table filled in; README / docs/development.md switch reference updated. - [ ] Screenshots for a change that shows on screen. - [ ] A row in `docs/tested-configurations.md` for each measured run. - [ ] `MKWVK_API_VERSION` bumped (`gpu/vk/vk_api.h`'s `MkwVkHost` or `MkwVkRenderer` changed). - [ ] The SPIR-V headers regenerated with glslang (a shader changed). - [x] A game-free test added for the fix, failing on `main` and passing here. - [ ] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. - [x] Docs updated.
- CONTRIBUTING, AGENTS.md, docs/workflow.md, docs/forge.md: a PR is work in progress (WIP: title) until it is measured
  and ready for review; the description is kept current and each new thing gets a comment; the label
  'needs measurements'.
- The PR template: Why, What changed, Flags and settings, Measurements (main @ <hash> and this PR @ <hash>, how to
  reproduce), Not tested, Screenshots, Risk and rollback, Reviewer notes, Issues, the checklists, each with a line of
  guidance; the AI trailers box is now If applicable.
- scripts/check_pr_description.py and .forgejo/workflows/pr-description.yml check the description (WIP PRs pass with
  a notice); forge.py pr create opens as WIP from the template with the commits filled in, pr ready runs the check.
- tests/test_check_pr_description.py, tests/test_forge_pr.py (offline, the API stood in), tests/pr_description/good.md.
Author
Owner

Filled in the description: the rules, the commands, the check, and the test runs on main @ d4a69456 and this PR @ 6b92b9d2, two interleaved runs each (489 and 491 passed, the same 2 known failures).

Filled in the description: the rules, the commands, the check, and the test runs on main @ d4a69456 and this PR @ 6b92b9d2, two interleaved runs each (489 and 491 passed, the same 2 known failures).
HumanBean changed title from WIP: feat(forge): pull requests open as WIP until measured, with pr ready, wip, edit, update, status and a description check to feat(forge): pull requests open as WIP until measured, with pr ready, wip, edit, update, status and a description check 2026-11-13 00:16:50 +00:00
The check takes one column as the change (this PR @ <hash>, or a named build that carries it) and one as a labelled
baseline (main @ <hash>, or a named build with its hash). main against this PR needs nothing more; anything else needs
a 'Baseline: <its column>' line. A 'this PR, <anything>' column is refused, and the main: and this PR: lines must name
their columns' commits. CONTRIBUTING's example now reads nightly @ 55b976c0 (the baseline) against main @ 87991bc8.
Author
Owner

Pushed bcaf516b on top: a measurement now names its baseline. The check takes one column as the change (this PR @ , or a named build that carries it) and one as a labelled baseline (main @ , or a named build with its hash). main against this PR needs nothing more; anything else needs a 'Baseline: ' line, and a 'this PR, ' column is refused. CONTRIBUTING's RTX 3080 example was the wrong way round: it now reads nightly @ 55b976c0 (the last nightly before #2602, the baseline) against main @ 87991bc8 (with #2602), noting that main also carried about 50 other merges. In the description: the commits are now bcaf516b, the test runs are measured again (main, this PR, main, this PR: 489 and 491 passed, the same 2 known failures), and the Windows host-code box is unticked, since this PR has no host code and nothing ran on Windows.

Pushed bcaf516b on top: a measurement now names its baseline. The check takes one column as the change (this PR @ <hash>, or a named build that carries it) and one as a labelled baseline (main @ <hash>, or a named build with its hash). main against this PR needs nothing more; anything else needs a 'Baseline: <its column>' line, and a 'this PR, <anything>' column is refused. CONTRIBUTING's RTX 3080 example was the wrong way round: it now reads nightly @ 55b976c0 (the last nightly before #2602, the baseline) against main @ 87991bc8 (with #2602), noting that main also carried about 50 other merges. In the description: the commits are now bcaf516b, the test runs are measured again (main, this PR, main, this PR: 489 and 491 passed, the same 2 known failures), and the Windows host-code box is unticked, since this PR has no host code and nothing ran on Windows.
HumanBean deleted branch pr-workflow 2026-11-13 00:53:19 +00:00
Sign in to join this conversation.
No description provided.