fix(bin): harden GitLab merge request verification - #10
Merged
Merged
Conversation
added 4 commits
July 22, 2026 20:57
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.
Intent
Autofix the remaining live GitLab merge-request creation verification bug exposed by KissCut issue 146. Identify and handle the exact GitLab API response semantics: create/update requests use remove_source_branch, while read responses distinguish the MR-specific should_remove_source_branch intent from force_remove_source_branch project policy and remove_source_branch_after_merge project defaults. Accept successful create or idempotent reuse only when title, exact description intent (allowing only null/empty normalization), draft state, source, target, head SHA, authenticated authorship, and requested source-branch deletion semantics truly match. Preserve ambiguous-success no-retry safety and never create a duplicate; conflicting existing state must refuse unless an explicitly safe guarded convergence path exists. Diagnostics must disclose only mismatched field names, never credentials or full untrusted MR bodies. Keep all fixes focused on GitLab MR create/reuse response semantics and field-only diagnostics, and add a live-shape regression fixture. The captain explicitly authorized per-task AUTOFIX via --yes for ordinary findings, but not destructive, irreversible, credential, or security-sensitive choices.
What Changed
Risk Assessment
Testing
The previously successful full baseline was supplemented by the focused GitLab forge suite and an end-to-end fake-API CLI run; exact live-shape reuse avoided duplicate creation, conflicting MR deletion intent refused with field-only diagnostics, and new draft creation preserved its body and deletion request, with a clean worktree afterward.
Evidence: GitLab MR create/reuse end-to-end transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
bin/fm-forge.sh:672- The required distinction between MR intent and project policy is violated: whenshould_remove_source_branchis unavailable, this fallback infers MR intent by comparingforce_remove_source_branchwithremove_source_branch_after_merge. Those are independent project-policy/default fields, so their inequality cannot prove the MR-specific choice and may falsely accept conflicting state. Require a booleanshould_remove_source_branch; otherwise fail closed.bin/fm-forge.sh:680- The required “exact description intent (allowing only null/empty normalization)” is not enforced. jq's//also converts booleanfalseand a missing member to"", allowing a malformed response to match an empty requested description. Requiredescriptionto be a string or explicit null, and normalize only null.bin/fm-forge.sh:1350- The forbidden diagnostic behavior remains: authorship mismatch messages interpolate the authenticated username instead of disclosing only mismatched field names. Report fields such asauthor.id,author.usernamewithout including their values; the same issue also affects created-MR verification at line 1382.🔧 Fix: Harden GitLab merge-request response verification
1 warning still open:
bin/fm-forge.sh:167-FM_GITLAB_PROJECT_REMOVE_SOURCE_DEFAULThas no remaining consumer after verification switched exclusively toshould_remove_source_branch. Parsing it adds dead state and can make everyload_trusted_projectcaller fail on an irrelevant malformed project-default field. Remove this parsing block and the global; the fixture can retain the field as part of the live response shape.✅ **Test** - passed
✅ No issues found.
command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"Baseline (already successful):command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"Focused regression suite:bash tests/fm-forge.test.shEvidence run:PS4='+${LINENO}: ' bash -x tests/fm-forge.test.shReviewed the evidence transcript for live-shape idempotent reuse, conflicting deletion-intent refusal without POST retry, field-only diagnostics, and successful draft MR creation preserving the exact body and deletion requestVerified the worktree remained clean withgit status --short✅ **Document** - passed
✅ No issues found.
🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix: Remove unused GitLab project deletion default
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.