fix(acms): normalize fragment paths to relative before context path matching #10985

Open
opened 2026-05-06 12:01:39 +00:00 by hamza.khyari · 0 comments
Member

Summary

PR #10975 introduced **/ prefix-based path matching to fix the absolute-vs-relative mismatch in _path_matches(). Two issues remain:

  1. Trailing ** bug: _matches_any("**/.opencode/**") returns False because match() requires trailing ** to consume at least one path component
  2. Workaround, not root fix: Prepending **/ to patterns is fragile — it doesn't match the specification's intent of relative-path matching

Spec Decision

Per discussion on #10972, the resolution is Option A — normalize fragment metadata paths to relative before matching:

Before matching: strip project root from fragment metadata["path"]
Then: match relative path against user-supplied globs directly

This aligns with spec examples ("src/**/*.py", "docs/architecture/**") and avoids all **/ prefix edge cases.

Fix

1. Normalize paths in _path_matches()

execute_phase_context_assembler.py:74-81 — replace _matches_any() with root-stripping logic:

@staticmethod
def _path_matches(path: str, include: list[str], exclude: list[str], 
                  project_root: str | None = None) -> bool:
    pure_path = PurePath(path)
    # Normalize to relative if absolute and root known
    if project_root and pure_path.is_absolute():
        try:
            pure_path = pure_path.relative_to(project_root)
        except ValueError:
            pass  # path outside project root — exclude
    for pattern in include:
        if not pure_path.match(pattern):
            return False
    for pattern in exclude:
        if pure_path.match(pattern):
            return False
    return True

2. Pass project root from resource metadata

In assemble(), retrieve the project root from the fragment's resource metadata or the resource registry:

resource_root = self._get_resource_root(fragment.resource_id)
if self._path_matches(path, include, exclude, resource_root):
    ...

3. Apply same fix to context_phase_analysis.py

Update _matches_pattern() similarly — but here the paths come from tiered fragments which already have resource context.

Affected Files

  • src/cleveragents/application/services/execute_phase_context_assembler.py:74-81
  • src/cleveragents/application/services/context_phase_analysis.py:108-126

Blocks

  • #10878 (agents plan hides results and gives incomplete results)

Depends On

  • #10972 (root cause analysis)
  • #10975 (first fix attempt — provides baseline to improve upon)

Metadata

  • Commit Message: fix(acms): normalize fragment paths to relative before context path matching
  • Branch: bugfix/acms-path-normalization
## Summary PR #10975 introduced `**/` prefix-based path matching to fix the absolute-vs-relative mismatch in `_path_matches()`. Two issues remain: 1. **Trailing `**` bug**: `_matches_any("**/.opencode/**")` returns `False` because `match()` requires trailing `**` to consume at least one path component 2. **Workaround, not root fix**: Prepending `**/` to patterns is fragile — it doesn't match the specification's intent of relative-path matching ## Spec Decision Per discussion on #10972, the resolution is **Option A — normalize fragment metadata paths to relative** before matching: ``` Before matching: strip project root from fragment metadata["path"] Then: match relative path against user-supplied globs directly ``` This aligns with spec examples (`"src/**/*.py"`, `"docs/architecture/**"`) and avoids all `**/` prefix edge cases. ## Fix ### 1. Normalize paths in `_path_matches()` `execute_phase_context_assembler.py:74-81` — replace `_matches_any()` with root-stripping logic: ```python @staticmethod def _path_matches(path: str, include: list[str], exclude: list[str], project_root: str | None = None) -> bool: pure_path = PurePath(path) # Normalize to relative if absolute and root known if project_root and pure_path.is_absolute(): try: pure_path = pure_path.relative_to(project_root) except ValueError: pass # path outside project root — exclude for pattern in include: if not pure_path.match(pattern): return False for pattern in exclude: if pure_path.match(pattern): return False return True ``` ### 2. Pass project root from resource metadata In `assemble()`, retrieve the project root from the fragment's resource metadata or the resource registry: ```python resource_root = self._get_resource_root(fragment.resource_id) if self._path_matches(path, include, exclude, resource_root): ... ``` ### 3. Apply same fix to `context_phase_analysis.py` Update `_matches_pattern()` similarly — but here the paths come from tiered fragments which already have resource context. ## Affected Files - `src/cleveragents/application/services/execute_phase_context_assembler.py:74-81` - `src/cleveragents/application/services/context_phase_analysis.py:108-126` ## Blocks - #10878 (`agents plan` hides results and gives incomplete results) ## Depends On - #10972 (root cause analysis) - #10975 (first fix attempt — provides baseline to improve upon) ## Metadata - **Commit Message**: `fix(acms): normalize fragment paths to relative before context path matching` - **Branch**: `bugfix/acms-path-normalization`
hamza.khyari added this to the v3.5.0 milestone 2026-05-06 12:01:39 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#10985
No description provided.