Repository navigation
feat: add Azure DevOps PR support and safer merge cleanup - #4543
martinstroher wants to merge 40 commits into
Conversation
|
Speaking as Kun's firstmate: re-opening to re-queue CI — this tip never received a workflow run. Conflict vs main remains; not merging. |
|
Speaking as Kun's firstmate: First look on HEAD Contract-class: opt-in. Azure DevOps PR transport ( VISION.md per-rule (inspected
Attestation: MATCH (body binds tip). CI never queued on this head (0 workflow runs / 0 check suites) even after close/reopen and a no-op body PATCH — cannot approve what does not exist. Require no-mistakes likewise absent. Blockers: merge conflicts vs main; no CI/NM to green. Not otherwise completely auto-merge-ready, so not resolving conflicts from here. waiting-captain / Firstmate flag: close-vs-leave vs conflict resolution path, and how to get Actions to attach to this fork tip. Security skim: |
0fdf41c to
8049817
Compare
[High impact] Both numbered findings are fixed, and no new blocking issue was found. Reviews (5) · Last reviewed commit: "no-mistakes(ci): Fixed both selected fin..." · Reviewed by Greptile |
|
Speaking as Kun's firstmate (OSS triage, not the captain). Thanks for the big rework, @martinstroher. I re-read the whole thread and inspected the new tip against main What changed since my 2026-09-15 stamp (head
Contract-class: new-default (changed from my earlier opt-in)The Azure DevOps forge path itself is still opt-in. It only engages for Azure PR URLs and Azure origins, plus an explicit
So the unconfigured run now cleans up rebased or squash-merged worktrees that main refused, and refuses some cases main accepted. That replaces the specified default teardown path, which makes this new-default. Teardown is destructive (hard-reset, worktree removal), so the captain decides. VISION.md, rule by rule
Where this standswaiting-ci. CI and no-mistakes are queued on |
…unchenguid#5427) Speaking as Kun's firstmate: squash-merging — opt-in (forge=gerrit registry-gated; default project-mode stdout restored to two words), attestation MATCH, CI+NM green, safe review, MERGEABLE.
* fix(bin): use gh-axi for the ship DoD draft check * no-mistakes(review): use PR number not URL in gh-axi draft check
…regression coverage
…-azure-pr.py that treated every Azure status as mandatory. Required statuses remain selected by enabled, blocking policy evaluations and must uniquely match the current iteration with successful results. Required approvals, policies, builds, revision-race guards, and non-bypass completion remain intact. Updated the corresponding documentation. Behavioral evidence: the guarded merge CLI previously refused optional pending, failed, stale, and unbound statuses while absent/green controls succeeded. Those cases now pass using synthetic transport. New regressions failed before the fix and pass afterward. A one-condition isBlocking counterfactual confirms the same failed status blocks only when mandatory. ci-4 declined; no implementation or test changes for this finding. bin/fm-project-mode.sh:152,166 defaults to fm/ and changes it only for an explicit project branch= annotation; bin/fm-brief.sh:196 and bin/fm-promote.sh:69 retain fm/ defaults; bin/fm-merge-local.sh:97-98 honors the recorded branch with the legacy fm/ fallback. Disposable-repository CLI tests verified default and explicit-prefix branch creation, promotion, and local landing. An unrelated project remained on fm/. Verification passed: all 29 Azure contract tests, all 28 delivery-contract test groups, documentation structural checks, and git diff --check. Before/after evidence and detailed dispositions are retained in state/ci-review/report.md and adjacent logs. ci-1 and ci-2 remain pending maintainer workflow approval. No approval was requested, granted, waived, or bypassed; no maintainer contact, workflow/authentication changes, live Azure mutations, real PR merge, activation, or pipeline control occurred. Live-Azure validation remains inconclusive and broad-suite coverage remains incomplete
…he exact tested merge c50c34d13479108a14dbeb26f6af0680a28dcb9d, comparing its actual base 99da16d with source 86137d8. Parallel 2, job 112600382607: confirmed a PR assertion regression, not a generated branch-targeting defect. The real brief CLI emits the correct base metadata, safety rule, GitHub --base and Azure --target-branch options. Two expectations still required the old GitHub-only wording. Updated only tests/fm-brief.test.sh to require both provider targets and preserved shell quoting, without relaxing existing safeguards. The original full suite passed on the actual base, failed on the tested merge with the reported error, and passed after the fix. Generated options preserved literal release/$HOTFIX when executed through Bash. One-condition mutations introducing incorrect GitHub/Azure targets or missing Azure quoting were rejected. The full fm-dod-lib suite, pinned targeted ShellCheck, and git diff --check also passed. Serial 2, job 112600382954: classified as inherited runtime variability exhausting the 30-minute job budget, not an established PR regression. Its host suite passed in 1615.124s; four later scripts passed before cancellation during board rendering. Historical CI on the actual base passed the unchanged host suite in 1409.781s and completed the lane. Its predecessor e06a46f passed the same host suite in 1570.991s but also suffered a serial-job deadline cancellation without this PR. All three host executions reported the same 73 successful checkpoints. Actual-base and tested-merge lane membership/order are identical. No speculative product, workflow, timeout, or scheduling change was made. Local serial counterfactuals remain explicitly inconclusive: base and tested merge both failed at the same dialog-wake fixture wait, and standalone board-render attempts both failed at fixture listener startup. These are retained as limitations, not passes or equivalents of the CI cancellation. The precise infrastructure mechanism behind timing variance is unproven. Evidence, reproduction scripts, complete logs, disconfirming results, and applied patch are preserved in ignored state/ci-046/report.md and adjacent files. CI is not declared green and no check was waived. Live-Azure validation remains inconclusive and broad-suite coverage incomplete. No live Azure mutation, merge, activation, publication, maintainer request, configuration change, or pipeline-control operation occurred; the outer executor owns publication and subsequent CI
b7ea197 to
ae83940
Compare
…st/<n> reports now enter the existing published-head check; behavioral tests reject unpublished work and accept remote-published or forge-recorded heads across modern and legacy Azure URLs. ci-2: the shared backlog converter records Azure PRs as notes, covering completion and sibling replay/retention paths. A behavioral cleanup test confirms a completed Azure task closes its active backlog item. Existing GitHub, GitLab, Gerrit and Forgejo cleanup cases passed. The full fm-dod-lib test script, pinned ShellCheck 0.11.0, shell syntax checks and git diff --check passed. Earlier bounded batches timed out; focused reruns passed, but the full teardown/broad suite was not completed. Live Azure validation remains untested/inconclusive. No workflow changes, pipeline control, live Azure mutation, merge or activation occurred. Evidence: state/ci-ready-backlog/result.md
|
Speaking as Kun's firstmate: tip moved to What is new: attestation now binds Contract-class: new-default (unchanged). The Azure forge path itself stays URL/origin gated, but the tip still replaces the default teardown "has this work landed?" proof for every project (including GitHub) via VISION.md, rule by rule
Next: waiting on the freshly approved CI / no-mistakes runs, not on you. Path when green: new-default → captain flag after Full (draft only until then). |
A project hosted on Azure DevOps Services could not ship through a pull request, because Firstmate recognized pull request links only from github.com, GitLab, Gerrit, and Forgejo. An Azure DevOps pull request now gets the same lifecycle: the worker opens it, Firstmate records the link it reports, watches it, completes it when approved, and confirms the work landed before cleanup. Both Azure DevOps Services URL forms parse, dev.azure.com and <org>.visualstudio.com with or without DefaultCollection, keeping the URL as written and validating project and repository as canonical percent-encoded segments. Because a pull request id is unique per organization, every az read binds the answer to the URL's project and repository. forge=azure-devops joins the closed registry binding; detection proposes it from an Azure DevOps origin host and the captain confirms it. The binding changes only the worker contract, which names az repos pr for opening, draft read-back, and the reported web URL. Completion verifies the pull request is active, not a draft, merges cleanly, and every applicable branch policy passes at the live source commit, then sends one az rest PATCH naming that commit as lastMergeSourceCommit, never bypassing policy or deleting the source branch, behind the existing merge-authority and green-check guards. Teardown proves landing from the completed record and the source commit, which holds for squash completions; other forges keep their cleanup proof. Review diffs compare the source commit behind refs/pull/<id>/merge. Builds on the open work in kunchenguid#4543 and kunchenguid#4871, which conflict with current main; docs/azure-devops-integration.md records the live verification.
Intent
Enable Azure DevOps support in Firstmate's existing PR workflow: recognize and track Azure PRs, verify required approvals and checks before an authorized merge, and confirm merged work before cleanup. The motivating Azure repository requires users//... branch naming instead of fm/.... Keep Firstmate's normal automated review before publication and the repository's colleague-approval requirements before merging.
Okay; then we got you your first task; do we ahve to configure something in order to do that? no-mistakes, yolo, etc?
For this specific case, i prefer if we used my personal gh account; martinstroher
No, do the more extensive automatic cleanup
The selected cleanup approach must reliably handle rebased and squash-merged work automatically while preserving later local changes that were not merged, rather than resolving the issue by leaving ordinary rewritten-history cases for manual cleanup. Cleanup must still refuse whenever safety cannot be proved.
Do the recommeneed
Replace the unsuccessful automatic-cleanup implementation rather than continue patching it.
Track locally changed regions, including later restorations, and verify their final contents at the correct locations in the merged result.
Preserve work whenever the available history cannot establish that those changes were merged.
Safely stop the obsolete review, preserve all existing work, and fully validate the replacement before publication.
No merge or activation is authorized.
What Changed
users/<username>/...branch-prefix configuration, and add regression coverage for Azure workflows and rewritten-history cleanup.Risk Assessment
Testing
Diff inspection, live local CLI scenarios, focused regressions, and synthetic Azure checks demonstrated branch selection and cleanup safeguards. Initial bounded batches were incomplete; focused reruns covered the critical cases. CLI transcripts and generated briefs were captured; screenshots are not applicable to this CLI-only surface. Live Azure remains untested under the accepted scope restrictions; no publication, merge, activation, or broad-suite validation was performed.
Evidence: Live branch, review, and rewritten-history CLI evidence
Source: Live branch, review, and rewritten-history CLI evidence
Evidence: Live hidden nested-submodule cleanup refusal
Source: Live hidden nested-submodule cleanup refusal
Evidence: Generated provider-aware release-target instructions
Source: Generated provider-aware release-target instructions
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
🔧 **Rebase** - 11 issues found → auto-fixed ✅
README.md- merge conflict rebasing onto origin/mainbin/fm-dod-lib.sh- merge conflict rebasing onto origin/mainbin/fm-pr-check.sh- merge conflict rebasing onto origin/mainbin/fm-pr-lib.sh- merge conflict rebasing onto origin/mainbin/fm-pr-merge.sh- merge conflict rebasing onto origin/mainbin/fm-pr-poll.sh- merge conflict rebasing onto origin/mainbin/fm-teardown.sh- merge conflict rebasing onto origin/mainbin/fm-test-run.sh- merge conflict rebasing onto origin/maintests/fm-pr-merge.test.sh- merge conflict rebasing onto origin/maintests/fm-review-diff.test.sh- merge conflict rebasing onto origin/maintests/fm-teardown.test.sh- merge conflict rebasing onto origin/main🔧 Fix applied.
✅ Re-checked - no issues remain.
🔧 **Review** - 5 issues found → auto-fixed ✅
bin/fm-content-containment.py:285- The previously accepted path-provenance fix is still absent. Concrete sequence: B lacks g; local C edits f; upstream U adds g containing 'zero\nanchor\ntail0\n'; M merges U into C; local D changes g's first line to 'one'. Publication rebases onto U2, which independently changes g's last line to 'tail1', then squash-merges. All local edits landed, but histories includes B/C where g is absent, so containment returns false. Removing this check alone is insufficient: unchanged B→C comparisons also erase g's anchors. Build path-specific obligations from actual local changes while retaining restoration protection. Related sites: bin/fm-content-containment.py:265 (unfiltered history), :292 (every comparison supplied for every path), :120 and :133 (irrelevant versions constrain anchors); bin/fm-teardown.sh:1656, :1774 and :1800 (Azure, PR and branch-content consumers).bin/fm-teardown.sh:2181- The previously accepted nested-untracked fix is still absent. Recursive status does not request --untracked-files=all, so an initialized nested module with status.showUntrackedFiles=no and only an untracked source file reports clean. Ancestor submodule ignore settings can hide it from the superproject check too. With committed work landed, cleanup can proceed toward forced return despite that uncommitted file. Request all untracked files at every recursive level, matching bin/fm-teardown.sh:2168. This shared guard must cover the initial check at :3775, stale-lock retry at :3782, post-reaper check at :3928 and return-retry callback at :4075. The regression at tests/fm-teardown.test.sh:823 currently exercises a tracked modification, not this hidden-untracked case.bin/fm-teardown.sh:2159- The previously accepted missing/reassigned-copy fix is still absent. Both callers at bin/fm-teardown.sh:3775 and :3928 require an owned, existing directory before entering this function. Consequently a non-Orca ship with an active, abandoned or unreadable registered Azure PR bypasses completion verification when its copy is missing or its pool slot was reassigned. Cleanup can then remove monitoring at :4165 and close the backlog item at :4224. Enforce registered Azure completion at the task-record cleanup boundary independently of copy ownership/existence. Keep content and dirt checks restricted to an owned, present copy; do not inspect another task's reassigned slot. The completion read at :1651 and missing-copy return at :1652 currently cannot protect these callers.bin/fm-pr-merge.sh:1884- Pinned Azure completion is unusable: a validfm-pr-merge.sh task URL --expected-head Hforwards--expected-head H, but bin/fm-azure-pr.py:306-308 accepts only action and URL. Argument parsing therefore rejects even a matching, fully approved revision before verification or PATCH. This contradicts the recorded requirement to preserve the 'expected-head, branch-prefix/base and safety contracts' and the changed header promising Azure support at bin/fm-pr-merge.sh:60 and :156. Restore the required contract by accepting and validating the optional expected head in the helper, comparing it with the verified source, and retaining that exact value through completion—not by dropping the flag. Related boundaries: bin/fm-azure-pr.py:182 (verification) and :289-292 (completion/CAS).bin/fm-teardown.sh:1730- An unavailable PR containment proof can be mislabeled as unlanded work. For example, the PR proof exceeds the alignment bound, setting CONTENT_LANDED_PROOF_ERROR here; the subsequent branch-content fallback clears it at bin/fm-teardown.sh:1790, then returns early because the selected branch cannot be fetched. The final refusal at :2229-2233 now claims 'not landed' instead of preserving the unavailable-proof classification. Retain unknown-proof evidence across failed fallback attempts and distinguish it from a completed negative proof. Related paths: :1774 and :1809 (PR-to-branch fallback), :1656 (Azure's equivalent fallback), and :1800 (shared proof invocation).🔧 Fix applied.
✅ Re-checked - no issues remain.
git status --short, targeted diffs, and interface documentation inspection for b77b66cb999876c4db19da36b9af5baaacdd52e5..b7aa4b93c8e44f4d0d13e12ffccce21e8245843f.python3 tests/azure-pr-contract.py -v: interrupted at the 850-second bound after 31 passing methods; the two remaining methods passed in a separate targeted invocation.tests/fm-task-delivery.test.shselected functions: project prefix selection, delivered definition of done, persisted promotion branch, shell-safe promotion command, and registry prefix resolution—all passed.bin/fm-test-run.sh --jobs 1 --per-script-timeout-secs 300 tests/fm-brief.test.sh tests/fm-review-diff.test.sh: incomplete due to command bounds; captured assertions passed before interruption.tests/fm-brief.test.shfocused rerun:test_base_branch_is_rendered_and_bounded,test_ship_branch_prefix_defaults_to_legacy_fm, andtest_branch_prefix_command_is_shell_safe—passed.python3 state/test-validation/live-checks.py: executed generated branch commands, reviewed the recorded personal branch, and drove the real containment executable against 24 disposable Git histories—all passed.python3 state/test-validation/live-dirty.py: real cleanup CLI refused hidden nested-submodule source changes and preserved file bytes, task head, and metadata.tests/fm-teardown.test.shfocused reruns: missing/reassigned-copy Azure completion guards, nested tracked/untracked/clean controls, unavailable-proof fallback classification, and path-provenance-created/restored cleanup—passed. The initial larger selected batch exceeded its bound.python3 tests/containment-contract.py -v: independent alignment and history-oracle checks passed.Captured public CLI responses, generated briefs, synthetic completion requests, cleanup diagnostics, and retained-state evidence. A supplemental Azure transcript-capture batch was interrupted after four passing methods; its cases had already passed in the primary contract run.Removed this turn's disposable homes, repositories, drivers, and caches; confirmed unchanged tracked files and HEAD b7aa4b93c8e44f4d0d13e12ffccce21e8245843f.✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.