Feature: Validation-gate hook blocks done column without validation proof #210
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/claude-custom#210
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Feature
Lineage
Standalone -- discovered while documenting the validation column flow in
sop-board-workflowandtemplate-validation. The right-side gate (validation -> done) mirrors the left-side gate (todo -> next_up via/review-ticket), but has no hook enforcement yet. The left gate hascheck-board-item.sh; the right gate has nothing.Repo
forgejo_admin/claude-customUser Story
As Betty Sue (PM agent)
I want the
donecolumn to reject board items that lack a validation note with PASS verdictSo that no ticket can be marked done without production verification, enforcing the DORA Lead Time definition (clock stops at validation PASS, not at merge).
Context
The kanban board has a
validationcolumn betweenneeds_approvalanddone(persop-board-workflow). Thetemplate-validationnote defines the validation note format: slugvalidation-{issue-number}-{YYYY-MM-DD}, tagsvalidation,pass, and a PASS/PARTIAL/FAIL verdict. Today, nothing prevents an agent from callingupdate_board_item(column="done")directly, bypassing validation. Theboard-item-on-merge.shPostToolUse hook already auto-moves items to done after merge -- this needs to either route through the gate or be updated to move tovalidationinstead.Enforcement signals available (researched):
GET /notes?tags=validation,passfiltered by issue number in slug. This is the primary signal. Naming convention:validation-{issue-num}-*.status:approvedlabel exists (set bylabel-on-verdict.sh). However, this means QA-approved, not production-validated. Not sufficient alone.forgejo_issue_url-- Needed to extract the issue number, which becomes the validation note lookup key.Decision: Use signal #1 (pal-e-docs validation note existence with
passtag). This is the only signal that proves someone actually ran the validation checks and recorded evidence.File Targets
Files the agent should modify or create:
hooks/gate-validation-done.sh(NEW) -- PreToolUse hook that interceptsupdate_board_itemcalls wherecolumn=done, extracts the issue number from the board item'sforgejo_issue_url, queries pal-e-docs for a validation note with tagpass, and denies if none exists. Follow the pattern inhooks/check-board-item.sh(jq parsing, fail-open, deny with reason).settings.json-- Add a new PreToolUse entry with matchermcp__pal-e-docs__update_board_itempointing togate-validation-done.sh.hooks/board-item-on-merge.sh-- Change target column from"done"to"validation"(line 133). After merge, items should land in validation, not done. This is a one-word change.Files the agent should NOT touch:
hooks/check-board-item.sh-- This gatescreate_board_item, notupdate_board_item. Different concern.hooks/boards-config.sh-- No changes needed; the new hook sources it forBOARDSarray.hooks/forgejo-helper.sh-- No changes needed; sourced for_load_forgejo_credsand URL construction.skills/-- The/validate-ticketskill is a separate concern (see Dependencies).Acceptance Criteria
update_board_item(column="done")on an item whoseforgejo_issue_urlhas no matchingvalidation-{issue-num}-*note withpasstag, the hook denies with a message explaining what's missingpasstag exists, the hook allows the move to doneupdate_board_itemis called with any column other thandone, the hook is a no-op (exit 0)update_board_itemis called withcolumn=doneon an item that has noforgejo_issue_url(e.g., note-type items), the hook allows it (fail-open -- only issue-type items require validation)board-item-on-merge.shmoves items tovalidationcolumn instead ofdoneTest Expectations
tool_input.column=doneand a known board item, verify deny outputpasstag for a test issue, re-run, verify allow (exit 0)tool_input.column=in_progress, verify exit 0 (no-op)echo '{"tool_input":{"board_slug":"board-pal-e-agency","item_id":123,"column":"done"}}' | bash hooks/gate-validation-done.shConstraints
trap 'exit 0' ERR-- network failures, missing jq, or API errors must never block agent workflow.GET /notes?tags=validation,passand filters results client-side by slug prefixvalidation-{issue-num}. No new API endpoint needed.board_sluganditem_idintool_input, but NOT theforgejo_issue_url. It must fetch the item first:GET /boards/{board_slug}/itemsand find the item by ID. This is the same patternboard-item-on-merge.shuses.validationcolumn must exist in the pal-e-docs DB beforeboard-item-on-merge.shcan target it. Issue #223 (pal-e-api PR #226) adds this column via alembic migration. If that PR is not yet merged, theboard-item-on-merge.shchange should be gated behind it or use a fallback. Recommendation: Ship the hook first (it only blocks moves TO done, which works regardless of whether the validation column exists). Ship theboard-item-on-merge.shchange separately after #223 merges./validate-ticketskill yet: The skill referenced intemplate-validation(skill-validate-ticket) does not exist. This hook enforces the gate; the skill is the tool for creating validation notes. They are independent -- the hook works without the skill (agents can create validation notes manually). The skill is tracked as discovered scope.Checklist
Related
pal-e-agency-- project this affectssop-board-workflow-- defines the validation column semantics and done criteriatemplate-validation-- defines the validation note format the hook checks forforgejo_admin/pal-e-api#223-- addsvalidationto BoardColumn DB enum (dependency for board-item-on-merge.sh change)hooks/board-item-on-merge.sh-- currently moves todone, needs to move tovalidationhooks/check-board-item.sh-- sibling pattern (PreToolUse on create_board_item)/validate-ticketskill (skill-validate-ticket note + skills/validate-ticket/SKILL.md)Scope Review: READY
Review note:
review-519-2026-03-28Ticket is fully scoped, traceable, and executable. All file targets verified, all dependencies satisfied.
Minor recommendations (non-blocking):
board-item-on-merge.shupdate_board_itemmatcher's hooks array (alongsidecheck-board-advance.sh) rather than a separate entry, to stay consistent with the Bash matcher pattern and to coverbulk_move_board_itemsas wellScope Review: READY (todo→next_up gate)
Review note:
review-519-2026-03-28-dispatchTicket is dispatch-ready. No changes to target files since prior review. All dependencies satisfied (pal-e-api#223 closed, validation column in production). No in-progress conflicts, no existing branches.
Prior review recommendations (line reference off-by-one, settings.json matcher placement) remain as implementation guidance — neither is a blocker.
Scope Review: READY (todo→next_up dispatch gate)
Review note:
review-519-2026-03-28-dispatchTicket is dispatch-ready. No changes to target files since prior review (
review-519-2026-03-28). All dependencies satisfied (pal-e-api#223 closed, validation column in production). No in-progress conflicts, no existing branches.Implementation notes for agent:
update_board_itemmatcher's hooks array (settings.json lines 194-201) rather than creating a duplicate matcher entryboard-item-on-merge.shtarget line is 132, not 133 as stated in issue body