resolve_canonical_repo_root fallback now uses commonpath only — no string split and no os.path.isdir gate — so MCP project_root = branches/<wt> still resolves to the repo root when the path is not yet on disk (#274 / review #551 regression).
This commit is contained in:
@@ -93,9 +93,10 @@ def resolve_canonical_repo_root(workspace_path: str, fallback_project_root: str)
|
||||
pass
|
||||
|
||||
# Fallback when git metadata is unavailable. Never string-split on
|
||||
# "/branches/" (review #531 Finding 2 / F-6): recover the repo root only
|
||||
# via resolved-path commonpath ancestry against a parent that owns a
|
||||
# real ``branches`` directory containing the fallback path.
|
||||
# "/branches/" (review #531 F2 / #551): recover the repo root only via
|
||||
# resolved-path commonpath ancestry. Do **not** require on-disk isdir —
|
||||
# MCP may launch with project_root = branches/<wt> before that path
|
||||
# exists, and #274 path-shaped worktree-as-project-root must still resolve.
|
||||
fallback = os.path.realpath(fallback_project_root or workspace_path or ".")
|
||||
cur = fallback
|
||||
for _ in range(64):
|
||||
@@ -103,16 +104,18 @@ def resolve_canonical_repo_root(workspace_path: str, fallback_project_root: str)
|
||||
if parent == cur:
|
||||
break
|
||||
branches_dir = os.path.realpath(os.path.join(parent, "branches"))
|
||||
if os.path.isdir(branches_dir):
|
||||
try:
|
||||
# Path-shaped: fallback is under parent/branches/ (commonpath).
|
||||
if os.path.commonpath([branches_dir, fallback]) == branches_dir:
|
||||
return parent
|
||||
except ValueError:
|
||||
pass
|
||||
# Also accept fallback itself being the branches directory.
|
||||
if os.path.basename(cur) == "branches" and os.path.isdir(cur):
|
||||
# Fallback path itself is the branches directory.
|
||||
if os.path.basename(os.path.realpath(cur)) == "branches":
|
||||
try:
|
||||
if os.path.commonpath([cur, fallback]) == cur:
|
||||
if os.path.commonpath([os.path.realpath(cur), fallback]) == os.path.realpath(
|
||||
cur
|
||||
):
|
||||
return parent
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@@ -86,6 +86,13 @@ class TestAssessAuthorMutationWorktree(unittest.TestCase):
|
||||
self.assertTrue(result["proven"])
|
||||
self.assertFalse(result["block"])
|
||||
|
||||
def test_path_shaped_branches_ancestry_without_isdir(self):
|
||||
"""Review #551: commonpath recovery must not require on-disk isdir."""
|
||||
fake_wt = "/repo/Gitea-Tools/branches/issue-274"
|
||||
root = amw.resolve_canonical_repo_root(fake_wt, fake_wt)
|
||||
self.assertEqual(root, "/repo/Gitea-Tools")
|
||||
self.assertNotIn('split("/branches/")', open(amw.__file__).read())
|
||||
|
||||
|
||||
class TestPreflightIntegration(unittest.TestCase):
|
||||
def test_verify_preflight_blocks_control_checkout_with_test_porcelain(self):
|
||||
|
||||
Reference in New Issue
Block a user