fix(release): harden /ca:release with tested guards (v2.release.0002-0006)#138
Merged
Conversation
…0006) Five red-team findings left load-bearing release steps prose-only and silently failable. Add stdlib _releaselib.py helpers - last_tag_select (ca-only baseline), notes_heading_matches, release_dates_consistent, classify_publish_state - plus a thin CLI; SKILL.md now invokes them, rebuilds farm.js unconditionally (CI tools job named as backstop), derives the release date once, and branches on publish-state instead of dead-ending on "tag exists". Wired into CI (hooks job) + tech-stack. Rename the pre-existing invalid board id ca-sandbox.release.0001 -> casandbox.release.0001 (failed the dotted-id grammar; latent because pure-board edits don't trigger the hooks CI job, which this branch does). Normalize SKILL.md CRLF->LF per coding-standards (68-line EOL delta; real content = 5 edits). Open v2.prune.0001 (prune metric conflates file-bytes vs context-tokens), riding this branch per request. CHANGELOG: /ca:release resolves the baseline tag, notes heading, release-date consistency, and half-finished-publish recovery through tested helpers, and rebuilds farm.js unconditionally every release. Ref: .codearbiter/specs/release-skill-hardening.md Claude-Session: https://claude.ai/code/session_011nnQYBPd5Dt1rmtf9CHNfU
This was referenced Jun 26, 2026
SUaDtL
added a commit
that referenced
this pull request
Jun 26, 2026
v2.rev.0020 (farm.ts god-module split) landed via #140. The five release-skill hardening tasks v2.release.0002-0006 landed via #138 but the board was never updated in that PR. Flip all six to done (2026-06-26). Claude-Session: https://claude.ai/code/session_0123LEtLuVCEzLMhWdktP7aC Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
This was referenced Jun 26, 2026
SUaDtL
added a commit
that referenced
this pull request
Jun 26, 2026
) A task isn't done until its PR merges, but open-tasks.md is itself versioned, so a board flip only goes live when its own change merges to main. That created a trap with no good side: flips drifted into lagging chore(board) PRs or post-commit edits that depended on cross-session memory, and silently fell off (#138 never marked v2.release.0002-0006 done; #140 needed the separate #141). ADR-0008 makes commit-gate the single board-sync chokepoint, co-locating the flip with the work commit: it is invisible on main until merge, lands atomically when the work does, and an abandoned PR abandons the flip with it -- so the "don't mark done before merge" and "don't lose the board update" rules become the same, self-correcting rule. No task-to-commit inference is introduced; the human still declares the transition via /ca:task. Mechanism: a new pure _taskboardlib.classify_board_diff recognizes a clean done/start/add transition vs an arbitrary board edit; commit-gate Phase 6 retains a classified transition instead of flagging it as scope creep; Phase 7 stages it by explicit path; the raise-new harvest moved to Phase 7 (pre-commit) so a discovered follow-up rides the work commit (contingent default -- a must-survive follow-up is filed as a GitHub issue). A read-only /ca:standup advisory sweep (hooks/boardsync.py reconcile, best-effort) surfaces any merged-but-not-flipped task; the fix still routes through /ca:task. Conflict-hierarchy level: maintainability/reliability (SMARTS, per ADR-0008). Folds into the unreleased 2.6.0 (payload already ahead of tag v2.5.2; no over-bump). All 10 plan tasks shipped test-first; full tech-stack suite green; security review PASS (one LOW hardened). CHANGELOG: commit-gate now lands task-board done/start/add transitions in the same commit as the work (no separate chore(board) PR); /ca:standup gains a read-only drift sweep for any merged-but-not-flipped task. Closes #142 Ref: ADR-0008 Claude-Session: https://claude.ai/code/session_018n3e8e2RWU7hLzzJjEAscb Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
SUaDtL
added a commit
that referenced
this pull request
Jun 27, 2026
) A task isn't done until its PR merges, but open-tasks.md is itself versioned, so a board flip only goes live when its own change merges to main. That created a trap with no good side: flips drifted into lagging chore(board) PRs or post-commit edits that depended on cross-session memory, and silently fell off (#138 never marked v2.release.0002-0006 done; #140 needed the separate #141). ADR-0008 makes commit-gate the single board-sync chokepoint, co-locating the flip with the work commit: it is invisible on main until merge, lands atomically when the work does, and an abandoned PR abandons the flip with it -- so the "don't mark done before merge" and "don't lose the board update" rules become the same, self-correcting rule. No task-to-commit inference is introduced; the human still declares the transition via /ca:task. Mechanism: a new pure _taskboardlib.classify_board_diff recognizes a clean done/start/add transition vs an arbitrary board edit; commit-gate Phase 6 retains a classified transition instead of flagging it as scope creep; Phase 7 stages it by explicit path; the raise-new harvest moved to Phase 7 (pre-commit) so a discovered follow-up rides the work commit (contingent default -- a must-survive follow-up is filed as a GitHub issue). A read-only /ca:standup advisory sweep (hooks/boardsync.py reconcile, best-effort) surfaces any merged-but-not-flipped task; the fix still routes through /ca:task. Conflict-hierarchy level: maintainability/reliability (SMARTS, per ADR-0008). Folds into the unreleased 2.6.0 (payload already ahead of tag v2.5.2; no over-bump). All 10 plan tasks shipped test-first; full tech-stack suite green; security review PASS (one LOW hardened). CHANGELOG: commit-gate now lands task-board done/start/add transitions in the same commit as the work (no separate chore(board) PR); /ca:standup gains a read-only drift sweep for any merged-but-not-flipped task. Closes #142 Ref: ADR-0008 Claude-Session: https://claude.ai/code/session_018n3e8e2RWU7hLzzJjEAscb Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
SUaDtL
added a commit
that referenced
this pull request
Jun 27, 2026
* docs(changelog): roll the 2.6.0 release notes Reconcile the [2.6.0] CHANGELOG section for the release: broaden the intro beyond the farm work, add context-drift provenance (#145) and file-scoped context injection (#146) under Added, note the MIT to AGPLv3 relicense (#147, ADR-0009) under Changed, and add a Fixed section for #143, #139, and #138. Dated 2026-06-27. Also flips v2.feature.0001 to done now that file-scoped context injection has shipped and merged; the flip rides this release commit per ADR-0008. No version bump: plugin.json is already 2.6.0 and the ca-scoped commit window is unchanged. The relicense and docs commits touch no plugins/ca/ payload. Claude-Session: https://claude.ai/code/session_01QaLw7nTrRbHwygFar2R6zu * docs(license): reserve the dual-licensing right without offering it yet Soften the README "Commercial licensing" wording. The prior text implied proprietary licenses were actively on offer; the intent is narrower: the owner retains sole ownership and reserves the right to dual-license, but is not offering commercial licenses at this time. Inquiries may still be sent through GitHub and will be considered if and when a commercial path is established. The legal substance is unchanged. AGPLv3 plus sole copyright already secures the right; this only corrects the public statement so it does not overstate an active commercial offering. ADR-0009, the CLA, and the CHANGELOG already use the reserves-the-right framing, so no other file changes. Claude-Session: https://claude.ai/code/session_01QaLw7nTrRbHwygFar2R6zu --------- Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Hardens
/ca:releaseagainst five red-team findings (v2.release.0002–0006) by moving load-bearing, prose-only steps onto tested mechanical helpers.New stdlib-only
.github/scripts/_releaselib.py(+test_release_lib.py), following the_metricslib/_taskboardliblib+test pattern, with a thin CLI the skill shells out to:last_tag_selectvX.Y.Z, excludes-beta/-rc/-alphaandca-sandbox-v*notes_heading_matches## vX.Y.Zheading equals the tag beforegh release createrelease_dates_consistent— DATE== tagReleased-at: DATE(date derived once viadate +%F)classify_publish_statepublish_fresh / resume_publish / already_published / abort_mismatch— resumes a half-finished publish instead of dead-ending on "tag exists"release/SKILL.mdnow invokes these, and (0002) rebuildsfarm.jsunconditionally with the CItoolsjob named as the mechanical backstop — the old form gated the rebuild on an in-windowfarm.tschange and missed a pre-stale bundle. Scope stays ca-only;sandbox.jsfreshness is left tocasandbox.release.0001.Why this shape
0002 stayed a prose + structural-test fix rather than a new guard because CI's
toolsjob already rebuilds-and-diffsfarm.json everyplugins/ca/**PR — a duplicate guard would add nothing. The other four findings have no CI coverage (release-time logic), so their tested helpers add genuinely new enforcement.Tests
test_release_lib.py(29 tests: unit + CLI + SKILL.md structural), wired into the CIhooksjob andtech-stack.md.security-reviewerPASS on the CI/infra change (no new permissions, no secrets, no injection).Incidental (in this PR)
ca-sandbox.release.0001→casandbox.release.0001— a pre-existing board id that violates the dotted-id grammar (hyphen in the group segment). It was latent because a pure.codearbiter/edit doesn't trigger CI'shooksjob; this branch does, sotest_taskboardlib's board-conformance check would otherwise fail. (Resolution chosen by the maintainer over loosening the grammar.)SKILL.mdCRLF→LF per coding-standards (it was the lone CRLF.md). Raw diff is 146 lines; real content delta is 5 (git diff --ignore-cr-at-eol).v2.prune.0001board finding (the prune metric conflates file-bytes with context-tokens) — rides this branch per request.Follow-up discovered (not fixed here)
The H-09b commit hook false-blocks
git commit -F - <<heredocmulti-line messages:commit_pathspecsparses the heredoc body as pathspecs, thengit diff HEAD -- <body tokens>errors and the gate fails closed. Heredoc is the recommended multi-line-commit pattern, so this bites legitimate commits. Worth a board finding againstpre-bash.pycommit_pathspecs(bound the pathspec parse to the actual command line, not heredoc/redirect bodies).https://claude.ai/code/session_011nnQYBPd5Dt1rmtf9CHNfU