feat(release): canonical immutable GitHub Release mechanism (ADR 0129) - #1030
feat(release): canonical immutable GitHub Release mechanism (ADR 0129)#1030seonghobae wants to merge 46 commits into
Conversation
…st yet scripts/ci/release_notes.py is not implemented yet, so read_declared_version/extract_changelog_section/render_release_notes/main all fail to import (FileNotFoundError via the importlib-by-path loader this repository's scripts/ci contract tests use). Confirmed failing: `python -m pytest tests/test_release_notes.py -q` -> 10 failed. Part of the canonical immutable release mechanism (docs/planning/adrs/0127-canonical-immutable-release.md). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
…project.toml Implements scripts/ci/release_notes.py per the RED test in ecac722: read_declared_version() reads pyproject.toml's [project] version field only (never guesses from a tag or CHANGELOG heading); extract_changelog_section() returns the body of the matching '## [X.Y.Z]' section, regardless of an '- Unreleased' or dated suffix, and fails closed on a missing or empty section; render_release_notes() adds commit/repository provenance; main() wires both together for .github/workflows/release.yml and fails closed (exit 2) when the requested --version does not match pyproject.toml. Confirmed: `python -m pytest tests/test_release_notes.py -q` -> 10 passed. `python -m interrogate -f 100 scripts/ci/release_notes.py` -> PASSED (100.0%). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
.github/workflows/release.yml is absent from this branch's parent (and from origin/main) at this point, so every structural assertion in tests/test_release_workflow_contract.py fails on FileNotFoundError. Confirmed failing both by direct pytest collection and by checking `git show origin/main:.github/workflows/release.yml` (no such file). Part of the canonical immutable release mechanism (docs/planning/adrs/0127-canonical-immutable-release.md). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Implements .github/workflows/release.yml per the RED test in c9b0154 and the design in docs/planning/adrs/0127-canonical-immutable-release.md: - workflow_dispatch only, with a required version input and no default — never push/schedule/pull_request-triggered, so a release is always a deliberate maintainer action; - runs only against github.ref == 'refs/heads/main'; - fails closed unless the dispatched commit equals main's live tip (gh api repos/$REPO/commits/main), guarding against a race with a concurrent merge; - fails closed unless pyproject.toml's declared version matches the dispatch input; - fails closed if tag v${VERSION} already exists locally or on origin — a release is never republished or moved onto a different commit; - reruns the full test suite fresh on the exact commit (the same `uv run --locked ... pytest -q` invocation as Makefile's `make test` and ci.yml's Tests job) rather than trusting a prior run's status; - renders release notes via the tested scripts/ci/release_notes.py; - creates and pushes an annotated tag, then publishes a GitHub Release, best-effort attaching the CycloneDX SBOM from the matching successful Security workflow run for this commit (a missing SBOM warns, it never blocks the release); - contents: write is scoped to the release job only; every other default stays contents: read. Also lists the two new release-mechanism test files in README.md's Check section, next to the existing release_authorization/release_authority tests they sit beside. Confirmed: `python -m pytest tests/test_release_workflow_contract.py -q` -> 15 passed. `python tests/test_release_workflow_contract.py` and `python tests/test_release_notes.py` (direct-execution wrapper) both pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
…n evidence Records the design decided before implementation: a new, distinct concern from contextual_orchestrator/release_authorization.py (which is a PR-scoped, buyer-facing product-evidence report never wired to any GitHub Actions workflow), sharing its fail-closed spirit without duplicating GitHub governance already enforced by branch protection at merge time. Cites the direct consumer evidence (keyverse#132, bandscope#881, the Wardnet handoff, EgressWeave#235) from contextual-orchestrator#971, and scopes out PyPI publishing, release-on-every-merge, automatic version bumps, and dynamic ruleset-derived required-check names as non-goals for this first mechanism. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Documents preconditions, the dispatch steps, what happens after a release, and rollback policy (a mistake gets a new patch release, never a routine moved/deleted tag) for a human cutting a real contextual-orchestrator release. Explicitly distinguishes this from docs/commercial_release_candidate.md, which answers a different question (buyer/procurement readiness) and is untouched by this change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
- product-technical-gap-baseline.md: dated 2026-09-02 entry with the Phase 1 research finding (release_authorization.py is a distinct, PR-scoped buyer-evidence concern, not a release publisher), the direct consumer evidence from contextual-orchestrator#971 (keyverse#132/bandscope#881/Wardnet/EgressWeave#235), what was built, and verification evidence. Explicitly notes no real release was triggered and the resumable-long-running-execution half of the gap is unaddressed here. - CHANGELOG.md: new [0.2.0] Added entry for the release mechanism itself. - conductor/tracks.md: new active track 005-canonical-immutable-release. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
|
Warning Review limit reachedNext included review available in 4 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (19)
📝 WalkthroughWalkthrough보호된 Changes정식 불변 릴리스
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant 운영자
participant verify
participant publish
participant GitHub
운영자->>verify: version으로 workflow_dispatch 실행
verify->>GitHub: main tip과 push check-run 검증
GitHub-->>verify: 검증 결과
verify->>publish: 릴리스 노트·SBOM·재개 상태 전달
publish->>GitHub: main과 check-run 재검증
publish->>GitHub: tag와 Release 생성 또는 재개
Merge Risk: 🟡 Moderate · up to The release workflow may mishandle valid project-version declarations and either reject a release or validate the wrong version; retries can also accept public release metadata that does not match the intended release. These are bounded but concrete correctness and release-integrity risks, so merge should wait for remediation or explicit owner acceptance. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR #1020 (#1020, `docs/planning/adrs/0127-evidence-based-per-model-timeout-allocator.md`) independently claimed ADR number 0127 before this PR was created, and PR #1012 (#1012) already holds 0128 from an earlier same-day collision fix. Per the ADR-uniqueness convention in this repo's CLAUDE.md ("a same-number collision is a rename, not a redesign") and the tie-breaker already applied once today (the more-recently-created/ updated PR bumps further), this PR's ADR renumbers to 0129 -- verified free against origin/main and all 38 currently open PRs by walking each PR's head tree for new docs/planning/adrs/*.md files not present on main. - Rename docs/planning/adrs/0127-canonical-immutable-release.md to 0129-canonical-immutable-release.md; update its front-matter id. - Update every in-repo reference to the old number: .github/workflows/release.yml, tests/test_release_workflow_contract.py, conductor/tracks.md, CHANGELOG.md, docs/product-technical-gap-baseline.md, docs/RELEASING.md. Verified: tests/test_release_notes.py, tests/test_release_workflow_contract.py, tests/test_planning_adr_identifiers.py, tests/test_product_planning_contract.py (30 passed); python -m interrogate -c pyproject.toml . (100.0%); a scratch- directory side-by-side check against PR #1020's 0127 file confirmed no residual collision at the new number. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
ADR number collision resolved: 0127 -> 0129This PR's New number: 0129 (not 0128 — #1012 already holds 0128 as an open PR, not yet on Verification performed before picking 0129:
Commit
Re-verified locally: Note for whoever reviews #1020 next: this repo also has an unrelated second collision in flight today — #1008 and #972 both independently added a new ADR at 0042 (different topics). Out of scope for this PR/comment, flagging only so it doesn't get missed. 🤖 Generated with Claude Code https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4 Generated by Claude Code |
PR #972 (feat(discovery): record parallel tool-call capability and exclude single-tool models from orchestrator/free) independently added docs/planning/adrs/0042-parallel-tool-call-capability.md, colliding with this PR's 0042-opencode-go-provider-discovery.md -- neither number exists on main yet. Per this repo's CLAUDE.md, "a same-number collision is a rename, not a redesign," and PR #972 was updated earlier than this PR, so this PR's ADR renumbers instead. 0130 is the next free number after checking docs/planning/adrs/ on current origin/main (highest: 0126) and every other open PR's added ADR files (0127 PR #1020, 0128 PR #1012, 0129 PR #1030, plus PR #972's untouched 0042). Renamed docs/planning/adrs/0042-opencode-go-provider-discovery.md to 0130-opencode-go-provider-discovery.md, updated its front-matter id, and updated the three in-repo prose references to "ADR 0042" for this ADR (contextual_orchestrator/model_discovery.py comment, tests/test_model_discovery.py docstring, docs/kv-credentials.md, CHANGELOG.d/opencode-go-provider-discovery.md). Left the coincidental "0042" substring in docs/planning/adrs/0004-pr-review-merge-loop.md (part of an unrelated git SHA) untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
…check Addresses Devin findings 1-3 on PR #1030 (all sharing one root cause: the tag is pushed before the fallible SBOM/GitHub-Release steps), plus the overlapping CodeRabbit findings and its CWE-269 least-privilege suggestion: - Finding 1 (concurrent merges produce stale releases): add a second, authoritative main-tip check in the `publish` job, immediately before tag creation and after every long-running gate (fresh test suite, note rendering) -- the original early check stays as a fast-fail. - Finding 2 (SBOM lookup strands every release): grant `actions: read` at the `verify` job's scope, and make every SBOM discovery call genuinely non-fatal via explicit `if !` guards instead of a bare `set -e` that aborted the whole job on the permission gap. - Finding 3 (publication failures block automated recovery): resolve an existing `vX.Y.Z` tag through the GitHub commits API into resume (points at this exact commit, no Release published yet -- skip re-tagging) vs. reject (points elsewhere, or already has a published Release), replacing the old any-existing-tag hard fail. - CodeRabbit's CWE-269 suggestion: split the job into a read-only, credential-less `verify` job (runs all repository-controlled code -- the test suite and note rendering -- with no write token or persisted git credential present) and a write-scoped `publish` job (tag + Release only, `needs: verify`). This also gives finding 1's final tip check its natural placement: the first thing `publish` does. Notes/SBOM cross the job boundary via upload-artifact/download-artifact. Finding 4 (tests miss operational invariants): `tests/ test_release_workflow_contract.py` gained a `_job_block` helper to bound assertions to one job's own steps instead of loose substring presence, plus new tests for job-scoped permissions and the final-check ordering. The resume/reject branching and least-privilege split get their own file, `tests/test_release_workflow_idempotency_contract.py` (12 tests), since they share the one root cause above. Verified the new/changed assertions actually fail against the pre-fix workflow (not vacuous) by running both files against a stash of the original file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Addresses two CodeRabbit findings on PR #1030: - Real bug: `read_declared_version`'s regex matched the first `version = "..."` line anywhere in pyproject.toml, so a same-named `version` key under an unrelated table declared earlier (e.g. `[tool.some_tool]`) would be read instead of `[project]`'s real version -- both by this script's own CLI and by release.yml's version-match gate (which now calls this same tested function instead of duplicating the regex, so both are fixed by one change). Bounds the search to the span between the `[project]` header and the next `[...]` table header. Added regression tests for a same-named key both before and after `[project]`'s body, plus a missing-`[project]`-table case. - Minor test bug: `pytest.raises(ValueError, match="0.9.9")` left the dots as unescaped regex metacharacters (RUF043); escaped to `match=r"0\.9\.9"`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Addresses Devin finding 5 and CodeRabbit's documentation-accuracy finding on PR #1030: - `/releases/latest` is a mutable alias that repoints to the newest release, not itself an immutable pin -- only `/releases/tag/vX.Y.Z` is. Both `docs/RELEASING.md` and ADR 0129's Consequences section previously described them as equally immutable pin targets, which undermines this PR's whole stated purpose if left wrong. Fixed in both places, and `docs/RELEASING.md`'s "Cutting a release" walkthrough and preconditions are updated to describe the two-job, idempotent-resume behavior from the companion workflow fix. - ADR 0129 gained a "Research grounding" section: this is release- engineering/DevOps process tooling, not a novel algorithm, so it cites the normative standards it implements -- SemVer 2.0.0, Keep a Changelog 1.1.0, and the GitHub Releases API -- instead of an academic literature review, per this org's research-grounding convention. CHANGELOG.md's `## [0.2.0] - Unreleased` entry and docs/product-technical-gap-baseline.md's narrative are updated to describe the mechanism's actual, fixed behavior (still unreleased, so this amends the existing entries rather than adding a separate "Fixed" bullet). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Devin + CodeRabbit findings addressedFixed all 5 Devin Review findings plus 4 additional CodeRabbit findings (3 of CodeRabbit's overlapped Devin's; those needed no extra work beyond what's below). Three commits, verified against current code (not blindly applying suggested prompts):
Verification
Pushed non-force to Generated by Claude Code |
…idual race Three Devin follow-up findings on this PR's release workflow: 1. "Unchecked main checks permit releases" -- the release gate only compared GITHUB_SHA to main's current tip; it never verified that push-triggered workflows (Security, Fuzz, ...) re-running on that new tip commit had actually finished green. Adds a check-runs verification step (querying commits/$SHA/check-runs, excluding this release run's own checks via GITHUB_RUN_ID) to both verify (fail fast) and publish (authoritative recheck immediately after the final main-tip check). Deliberately checks every reported check rather than a ruleset-derived "required" subset, per ADR 0129's existing rationale for avoiding administration:read. 2. "Failed asset upload strands releases" -- `gh release create` can publish the Release object and then fail partway through uploading the SBOM asset, but the existing resume logic treated "Release already exists" as nothing left to do and rejected the retry outright. Splits the previous single tag_resume output into tag_resume and release_resume, splits "Publish the GitHub Release" into a conditionally-skipped "Create the GitHub Release" step and an always-run best-effort "Attach any still-missing release assets" step so a retry can complete a stranded release's asset upload. 3. "Final tip check leaves race" (the original TOCTOU finding this PR's final main-tip recheck already addressed) -- assessed the residual check-then-act window after that recheck and concluded it is an inherent limitation (GitHub exposes no atomic check-then-tag primitive) that is already close to minimal for a workflow_dispatch-only, maintainer-triggered path. Documents it as an accepted, bounded residual risk in ADR 0129's new "Known limitations" section and docs/RELEASING.md, including the recovery guidance (cut a new release from the real tip; never retag) if it is ever actually hit, rather than adding disproportionate complexity chasing it to zero. Also fixed a real jq context bug found while testing the new check-runs filter by hand (index(.conclusion) inside a piped array literal indexed the array, not the check-run object). tests/test_release_workflow_contract.py and tests/test_release_workflow_idempotency_contract.py updated/extended to match; ADR/RELEASING.md/CHANGELOG.md prose kept in sync with the new resume and checks-gate behavior. Verified: tests/test_release_notes.py, tests/test_release_workflow_contract.py, tests/test_release_workflow_idempotency_contract.py, tests/test_planning_adr_identifiers.py, tests/test_product_planning_contract.py (53 passed); manual bash+jq simulation of both new gate/attach steps against a stubbed gh CLI covering all-green/pending/failed/empty/multi-page and missing/new/already-attached/upload-failed cases; python -m interrogate -c pyproject.toml . -> 100.0%; release.yml parses as valid YAML. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
|
Pushed cf69dc3 addressing the latest Devin round on
Verification: 🤖 Generated with Claude Code https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4 Generated by Claude Code |
Two more genuine Devin findings on the release workflow's checks-green gate and tag/release lookup logic, both real gaps left after cf69dc3: 1. "Missing checks pass release gate" (checks-green gate, still a real gap despite the earlier reply on this thread claiming it was fully fixed): a dispatch fired moments after a merge can race GitHub's own registration of the push-triggered check-runs for the new main tip. `commits/$SHA/check-runs` can legitimately come back empty or partial before Security/Fuzz/CodeQL even exist as entries, and filtering an empty/partial list for "not complete+green" is vacuously empty too -- so the gate could PASS before those checks had even started. Adds a top-level `RELEASE_EXPECTED_PUSH_CHECKS` env: this repository's own known push-triggered job names (ci.yml's two jobs, fuzz.yml's two, security.yml's two). Both the `verify` and `publish` checks-green steps now compute `missing_checks` against that list *before* the existing not-ready/green check, and fail closed if any expected check has not registered yet. Still no ruleset/`administration: read` lookup, consistent with ADR 0129's existing rationale for avoiding it -- just a fixed, repository-owned name list cross-referenced against the real API response. 2. "API failures block release recovery": the tag-existence lookup (via the commits API) and the `gh release view` release-existence lookup both treated any nonzero exit as "absent," so a transient rate-limit, auth, network, or 5xx failure during a resume attempt would have been misread as "safe to create fresh." Both lookups now distinguish a confirmed absence (an HTTP 404 from the commits API; "release not found" from `gh release view`, with the raw HTTP-404 rendering also matched as a defensive fallback) from every other failure class. Only a confirmed absence proceeds as a fresh publish/resume; anything else fails the step closed with a clear re-dispatch-to-retry message. 3. "ADR retains obsolete tag policy": ADR 0129's Gate section still described tag existence as an unconditional reject, contradicting the tag_resume/release_resume policy this workflow has actually implemented since an earlier fix pass. Updated alongside fix 2 above, since both touch the same paragraph. docs/planning/adrs/0129-canonical-immutable-release.md and docs/RELEASING.md updated to describe both refinements; CHANGELOG.md's existing Unreleased entry for this mechanism folds them in (this feature has not shipped yet, so amending its one entry in place matches this branch's established convention rather than adding separate Fixed entries). tests/test_release_workflow_contract.py: adds test_expected_push_checks_matches_this_repositorys_actual_push_triggered_jobs (drift guard against ci.yml/fuzz.yml/security.yml's real job names), test_checks_gate_requires_expected_checks_before_checking_they_are_green, and four tests that execute the checks-green step's real, unmodified script under bash against a stubbed `gh` CLI (zero/partial/complete registration, plus a still-pending check after full registration) -- asserting real exit codes and error text, not just YAML text/order. tests/test_release_workflow_idempotency_contract.py: restructures the Release-lookup branch test for the new three-way (success / confirmed absent / fail-closed) structure, adds matching tag-lookup branch tests, and adds six tests that execute the tag_state step's real script under bash against a stubbed `gh` covering confirmed-404, rate-limited, and network-error tag lookups plus confirmed-absent/rate-limited/exists release lookups -- asserting the real exit code and the actual GITHUB_OUTPUT lines written for each. Verified: tests/test_release_notes.py, tests/test_release_workflow_contract.py (26 passed), tests/test_release_workflow_idempotency_contract.py (25 passed), tests/test_planning_adr_identifiers.py, tests/test_product_planning_contract.py (69 passed total); hand-simulated both new bash+jq/gh blocks against stubbed data before encoding them as tests (zero/partial/complete check-runs registration; confirmed-404/rate-limited/network-error tag lookup; confirmed-absent/rate-limited/exists release lookup -- all six tag/release scenarios behaved exactly as intended); `bash -n` on every extracted step script; `python -m interrogate -c pyproject.toml .` -> 100.0%; release.yml parses as valid YAML (PyYAML ad hoc check, matching this repo's existing no-new-dependency workflow-contract convention). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Devin follow-up review round: two more real fixes on
|
|
CO 자동 배포/release adoption 선행조건을 연결합니다. 현재 fast-mlsirm의 release foundation은 배포 순서는 fail closed로 유지합니다: #1902 terminal-verdict recovery → #1692 protected integration/independent approval → #1471 exact v0.9.2 recut/version consistency/protected integration → existing fast-mlsirm publish workflow로 registry publication 및 exact filename/digest verification → 그 immutable released package/revision을 CO consumer/release lane에서 채택 → 실제 consumer install/runtime smoke 및 CO service deployment를 별도 검증. 현재 PyPI package publication이 없고 GitHub release는 v0.9.1만 존재하는 전제이므로, CO #1030에서 source checkout/branch를 release처럼 소비하거나 미게시 버전을 설치 성공으로 간주하지 마세요. Package registry publish success와 CO/service deployment success는 별도 acceptance evidence입니다. Secrets 값, provider credentials, protection settings는 변경하지 않습니다. |
Signed-off-by: Seongho Bae <me@seonghobae.me>
Signed-off-by: Seongho Bae <me@seonghobae.me>
|
독립 검증: 원격과 동일한 8443719334d31012d8306dbb517cce6e023443c7의 깨끗한 격리 작업 트리에서 release workflow, supply-chain, idempotency 검사 71개를 직접 실행해 19.47초, exit 0을 확인했습니다. 실행 전후 HEAD와 clean 상태가 일치합니다. 실제 attachment shell을 실행하는 테스트는 동일 바이트, 다른 바이트, 최초 업로드, 다운로드/업로드 실패, 성공 응답 뒤 파일 누락/빈 파일을 구분합니다. 후속 수정은 기존 자산을 덮어쓰지 않고 바이트 일치 여부를 검사합니다. 이 검증은 로컬 모의 GitHub 응답 기반이며 실제 registry 게시, 독립 GitHub 승인, 보호 병합 또는 배포 성공은 아닙니다. 공개 Release 생성과 SBOM 부착 사이의 중간 상태 및 검증 직후 원격 변경 가능성도 별도 미해결 경계입니다. |
Signed-off-by: Seongho Bae <me@seonghobae.me>
Completed verification and successor boundaryExact source head
Local full session14009 separately completed with 3484 passed, 2 skipped in Doc-only successor |
…nventory-20260907
|
Integration checkpoint: Focused local verification on the integrated source completed: release notes, supply-chain, workflow, and idempotency contracts 89 passed in 106.62 seconds; provider reliability 32 passed in 86.93 seconds. Both commands used the existing main-checkout project virtual environment from the release worktree. This is not a fresh dependency installation or a full-suite result. The PR remains Draft. Required hosted checks, independent review, protected merge, immutable package publication, schema provenance, and installed-consumer proof remain outstanding; the integration does not establish a published artifact. |
|
긴급 복구 병합 뒤의 release/adoption 인계입니다. 이 PR의 소스·브랜치는 변경하지 않았습니다. CO #1105는 실제 통합 검증: 중앙 collector .github#1978/#2053은 이 기존 release lane에서 필요한 다음 완료 조건을 연결합니다: 현재 main을 유효 delta 손실 없이 통합 → 실제 exact-head 검증 → 공개 Release에 필수 SBOM이 빠지는 구간과 동시 asset 변경 처리 수리 → 같은 커밋의 버전/CHANGELOG/불변 artifact/provenance 발행 → 중앙 .github#1661의 released API/consumer 계약으로 채택 → OpenCode/Strix/Noema 실제 canary에서 설치 revision, 90초를 넘는 정상 요청, 서버 request_id와 bounded collector receipt를 확인. probe/retention을 모델 공통 timeout으로 재사용하거나 paid fallback으로 우회하지 않습니다.
|
|
Release-unblock reconciliation, 2026-09-10, exact release head The Python-floor prerequisite is already carried here: live comparison from #995 One release-identity finding is still supported by current source: New protected owner merges now include #1007 |
|
Implemented the specific annotated-tag repair requested in the September 10 checkpoint as stacked contribution #1147, preserving this PR's exact b0e3d62 source and all existing delta. Child head 7a37d59 rejects lightweight tags before writing resume outputs. The existing bash fixture now returns a real annotated-tag ref and a commit on dereference. The new regression was RED before the production guard; the complete idempotency contract file is GREEN (33 tests). Read-only agent review found no actionable defects; no independent GitHub approval or hosted Security success is claimed. Please integrate this two-file child patch through the existing release lane. Fresh confirmed-404 publishing, annotated-tag ancestry checks, SBOM and immutable artifact requirements remain in force. No release was published. |
|
Fresh release-consumer acceptance evidence from central Noema makes this release lane more urgent, but not merge-ready as-is. Protected CO is now Why the consumer canary matters: Add this unchanged #2126 head as a post-publication consumer canary: after an immutable release is created from the then-current protected CO exact head, the central consumer must pin that released identity (not mutable main), then rerun #2126 without source churn and demonstrate that the legacy implicit 90-second runtime is absent and the review path yields an authenticated exact-head verdict or an explicit typed unavailable outcome. This does not waive the current 175-commit reconciliation, release checks, SBOM/provenance, independent review, or normal protected integration. |
…ed-tag-acceptance-20260912 fix(release): reject lightweight tags before publication resume
|
Current-head documentation reconciliation after #1147 normal carryover:
No force update, protection weakening, release publication, or predecessor-evidence transfer was performed. |
|
Foundation order correction from fresh live refs: #995 is no longer the stale This release lane's current The #995 conflict resolution is source-stable: immutable |
|
Prerequisite order correction from fresh #995 review evidence:
Therefore release order is now |
|
LifeOS release-unblock repair, scoped writer claim (2026-09-14 KST). Fresh owner head inspected: b51009c. GitHub Releases inventory is empty. The current publisher creates a public Release before attaching its mandatory SBOM; GitHub release immutability forbids that later upload. I am preparing a bounded test-first repair on this existing release lane: draft-before-assets, content verification before finalization, and fail-closed verification of the immutable published result. Scope: .github/workflows/release.yml, focused release workflow tests, and docs/RELEASING.md. No source/runtime/provider/credential changes, no rebase or protected-main reconciliation, no publication or integration claim. Existing .github#1398 → #995 → #1030 prerequisite order remains intact. This claim applies only to this interactive repair; exact branch head/blob will be checked before a non-force update. Other active source writers should not overlap these files until the repair is published or this claim is explicitly released. |
Immutable-publication repair delivered — 2026-09-14 KSTThe scoped writer claim in #issuecomment-5654583092 is RELEASED. Non-force changes are published on this existing lane; no protected-main reconciliation or publication was attempted.
The old workflow created a public release before uploading its mandatory SBOM, which cannot work when GitHub release immutability is enabled. It now creates a Draft, completes mandatory attachment and byte comparison first, validates existing lifecycle before resume mutations, then publishes and requires actual Executed locally against the actual workflow shell with a stateful remote-CLI boundary: original exact workflow 16 failed, 2 passed; fixed workflow 18 passed. YAML parse, all bash run-step syntax, new-test compileall and diff whitespace checks passed. This was a hash-verified partial fixture, not a full dependency-installed checkout or hosted acceptance. Existing full repository tests and exact-head security/review gates still apply. Fresh prerequisite reads still show Companion EgressWeave repair is ContextualWisdomLab/EgressWeave#247. Neither this repair nor that PR is evidence that LifeOS can consume a released owner: real immutable publication and the executable API/authentication/deployment-identity contract in #1023 remain required. @coderabbitai review |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== HEAD AND DIFF STAT =='
git rev-parse HEAD
git status --short
git diff --stat origin/main...HEAD
git diff --name-status origin/main...HEAD
echo '== WORKFLOW OUTLINE / JOB MARKERS =='
rg -n -C 3 '^(name:|on:|env:|jobs:| (verify|publish):| [A-Za-z][^:]*:)$|gh release|release (create|edit|verify|verify-asset)|SBOM|TARGET_SHA|tag_state|release_state' .github/workflows/release.yml
echo '== RELEASE SCRIPTS =='
fd . scripts/ci -t f | sort
ast-grep outline scripts/ci --items all --type function
echo '== TEST FILES =='
fd 'test_release.*\.py' tests -t f | sort
ast-grep outline tests/test_release_workflow_idempotency_contract.py --items all --type function
ast-grep outline tests/test_release_workflow_contract.py --items all --type function
echo '== RUNBOOK LOCATIONS =='
rg -n -C 3 'draft|Draft|immutable|SBOM|resume|asset|publish|release' docs/RELEASING.md
echo '== REPAIR-RELATED DIFF =='
git diff --find-renames origin/main...HEAD -- .github/workflows/release.yml docs/RELEASING.md tests/test_release_workflow_idempotency_contract.py tests/test_release_workflow_contract.py scripts/ciLength of output: 145971 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== PUBLISH LIFECYCLE BLOCKS =='
nl -ba .github/workflows/release.yml | sed -n '330,456p'
echo '== IMMUTABLE PUBLICATION TEST OUTLINE =='
ast-grep outline tests/test_release_immutable_publication.py --items all --type function
echo '== IMMUTABLE PUBLICATION TEST: FIXTURE AND LIFECYCLE TESTS =='
rg -n -C 3 'def _|def test_|release edit|release upload|release verify|immutable|draft|asset|clobber|state' tests/test_release_immutable_publication.py
echo '== SUPPLY CHAIN CONTRACT =='
ast-grep outline tests/test_release_supply_chain_contract.py --items all --type function
rg -n -C 3 'def test_|SBOM|attest|provenance|release verify|verify-asset|immutable' tests/test_release_supply_chain_contract.py
echo '== CHANGELOG RELEASE CLAIMS =='
rg -n -C 3 'release|Release|SBOM|tag|immutable|best-effort|commit' CHANGELOG.mdLength of output: 34655 🤖 web_search executed:
Length of output: 9520
Update this changelog entry to match ✏️ Learnings added
|
Current verified release repair — 2026-09-08
b0e3d62390894af105a3577eb7daf97221330e28; merged maina080297d2546bb61e89520d637cabc202db331ecnormally, preserving predecessor27293e637103da78b3c53ff7dc30c9b5763e67ce.git diff --checkpassed. These are scoped local checks, not a fresh dependency install, full hosted acceptance, or publication.34179014058SBOM/security job succeeded; tests/fuzz and required reviews were not yet terminal-valid at this observation. Earlier runs below are historical and do not transfer to this head.fast-mlsirmJSON endpoint returned HTTP 404. Existing owner #1692 remains open and #1471 remains Draft. CO still declares the v0.9.1 direct archive URL.34cf7decreplaces six obsolete required check names with the three actual jobs in the integratedsecurity.yml. Its regression compares the release inventory against that workflow, rather than repeating stale constants. RED: one failure; GREEN: 64 release tests.92ca4cf3downloads the published SBOM and compares bytes against the verified artifact. Same-name/different-content and download-failure cases first reproduced two false successes. Existing assets are never overwritten;--clobberwas removed.84437193adds successful-download-but-missing/empty-file cases and keeps test temporary files inside pytest cleanup ownership. Combined local result: 71 passed in 12.11s, session 34492 terminal exit 0. This is mocked GitHub CLI execution of the real attachment step, not live publication.84437193run34081995823also completed successfully and is historical evidence, not a live wait.fast-mlsirmdependency needs the canonical owner's registry release before a PyPI-compatible dependency can be adopted. Existing owner work is fast-mlsirm #1692 and #1471; no duplicate publisher or dependency removal.PIPY_TOKEN,PIPY_USERNAME, andCARGO_REGISTRY_TOKENwith all-repository visibility. Values were not inspected; metadata alone does not prove token validity.The older snapshots below preserve lineage and must not override the current head or be interpreted as current prerequisite status.
목적
contextual-orchestrator가 소비자에게 제공할 canonical immutable GitHub Release 경로를 소유합니다.
vX.Y.Zannotated tag, GitHub Release, exact-commit CycloneDX SBOM을 하나의 재개 가능한 publication 계약으로 묶습니다. 상업 release-candidate 평가는 별도 bounded context입니다.Historical authority snapshot (superseded below)
main@2e414d15ba58f28597751b625a8a2f00fc9fadcff753f453ce4fc3dbc612bb9bdbb8db4cbfd93c162b84a752b1b5924743664181d7dcb95dab34104cPublication invariants
maintip; version input,[project].version, and CHANGELOG release section must agree;refs/tags/vX.Y.Z; annotated tags peel to the exact commit and are never moved or reused;Current prerequisite order — repaired 2026-09-05
Fresh repository execution proved the prior
#1066 → #1068order was wrong for the time-bounded NIM evidence contract. #1066 run33923471573, job101186730296, materialized successfully on a GitHub-hosted runner but the full suite failed5 failed, 3390 passed, 2 skippedbecause protected main's NIM hosted-access evidence expired after 2026-09-04 before child #1068 could supply the refresh.The corrected foundation order is:
b0bd71dfa5d6ca065052bc951ad9c9209b88413b: direct child of protected main, exactly six NIM evidence/test/doc files. NVIDIA's officialRun NIM Anywhereterms were re-reviewed 2026-09-05; the bounded prototype-access evidence remains fail-closed after 2026-10-04. This does not assert production pricing, licensing, support, or deployed capacity.51c8824e219c887425d2e7147e87f088d5f1a77d: two-file stacked-PR security validation repair. It is Draft after the exact-head test failure and must non-force restack only after fix(nim): refresh hosted access evidence before security stack #1069 reaches protected main.0cdc0307f0fd9f368f89eba3036c5538edbefb72: existing trusted successor for fork fix(nim): refresh hosted access evidence #1063. After fix(nim): refresh hosted access evidence before security stack #1069 and the restacked ci(security): materialize stacked-PR validation on trusted branch #1066 are integrated, reconcile it again; close only if fix(nim): refresh hosted access evidence before security stack #1069/protected main fully inherits every valid semantic/test/doc delta and the effective child delta is verified empty.e2df7803b5cb77b65ffd3f2a2ce57b2a2cda5a0a: Python 3.12+ / fast-mlsirm runtime prerequisite remains independent and must satisfy then-live protected governance.Fork #1063 remains lineage until trusted protected-main equivalence is verified. Predecessor checks and local test counts do not transfer across the reordered stack.
Actual consumer RED
ContextualWisdomLab/ThreadWeave#43@fe8a9acb2df10ee3a73ac361461c63ee4ef3d01ahas converged onorchestrator/freebut still clones CO source, installsrequirements.lock, bootstraps the gateway, and owns provider credential inventory because no canonical immutable CO Release + central reusable consumer contract exists. The consumer is Draft. Dedicated.github#1661already has the owner-path RED/GREEN requiring an immutable reusableworkflow_callthat exposes only gateway token +orchestrator/free, with leaf provider secrets/source checkout reduced to zero.Release boundary
Only after all prerequisites reach protected main normally do we non-force reconcile this release lane to the then-current protected tip. On one unchanged exact successor head, all required tests/security/CodeQL/SAST/review plus SBOM/provenance must be terminal-valid before Ready/merge/tag/publish. Actual canonical Release asset, reproducibility/rollback evidence, and at least one thin consumer canary are required before ADR 0129 can move beyond Proposed.
No force push, destructive rebase, self-approval, administrator bypass, tag movement, SBOM weakening, no-op retrigger, or predecessor-evidence transfer is acceptance evidence.