Skip to content

fix(bin): honor GitLab merge request defaults - #11

Merged
eyevanovich merged 3 commits into
mainfrom
fm/firstmate-gitlab-mr-defaults
Jul 25, 2026
Merged

eyevanovich merged 3 commits into
mainfrom
fm/firstmate-gitlab-mr-defaults

Conversation

@eyevanovich

Copy link
Copy Markdown
Owner

Intent

Diagnose and fix Firstmate's GitLab merge-request submission behavior so future direct GitLab MRs reliably request and verify both Delete source branch and Squash commits without false metadata failures. Treat source-deletion verification and missing squash submission as distinct faults until evidence joins them; compare creation and exact-MR reuse, GitLab request payloads, response fields, project defaults, and read-back behavior. Provide explicit idempotent mr-create options, preserve ambiguous-success no-retry safety and exact identity/head/authorship checks, keep omitted options delegated to GitLab project defaults, and apply this captain's local squash-and-delete preference through the existing captain-preference configuration seam rather than imposing it on every Firstmate user. Update exact help, configuration documentation, and regression coverage for creation, reuse, project defaults, response variation, and true mismatch behavior. Do not mutate existing live MRs or weaken guarded verification.

What Changed

  • Add explicit --squash and --remove-source-branch options to GitLab MR creation, while leaving omitted settings to project defaults.
  • Verify requested squash and source-deletion behavior from exact-MR read-back for both newly created and reused MRs, including supported GitLab response variations.
  • Apply affirmative captain preferences to generated direct-PR briefs, document the accepted preference grammar, and expand regression coverage for defaults, reuse, and mismatch handling.

Risk Assessment

✅ Low: Captain, the change is well-bounded, the strict affirmative preference grammar resolves the prior findings, and the guarded GitLab MR creation and reuse invariants remain intact.

Testing

The previously successful full baseline plus focused adapter, generated-brief, help, and request/read-back checks demonstrated explicit squash/delete creation, exact-MR reuse, project-default omission, response-shape fallbacks, distinct mismatch failures, guarded identity verification, and captain-scoped preference behavior; all passed with reviewer-visible CLI evidence and no UI screenshot because this change has no rendered UI surface.

Evidence: GitLab MR behavior transcript
$ bin/fm-forge.sh --help | sed -n /mr-create/,/mr-note/p
  fm-forge.sh mr-create <repo> --title <text> --source <branch>
    [--target <branch>] [--body-file <file>] [--draft]
    [--remove-source-branch] [--squash]
  fm-forge.sh mr-view <repo> <iid|canonical-url> [--target <branch>]
  fm-forge.sh mr-find <repo> <source-branch> [--target <branch>]
  fm-forge.sh mr-claim <repo> <iid|canonical-url> [--target <branch>]
  fm-forge.sh mr-status <repo> <iid|canonical-url> [--target <branch>]
    --status in-progress|blocked|deferred
  fm-forge.sh mr-release <repo> <iid|canonical-url> [--target <branch>]
    --status blocked|deferred|ready
  fm-forge.sh mr-labels <repo> <iid|canonical-url> [--target <branch>]
    (--add <existing-label>|--remove <existing-label>)...
  fm-forge.sh mr-note <repo> <iid|canonical-url> [--target <branch>]

$ bash -x tests/fm-forge.test.sh 2>&1 | grep relevant request/read-back assertions
+ assert_grep merge_requests/5 /var/folders/j_/g4b3__rs5j95fq6xf9fb17sc0000gn/T//fm-forge-tests.MqNey8/glab.log 'exact reuse did not read back the exact merge request'
+ assert_no_grep '--method POST' /var/folders/j_/g4b3__rs5j95fq6xf9fb17sc0000gn/T//fm-forge-tests.MqNey8/glab.log 'project-default reuse created another merge request'
+ assert_no_grep '--method POST' /var/folders/j_/g4b3__rs5j95fq6xf9fb17sc0000gn/T//fm-forge-tests.MqNey8/glab.log 'reduced-list reuse created another merge request'
+ expect_code 1 1 'conflicting merge-request remove-source intent'
+ local expected=1 actual=1 'label=conflicting merge-request remove-source intent'
+ expect_code 1 1 'unproven merge-request remove-source intent'
Evidence: GitLab MR adapter validation
$ bash tests/fm-forge.test.sh
ok - forge identity comes only from the origin remote
ok - GitLab authentication uses the trusted host and stored credential only
ok - public GitHub identity resolves without a credentialed call
ok - self-hosted GitLab requires an exact trusted registration
ok - unsupported and GitHub Enterprise-ambiguous hosts fail before credentials
ok - issue output uses a minimal schema and bounded body
ok - merge-request URLs cannot override the origin host or project
ok - issue and merge-request URLs share strict canonical validation
ok - merge-request body files cannot exfiltrate files outside the worktree
ok - merge-request lookup requires one exact source project and branch pair
ok - merge-request creation reuses only one exact trusted candidate
ok - every merge-request lifecycle action verifies trusted identity
ok - pipeline checks are aggregated and only actionable jobs are returned
ok - an empty pipeline list remains pending during pipeline creation
ok - only an independently disabled CI feature authorizes a no-CI merge
ok - a running GitLab pipeline blocks merge
ok - a failing GitLab pipeline blocks merge
ok - a passing pipeline for an older SHA cannot authorize merge
ok - GitLab merge pins the reviewed head and verifies the merged state
ok - GitLab merge requires and rechecks the reviewed head SHA
ok - GitLab checks remain pinned to the reviewed head SHA
ok - non-default targets remain explicit through every lifecycle action
ok - GitLab merge poll emits one line only after merge
ok - local and unsupported remote schemes never select a credentialed forge
ok - unsafe remote text is rejected and never evaluated
Evidence: Captain preference validation
$ bash tests/fm-brief.test.sh
ok - fm-brief.sh: bash -n succeeds
ok - fm-brief.sh: --help renders the complete header
ok - fm-brief.sh: no-mistakes/direct-PR/local-only briefs generate cleanly
ok - fm-brief.sh: ship and scout work use named guarded GitLab mutation commands
ok - fm-brief.sh: GitLab direct-PR commands honor only configured captain defaults
ok - fm-brief.sh: faster paths use configured authority without stacked review
ok - fm-brief.sh: no-mistakes DOD wording and signing preflight stay intact
ok - fm-brief.sh: ship project-memory wording carries the AGENTS.md authoring bar
ok - fm-brief.sh: --herdr-lab emits the complete hard safety contract
ok - fm-brief.sh: --herdr-lab uses its quoted Firstmate-owned helper path
ok - fm-brief.sh: ship and scout scaffolds make omitted Herdr intent fail-visible
ok - fm-brief.sh: Herdr lab contract covers scouts and rejects secondmate misuse
ok - fm-brief.sh: --no-projects scaffolds a project-less charter and guards misuse
ok - fm-brief.sh: custom pause verb renders in every scaffold
ok - fm-brief.sh: investigation and visual-review completions load the shared decision policy
ok - fm-brief: scout and secondmate code paths still scaffold well-formed briefs

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed (2) ✅
  • ⚠️ bin/fm-brief.sh:120 - Intent requires “affirmative MR defaults,” but the parser treats any recognized line containing squash or delete/remove source branch as affirmative. For example, - GitLab MR defaults: do not squash; do not delete source branch enables both flags, contradicting docs/configuration.md’s claim that negative prose is ignored. Captain, either reject negated phrases or define a strict positive-token grammar and add regression coverage.

🔧 Fix: Honor negated GitLab MR preferences
1 warning still open:

  • ⚠️ bin/fm-brief.sh:120 - Captain, the negation fix still treats common negative forms such as GitLab MR defaults: squash disabled or squash: false as affirmative because it recognizes only a fixed phrase list. This still conflicts with the intent’s “affirmative MR defaults” requirement and docs/configuration.md’s claim that negative prose is ignored. Use a strict positive grammar or explicitly parse option values instead of enumerating negation phrases.

🔧 Fix: Enforce affirmative GitLab MR preference grammar
✅ Re-checked - no issues remain.

✅ **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"
  • Confirmed the configured baseline had already passed: command -v tmux …; for t in tests/*.test.sh; do bash &#34;$t&#34;; done
  • Inspected the change from 9845ea3e043deb43814e826f2f337ff09be8194d to f7888c4b440e91fab17f8fda57afa40e21894aba
  • bash tests/fm-forge.test.sh
  • bash tests/fm-brief.test.sh
  • bin/fm-forge.sh --help | sed -n '/mr-create/,/mr-note/p'
  • bash -x tests/fm-forge.test.sh 2>&1 | grep -E '<relevant request/read-back assertions>'
  • git status --short
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@eyevanovich
eyevanovich merged commit b75c898 into main Jul 25, 2026
@eyevanovich
eyevanovich deleted the fm/firstmate-gitlab-mr-defaults branch July 25, 2026 07:20
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.

1 participant