Skip to content

feat(commit-gate): land board transitions with the work (ADR-0008)#144

Merged
SUaDtL merged 1 commit into
mainfrom
feat/commit-gate-board-sync
Jun 26, 2026
Merged

feat(commit-gate): land board transitions with the work (ADR-0008)#144
SUaDtL merged 1 commit into
mainfrom
feat/commit-gate-board-sync

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

What & why

Implements ADR-0008 (accepted) — commit-gate is the single board-sync chokepoint. Resolves the order-of-operations trap behind #142: because open-tasks.md is versioned, a board flip only goes live when its own change merges, so 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).

Co-locating the flip with the work commit makes it self-correcting: invisible on main until merge, atomic when the work lands, and abandoned with the PR if the PR is abandoned. No task→commit inference is introduced — the human still declares the transition via /ca:task.

How

  • _taskboardlib.classify_board_diff — a pure classifier that recognizes a clean done-flip / start-flip / single queued-add vs an arbitrary board edit (tight: state-cell + date only, no description ride-along; single-contiguous-insert for adds).
  • commit-gate Phase 6 retains a classified transition instead of flagging it as scope creep; Phase 7 stages it by explicit path. The secret/crypto/migration gates are untouched — an arbitrary open-tasks.md edit still flags.
  • 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, not the board.
  • /ca:standup gains a read-only, best-effort advisory drift sweep (hooks/boardsync.py reconcile) surfacing any merged-but-not-flipped task; the fix still routes through /ca:task (never auto-flipped).
  • Docs in lockstep: commit-gate/SKILL.md, harvest.md, /ca:task doc.

Verification

  • 10 plan tasks, all shipped test-first; new coverage in test_taskboardlib.py (classifier / id-extract / drift), test_boardsync.py (read-only byte-identical proof), and structural test_board_sync.py (registered in tech-stack + CI).
  • Full tech-stack suite green; hooks/tests discover green; plugin-ref graph intact.
  • Security review PASS — 0 CRITICAL/HIGH/MEDIUM; the exemption was confirmed non-bypassing and boardsync.py write-free/injection-free. One LOW (unguarded main() I/O) hardened.
  • Caught and fixed silent LF→CRLF drift on standup.md before it bloated the diff.

Notes

  • Folds into the unreleased 2.6.0 (payload already ahead of tag v2.5.2; no over-bump). CHANGELOG updated.
  • Conflict-hierarchy level of the tradeoff: maintainability / reliability (SMARTS, per ADR-0008).
  • Dogfoods its own rule: this PR stages the harvested docs-site-mirror task into open-tasks.md within the work commit.
  • Fast-follow tracked on the board: sync the site/ command-doc mirrors for task.md/standup.md.

Closes #142

https://claude.ai/code/session_018n3e8e2RWU7hLzzJjEAscb

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
@SUaDtL
SUaDtL merged commit 4223255 into main Jun 26, 2026
22 checks passed
@SUaDtL
SUaDtL deleted the feat/commit-gate-board-sync branch June 26, 2026 20:09
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>
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.

Process: land task-board done-flips atomically with the work (in commit-gate), not in a lagging follow-up PR

1 participant