Skip to content

Release candidate branch policy and versioning workflow#342

Open
OluRemiFour wants to merge 1 commit into
ancore-org:mainfrom
OluRemiFour:release-candidate-branch
Open

Release candidate branch policy and versioning workflow#342
OluRemiFour wants to merge 1 commit into
ancore-org:mainfrom
OluRemiFour:release-candidate-branch

Conversation

@OluRemiFour
Copy link
Copy Markdown

@OluRemiFour OluRemiFour commented Apr 24, 2026

Close: #284

Description

I have successfully implemented the Release Candidate (RC) branch policy and versioning workflow for Ancore.

Key Accomplishments:
Defined RC Branching Strategy: Created

BRANCH_POLICY.md
which establishes the use of release/vX.Y.Z branches and RC tags (vX.Y.Z-rc.N), ensuring a stable path from development to production.
Updated Release Documents: Refined the

runbook
and

checklist
to integrate the new branching model and add blocking checks for version consistency.
Automated Version Enforcement: Added a new gate to the

release-gate.yml
CI workflow. This gate automatically verifies that all Node packages and Rust contracts in the monorepo share a synchronized version.
Release Tracking Template: Created a

GitHub Issue template
to provide maintainers with a centralized, trackable checklist for each release cycle.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📝 Documentation update
  • 🔧 Configuration change
  • ♻️ Code refactoring
  • ⚡ Performance improvement
  • ✅ Test addition/improvement

Security Impact

  • This change involves cryptographic operations
  • This change affects account validation logic
  • This change modifies smart contracts
  • This change handles user private keys
  • This change affects authorization/authentication
  • No security impact

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • E2E tests added/updated (if applicable)

Test Coverage

  • Current coverage: __%
  • New/modified code coverage: __%

Manual Testing Steps

Breaking Changes

  • This PR introduces breaking changes

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

For High-Security Changes

  • I have documented all security assumptions
  • I have considered attack vectors
  • I have added security-focused test cases
  • I have reviewed against the threat model

Related Issues

Closes #284
Related to #

Additional Context

Reviewer Notes


Summary by CodeRabbit

  • Documentation

    • Introduced release branch policy documentation defining a structured release process
    • Updated release runbook and checklist with new branch-based workflow procedures
  • Chores

    • Added release tracking issue template for coordinated release management
    • Added automated version consistency validation across all packages and contracts

@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented Apr 24, 2026

@OluRemiFour Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

Establishes a release candidate (RC) branch policy and versioning workflow for the Ancore monorepo. Introduces a new GitHub issue template for release tracking, a GitHub Actions job enforcing version consistency across package.json and Cargo.toml files, and documentation defining the RC branch lifecycle, version synchronization rules, and rollback procedures.

Changes

Cohort / File(s) Summary
Release Process Documentation
docs/release/BRANCH_POLICY.md, docs/release/checklist.md, docs/release/runbook.md
Introduces RC branch policy defining stabilization branch lifecycle, SemVer rules, and rollback protocol. Updates checklist to require branch-based release flow and version synchronization. Modifies runbook to shift version bumping and RC tagging to release branches instead of main.
CI/CD Infrastructure
.github/workflows/release-gate.yml
Adds new "Gate 6: Version Consistency" job that validates semantic version parity across root package.json, nested workspace packages, contracts/Cargo.toml, and release tags, blocking release on mismatches.
Release Template
.github/ISSUE_TEMPLATE/release.md
New GitHub issue template providing structured release tracking with metadata fields (version, branch, target date) and multi-stage checklist covering preparation, release gates, tagging, and finalization.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A release branch hops to life so clean,
With versions synced in every bean,
From main to RC, then tag so true,
The rabbit gates ensure it's new,
In harmony, our versions blend! 🌿✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing a release candidate branch policy and versioning workflow as described in the PR.
Linked Issues check ✅ Passed The PR addresses all core requirements from issue #284: documents RC branch strategy and rollback protocol, adds CI checks for version consistency, and creates release checklist template.
Out of Scope Changes check ✅ Passed All changes are scoped to the objectives: release documentation, CI workflow for version checking, issue template, and runbook updates—no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@OluRemiFour
Copy link
Copy Markdown
Author

Done, Close: #342

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/release/runbook.md (1)

79-91: ⚠️ Potential issue | 🟠 Major

Gate-failure guidance contradicts the new RC branch policy.

Step 2 says "Fix the root cause on main" and then re-tag, but per BRANCH_POLICY.md §1 lifecycle and the rest of this runbook, tags are cut from release/vX.Y.Z. During RC stabilization the fix must land on the release branch (and be backported to main), otherwise re-tagging from release/vX.Y.Z won't include the fix and re-tagging from main violates the policy.

Also consider that while RC-tag re-pushes are acceptable, rewriting a final vX.Y.Z tag after it has been publicly pushed is usually not — callers should supersede with vX.Y.Z.1/vX.Y.(Z+1) instead of force-moving a published tag.

📝 Suggested rewrite
 1. Identify the failing gate from the summary report.
-2. Fix the root cause on `main`.
-3. Delete and re-push the tag:
+2. Fix the root cause on `release/vX.Y.Z` (and open a backport PR to `main`
+   per BRANCH_POLICY.md §1).
+3. For an **RC tag** that has not yet been consumed, delete and re-push,
+   or simply bump to the next RC (`vX.Y.Z-rc.(N+1)`) and push a new tag.
+   For an already-published **final** `vX.Y.Z` tag, do **not** rewrite it —
+   cut a new patch release instead.
    ```bash
-   git tag -d vX.Y.Z
-   git push origin :refs/tags/vX.Y.Z
-   git tag -a vX.Y.Z -m "Release vX.Y.Z"
-   git push origin vX.Y.Z
+   git checkout release/vX.Y.Z
+   # ...commit fix...
+   git tag -a vX.Y.Z-rc.$((N+1)) -m "Release Candidate vX.Y.Z-rc.$((N+1))"
+   git push origin vX.Y.Z-rc.$((N+1))
    ```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/release/runbook.md` around lines 79 - 91, Update the Gate failure
section to follow BRANCH_POLICY.md §1 by instructing fixes to be committed to
the release branch (release/vX.Y.Z) during RC stabilization rather than to main,
and change the re-tag guidance to create a new RC tag (e.g., vX.Y.Z-rc.N+1)
pushed as an RC instead of deleting or force-moving an already-published final
vX.Y.Z tag; also note that final published tags should not be rewritten and
callers should use a new patch/follow-on tag (e.g., vX.Y.Z.1 or vX.Y.(Z+1))
instead of force-updating vX.Y.Z.
🧹 Nitpick comments (5)
.github/workflows/release-gate.yml (3)

311-316: Minor: tag-vs-root check only runs for tag-push events — document that workflow_dispatch skips it intentionally.

GITHUB_REF for manual runs will be a branch ref (refs/heads/…), so the tag-parity check is silently skipped. That is the right behavior for the override flow, but readers may assume the check always runs. A single-line log (print("Skipping tag/version parity check: not a tag push") in the else) makes the skip explicit in CI logs and avoids false assurance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-gate.yml around lines 311 - 316, The
tag-versus-root check currently only executes when GITHUB_REF starts with
"refs/tags/v" and silently skips for manual runs; add an explicit log in the
else branch so CI shows the skip. Modify the block that reads ref =
os.environ.get("GITHUB_REF", "") and the if ref.startswith("refs/tags/v"): ...
else: to print a single-line message like "Skipping tag/version parity check:
not a tag push" (so readers see why tag_version vs root_version comparison is
not performed), leaving the existing errors.append behavior unchanged when the
tag check runs.

253-330: Add a minimal unit/smoke test for the version-consistency script.

Per the linked issue #284 DoD ("unit/integration tests cover success and critical failure paths"), the one piece of new executable logic this PR introduces — the Gate 6 Python block — currently has no test coverage. Because it is embedded as a heredoc in YAML, a failure mode (e.g. the workspace-inheritance hole above) will only be discovered during an actual release. Consider extracting the logic to scripts/release/check_versions.py and invoking it from the workflow, then adding a small pytest (or even python -m unittest) that covers: root/crate mismatch, workspace-inherited version, missing package version on a non-private package, tag/root mismatch, and the happy path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-gate.yml around lines 253 - 330, The Gate 6
version-consistency logic is embedded in a YAML heredoc and has no unit/smoke
tests; extract the Python logic into a standalone module (e.g.
scripts/release/check_versions.py) preserving functions like get_root_version()
and get_cargo_version() and a main entry that returns non-zero on errors, update
the workflow step gate-version-consistency to call that script instead of
inlining the heredoc, and add minimal tests (pytest or unittest) for the
critical paths: root/crate mismatch, workspace-inherited package version
mismatch, missing version field on a non-private package, tag vs root mismatch,
and the happy path to assert exit codes and error messages.

273-289: Use a TOML parser instead of regex for contracts/Cargo.toml version extraction to improve clarity and robustness.

The current regex-based approach happens to work for the actual repository structure (where contracts/Cargo.toml correctly declares version under [workspace.package] and the regex matches it), but it is fragile:

  1. Ambiguous first-match. The regex ^version\s*=\s*"([^"]+)" with re.M matches the first top-level version = "…" line anywhere in the file. While it currently matches [workspace.package].version, any future addition of sections containing version literals above that line could silently cause the wrong version to be extracted.

  2. Future maintainability. Python 3.11+ includes tomllib in the standard library (available on ubuntu-latest). Using a proper TOML parser explicitly documents intent, handles workspace-inheritance patterns unambiguously, and avoids regex brittleness.

Use tomllib.load() to parse the file, then:

  • Check data["package"]["version"] (direct crate version)
  • Fall back to data["workspace"]["package"]["version"] (workspace-inherited version)
  • Treat unresolvable version as an error rather than a silent pass
📝 Proposed fix
-          def get_cargo_version():
-              if not os.path.exists("contracts/Cargo.toml"):
-                  return None
-              with open("contracts/Cargo.toml") as f:
-                  content = f.read()
-                  match = re.search(r'^version\s*=\s*"([^"]+)"', content, re.M)
-                  return match.group(1) if match else None
+          def get_cargo_version():
+              import tomllib
+              path = "contracts/Cargo.toml"
+              if not os.path.exists(path):
+                  return None, None
+              with open(path, "rb") as f:
+                  data = tomllib.load(f)
+              pkg = data.get("package", {})
+              if isinstance(pkg.get("version"), str):
+                  return pkg["version"], None
+              ws_pkg = data.get("workspace", {}).get("package", {})
+              if isinstance(ws_pkg.get("version"), str):
+                  return ws_pkg["version"], None
+              return None, f"{path}: could not resolve crate version"
@@
-          # 1. Check Cargo.toml
-          cargo_version = get_cargo_version()
-          if cargo_version and cargo_version != root_version:
-              errors.append(f"contracts/Cargo.toml version ({cargo_version}) != root ({root_version})")
+          # 1. Check Cargo.toml
+          cargo_version, cargo_err = get_cargo_version()
+          if cargo_err:
+              errors.append(cargo_err)
+          elif cargo_version is not None and cargo_version != root_version:
+              errors.append(f"contracts/Cargo.toml version ({cargo_version}) != root ({root_version})")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-gate.yml around lines 273 - 289, Replace the
fragile regex in get_cargo_version() with a TOML parse using tomllib.load() to
read contracts/Cargo.toml; look first for data["package"]["version"], then fall
back to data["workspace"]["package"]["version"], and return that version (or
raise/append an error if neither key exists) instead of returning None; update
callers that expect None to treat missing version as an explicit error
condition.
docs/release/runbook.md (1)

25-31: Make version synchronization mechanical, not a prose comment.

Step 4 tells the release engineer to "use a script if available or manual update" to synchronize versions across all workspace packages and contracts/Cargo.toml. With Gate 6 now failing any drift, a manual-or-scripted ambiguity is a foot-gun: if the script doesn't exist yet, every release will produce a Gate 6 failure on the first push. Either land a scripts/release/bump-version.sh (or a pnpm version recipe that also updates Cargo.toml) and reference it concretely here, or open a follow-up issue to track it.

Want me to draft scripts/release/bump-version.sh that updates the root package.json, all workspace package.json files, and contracts/Cargo.toml in one pass?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/release/runbook.md` around lines 25 - 31, The runbook step for bumping
versions is ambiguous and must be replaced with a concrete, mechanical process;
add and reference a deterministic script (e.g., scripts/release/bump-version.sh)
or a pnpm/pnpm-workspace recipe that updates the root package.json, all
workspace package.json files, and contracts/Cargo.toml in one atomic operation,
then update the runbook to call that script (or link the follow-up issue
tracking its implementation) so Gate 6 drift checks won't fail on first push and
the command to run the script replaces the current "use a script if available or
manual update" prose.
docs/release/checklist.md (1)

67-69: Minor: these items are preparation/process, not approvals.

Items 67 ("release branch created") and 69 ("tag created from release branch") are workflow preconditions, not sign-offs. They work fine as BLOCKING here (Gate 5's regex will pick them up), but for readability consider moving them under a new "Release Process" BLOCKING section (or into the existing 8. renamed accordingly), and keep 8. Approvals limited to human sign-offs. Item 68 is additionally enforced automatically by the new Gate 6, so the checkbox is effectively a manual confirmation of automated state — worth a short note to readers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/release/checklist.md` around lines 67 - 69, Move the two
workflow-precondition checkboxes "- [ ] Release branch `release/vX.Y.Z` created
from `main`" and "- [ ] Release tag created from the release branch (not `main`
or feature branch`)" out of the "Approvals" block and into a new "Release
Process" BLOCKING section (or rename the existing `8.` to "Release Process" and
keep approvals strictly human sign-offs); also update the middle item "- [ ]
Version in all packages and contracts synchronized with root `package.json`" to
note that this is enforced automatically by Gate 6 (e.g., add a parenthetical
like "(enforced by Gate 6)") so readers understand it is an automated check
rather than a manual approval.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/ISSUE_TEMPLATE/release.md:
- Line 22: The template contains a broken absolute Windows file URL
("file:///c:/Users/ADMIN/.../docs/release/checklist.md"); replace that URL with
a repository-relative link (for example "docs/release/checklist.md" or
"/docs/release/checklist.md") in the release issue template so GitHub renders
the link correctly; update the text that currently references the
"file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/checklist.md"
string accordingly.

In @.github/workflows/release-gate.yml:
- Around line 292-309: The os.walk pruning and error handling in the
package.json version check must be hardened: extend the prune list in the
os.walk loop (where dirs is modified) to remove common build and virtualenv dirs
like dist, build, out, .next, .turbo, coverage, target, vendor, .venv, etc., so
stray package.json files are skipped; move the open(p) call inside the try block
that currently wraps json.load so OSError is captured into errors instead of
crashing; when reading the JSON, treat missing or falsy "version" specially by
checking ver and the "private" field from the loaded dict and add clearer
messages to errors (e.g., skip or note private packages vs. explicit version
mismatches using package_files, ver, root_version, and errors identifiers); keep
the existing behavior of appending errors for real mismatches but avoid
reporting "None" as a version and prefer informative text like "missing version"
or "private: true" where appropriate.

In `@docs/release/BRANCH_POLICY.md`:
- Line 60: In docs/release/BRANCH_POLICY.md replace the Windows-local file:///
URL that points to c:/Users/... with a repo-relative Markdown link to the
rollback doc; locate the offending line containing the link (the text
referencing rollback-drill.md) and change it to use
docs/release/rollback-drill.md (or ./docs/release/rollback-drill.md) so the link
is valid in the repo and doesn't leak a local filesystem path.

In `@docs/release/runbook.md`:
- Line 60: The link in runbook.md currently uses a Windows-local file:/// URL
which breaks on GitHub; replace the file:///c:/.../BRANCH_POLICY.md URL with a
repo-relative path like docs/release/BRANCH_POLICY.md (e.g.,
[docs/release/BRANCH_POLICY.md](docs/release/BRANCH_POLICY.md)) so the link
resolves correctly in the repository and IDE; update the text in the runbook.md
entry that references BRANCH_POLICY.md to use the repo-relative link.

---

Outside diff comments:
In `@docs/release/runbook.md`:
- Around line 79-91: Update the Gate failure section to follow BRANCH_POLICY.md
§1 by instructing fixes to be committed to the release branch (release/vX.Y.Z)
during RC stabilization rather than to main, and change the re-tag guidance to
create a new RC tag (e.g., vX.Y.Z-rc.N+1) pushed as an RC instead of deleting or
force-moving an already-published final vX.Y.Z tag; also note that final
published tags should not be rewritten and callers should use a new
patch/follow-on tag (e.g., vX.Y.Z.1 or vX.Y.(Z+1)) instead of force-updating
vX.Y.Z.

---

Nitpick comments:
In @.github/workflows/release-gate.yml:
- Around line 311-316: The tag-versus-root check currently only executes when
GITHUB_REF starts with "refs/tags/v" and silently skips for manual runs; add an
explicit log in the else branch so CI shows the skip. Modify the block that
reads ref = os.environ.get("GITHUB_REF", "") and the if
ref.startswith("refs/tags/v"): ... else: to print a single-line message like
"Skipping tag/version parity check: not a tag push" (so readers see why
tag_version vs root_version comparison is not performed), leaving the existing
errors.append behavior unchanged when the tag check runs.
- Around line 253-330: The Gate 6 version-consistency logic is embedded in a
YAML heredoc and has no unit/smoke tests; extract the Python logic into a
standalone module (e.g. scripts/release/check_versions.py) preserving functions
like get_root_version() and get_cargo_version() and a main entry that returns
non-zero on errors, update the workflow step gate-version-consistency to call
that script instead of inlining the heredoc, and add minimal tests (pytest or
unittest) for the critical paths: root/crate mismatch, workspace-inherited
package version mismatch, missing version field on a non-private package, tag vs
root mismatch, and the happy path to assert exit codes and error messages.
- Around line 273-289: Replace the fragile regex in get_cargo_version() with a
TOML parse using tomllib.load() to read contracts/Cargo.toml; look first for
data["package"]["version"], then fall back to
data["workspace"]["package"]["version"], and return that version (or
raise/append an error if neither key exists) instead of returning None; update
callers that expect None to treat missing version as an explicit error
condition.

In `@docs/release/checklist.md`:
- Around line 67-69: Move the two workflow-precondition checkboxes "- [ ]
Release branch `release/vX.Y.Z` created from `main`" and "- [ ] Release tag
created from the release branch (not `main` or feature branch`)" out of the
"Approvals" block and into a new "Release Process" BLOCKING section (or rename
the existing `8.` to "Release Process" and keep approvals strictly human
sign-offs); also update the middle item "- [ ] Version in all packages and
contracts synchronized with root `package.json`" to note that this is enforced
automatically by Gate 6 (e.g., add a parenthetical like "(enforced by Gate 6)")
so readers understand it is an automated check rather than a manual approval.

In `@docs/release/runbook.md`:
- Around line 25-31: The runbook step for bumping versions is ambiguous and must
be replaced with a concrete, mechanical process; add and reference a
deterministic script (e.g., scripts/release/bump-version.sh) or a
pnpm/pnpm-workspace recipe that updates the root package.json, all workspace
package.json files, and contracts/Cargo.toml in one atomic operation, then
update the runbook to call that script (or link the follow-up issue tracking its
implementation) so Gate 6 drift checks won't fail on first push and the command
to run the script replaces the current "use a script if available or manual
update" prose.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4602de48-41a3-489b-848b-062d2842a19f

📥 Commits

Reviewing files that changed from the base of the PR and between 25979c0 and 60c59dc.

📒 Files selected for processing (5)
  • .github/ISSUE_TEMPLATE/release.md
  • .github/workflows/release-gate.yml
  • docs/release/BRANCH_POLICY.md
  • docs/release/checklist.md
  • docs/release/runbook.md

- [ ] `docs/release/checklist.md` reset and committed to release branch

## 2. Release Gate Checklist
> Refer to [docs/release/checklist.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/checklist.md) for detailed requirements.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Broken doc link — same Windows-local file:/// URL leak as in BRANCH_POLICY.md.

When this issue template is rendered by GitHub, file:///c:/Users/ADMIN/... will not resolve. Use a repository-relative link so it works for all maintainers.

📝 Proposed fix
-> Refer to [docs/release/checklist.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/checklist.md) for detailed requirements.
+> Refer to [`docs/release/checklist.md`](../../docs/release/checklist.md) for detailed requirements.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
> Refer to [docs/release/checklist.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/checklist.md) for detailed requirements.
> Refer to [`docs/release/checklist.md`](../../docs/release/checklist.md) for detailed requirements.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/ISSUE_TEMPLATE/release.md at line 22, The template contains a broken
absolute Windows file URL
("file:///c:/Users/ADMIN/.../docs/release/checklist.md"); replace that URL with
a repository-relative link (for example "docs/release/checklist.md" or
"/docs/release/checklist.md") in the release issue template so GitHub renders
the link correctly; update the text that currently references the
"file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/checklist.md"
string accordingly.

Comment on lines +292 to +309
package_files = []
for root, dirs, files in os.walk("."):
if "node_modules" in dirs:
dirs.remove("node_modules")
if ".git" in dirs:
dirs.remove(".git")
for file in files:
if file == "package.json" and root != ".":
package_files.append(os.path.join(root, file))

for p in package_files:
with open(p) as f:
try:
ver = json.load(f).get("version")
if ver != root_version:
errors.append(f"{p} version ({ver}) != root ({root_version})")
except Exception as e:
errors.append(f"Error parsing {p}: {e}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Expand os.walk prune list and tolerate packages without a version field.

  • The walker only prunes node_modules and .git. On a fresh checkout this is usually fine, but any committed fixture or build output (e.g. dist/, build/, out/, .next/, .turbo/, coverage/, target/, vendor/, .venv/) that contains a stray package.json will be pulled into the comparison and produce a spurious Gate 6 failure. Prune these proactively.
  • Private workspace packages often omit version (or set it to "0.0.0") intentionally. ver will then be None and get reported as "… version (None) != root …" with a confusing message. At minimum emit a clearer message; ideally, honor "private": true packages per the policy (or document the requirement to version them anyway).
  • The generic except Exception only covers json.load; an OSError on open() will crash the whole job with a traceback instead of being collected into errors. Move open() inside the try.
📝 Proposed fix
-          # 2. Check all package.json in workspace
-          package_files = []
-          for root, dirs, files in os.walk("."):
-              if "node_modules" in dirs:
-                  dirs.remove("node_modules")
-              if ".git" in dirs:
-                  dirs.remove(".git")
-              for file in files:
-                  if file == "package.json" and root != ".":
-                      package_files.append(os.path.join(root, file))
-
-          for p in package_files:
-              with open(p) as f:
-                  try:
-                      ver = json.load(f).get("version")
-                      if ver != root_version:
-                          errors.append(f"{p} version ({ver}) != root ({root_version})")
-                  except Exception as e:
-                      errors.append(f"Error parsing {p}: {e}")
+          # 2. Check all package.json in workspace
+          PRUNE = {
+              "node_modules", ".git", "dist", "build", "out",
+              ".next", ".turbo", ".svelte-kit", "coverage",
+              "target", "vendor", ".venv", ".yarn",
+          }
+          package_files = []
+          for root, dirs, files in os.walk("."):
+              dirs[:] = [d for d in dirs if d not in PRUNE]
+              if "package.json" in files and root != ".":
+                  package_files.append(os.path.join(root, "package.json"))
+
+          for p in package_files:
+              try:
+                  with open(p) as f:
+                      pkg = json.load(f)
+              except Exception as e:
+                  errors.append(f"Error reading {p}: {e}")
+                  continue
+              ver = pkg.get("version")
+              if ver is None:
+                  # Unversioned (often `"private": true`) — skip or flag per policy.
+                  if not pkg.get("private"):
+                      errors.append(f"{p} has no `version` field and is not marked `private`")
+                  continue
+              if ver != root_version:
+                  errors.append(f"{p} version ({ver}) != root ({root_version})")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
package_files = []
for root, dirs, files in os.walk("."):
if "node_modules" in dirs:
dirs.remove("node_modules")
if ".git" in dirs:
dirs.remove(".git")
for file in files:
if file == "package.json" and root != ".":
package_files.append(os.path.join(root, file))
for p in package_files:
with open(p) as f:
try:
ver = json.load(f).get("version")
if ver != root_version:
errors.append(f"{p} version ({ver}) != root ({root_version})")
except Exception as e:
errors.append(f"Error parsing {p}: {e}")
# 2. Check all package.json in workspace
PRUNE = {
"node_modules", ".git", "dist", "build", "out",
".next", ".turbo", ".svelte-kit", "coverage",
"target", "vendor", ".venv", ".yarn",
}
package_files = []
for root, dirs, files in os.walk("."):
dirs[:] = [d for d in dirs if d not in PRUNE]
if "package.json" in files and root != ".":
package_files.append(os.path.join(root, "package.json"))
for p in package_files:
try:
with open(p) as f:
pkg = json.load(f)
except Exception as e:
errors.append(f"Error reading {p}: {e}")
continue
ver = pkg.get("version")
if ver is None:
# Unversioned (often `"private": true`) — skip or flag per policy.
if not pkg.get("private"):
errors.append(f"{p} has no `version` field and is not marked `private`")
continue
if ver != root_version:
errors.append(f"{p} version ({ver}) != root ({root_version})")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-gate.yml around lines 292 - 309, The os.walk
pruning and error handling in the package.json version check must be hardened:
extend the prune list in the os.walk loop (where dirs is modified) to remove
common build and virtualenv dirs like dist, build, out, .next, .turbo, coverage,
target, vendor, .venv, etc., so stray package.json files are skipped; move the
open(p) call inside the try block that currently wraps json.load so OSError is
captured into errors instead of crashing; when reading the JSON, treat missing
or falsy "version" specially by checking ver and the "private" field from the
loaded dict and add clearer messages to errors (e.g., skip or note private
packages vs. explicit version mismatches using package_files, ver, root_version,
and errors identifiers); keep the existing behavior of appending errors for real
mismatches but avoid reporting "None" as a version and prefer informative text
like "missing version" or "private: true" where appropriate.


### 2. Rollback Deployment
- Use the `rollback-drill.yml` workflow or `scripts/release/rollback-drill.sh`.
- Follow the instructions in [docs/release/rollback-drill.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/rollback-drill.md).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Broken doc link — replace Windows-local file:/// URL with a repo-relative path.

file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/rollback-drill.md points at the author's local filesystem and will be a dead link for every other reader (and on GitHub). It also leaks the author's local path. Use a plain repo-relative Markdown link instead.

📝 Proposed fix
-- Follow the instructions in [docs/release/rollback-drill.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/rollback-drill.md).
+- Follow the instructions in [docs/release/rollback-drill.md](./rollback-drill.md).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Follow the instructions in [docs/release/rollback-drill.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/rollback-drill.md).
- Follow the instructions in [docs/release/rollback-drill.md](./rollback-drill.md).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/release/BRANCH_POLICY.md` at line 60, In docs/release/BRANCH_POLICY.md
replace the Windows-local file:/// URL that points to c:/Users/... with a
repo-relative Markdown link to the rollback doc; locate the offending line
containing the link (the text referencing rollback-drill.md) and change it to
use docs/release/rollback-drill.md (or ./docs/release/rollback-drill.md) so the
link is valid in the repo and doesn't leak a local filesystem path.

Comment thread docs/release/runbook.md
```

Pushing the tag triggers the `Release Gate` workflow automatically.
See [docs/release/BRANCH_POLICY.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/BRANCH_POLICY.md) for detailed rules.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Broken doc link — same Windows-local file:/// URL problem.

Replace with a repo-relative path so the link resolves on GitHub and local IDEs.

📝 Proposed fix
-See [docs/release/BRANCH_POLICY.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/BRANCH_POLICY.md) for detailed rules.
+See [`BRANCH_POLICY.md`](./BRANCH_POLICY.md) for detailed rules.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
See [docs/release/BRANCH_POLICY.md](file:///c:/Users/ADMIN/Desktop/lekan-drips/ancore/docs/release/BRANCH_POLICY.md) for detailed rules.
See [`BRANCH_POLICY.md`](./BRANCH_POLICY.md) for detailed rules.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/release/runbook.md` at line 60, The link in runbook.md currently uses a
Windows-local file:/// URL which breaks on GitHub; replace the
file:///c:/.../BRANCH_POLICY.md URL with a repo-relative path like
docs/release/BRANCH_POLICY.md (e.g.,
[docs/release/BRANCH_POLICY.md](docs/release/BRANCH_POLICY.md)) so the link
resolves correctly in the repository and IDE; update the text in the runbook.md
entry that references BRANCH_POLICY.md to use the repo-relative link.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Release candidate branch policy and versioning workflow

1 participant