From 41c89623fea5500291b5205043eb15dc82b683eb Mon Sep 17 00:00:00 2001 From: Yicong Huang <17627829+Yicong-Huang@users.noreply.github.com> Date: Fri, 7 Aug 2026 16:19:27 -0700 Subject: [PATCH 1/4] docs: define how to pick a PR title's type and scope Closes #7393 Co-Authored-By: Claude Opus 5 (1M context) --- .github/PULL_REQUEST_TEMPLATE | 14 ++++++-- AGENTS.md | 47 +++++++++++++++++++++----- CONTRIBUTING.md | 31 +++++++++++++++++ docs/contribution-guidelines/_index.md | 25 ++++++++++++++ 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index 41287564ff3..fb71ef98acb 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -4,8 +4,18 @@ Thanks for sending a pull request (PR)! Here are some tips for you: [Contributing to Texera](https://github.com/apache/texera/blob/main/CONTRIBUTING.md) 2. Ensure you have added or run the appropriate tests for your PR 3. If the PR is work in progress, mark it a draft on GitHub. - 4. Please write your PR title to summarize what this PR proposes, we - are following Conventional Commits style for PR titles as well. + 4. Please write your PR title to summarize what this PR proposes, we + are following Conventional Commits style for PR titles as well: + - `fix` is for behavior that worked before and no longer does; adding, + removing, or reworking a functionality is a `feat`; a change that + leaves the user-facing behavior unchanged is a `refactor`. + - A test-only PR is `test(): ...`; repairing a broken test is + `fix(test, ): ...`. + - A dependency bump is `fix(deps, ): ...` when it patches a CVE + and `chore(deps, ): ...` otherwise. + - A PR targeting a release branch appends the version as the last scope + component, e.g. `fix(deps, frontend, v1.2): ...`. + See CONTRIBUTING.md for the full convention. 5. Be sure to keep the PR description updated to reflect all changes. --> diff --git a/AGENTS.md b/AGENTS.md index 7118073a781..04a7027d569 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -138,18 +138,47 @@ Short, **Conventional Commits**, same shape for branch and commit subject. | Feature | `feat/agent-workflow-edit` | `feat(agent-service): enable workflow edit` | | Bug fix | `fix/marker-replay` | `fix(amber): marker replay during reconfiguration` | | Tests | `test/pyamber-handlers` | `test(pyamber): add handler unit tests` | -| Chore | `chore/angular-21` | `chore(deps): upgrade frontend to Angular 21` | +| Chore | `chore/angular-21` | `chore(deps, frontend): upgrade to Angular 21` | | CI | `ci/cache-action-bump` | `ci: bump coursier/cache-action to v8.1.0` | Both ≤ ~60 chars. For code changes, if you use a scope, use the module name (`amber`, `pyamber`, `frontend`, `agent-service`, `file-service`, …) — not -`amber-python`. Dependency-only updates split by semantics: `fix(deps): ...` for -runtime/production dependency bumps (they ship to users), -`chore(deps): ...` for dev/toolchain-only bumps, and `ci: ...` for -CI-only changes (including GitHub Actions bumps). Append the module -as a second scope when the bump is module-specific, e.g. -`fix(deps, pyamber): ...`; omit it for cross-module bumps (sbt). No `Co-authored-by:` trailer for the repo -owner. +`amber-python`. No `Co-authored-by:` trailer for the repo owner. + +**Choosing the type** turns on what happens to the behavior, not on how big +the diff is: + +| The change | Type | +| --- | --- | +| Worked before, broken now | `fix` | +| Support never existed; adding it | `feat` | +| Support exists; removing it | `feat` | +| Works, but is hard to use; reworking it | `feat` | +| User-facing behavior unchanged | `refactor` | + +`refactor` claims the **user-facing** behavior is identical. Tests that pin a +user-facing API must pass untouched — editing one of those assertions means +the behavior moved, so it is a `feat` or a `fix`. Tests that pin internals (a +private helper's signature, call order between collaborators, the shape of an +intermediate value) mirror the implementation, so rewriting them alongside the +code they mirror is still a `refactor`. + +**Tests.** A test-only PR is `test(): ...`. Repairing a broken or +flaky test is a bug fix in test code: `fix(test, ): ...`. + +**Dependencies.** Split by whether the bump carries a security fix: + +| Bump | Commit | +| --- | --- | +| Patches a CVE | `fix(deps, ): ...` | +| Everything else | `chore(deps, ): ...` | +| CI-only, incl. GitHub Actions | `ci: ...` | + +Omit the module for cross-module bumps (sbt). + +**Backports.** A PR targeting `release/vX.Y` appends the version as the last +scope component — `fix(deps, frontend, v1.2): ...`. Version tags belong only +on release-branch PRs, never on one targeting `main`. ### Issues and PRs @@ -193,7 +222,7 @@ write/adjust test (red) -> edit source (green) -> refactor | New feature / behavior change | Failing test, then implement. | | Bug fix | Regression test reproducing the bug, then fix. | | Code with **no tests** | **Characterization tests** pin current behavior first; only then change source. | -| Refactor (no behavior change) | Tests stay green throughout — no assertion edits. | +| Refactor (no user-facing behavior change) | Tests stay green throughout. User-facing API assertions stay untouched; tests that mirror internals may be rewritten with the code. | Every test must cover: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7557eb7a286..2cef460851f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,6 +54,37 @@ Thank you for your interest in contributing to Texera! Please follow the steps b - `fix(ui): prevent racing of requests` - `chore(deps): bump numpy to version 2.0.0` +##### Choosing between `feat`, `fix`, and `refactor` + +The type depends on what happens to the behavior, not on how large the change is. + +| Your change | Type | +| ----------- | ---- | +| A functionality worked before and no longer does | `fix` | +| A functionality or a form of support never existed and you are adding it | `feat` | +| A functionality exists and you are removing support for it | `feat` | +| A functionality works but is hard to use, and you are reworking it | `feat` | +| The change leaves the user-facing behavior unchanged | `refactor` | + +`refactor` is a strong claim: it says the **user-facing** behavior is identical. The test suite is how you check that, but not every test carries the same weight. A test that pins a user-facing API is the contract — if you had to change one of its assertions to make the suite green, the behavior moved, and the PR is a `feat` or a `fix`. A test that pins internals, such as a private helper's signature, the call order between two collaborators, or the shape of an intermediate value, is mirroring the implementation; rewriting it alongside the code it mirrors is expected and still a `refactor`. + +##### Tests and dependency bumps + +Two cases use a two-part scope, written as `(, ): `: + +| Your change | Title | +| ----------- | ----- | +| A test-only PR — adding or updating tests | `test(): ...`, e.g. `test(amber): add marker replay specs` | +| Repairing a broken or flaky test | `fix(test, ): ...`, e.g. `fix(test, frontend): stabilize the dashboard spec` | +| A dependency bump that patches a CVE | `fix(deps, ): ...`, e.g. `fix(deps, pyamber): bump protobuf for CVE-2025-4565` | +| Any other dependency bump | `chore(deps, ): ...`, e.g. `chore(deps, frontend): bump numpy to 2.0.0` | + +Omit the module for bumps that span modules, and use `ci: ...` for CI-only changes, including GitHub Actions bumps. + +##### Backports + +A PR targeting a release branch appends the release version as the **last scope component**, so a backport of `fix(deps, frontend): ...` to `release/v1.2` is titled `fix(deps, frontend, v1.2): ...`. Version tags belong only on release-branch PRs — never put one on a PR targeting `main`. + > 💡 You can use the [Conventional Commits plugin](https://plugins.jetbrains.com/plugin/13389-conventional-commit) in IntelliJ to help format commit messages correctly. #### PR Description diff --git a/docs/contribution-guidelines/_index.md b/docs/contribution-guidelines/_index.md index eb062a75295..800cc3872d0 100644 --- a/docs/contribution-guidelines/_index.md +++ b/docs/contribution-guidelines/_index.md @@ -72,6 +72,31 @@ We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/): - `chore(deps): bump dependency versions` - The PR title becomes the final squashed commit message upon merge. +Pick the type by what happens to the behavior, not by how large the change is: + +| Your change | Type | +| ----------- | ---- | +| A functionality worked before and no longer does | `fix` | +| A functionality or a form of support never existed and you are adding it | `feat` | +| A functionality exists and you are removing support for it | `feat` | +| A functionality works but is hard to use, and you are reworking it | `feat` | +| The change leaves the user-facing behavior unchanged | `refactor` | + +`refactor` claims the **user-facing** behavior is identical. A test that pins a user-facing API must keep passing untouched — changing one of its assertions means the behavior moved, so the PR is a `feat` or a `fix`. A test that pins internals mirrors the implementation and may be rewritten alongside the code it mirrors. + +Tests and dependency bumps use a two-part scope: + +| Your change | Title | +| ----------- | ----- | +| A test-only PR | `test(): ...` | +| Repairing a broken or flaky test | `fix(test, ): ...` | +| A dependency bump that patches a CVE | `fix(deps, ): ...` | +| Any other dependency bump | `chore(deps, ): ...` | + +Omit the module for bumps that span modules, and use `ci: ...` for CI-only changes, including GitHub Actions bumps. + +A PR targeting a release branch appends the version as the last scope component — a backport of `fix(deps, frontend): ...` to `release/v1.2` becomes `fix(deps, frontend, v1.2): ...`. Never put a version tag on a PR targeting `main`. + #### PR Description Should Include: - **Purpose:** use `Closes #1234` to auto-close an issue. - **Summary:** short overview of your changes. From 2d0c9d04ff59915dea2880f19d70304e33501569 Mon Sep 17 00:00:00 2001 From: Yicong Huang <17627829+Yicong-Huang@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:08:14 -0700 Subject: [PATCH 2/4] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Yicong Huang <17627829+Yicong-Huang@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2cef460851f..9e0b2b39818 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,7 +77,7 @@ Two cases use a two-part scope, written as `(, ): ): ...`, e.g. `test(amber): add marker replay specs` | | Repairing a broken or flaky test | `fix(test, ): ...`, e.g. `fix(test, frontend): stabilize the dashboard spec` | | A dependency bump that patches a CVE | `fix(deps, ): ...`, e.g. `fix(deps, pyamber): bump protobuf for CVE-2025-4565` | -| Any other dependency bump | `chore(deps, ): ...`, e.g. `chore(deps, frontend): bump numpy to 2.0.0` | +| Any other dependency bump | `chore(deps, ): ...`, e.g. `chore(deps, pyamber): bump numpy to 2.0.0` | Omit the module for bumps that span modules, and use `ci: ...` for CI-only changes, including GitHub Actions bumps. From c0a2292b8a632bb7a67f8ab464e4b4eba1f6551c Mon Sep 17 00:00:00 2001 From: Yicong Huang <17627829+Yicong-Huang@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:27:52 -0700 Subject: [PATCH 3/4] docs: align the GitHub Actions bump form with renovate.json5 and define rework by user-facing behavior --- .github/PULL_REQUEST_TEMPLATE | 10 ++++++---- AGENTS.md | 15 ++++++++++----- CONTRIBUTING.md | 10 ++++++---- docs/contribution-guidelines/_index.md | 10 ++++++---- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index fb71ef98acb..10248925cbd 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -6,13 +6,15 @@ Thanks for sending a pull request (PR)! Here are some tips for you: 3. If the PR is work in progress, mark it a draft on GitHub. 4. Please write your PR title to summarize what this PR proposes, we are following Conventional Commits style for PR titles as well: - - `fix` is for behavior that worked before and no longer does; adding, - removing, or reworking a functionality is a `feat`; a change that - leaves the user-facing behavior unchanged is a `refactor`. + - `fix` is for behavior that worked before and no longer does; adding or + removing a functionality, or reworking one so that user-facing behavior + intentionally changes, is a `feat`; a change that leaves the user-facing + behavior unchanged is a `refactor`. - A test-only PR is `test(): ...`; repairing a broken test is `fix(test, ): ...`. - A dependency bump is `fix(deps, ): ...` when it patches a CVE - and `chore(deps, ): ...` otherwise. + and `chore(deps, ): ...` otherwise; GitHub Actions bumps take + `ci` as their module, e.g. `chore(deps, ci): ...`. - A PR targeting a release branch appends the version as the last scope component, e.g. `fix(deps, frontend, v1.2): ...`. See CONTRIBUTING.md for the full convention. diff --git a/AGENTS.md b/AGENTS.md index 04a7027d569..c94002c86a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -139,7 +139,7 @@ Short, **Conventional Commits**, same shape for branch and commit subject. | Bug fix | `fix/marker-replay` | `fix(amber): marker replay during reconfiguration` | | Tests | `test/pyamber-handlers` | `test(pyamber): add handler unit tests` | | Chore | `chore/angular-21` | `chore(deps, frontend): upgrade to Angular 21` | -| CI | `ci/cache-action-bump` | `ci: bump coursier/cache-action to v8.1.0` | +| CI | `ci/merge-queue-stacking` | `ci: stack merge-queue builds by module` | Both ≤ ~60 chars. For code changes, if you use a scope, use the module name (`amber`, `pyamber`, `frontend`, `agent-service`, `file-service`, …) — not @@ -153,9 +153,12 @@ the diff is: | Worked before, broken now | `fix` | | Support never existed; adding it | `feat` | | Support exists; removing it | `feat` | -| Works, but is hard to use; reworking it | `feat` | +| Reworked so user-facing behavior intentionally changes | `feat` | | User-facing behavior unchanged | `refactor` | +Behavior is what the code does, not what a doc or an old PR description claims +it does: implementing something that was never actually there is a `feat`. + `refactor` claims the **user-facing** behavior is identical. Tests that pin a user-facing API must pass untouched — editing one of those assertions means the behavior moved, so it is a `feat` or a `fix`. Tests that pin internals (a @@ -166,15 +169,17 @@ code they mirror is still a `refactor`. **Tests.** A test-only PR is `test(): ...`. Repairing a broken or flaky test is a bug fix in test code: `fix(test, ): ...`. -**Dependencies.** Split by whether the bump carries a security fix: +**Dependencies.** `fix` only when the bump carries a security fix: | Bump | Commit | | --- | --- | | Patches a CVE | `fix(deps, ): ...` | | Everything else | `chore(deps, ): ...` | -| CI-only, incl. GitHub Actions | `ci: ...` | +| GitHub Actions | `chore(deps, ci): ...` | -Omit the module for cross-module bumps (sbt). +Omit the module for cross-module bumps (sbt). GitHub Actions bumps take `ci` +as their module — that is what [`.github/renovate.json5`](.github/renovate.json5) +opens them with; a bare `ci: ...` is for hand-written CI and workflow changes. **Backports.** A PR targeting `release/vX.Y` appends the version as the last scope component — `fix(deps, frontend, v1.2): ...`. Version tags belong only diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e0b2b39818..d45d87d1090 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,7 +52,7 @@ Thank you for your interest in contributing to Texera! Please follow the steps b - Example PR titles: - `feat: add a new join operator` - `fix(ui): prevent racing of requests` - - `chore(deps): bump numpy to version 2.0.0` + - `chore(deps, pyamber): bump numpy to version 2.0.0` ##### Choosing between `feat`, `fix`, and `refactor` @@ -63,14 +63,16 @@ The type depends on what happens to the behavior, not on how large the change is | A functionality worked before and no longer does | `fix` | | A functionality or a form of support never existed and you are adding it | `feat` | | A functionality exists and you are removing support for it | `feat` | -| A functionality works but is hard to use, and you are reworking it | `feat` | +| A functionality is reworked in a way that intentionally changes user-facing behavior | `feat` | | The change leaves the user-facing behavior unchanged | `refactor` | +Behavior is defined by the code, not by what a document or an old PR description says the code does. A functionality that was never implemented does not exist, so implementing it is a `feat` even when the docs already described it as present. + `refactor` is a strong claim: it says the **user-facing** behavior is identical. The test suite is how you check that, but not every test carries the same weight. A test that pins a user-facing API is the contract — if you had to change one of its assertions to make the suite green, the behavior moved, and the PR is a `feat` or a `fix`. A test that pins internals, such as a private helper's signature, the call order between two collaborators, or the shape of an intermediate value, is mirroring the implementation; rewriting it alongside the code it mirrors is expected and still a `refactor`. ##### Tests and dependency bumps -Two cases use a two-part scope, written as `(, ): `: +Test and dependency PRs take the titles below. Where the table shows a two-part scope, it is written as `(, ): `: | Your change | Title | | ----------- | ----- | @@ -79,7 +81,7 @@ Two cases use a two-part scope, written as `(, ): ): ...`, e.g. `fix(deps, pyamber): bump protobuf for CVE-2025-4565` | | Any other dependency bump | `chore(deps, ): ...`, e.g. `chore(deps, pyamber): bump numpy to 2.0.0` | -Omit the module for bumps that span modules, and use `ci: ...` for CI-only changes, including GitHub Actions bumps. +Omit the module for bumps that span modules. GitHub Actions bumps are dependency bumps too and take the `ci` module — `chore(deps, ci): ...`, or `fix(deps, ci): ...` when the bump patches a CVE — which is the form [`.github/renovate.json5`](.github/renovate.json5) opens them with. Reserve a bare `ci: ...` for hand-written CI and workflow changes. ##### Backports diff --git a/docs/contribution-guidelines/_index.md b/docs/contribution-guidelines/_index.md index 800cc3872d0..7a4abf27dc4 100644 --- a/docs/contribution-guidelines/_index.md +++ b/docs/contribution-guidelines/_index.md @@ -79,21 +79,23 @@ Pick the type by what happens to the behavior, not by how large the change is: | A functionality worked before and no longer does | `fix` | | A functionality or a form of support never existed and you are adding it | `feat` | | A functionality exists and you are removing support for it | `feat` | -| A functionality works but is hard to use, and you are reworking it | `feat` | +| A functionality is reworked in a way that intentionally changes user-facing behavior | `feat` | | The change leaves the user-facing behavior unchanged | `refactor` | +Behavior is defined by the code, not by what a document or an old PR description says the code does. A functionality that was never implemented does not exist, so implementing it is a `feat` even when the docs already described it as present. + `refactor` claims the **user-facing** behavior is identical. A test that pins a user-facing API must keep passing untouched — changing one of its assertions means the behavior moved, so the PR is a `feat` or a `fix`. A test that pins internals mirrors the implementation and may be rewritten alongside the code it mirrors. -Tests and dependency bumps use a two-part scope: +Test and dependency PRs take the titles below. Where the table shows a two-part scope, it is written as `(, ): `: | Your change | Title | | ----------- | ----- | -| A test-only PR | `test(): ...` | +| A test-only PR — adding or updating tests | `test(): ...` | | Repairing a broken or flaky test | `fix(test, ): ...` | | A dependency bump that patches a CVE | `fix(deps, ): ...` | | Any other dependency bump | `chore(deps, ): ...` | -Omit the module for bumps that span modules, and use `ci: ...` for CI-only changes, including GitHub Actions bumps. +Omit the module for bumps that span modules. GitHub Actions bumps are dependency bumps too and take the `ci` module — `chore(deps, ci): ...`, or `fix(deps, ci): ...` when the bump patches a CVE — which is the form Renovate opens them with. Reserve a bare `ci: ...` for hand-written CI and workflow changes. A PR targeting a release branch appends the version as the last scope component — a backport of `fix(deps, frontend): ...` to `release/v1.2` becomes `fix(deps, frontend, v1.2): ...`. Never put a version tag on a PR targeting `main`. From 5cc5ff3adab1c70ae799868463c37a4c5b003893 Mon Sep 17 00:00:00 2001 From: Yicong Huang <17627829+Yicong-Huang@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:30:59 -0700 Subject: [PATCH 4/4] docs: use the module name in the scope examples and state the scope rule --- CONTRIBUTING.md | 4 +++- docs/contribution-guidelines/_index.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d45d87d1090..99e3e009886 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,9 +51,11 @@ Thank you for your interest in contributing to Texera! Please follow the steps b - All PR titles will be used as the **squashed commit message** when merged into the `main` branch. - Example PR titles: - `feat: add a new join operator` - - `fix(ui): prevent racing of requests` + - `fix(frontend): prevent racing of requests` - `chore(deps, pyamber): bump numpy to version 2.0.0` +A scope names the module the change lands in — `amber`, `pyamber`, `frontend`, `agent-service`, `file-service`, and so on. Use the module's own name rather than an informal synonym, and when a PR spans modules, scope it to the one carrying the substantive change. + ##### Choosing between `feat`, `fix`, and `refactor` The type depends on what happens to the behavior, not on how large the change is. diff --git a/docs/contribution-guidelines/_index.md b/docs/contribution-guidelines/_index.md index 7a4abf27dc4..007f9efa9c9 100644 --- a/docs/contribution-guidelines/_index.md +++ b/docs/contribution-guidelines/_index.md @@ -68,10 +68,12 @@ Fork the [Texera repository](https://github.com/apache/texera) on GitHub and clo We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/): - Example PR titles: - `feat: add new join operator` - - `fix(ui): resolve workflow panel crash` + - `fix(frontend): resolve workflow panel crash` - `chore(deps): bump dependency versions` - The PR title becomes the final squashed commit message upon merge. +A scope names the module the change lands in — `amber`, `pyamber`, `frontend`, `agent-service`, `file-service`, and so on. Use the module's own name rather than an informal synonym, and when a PR spans modules, scope it to the one carrying the substantive change. + Pick the type by what happens to the behavior, not by how large the change is: | Your change | Type |