fix(guard): derive target base ref for cross-repository checkouts #984
Merged
sysadmin
merged 2 commits from 2026-07-31 00:05:24 -05:00
fix/issue-983-cross-repo-base-ref into master
Labels
Clear labels
allocator
anti-stomp
architecture
bug
chore
codex
concurrency
contamination
control-plane
dashboard
database
design
documentation
enhancement
gitea
glitchtip
important
incident
incident-bridge
integration
jenkins
labels
leases
mcp
mcp-health
mcp-menu
multi-project
mutating
nice-to-have
observability
portability
preflight
protected-branch
queue
read-only
reconnect
recovery
refactor
release
reliability
resumable-review
reviewer
roadmap
safety
security
self-hosted
sentry
stale-runtime
status:blocked
status:in-progress
status:pr-open
status:ready
terminal-lock
testing
tracker
type:bug
type:feature
type:feature
type:guardrail
visibility
workflow
workflow-hardening
workflow-hardening
Controller-owned work allocator
Prevent concurrent LLM session stomping
Architecture / structural design
OpenAI Codex client / workflow session surface
Concurrent session safety
Workflow or session contamination incident
MCP control-plane coordination and allocation authority
MCP operational dashboard/queue view
Internal coordination storage (SQLite/Postgres)
Design / investigation, no implementation
Docs / runbooks
New feature or improvement
Gitea MCP workflow
GlitchTip integration
Operational or process incident requiring durable audit trail
Sentry-to-Gitea incident bridging
Integration testing
Jenkins integration
Label taxonomy management
Lease adopt/release/expire lifecycle
MCP server / tooling
MCP namespace and runtime health
MCP menu surface
Work spanning multiple monitoring projects or Gitea repos
Mutating action; requires gating
Observability, metrics, traces, error reporting
Cross-platform / portability
Shared preflight gates before mutation
Protected branch / stable-branch policy concern
Work queue visibility and allocation
Read-only, no mutation
MCP client reconnect/reload recovery path
Recovery paths for stale/foreign leases
Code refactor / restructure
Release / versioning
Reliability / failure handling
Persist and resume prepared review verdicts across sessions
Reviewer workflow tooling
Roadmap / umbrella issue
Safety rails and fail-closed mutation guards
Security / trust boundary
Self-hosted infrastructure integration
Sentry error monitoring integration
Stale backend daemon / runtime-vs-master parity failures
Issue is blocked
Issue is being worked on
Issue has an open pull request
Issue is ready for work
Terminal review lock (#332) path
Tests / test coverage
Issue tracker hygiene / meta
Bug or defect
Feature or enhancement
Feature or enhancement
Safety gate or guardrail
Workflow state visibility for LLMs/operators
Cross-tool workflow
LLM workflow coordination hardening
LLM workflow coordination hardening
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Scaled-Tech-Consulting/Gitea-Tools#984
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Hardcoded assumptions removed
Two independent modules each hardcoded a base ref, and they disagreed with each other:
root_checkout_guard.pyREMOTE_MASTER_REFS = ("prgs/master", "refs/remotes/prgs/master")as the silent default ofresolve_remote_master_sha(). All four production callers omittedremote_refsand inherited it.root_checkout_guard.pyprgs/masterbaked into the operator-facing contamination message.master_parity_gate.pyrefs/remotes/origin/masteras the defaulttracking_ref.master_parity_gate.pygit remote get-url origin— a hardcoded remote name — for repository identity.Gating assumed remote
prgs; reporting assumed remoteorigin. At most one could be right for any repository, and for a repository using neither, both were wrong.Both constants are retained for callers that still pass an explicit override; neither is a silent default any more.
How the authoritative target is resolved
canonical_repository_root.pyis the existing authoritative repository/context resolver (#706/#973), so it was extended rather than adding a second source of repository truth.It already probed remotes and identified the right one while resolving
owner/repository— then discarded the remote name.resolve_identity_remote()now returns that name, andrepository_identity_slug()becomes a thin wrapper over it, so its behaviour is unchanged.resolve_target_base_ref()then derives, in order:MDCPSis reachable only asMDCPS; the lowercasemdcpsprobe candidate simply does not resolve, and the exact name arrives fromgit remote.refs/remotes/<remote>/HEAD, which is git's own record of that remote's default branch, written bycloneandremote set-head.master/main/devremote-tracking ref.No new configuration field was required, and none was added. Step 2 is authoritative repository state that already exists, which is the proof that a new field is unnecessary.
Fail-closed behaviour preserved
Derivation returns
proven: false, an emptytracking_refs, and a machine-checkablereason_codewhen:reason_codeno_identity_remoteambiguous_identity_remoteambiguous_integration_branchno_integration_branch_refAn underivable target yields
sha = None— exactly whatresolve_remote_master_sha()already returned whenrev-parsefailed — so the #749/#757 bootstrap still treats it as missing evidence, never as "no constraint". It never invents a branch, writes a ref, or falls back to another repository's commit. Derivation is strictly read-only, asserted by a test that snapshots every ref and remote before and after.The bootstrap callers now surface the derivation
reasons, so a refusal states its cause instead of only "live master tip is unknown".One consistent target for gating and reporting
Both sides now consume the same resolver, so they cannot diverge again.
assess_target_repository_parity()gainsbase_remote,base_branch, andtracking_ref_source; a test asserts the gate and the report agree on remote, branch, and SHA.Repository identity is resolved independently of the base ref: a target that has never been fetched still has a provable identity, and reporting it as unidentifiable would discard real information over a missing ref that does not bear on identity.
PRGS compatibility
Unchanged.
prgs/masterresolves through the recorded remote HEAD to the identical SHA, and an explicitremote_refsoverride keeps the historical probe path verbatim. Verified live in this checkout:prgs/master->refs/remotes/prgs/master, sourceremote_head_symref.This also repairs an observable defect in this repository.
refs/remotes/origin/mastersurvives here as an orphan ref from a removed remote (git config --get remote.origin.urlexits 1). The parity gate read that abandoned ref and reported:After this change, against the same checkout:
Cross-repository MDCPS/dev regression coverage
tests/test_issue_983_cross_repo_base_ref.pybuilds hermetic git repositories on disk — no network, no fetch — and covers all ten required cases:prgs/masterbehaviour preserved, plus the legacy explicit-remote_refspathMDCPS, branchdev->refs/remotes/MDCPS/devoriginMDCPSPlus the orphan-
origin-ref case reproducing the live symptom above, and a read-only proof that no refs or remotes are mutated.MDCPS is never special-cased; neither is
WeeklyBriefings-Metaordev. No MDCPS or Weekly Briefings repository was touched.Production callers traced
Five, not four. The four
resolve_remote_master_shasites named in the report, plusanti_stomp_preflight.py:551, which callsassess_root_checkout_guarddirectly and would have emitted the same misleading message:gitea_mcp_server.py:1059— author issue bootstrapgitea_mcp_server.py:1094— create-issue bootstrap (#749/#757)gitea_mcp_server.py:1318— namespace mutation preflightgitea_mcp_server.py:2005—_enforce_root_checkout_guard(#475)anti_stomp_preflight.py:551— root-checkout check, now forwardingremote_master_refExact test results
Focused, in the issue worktree at
2d5d5c9:Directly affected suites (16 modules):
Full suite, issue branch:
Full suite, clean baseline worktree at the identical base commit
108cbfa:The two
FAILEDlists were captured, sorted, and diffed: byte-identical, zero introduced failures. All 28 are pre-existing at108cbfaand do not depend on this change. The+25passed delta is this PR's 24 new tests plus one added guard test.Test updated with the behaviour
tests/test_root_checkout_guard.py::test_head_behind_prgs_master_blockedasserted the literaldoes not match prgs/master, which is exactly the string this issue removes. It is renamed totest_head_behind_tracking_base_ref_blockedand now asserts the generic wording, with a new sibling test proving a named ref is reported accurately and never asprgs/master.One test I first wrote asserted that
refs/remotes/mdcps/devfails to resolve. It failed on macOS: a case-insensitive filesystem resolves loose refs either way, so that assertion tested the filesystem rather than this code. It was replaced with the portable guarantee — git remote names are case-sensitive config subsections on every platform (git remote get-url mdcps->error: No such remote 'mdcps').Closes #983
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #984
issue: #983
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 34009-378909a42165
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr984-2d5d5c9
phase: claimed
candidate_head:
2d5d5c9d17target_branch: master
target_branch_sha:
108cbfa173last_activity: 2026-07-31T02:54:01Z
expires_at: 2026-07-31T03:04:01Z
blocker: none
Canonical PR State
STATE: blocked
WHO_IS_NEXT: author
NEXT_ACTION: Fix B1 (stop trusting the stale refs/remotes//HEAD cache as the integration branch) and B2 (stop passing the derived identity remote back into resolve_target_base_ref, which disables the ambiguity gate), add the two missing regression fixtures, and push to fix/issue-983-cross-repo-base-ref.
NEXT_PROMPT: Continue authoring issue #983 on PR #984. Reviewer verdict at head
2d5d5c9d17is REQUEST_CHANGES with two blocking findings. B1: resolve_target_base_ref treats refs/remotes//HEAD as authoritative, but it is a local cache written at clone time and never refreshed by fetch; on the real target /Users/jasonwalker/Development/weekly-briefings it still says refs/remotes/MDCPS/main while the upstream default is dev (git ls-remote --symref MDCPS HEAD returns refs/heads/dev), so the guard compares HEAD a37ac427c18b against MDCPS/main 9a84325a1b68 and blocks a checkout that is exactly on its integration tip. B2: master_parity_gate.py:498 passes remote=identity_remote into resolve_target_base_ref, and that function skips its ambiguity check whenever a remote is named, so DENY_AMBIGUOUS_REMOTE can never fire from the reporting path; the gate refuses an ambiguous target while the report silently names a different repository with stale=false and no reasons. Add a fixture where refs/remotes//HEAD disagrees with the checkout upstream, and a fixture asserting gate and report agree on an ambiguous target. Do not fetch and do not run git remote set-head. Then request re-review.WHAT_HAPPENED: Independent review at the PR head. Diff, all five production call paths, and the resolver were inspected, and the resolver was executed against both the live PRGS control checkout and the real Weekly Briefings target. PRGS behaviour and the orphan-origin repair verified correct; two blocking defects found that the current test suite cannot see.
WHY: The PR replaces the hardcoded prgs/master with a derivation that is wrong for the very repository the issue was filed to unblock, and the gating/reporting consistency the issue requires is not actually achieved on ambiguous targets.
ISSUE: #983
HEAD_SHA:
2d5d5c9d17REVIEW_STATUS: request_changes
MERGE_READY: false
BLOCKERS: B1 and B2 below; unblocked only after the integration branch is derived from a signal that is not the stale remote-HEAD cache, and after the ambiguity gate is reachable from the parity-reporting path, each with a regression test that fails on the current code.
VALIDATION: tests/test_issue_983_cross_repo_base_ref.py 24 passed; 12 affected suites 220 passed, 95 subtests passed; both blocking defects reproduced live against /Users/jasonwalker/Development/weekly-briefings and a hermetic two-remote repository.
LAST_UPDATED_BY: reviewer
Verdict
REQUEST_CHANGES at head
2d5d5c9d174ae5f7a36c57e724af298fc5cff8dc, basemaster@108cbfa173de.Reviewed as
prgs-reviewer/sysadmin; PR author isjcwalker3, so identities differ. Runtime parity green,mutation_safe: true. Review worktreebranches/review-pr984-2d5d5c9detached at the PR head. One commit on top of master,merge-base == 108cbfa, nothing extraneous carried.The direction of this change is right and the structural work is good. Two findings block, and the first is not a corner case — it is the Weekly Briefings target this issue exists for.
What was verified as correct
resolve_target_base_refreturnsprgs/master/refs/remotes/prgs/master, sourceremote_head_symref.originreporting defect described in the issue is genuinely repaired.assess_target_repository_parityon this repository now returns slugScaled-Tech-Consulting/Gitea-Tools,tracking_refrefs/remotes/prgs/master,stale: false,reasons: [], where it previously read the abandonedrefs/remotes/origin/masterand reported a falsestale: truewith a null identity.originremains in the derivation path.MDCPStomdcps.devspecial-casing anywhere in the diff.resolve_remote_master_sha(canonical_root)call site is gone, replaced byresolve_remote_master_ref_state. The fifth caller,anti_stomp_preflight.py:551, was correctly identified and wired.Both findings below are green under the current suite. That is part of the problem.
B1 (blocking) — the remote-HEAD symref is a stale local cache, and the real target derives the wrong branch
Step 2 of
resolve_target_base_reftreatsrefs/remotes/<remote>/HEADas truth. The PR body states this explicitly:That premise does not hold.
refs/remotes/<remote>/HEADis a local cache written once at clone time. Git never refreshes it on fetch; only an explicitgit remote set-head -aupdates it. When the upstream default branch changes afterwards, the cache keeps pointing at the old branch.That is exactly the state of the repository this issue exists to unblock. Measured read-only against
/Users/jasonwalker/Development/weekly-briefings:The checkout sits exactly on its integration tip. Every independent signal — the upstream's own HEAD, the checked-out branch, and that branch's configured upstream — says
dev. Only the stale cache saysmain.Running this PR's code against that real target:
Consequences:
assess_root_checkout_guardcompares HEADa37ac427against9a84325aand blocks with "control checkout HEAD does not match refs/remotes/MDCPS/main" — for a checkout that is not behind anything.main, so they fail closed against a branch the repository does not integrate onto.stale: truewith an emptyreasonslist — a bare boolean with no stated cause, the same operator-hostile shape as the original defect.So Weekly Briefings Author work stays blocked.
prgs/masteris replaced byMDCPS/main; the ref is different and the refusal message is now honest about which ref it used, but it is still the wrong ref and the mutation still fails closed.Acceptance criterion 2 — a repository using remote
MDCPSand branchdevresolvesrefs/remotes/MDCPS/dev— is not met against the actual repository.test_mdcps_dev_resolvespasses only because the fixture calls_set_remote_head(root, "MDCPS", "dev"), manufacturing the cache state the real checkout does not have. No fixture in the suite ever creates arefs/remotes/<remote>/HEADthat disagrees with the checkout's branch or its configured upstream, which is why a resolver that trusts a stale cache is fully green.Remediation is the author's design call, but the constraints are firm: no network fetch, since the module documents that no network call is made, and no
git remote set-head, since the PR's own read-only test forbids mutating refs. Signals already present locally and not currently consulted:branch.<current>.remoteplusbranch.<current>.merge, i.e.@{upstream}— the checkout's own configured integration target. On this repository it yieldsMDCPS/devcorrectly.Please add a regression fixture where
refs/remotes/<remote>/HEADpoints at a different branch than the checkout's upstream. Without it this class of bug stays invisible.B2 (blocking) — parity reporting bypasses the ambiguity gate, so gating and reporting still diverge
assess_target_repository_parityresolves the identity remote first, then passes it back in:But
resolve_target_base_refuses a caller-supplied remote as the signal that the caller has disambiguated:Here the caller is not an operator naming a remote — it is the same first-wins probe.
identity_remoteis always non-empty whenever identity resolves, soDENY_AMBIGUOUS_REMOTEcan never fire from the reporting path.Reproduced on a hermetic repository with two remotes claiming different repositories,
MDCPStoMDCPS/WeeklyBriefings-MetaandprgstoScaled-Tech-Consulting/Gitea-Tools:The gate refuses. The report confidently names a different repository's slug and base ref,
stale: false, with no reasons at all.This contradicts the PR body's claim that both sides now consume the same resolver and cannot diverge again, and misses acceptance criteria 8 (ambiguity fails closed rather than guessing) and 9 (gating and reporting resolve the same target).
Existing coverage does not catch it:
test_ambiguous_identity_remote_fails_closedat line 299 exercises the resolver directly, andtest_same_resolved_target_for_gate_and_reportat line 369 uses a single-remote repository. Neither crosses ambiguity with the reporting path.The fix appears to be dropping the argument.
resolve_target_base_ref(canonical_root)re-derives the identical identity remote internally and restores the ambiguity check. Verified behaviour-neutral on the live control checkout: with no remote argument and withremote="prgs"the result is identical (prgs/master/refs/remotes/prgs/master,remote_head_symref), so the orphan-originrepair and the criterion-9 test are unaffected. Please pair it with a test asserting gate and report agree on an ambiguous target.Not blocking, for the author's judgement
resolve_target_base_refreturnsproven: truefor a symref pointing at a branch that has no corresponding tracking ref. Downstream still fails closed atrev-parse, so safety holds, butproven: truewith an unresolvabletracking_refis a misleading contract.assess_target_repository_parityreturnsdeterminable: Truewhen base-ref derivation fails. That matches the pre-existing shape for a missing tracking ref, so it is not a regression — noted only because B1 makes the path reachable far more often.Reviewed head
2d5d5c9d174ae5f7a36c57e724af298fc5cff8dc. Not merged. No restart and no binding change performed.repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #984
issue: #983
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 34009-378909a42165
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr984-2d5d5c9
phase: released
candidate_head:
2d5d5c9d17target_branch: master
target_branch_sha:
108cbfa173last_activity: 2026-07-31T02:59:45Z
expires_at: 2026-07-31T03:09:45Z
blocker: manual-release
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #984
issue: #983
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 52142-ac568169b8e7
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr984-03b434a0
phase: claimed
candidate_head:
03b434a0b6target_branch: master
target_branch_sha:
108cbfa173last_activity: 2026-07-31T04:24:12Z
expires_at: 2026-07-31T04:34:12Z
blocker: none
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #984
issue: #983
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 52142-ac568169b8e7
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr984-03b434a0
phase: claimed
candidate_head:
03b434a0b6target_branch: master
target_branch_sha:
108cbfa173last_activity: 2026-07-31T04:51:16Z
expires_at: 2026-07-31T05:01:16Z
blocker: none
Canonical PR State
STATE: approve-at-current-head
WHO_IS_NEXT: merger
NEXT_ACTION: Merge PR #984 into master at head
03b434a0b6once a merger session holds the canonical merger lease; no author work remains.NEXT_PROMPT: Continue Merger work on Gitea-Tools PR #984 (issue #983) as namespace gitea-merger, profile prgs-merger, repository Scaled-Tech-Consulting/Gitea-Tools. Invoke the canonical gitea-workflow skill first and verify runtime parity, repository binding, and merger mutation capability with fresh native calls. The reviewer verdict is an approval at head
03b434a0b6with merge-base 108cbfa173de34470d7abc022b929e6b3adc418a; confirm approval_at_current_head is true and has_blocking_change_requests is false before acting, because the superseded REQUEST_CHANGES review 658 at head2d5d5c9d17remains on the record undismissed by design. Acquire the merger PR lease, merge into master, then reconcile the terminal labels and clean up the source branch fix/issue-983-cross-repo-base-ref and the review worktrees branches/review-pr984-2d5d5c9 and branches/review-pr984-03b434a0. Note that the PR description text is stale in three places and issue comment 18890 is the accurate record; do not treat the PR body as authoritative.WHAT_HAPPENED: Independent re-review at the new head. The complete diff from base
108cbfawas read rather than only the increment since review 658, all six production call paths were traced, and the resolver, guard, and parity report were executed read-only against the live Weekly Briefings target, the live PRGS control checkout, and four hermetic repositories. B1 and B2 are both remediated and the two previously non-blocking contract notes are also addressed.WHY: The stale clone-time remote-HEAD cache is no longer authoritative; the checkout's configured upstream now decides the integration branch, so a Weekly Briefings checkout sitting exactly on its MDCPS/dev tip derives MDCPS/dev instead of MDCPS/main. The parity report no longer hands its own inferred remote back to the resolver, so an ambiguous two-remote target now fails closed identically in gating and in reporting instead of the report naming one plausible repository.
ISSUE: #983
HEAD_SHA:
03b434a0b6REVIEW_STATUS: approve
MERGE_READY: true
NATIVE_REVIEW_PROOF: transport=native_mcp; bound_transport=stdio; entrypoint=mcp_server; entrypoint_path=/Users/jasonwalker/Development/Gitea-Tools/gitea_mcp_server.py; mode=production; production_native_mcp_transport=true; pytest=false; pid=52142; token_fingerprint=adba475da9fda9f1
BLOCKERS: none
VALIDATION: Focused tests/test_issue_983_cross_repo_base_ref.py 37 passed; 29 affected suites 853 passed with 192 subtests passed and 6 pre-existing failures, against the same 28 suites at base
108cbfashowing 815 passed with 192 subtests passed and the identical 6 failures; full suite at the PR head 28 failed, 6204 passed, 6 skipped, 1106 subtests passed, against the full suite at base108cbfa28 failed, 6166 passed, 6 skipped, 1106 subtests passed, with both sorted FAILED lists byte-identical at sha1 fdebb1c202c86326d2afb0fd13df71e6790f4ad2, so zero failures were introduced and the plus-38 passed delta is this PR's own new coverage.LAST_UPDATED_BY: reviewer
Verdict
APPROVE at head
03b434a0b631a197005068725176b3726a46ae89, basemaster@108cbfa173de.Reviewed as
prgs-reviewer/sysadmin; the PR author isjcwalker3, so identities differ. Runtime parity green,mutation_safe: true, one MCP cohort, no duplicate-cohort blocker. Review worktreebranches/review-pr984-03b434a0detached at the PR head;merge-base == 108cbfa173de, two commits on top of master, nothing extraneous carried.Both blocking findings from review 658 are fixed, and fixed at the root rather than papered over. The remediation is the stronger of the two options I described: the cache is not merely demoted below the configured upstream, it is removed from the decision entirely and kept only as a reported observation.
B1 — resolved
refs/remotes/<remote>/HEADis no longer a resolution step.BASE_REF_SOURCE_*names onlyconfigured_branch_upstreamandunique_integration_branch_ref, and the module documents why the cache is excluded. Order is now: identity remote (ambiguity-aware) → the checkout'sbranch.<current>.remote+branch.<current>.merge, accepted only when it names that remote and its tracking ref exists → exactly one presentmaster/main/devtracking ref.Executed read-only against the live target
/Users/jasonwalker/Development/weekly-briefings, whose state is unchanged from the one that produced review 658 — cachedrefs/remotes/MDCPS/HEADstill namesmainat9a84325a1b68,refs/remotes/MDCPS/devisa37ac427c18b, local HEAD is on branchdevata37ac427c18b,@{upstream}isMDCPS/dev:The checkout that review 658 showed being gated against
MDCPS/mainis now compared againstMDCPS/devand reports in-parity. Acceptance criterion 2 is met against the actual repository, not only a fixture. The stale cache is surfaced honestly ascached_remote_head_conflicts: truerather than silently obeyed.PRGS is unchanged. Against the live control checkout:
prgs/master/refs/remotes/prgs/master, slugScaled-Tech-Consulting/Gitea-Tools,checkout_head == remote_tracking_head == 108cbfa173de,stale: false,reasons: []. The source label is nowconfigured_branch_upstreamrather thanremote_head_symref, which is the intended consequence of the fix; the resolved remote, branch, ref and SHA are identical. The orphan-originrepair still holds — the running server at108cbfastill reportstracking_ref: refs/remotes/origin/master,repository_slug: null,stale: true, and this branch fixes exactly that.Read-only is proven, not asserted: refs, config, remotes, HEAD and
--untracked-files=allstatus were snapshotted before and after every probe on both live repositories and compared equal. No fetch, nogit remote set-head, no ref write. The Weekly Briefings repository was not modified.The requested regression fixture exists and is genuine.
_RepoCasebuilds remoteMDCPS, checks outdev, sets upstreamMDCPS/dev, and creates bothdevandmaintracking refs at different commits withrefs/remotes/MDCPS/HEADcached atmain.test_configured_upstream_beats_stale_cached_remote_headasserts the cache still saysmain, asserts the two SHAs differ, and assertsdevis derived — so it fails against the previous head rather than passing vacuously.test_cached_remote_head_alone_never_proves_a_targetandtest_cached_remote_head_never_breaks_a_tieclose the class.B2 — resolved
master_parity_gate.assess_target_repository_paritynow calls_crr.assess_identity_remote(canonical_root)and_crr.resolve_target_base_ref(canonical_root)with no remote argument, and returns early when identity is ambiguous. The parameter is renamedexplicit_remotethroughoutresolve_target_base_ref,resolve_remote_master_shaandresolve_remote_master_ref_state, which makes the contract enforceable rather than conventional, andtest_no_production_caller_supplies_an_explicit_remoteholds the line. I confirmed by grep that no production module passes it.Reproduced on a hermetic repository with
MDCPS→MDCPS/WeeklyBriefings-Metaandprgs→Scaled-Tech-Consulting/Gitea-Tools:Gate and report now refuse together and carry the same
reason_code. The report no longer names a repository the gate refuses. Operator disambiguation still works and is correctly distinguished:explicit_remote="prgs"andexplicit_remote="MDCPS"each resolve their own target withidentity_explicit: true, whileexplicit_remote="nonexistent"cannot unlock the ambiguous target.Two further hermetic cases behave correctly: with no configured upstream and both
devandmainpresent, resolution fails closed withambiguous_integration_brancheven though the cache namesmain— the cache is explicitly refused as a tie-breaker and the refusal text says so and states the read-only remedy. With no candidate ref at all,no_integration_branch_ref. In every case gate and report agreed.Previously non-blocking notes, both now addressed
proven: truewith an unresolvabletracking_refis gone. Steps 2 and 3 each require_ref_existsbefore returning proven, andtest_every_proven_target_resolvespins it.determinable: Truealongside a failed base-ref derivation remains, but it is now accompanied by a populatedreason_codeandreasons, so the refusal states its cause. It matches the pre-existing shape and does not block.Production callers
Six paths traced, all consistent:
gitea_mcp_server.py:1059(author bootstrap),:1094(create-issue bootstrap, #749/#757),:1321(namespace mutation preflight),:2011(_enforce_root_checkout_guard, #475),anti_stomp_preflight.py:551(root-checkout check, now receivingremote_master_ref), andgitea_mcp_server.py:19983(assess_target_repository_parity). Everyresolve_remote_master_sha(canonical_root)production call is gone.REMOTE_MASTER_REFSandDEFAULT_TARGET_TRACKING_REFsurvive as explicit-override constants with no production consumer, which is the documented intent.No
MDCPS,WeeklyBriefings-Metaordevspecial-casing exists in the derivation path — only documentation prose and the pre-existing lowercasemdcpsentry in_IDENTITY_REMOTE_CANDIDATES, which is unchanged by this diff and provably cannot supply the remote name.Independent test results
Run by me in
branches/review-pr984-03b434a0at03b434a0, with the base comparison inbranches/baseline-980-108cbfaat108cbfa:The six affected-suite failures are root-checkout-guard and workspace-guard tests that patch
resolve_remote_master_sha; they fail identically at base108cbfa, so they are pre-existing and not caused by the call-site move. All 28 full-suite failures are pre-existing. Zero introduced failures; the+38passed delta is this PR's own coverage.Coverage confirmed for every required case: PRGS
prgs/master; cross-repository<remote>/dev; stale cached remote HEAD; nooriginremote; case-sensitive remote names; matching tip; behind and divergent; missing remote and missing ref; ambiguous remotes and ambiguous branch; gate/report consistency including on ambiguous targets; explicit versus inferred disambiguation; read-only resolver behaviour; and every affected production caller.One record-keeping note for the merger
The PR description text is stale in three places — it still describes step 2 as
refs/remotes/<remote>/HEAD, still cites sourceremote_head_symreffor PRGS, and still cites the previous head's test counts of 24 / 375 / 6191. The author documented this in issue comment 18890 and could not edit the description from the author role under the #618 wall. Issue comment 18890 is the accurate record. This is a documentation artefact only; the code, tests and behaviour at this head are correct, so it does not block.Reviewed head
03b434a0b631a197005068725176b3726a46ae89. Not merged. Review 658 left in place, not dismissed and not overwritten. No restart, no binding change, no credential or profile change, and no mutation of any Weekly Briefings repository.repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #984
issue: #983
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 52142-ac568169b8e7
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr984-03b434a0
phase: released
candidate_head:
03b434a0b6target_branch: master
target_branch_sha:
108cbfa173last_activity: 2026-07-31T04:54:29Z
expires_at: 2026-07-31T05:04:29Z
blocker: manual-release
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #984
issue: #983
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 91323-1e01d8c22104
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr984-03b434a0
phase: claimed
candidate_head:
03b434a0b6target_branch: master
target_branch_sha:
108cbfa173last_activity: 2026-07-31T05:04:10Z
expires_at: 2026-07-31T05:14:10Z
blocker: none
Stale #332 review-decision lock cleanup (#594)
Status: APPLIED
sysadminprgs-merger2026-07-31T05:05:28.876343+00:00approveon PR fix(guard): derive target base ref for cross-repository checkouts (#984)closed(merged=True)32ab839289e6efffa5cbfe978af30178b53d63ab3prgs-reviewerManual deletion of session-state files is not the workflow.
This path only clears a lock when the referenced PR is merged/closed.