From f61cc1b85de538321d2c6a4d6e3d81a8497366fe Mon Sep 17 00:00:00 2001 From: Taylor Mutch Date: Tue, 27 Oct 2026 08:19:26 -0700 Subject: [PATCH 1/4] fix(ci): allow accepted protobuf breaks for one prerelease Signed-off-by: Taylor Mutch --- .agents/skills/release-captain/SKILL.md | 12 ++ .agents/skills/watch-github-actions/SKILL.md | 2 + .github/workflows/release-qualification.yml | 8 + CI.md | 7 + tasks/scripts/check_proto_compatibility.py | 12 +- .../scripts/check_proto_compatibility_test.py | 158 ++++++++++++++++++ .../scripts/generate-qualification-summary.sh | 15 ++ 7 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 tasks/scripts/check_proto_compatibility_test.py diff --git a/.agents/skills/release-captain/SKILL.md b/.agents/skills/release-captain/SKILL.md index 6ad534404f..5819391020 100644 --- a/.agents/skills/release-captain/SKILL.md +++ b/.agents/skills/release-captain/SKILL.md @@ -42,6 +42,18 @@ tag, or start a second `Pre-release` run for a tag; it has no concurrency guard. picks the highest `-pre.N` on `main` whose whole `Pre-release` run passed, creates the stable tag on that commit, and publishes without requalifying. +### One-candidate protobuf exception + +`v0.1.6-pre.7` has a release-captain-approved protobuf compatibility exception +in `release-qualification.yml`. The check still compiles both protobuf snapshots +and runs Buf; only detected breaking changes are allowed. Compilation and tooling +errors still fail. Other candidates retain normal version-based enforcement. +The run summary and qualification JSON record the exception and reason. Review +all protobuf findings for this candidate and include migration guidance in the +release notes; the exception does not accept other compatibility-review findings. +Remove the workflow exception after promotion. If another candidate is needed, +obtain explicit acceptance for that candidate before changing the tag scope. + ## Setup ```shell diff --git a/.agents/skills/watch-github-actions/SKILL.md b/.agents/skills/watch-github-actions/SKILL.md index 3443407d38..90f20e3983 100644 --- a/.agents/skills/watch-github-actions/SKILL.md +++ b/.agents/skills/watch-github-actions/SKILL.md @@ -169,6 +169,8 @@ the shared `check-protobuf-compatibility` action with `nix run .#check-protobuf- During `0.x`, a minor train permits compatibility findings as warnings; a patch train or no active train rejects them. Compare the current train's version with the latest stable release; commit messages are irrelevant. +For the one-candidate `v0.1.6-pre.7` exception, inspect the run summary and the +qualification JSON's `exceptions` array; see `release-captain` for disposition. Compilation, baseline, and tool errors remain fatal. The `protobuf_compatibility` suite participates in the `release-tag-v1` qualification profile. Pre-release calls the reusable `release-qualification.yml` workflow after building, in parallel with publication. Release diff --git a/.github/workflows/release-qualification.yml b/.github/workflows/release-qualification.yml index 3dc0ca3c9e..a0a3227293 100644 --- a/.github/workflows/release-qualification.yml +++ b/.github/workflows/release-qualification.yml @@ -30,6 +30,9 @@ permissions: env: RELEASE_TAG: ${{ inputs.release-tag }} + # One-candidate exception accepted by the release captain. Remove after promotion. + PROTO_COMPATIBILITY_EXCEPTION_TAG: ${{ inputs.is-prerelease && inputs.release-tag == 'v0.1.6-pre.7' && inputs.release-tag || '' }} + PROTO_COMPATIBILITY_EXCEPTION_REASON: Release captain accepted protobuf breaking changes for v0.1.6-pre.7; migration guidance must accompany the release. defaults: run: @@ -212,6 +215,11 @@ jobs: echo "| Docker E2E | ${DOCKER_E2E_RESULT} |" echo "| VM E2E | ${VM_E2E_RESULT} |" echo + if [[ -n "${PROTO_COMPATIBILITY_EXCEPTION_TAG}" ]]; then + echo "- Protobuf compatibility exception: \`${PROTO_COMPATIBILITY_EXCEPTION_TAG}\`" + echo "- Reason: ${PROTO_COMPATIBILITY_EXCEPTION_REASON}" + echo + fi echo "Advisory compatibility findings do not affect the qualification result." echo "See the Compatibility Review job and compatibility-review-run-${GITHUB_RUN_ID}-attempt-${GITHUB_RUN_ATTEMPT} artifact in [this run](${run_url})." } >> "${GITHUB_STEP_SUMMARY}" diff --git a/CI.md b/CI.md index df66dc0ad3..600c28a678 100644 --- a/CI.md +++ b/CI.md @@ -48,6 +48,13 @@ remains in Actions. This checks protobuf compatibility; SDK/configuration compatibility and migration review remain separate qualification work. +The release qualification workflow has a one-candidate, release-captain-approved +exception for `v0.1.6-pre.7`. It still runs Buf and fails on compilation or tooling +errors, but accepts detected protobuf breaking changes for that tag. The run +summary and qualification JSON's `exceptions` array record the scope and reason. +Other candidates retain the normal version policy. Remove the workflow exception +after promotion; release notes must describe the accepted changes and migration. + Fetch the target and tags to check committed branch changes locally, replacing `origin/main` for another target: diff --git a/tasks/scripts/check_proto_compatibility.py b/tasks/scripts/check_proto_compatibility.py index 8a2ba37134..d2ca37ba0a 100644 --- a/tasks/scripts/check_proto_compatibility.py +++ b/tasks/scripts/check_proto_compatibility.py @@ -103,7 +103,8 @@ def compare(candidate: str, baseline: str, allows_breaks: bool) -> int: if result.returncode == 100 and allows_breaks: print(diagnostics.replace("::error ", "::warning "), end="") print( - "Breaking changes allowed by the version increment; review migration guidance." + "Breaking changes allowed by the version policy or an explicit " + "maintainer exception; review migration guidance." ) return 0 print(diagnostics, end="") @@ -122,6 +123,15 @@ def main() -> int: ) release = ref.removeprefix("refs/tags/") if ref.startswith("refs/tags/") else None stable, train, allows_breaks = train_policy(candidate, release) + exception_tag = os.environ.get("PROTO_COMPATIBILITY_EXCEPTION_TAG", "") + if exception_tag: + if release != exception_tag or not _parse_prerelease_tag(exception_tag): + raise ValueError("Protobuf exception must match the exact prerelease tag.") + reason = os.environ.get("PROTO_COMPATIBILITY_EXCEPTION_REASON", "").strip() + if not reason: + raise ValueError("Protobuf exception requires a reason.") + print(f"Protobuf compatibility exception for {release}: {reason}", flush=True) + allows_breaks = True baseline = f"refs/tags/{stable}" if release else candidate if not release: # merge-tree writes only Git objects, leaving HEAD and the worktree diff --git a/tasks/scripts/check_proto_compatibility_test.py b/tasks/scripts/check_proto_compatibility_test.py new file mode 100644 index 0000000000..f1a540416d --- /dev/null +++ b/tasks/scripts/check_proto_compatibility_test.py @@ -0,0 +1,158 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. +# SPDX-License-Identifier: Apache-2.0 + +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path +from unittest.mock import patch + +import pytest + +sys.path.insert(0, str(Path(__file__).resolve().parent)) + +import check_proto_compatibility as compatibility + +TAG = "v0.1.6-pre.7" +REASON = "Release captain accepted the protobuf changes." + + +@pytest.mark.parametrize( + ("ref", "exception_tag", "reason", "expected"), + [ + (f"refs/tags/{TAG}", TAG, REASON, True), + ("refs/tags/v0.1.6-pre.8", "", "", False), + (f"refs/tags/{TAG}", "", "", False), + ("refs/tags/v0.1.6-pre.8", TAG, REASON, ValueError), + ("refs/tags/v0.1.6", "v0.1.6", REASON, ValueError), + ("refs/heads/main", TAG, REASON, ValueError), + (f"refs/tags/{TAG}", TAG, " ", ValueError), + ], +) +def test_exception_scope(monkeypatch, ref, exception_tag, reason, expected): + monkeypatch.setenv("PROTO_COMPATIBILITY_EXCEPTION_TAG", exception_tag) + monkeypatch.setenv("PROTO_COMPATIBILITY_EXCEPTION_REASON", reason) + monkeypatch.setattr(sys, "argv", ["check", ref]) + with ( + patch.object(compatibility, "git", side_effect=[ref, "candidate-sha"]), + patch.object( + compatibility, "train_policy", return_value=("v0.1.5", "v0.1.6", False) + ), + patch.object(compatibility, "compare", return_value=0) as compare, + ): + if expected is ValueError: + with pytest.raises(ValueError): + compatibility.main() + compare.assert_not_called() + else: + assert compatibility.main() == 0 + assert compare.call_args.args[2] is expected + + +@pytest.mark.parametrize( + ("allows_breaks", "exit_code", "expected"), + [(False, 100, 100), (True, 100, 0), (True, 1, 1), (True, 0, 0)], +) +def test_exception_only_accepts_breaking_diagnostics( + allows_breaks, exit_code, expected +): + with ( + patch.object(compatibility, "export_proto"), + patch.object( + compatibility.subprocess, + "run", + side_effect=[ + subprocess.CompletedProcess([], 0), + subprocess.CompletedProcess([], 0), + subprocess.CompletedProcess([], exit_code, stdout="", stderr=""), + ], + ) as run, + ): + assert compatibility.compare("candidate", "baseline", allows_breaks) == expected + assert [call.args[0][1] for call in run.call_args_list] == [ + "build", + "build", + "breaking", + ] + + +@pytest.mark.parametrize("failed_snapshot", [0, 1]) +def test_exception_does_not_accept_invalid_protobufs(failed_snapshot): + results = [subprocess.CompletedProcess([], 0)] * failed_snapshot + results.append(subprocess.CalledProcessError(100, ["buf", "build"])) + with ( + patch.object(compatibility, "export_proto"), + patch.object(compatibility.subprocess, "run", side_effect=results) as run, + pytest.raises(subprocess.CalledProcessError), + ): + compatibility.compare("candidate", "baseline", True) + assert run.call_count == failed_snapshot + 1 + + +@pytest.mark.skipif(shutil.which("buf") is None, reason="Buf is not installed") +@pytest.mark.parametrize("allows_breaks", [False, True]) +def test_real_buf_field_rename(monkeypatch, allows_breaks): + def export_fixture(ref, destination): + (destination / "proto").mkdir(parents=True) + (destination / "buf.yaml").write_text( + "version: v2\nmodules:\n - path: proto\nbreaking:\n use:\n - FILE\n" + ) + field = "old_name" if ref == "baseline" else "new_name" + (destination / "proto" / "test.proto").write_text( + 'syntax = "proto3";\npackage test.v1;\n' + f"message Request {{ bool {field} = 3; }}\n" + ) + + monkeypatch.setattr(compatibility, "export_proto", export_fixture) + assert compatibility.compare("candidate", "baseline", allows_breaks) == ( + 0 if allows_breaks else 100 + ) + + +@pytest.mark.parametrize("exception", [False, True]) +@pytest.mark.parametrize("proto_result", ["success", "failure", "skipped"]) +def test_qualification_records_exception_without_bypassing_results( + tmp_path, exception, proto_result +): + output = tmp_path / "qualification.json" + env = { + **os.environ, + "RELEASE_TAG": TAG, + "SOURCE_SHA": "candidate-sha", + "IS_PRERELEASE": "true", + "GITHUB_RUN_ID": "123", + "GITHUB_RUN_ATTEMPT": "1", + "GITHUB_SERVER_URL": "https://github.com", + "GITHUB_REPOSITORY": "NVIDIA/OpenShell", + "PROTO_COMPATIBILITY_RESULT": proto_result, + "PROTO_COMPATIBILITY_EXCEPTION_TAG": TAG if exception else "", + "PROTO_COMPATIBILITY_EXCEPTION_REASON": REASON, + } + for suite in ( + "SECURITY", + "CONFORMANCE", + "FEATURE_INTEGRATION", + "DOCKER_E2E", + "VM_E2E", + ): + env[f"{suite}_RESULT"] = "success" + subprocess.run( + [ + "bash", + str(Path(__file__).with_name("generate-qualification-summary.sh")), + str(output), + ], + env=env, + check=True, + capture_output=True, + text=True, + ) + summary = json.loads(output.read_text()) + assert summary["current_profile_passed"] is (proto_result == "success") + assert summary["exceptions"] == ( + [{"suite": "protobuf_compatibility", "tag": TAG, "reason": REASON}] + if exception + else [] + ) diff --git a/tasks/scripts/generate-qualification-summary.sh b/tasks/scripts/generate-qualification-summary.sh index 78f55c239e..0e229cf85d 100755 --- a/tasks/scripts/generate-qualification-summary.sh +++ b/tasks/scripts/generate-qualification-summary.sh @@ -22,12 +22,20 @@ require_env() { [[ $# -eq 1 ]] || die "usage: $0 OUTPUT" output=$1 current_profile_passed=true +proto_exception_tag=${PROTO_COMPATIBILITY_EXCEPTION_TAG:-} +proto_exception_reason=${PROTO_COMPATIBILITY_EXCEPTION_REASON:-} require_env \ RELEASE_TAG SOURCE_SHA IS_PRERELEASE GITHUB_RUN_ID GITHUB_RUN_ATTEMPT \ GITHUB_SERVER_URL GITHUB_REPOSITORY SECURITY_RESULT CONFORMANCE_RESULT \ FEATURE_INTEGRATION_RESULT DOCKER_E2E_RESULT VM_E2E_RESULT PROTO_COMPATIBILITY_RESULT +if [[ -n "${proto_exception_tag}" ]]; then + [[ "${IS_PRERELEASE}" == true && "${proto_exception_tag}" == "${RELEASE_TAG}" ]] || + die "protobuf exception must match the prerelease tag" + [[ -n "${proto_exception_reason//[[:space:]]/}" ]] || die "protobuf exception requires a reason" +fi + for result in \ "${PROTO_COMPATIBILITY_RESULT}" \ "${SECURITY_RESULT}" \ @@ -53,6 +61,8 @@ jq -n \ --arg generated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --arg security "${SECURITY_RESULT}" \ --arg protobuf_compatibility "${PROTO_COMPATIBILITY_RESULT}" \ + --arg proto_exception_tag "${proto_exception_tag}" \ + --arg proto_exception_reason "${proto_exception_reason}" \ --arg conformance "${CONFORMANCE_RESULT}" \ --arg feature_integration "${FEATURE_INTEGRATION_RESULT}" \ --arg docker_e2e "${DOCKER_E2E_RESULT}" \ @@ -72,6 +82,11 @@ jq -n \ ] }, current_profile_passed: $current_profile_passed, + exceptions: (if $proto_exception_tag == "" then [] else [{ + suite: "protobuf_compatibility", + tag: $proto_exception_tag, + reason: $proto_exception_reason + }] end), run: { id: $run_id, attempt: $run_attempt, From 0b6793388e8907d379d34b510b0f671d4983a30c Mon Sep 17 00:00:00 2001 From: Taylor Mutch Date: Tue, 27 Oct 2026 08:21:48 -0700 Subject: [PATCH 2/4] fix(ci): cover all v0.1.6 prerelease candidates Signed-off-by: Taylor Mutch --- .agents/skills/release-captain/SKILL.md | 12 ++++++------ .agents/skills/watch-github-actions/SKILL.md | 2 +- .github/workflows/release-qualification.yml | 6 +++--- CI.md | 7 ++++--- tasks/scripts/check_proto_compatibility_test.py | 13 +++++++++---- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/.agents/skills/release-captain/SKILL.md b/.agents/skills/release-captain/SKILL.md index 5819391020..e018860b07 100644 --- a/.agents/skills/release-captain/SKILL.md +++ b/.agents/skills/release-captain/SKILL.md @@ -42,17 +42,17 @@ tag, or start a second `Pre-release` run for a tag; it has no concurrency guard. picks the highest `-pre.N` on `main` whose whole `Pre-release` run passed, creates the stable tag on that commit, and publishes without requalifying. -### One-candidate protobuf exception +### Patch-train protobuf exception -`v0.1.6-pre.7` has a release-captain-approved protobuf compatibility exception +All `v0.1.6-pre.N` candidates have a release-captain-approved protobuf compatibility exception in `release-qualification.yml`. The check still compiles both protobuf snapshots and runs Buf; only detected breaking changes are allowed. Compilation and tooling -errors still fail. Other candidates retain normal version-based enforcement. +errors still fail. Other versions retain normal version-based enforcement. The run summary and qualification JSON record the exception and reason. Review -all protobuf findings for this candidate and include migration guidance in the +all protobuf findings for each candidate and include migration guidance in the release notes; the exception does not accept other compatibility-review findings. -Remove the workflow exception after promotion. If another candidate is needed, -obtain explicit acceptance for that candidate before changing the tag scope. +Remove the workflow exception after promoting v0.1.6. A new prerelease number +within this patch train retains the exception; other patch or minor trains do not. ## Setup diff --git a/.agents/skills/watch-github-actions/SKILL.md b/.agents/skills/watch-github-actions/SKILL.md index 90f20e3983..f80ef25b12 100644 --- a/.agents/skills/watch-github-actions/SKILL.md +++ b/.agents/skills/watch-github-actions/SKILL.md @@ -169,7 +169,7 @@ the shared `check-protobuf-compatibility` action with `nix run .#check-protobuf- During `0.x`, a minor train permits compatibility findings as warnings; a patch train or no active train rejects them. Compare the current train's version with the latest stable release; commit messages are irrelevant. -For the one-candidate `v0.1.6-pre.7` exception, inspect the run summary and the +For the patch-train `v0.1.6-pre.N` exception, inspect the run summary and the qualification JSON's `exceptions` array; see `release-captain` for disposition. Compilation, baseline, and tool errors remain fatal. The `protobuf_compatibility` suite participates in the `release-tag-v1` qualification profile. Pre-release calls the reusable diff --git a/.github/workflows/release-qualification.yml b/.github/workflows/release-qualification.yml index a0a3227293..14370918cf 100644 --- a/.github/workflows/release-qualification.yml +++ b/.github/workflows/release-qualification.yml @@ -30,9 +30,9 @@ permissions: env: RELEASE_TAG: ${{ inputs.release-tag }} - # One-candidate exception accepted by the release captain. Remove after promotion. - PROTO_COMPATIBILITY_EXCEPTION_TAG: ${{ inputs.is-prerelease && inputs.release-tag == 'v0.1.6-pre.7' && inputs.release-tag || '' }} - PROTO_COMPATIBILITY_EXCEPTION_REASON: Release captain accepted protobuf breaking changes for v0.1.6-pre.7; migration guidance must accompany the release. + # Patch-train exception accepted by the release captain. Remove after promotion. + PROTO_COMPATIBILITY_EXCEPTION_TAG: ${{ inputs.is-prerelease && startsWith(inputs.release-tag, 'v0.1.6-pre.') && inputs.release-tag || '' }} + PROTO_COMPATIBILITY_EXCEPTION_REASON: Release captain accepted protobuf breaking changes for the v0.1.6 prerelease train; migration guidance must accompany the release. defaults: run: diff --git a/CI.md b/CI.md index 600c28a678..fc7f3de958 100644 --- a/CI.md +++ b/CI.md @@ -48,11 +48,12 @@ remains in Actions. This checks protobuf compatibility; SDK/configuration compatibility and migration review remain separate qualification work. -The release qualification workflow has a one-candidate, release-captain-approved -exception for `v0.1.6-pre.7`. It still runs Buf and fails on compilation or tooling +The release qualification workflow has a release-captain-approved exception +for all `v0.1.6-pre.N` candidates, including replacement candidates after a failed +run. It still runs Buf and fails on compilation or tooling errors, but accepts detected protobuf breaking changes for that tag. The run summary and qualification JSON's `exceptions` array record the scope and reason. -Other candidates retain the normal version policy. Remove the workflow exception +Other versions retain the normal version policy. Remove the workflow exception after promotion; release notes must describe the accepted changes and migration. Fetch the target and tags to check committed branch changes locally, replacing diff --git a/tasks/scripts/check_proto_compatibility_test.py b/tasks/scripts/check_proto_compatibility_test.py index f1a540416d..2e3cfeb731 100644 --- a/tasks/scripts/check_proto_compatibility_test.py +++ b/tasks/scripts/check_proto_compatibility_test.py @@ -23,7 +23,11 @@ ("ref", "exception_tag", "reason", "expected"), [ (f"refs/tags/{TAG}", TAG, REASON, True), + ("refs/tags/v0.1.6-pre.8", "v0.1.6-pre.8", REASON, True), + ("refs/tags/v0.1.6-pre.12", "v0.1.6-pre.12", REASON, True), ("refs/tags/v0.1.6-pre.8", "", "", False), + ("refs/tags/v0.1.7-pre.1", "", "", False), + ("refs/tags/v0.2.0-pre.1", "", "", False), (f"refs/tags/{TAG}", "", "", False), ("refs/tags/v0.1.6-pre.8", TAG, REASON, ValueError), ("refs/tags/v0.1.6", "v0.1.6", REASON, ValueError), @@ -113,13 +117,14 @@ def export_fixture(ref, destination): @pytest.mark.parametrize("exception", [False, True]) @pytest.mark.parametrize("proto_result", ["success", "failure", "skipped"]) +@pytest.mark.parametrize("tag", [TAG, "v0.1.6-pre.8"]) def test_qualification_records_exception_without_bypassing_results( - tmp_path, exception, proto_result + tmp_path, exception, proto_result, tag ): output = tmp_path / "qualification.json" env = { **os.environ, - "RELEASE_TAG": TAG, + "RELEASE_TAG": tag, "SOURCE_SHA": "candidate-sha", "IS_PRERELEASE": "true", "GITHUB_RUN_ID": "123", @@ -127,7 +132,7 @@ def test_qualification_records_exception_without_bypassing_results( "GITHUB_SERVER_URL": "https://github.com", "GITHUB_REPOSITORY": "NVIDIA/OpenShell", "PROTO_COMPATIBILITY_RESULT": proto_result, - "PROTO_COMPATIBILITY_EXCEPTION_TAG": TAG if exception else "", + "PROTO_COMPATIBILITY_EXCEPTION_TAG": tag if exception else "", "PROTO_COMPATIBILITY_EXCEPTION_REASON": REASON, } for suite in ( @@ -152,7 +157,7 @@ def test_qualification_records_exception_without_bypassing_results( summary = json.loads(output.read_text()) assert summary["current_profile_passed"] is (proto_result == "success") assert summary["exceptions"] == ( - [{"suite": "protobuf_compatibility", "tag": TAG, "reason": REASON}] + [{"suite": "protobuf_compatibility", "tag": tag, "reason": REASON}] if exception else [] ) From 90b92c80fb41ffde39bc09bf307c3a9a85b89ac1 Mon Sep 17 00:00:00 2001 From: Taylor Mutch Date: Tue, 27 Oct 2026 08:24:17 -0700 Subject: [PATCH 3/4] docs(ci): document full rollback of temporary protobuf exception Signed-off-by: Taylor Mutch --- .agents/skills/release-captain/SKILL.md | 5 ++++- .github/workflows/release-qualification.yml | 3 ++- CI.md | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.agents/skills/release-captain/SKILL.md b/.agents/skills/release-captain/SKILL.md index e018860b07..90ddc1286f 100644 --- a/.agents/skills/release-captain/SKILL.md +++ b/.agents/skills/release-captain/SKILL.md @@ -51,7 +51,10 @@ errors still fail. Other versions retain normal version-based enforcement. The run summary and qualification JSON record the exception and reason. Review all protobuf findings for each candidate and include migration guidance in the release notes; the exception does not accept other compatibility-review findings. -Remove the workflow exception after promoting v0.1.6. A new prerelease number +Squash-merge PR #4976 and, after verifying v0.1.6 publication, prepare a cleanup PR +reverting its entire squash-merge commit. Follow "Remove the v0.1.6 exception" in +`CI.md`; remove the checker support and metadata along with the workflow exception. +A new prerelease number within this patch train retains the exception; other patch or minor trains do not. ## Setup diff --git a/.github/workflows/release-qualification.yml b/.github/workflows/release-qualification.yml index 14370918cf..b65a34b636 100644 --- a/.github/workflows/release-qualification.yml +++ b/.github/workflows/release-qualification.yml @@ -30,7 +30,8 @@ permissions: env: RELEASE_TAG: ${{ inputs.release-tag }} - # Patch-train exception accepted by the release captain. Remove after promotion. + # TEMPORARY (#4976): squash-merge and revert after v0.1.6 publication is verified. + # See CI.md's "Remove the v0.1.6 exception" procedure. PROTO_COMPATIBILITY_EXCEPTION_TAG: ${{ inputs.is-prerelease && startsWith(inputs.release-tag, 'v0.1.6-pre.') && inputs.release-tag || '' }} PROTO_COMPATIBILITY_EXCEPTION_REASON: Release captain accepted protobuf breaking changes for the v0.1.6 prerelease train; migration guidance must accompany the release. diff --git a/CI.md b/CI.md index fc7f3de958..5252a4f330 100644 --- a/CI.md +++ b/CI.md @@ -75,6 +75,23 @@ For an intentional minor-train incompatibility, record the Buf finding, linked issue, consumer impact, and migration plan in the PR. Keep the finding visible; do not disable the job or add a broad Buf ignore rule. +### Remove the v0.1.6 exception + +Squash-merge [PR #4976](https://github.com/NVIDIA/OpenShell/pull/4976) so the +exception, checker support, qualification metadata, tests, and temporary guidance +can be removed together with one revert. After verifying stable v0.1.6 publication, +open a cleanup PR from current `main` and revert that PR's squash-merge commit: + +```shell +git revert --no-commit +git commit --signoff -m "revert(ci): remove temporary v0.1.6 protobuf exception" +``` + +Use the final squash-merge SHA shown on the merged PR, not a branch commit SHA. +Validate the reverted workflow with Actionlint and run the normal protobuf check +before merging the cleanup. Reverting the whole PR restores normal enforcement +and removes the exception mechanism; do not leave the bypass support behind. + ### Windows validation Native Windows implementation and releases use the From 9a152f1207cef6571c4e3b99a110960c050cfd45 Mon Sep 17 00:00:00 2001 From: Taylor Mutch Date: Tue, 27 Oct 2026 08:31:15 -0700 Subject: [PATCH 4/4] fix(ci): complete protobuf test copyright header Signed-off-by: Taylor Mutch --- tasks/scripts/check_proto_compatibility_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/scripts/check_proto_compatibility_test.py b/tasks/scripts/check_proto_compatibility_test.py index 2e3cfeb731..ce80e06c13 100644 --- a/tasks/scripts/check_proto_compatibility_test.py +++ b/tasks/scripts/check_proto_compatibility_test.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 import json