From 6b08736cb895664555c429d53624ccb1ef9807fc Mon Sep 17 00:00:00 2001 From: HAL9000 Date: Fri, 8 May 2026 07:05:49 +0000 Subject: [PATCH 1/2] fix(acms): normalize context path matching for absolute paths in _path_matches (#10975) Added leading-slash stripping and sub-suffix enumeration inside ACMSExecutePhaseContextAssembler._path_matches() so that relative include/exclude globs (e.g. src/**/*.py) still match files whose metadata carries full POSIX paths (e.g. /home/user/src/main.py) emitted by the UKO indexer / file walker. Without this fix, absolute paths were silently excluded by every relative pattern, causing the execute-phase context pipeline to discard source files in sandbox or Docker-container workflows where paths are stored as canonical POSIX strings. Also added three new Behave scenarios for absolute-path include/exclude matching. ISSUES CLOSED: #10975 --- CHANGELOG.md | 13 +++++ CONTRIBUTORS.md | 1 + ...e_phase_context_assembler_coverage.feature | 12 ++++ .../execute_phase_context_assembler.py | 56 ++++++++++++++++--- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fba107b5f..1cb058bb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Fixed + +- **fix(acms): normalize context path matching for absolute paths in `_path_matches`** (#10975): + Added leading-slash stripping and sub-suffix enumeration inside + ``ACMSExecutePhaseContextAssembler._path_matches()`` so that relative include/exclude + globs (e.g. ``src/**/*.py``) still match files whose metadata carries full POSIX paths + (e.g. ``/home/user/src/main.py``) emitted by the UKO indexer / file walker. Without this + fix, absolute paths were silently excluded by every relative pattern, causing the execute-phase + context pipeline to discard a large fraction of valid source files — especially in sandbox or + Docker-container workflows where paths are stored as canonical POSIX strings. Also added + three new Behave scenarios covering absolute-path include matches, includes that still reject + correctly after normalisation, and absolute-path exclude matching post-normalisation. + - Fixed `ReactiveEventBus.emit()` exception handler to log the full exception message (`str(exc)`) and enable traceback forwarding (`exc_info=True`). Previously the handler logged only the exception type name (e.g. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 382d4fe35..54e73c2ec 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -33,4 +33,5 @@ Below are some of the specific details of various contributions. * HAL 9000 has contributed the LLMTraceRepository data-integrity fix (PR #8185 / issue #7505): replaced the unconditional `session.commit()` in `LLMTraceRepository.save()` with a dual-path implementation that respects the UnitOfWork pattern — flushing only when an external session is provided, and flushing + committing + closing when operating standalone. This eliminates premature transaction commits, loss of rollback capability, and a docstring/implementation mismatch. * HAL 9000 has contributed the ACMS Index Data Model and File Traversal Engine (PR #9664 / issue #9579): foundational data structures for indexed context entries with hot/warm/cold/archive storage tier classification, tag system, and a timeout-safe chunked file traversal engine for large projects with 10,000+ files. * HAL 9000 has contributed the error-suppression removal fix (PR #9247 / issue #9060): removed both `try...except Exception:` blocks in `register_registry_agents()` that silently suppressed errors from `actor_registry.list_actors()` and the route bridge refresh, enabling exceptions to propagate per CONTRIBUTING.md fail-fast policy. Added three Behave scenarios verifying RuntimeError, AttributeError, and TypeError propagation. + * HAL 9000 has contributed the ACMS path-matching normalisation fix (PR #10975 / issue #10975): added sub-suffix enumeration in `ACMSExecutePhaseContextAssembler._path_matches()` via leading-slash stripping so relative include/exclude globs match absolute POSIX paths from the indexer. Includes three new Behave scenarios for absolute-path matching edge cases. * HAL 9000 has contributed the Strategize phase full context snapshot fix (issue #9056): added `_build_strategize_context_snapshot()` helper to `PlanLifecycleService`, updated `_try_record_decision()` to accept and forward a `ContextSnapshot` parameter, and added BDD test coverage verifying all four `ContextSnapshot` fields (`hot_context_hash`, `hot_context_ref`, `actor_state_ref`, `relevant_resources`) are populated during the Strategize phase. diff --git a/features/execute_phase_context_assembler_coverage.feature b/features/execute_phase_context_assembler_coverage.feature index 58e24a72d..d050c2bfa 100644 --- a/features/execute_phase_context_assembler_coverage.feature +++ b/features/execute_phase_context_assembler_coverage.feature @@ -46,6 +46,18 @@ Feature: Execute-phase context assembler coverage When epcov I check path matching for "src/foo.py" with exclude "src/secret*" Then epcov the path should match + Scenario: epcov absolute path matches relative include pattern after normalisation + When epcov I check path matching for "/home/user/src/main.py" with include "src/**/*.py" + Then epcov the path should match + + Scenario: epcov absolute path does not match unrelated relative include pattern + When epcov I check path matching for "/home/user/docs/readme.md" with include "src/**/*.py" + Then epcov the path should not match + + Scenario: epcov absolute path excluded by relative exclude pattern after normalisation + When epcov I check path matching for "/var/lib/src/secret.py" with exclude "src/secret*" + Then epcov the path should not match + # ---- _resource_matches static method ---- Scenario: epcov resource matches with no rules passes all diff --git a/src/cleveragents/application/services/execute_phase_context_assembler.py b/src/cleveragents/application/services/execute_phase_context_assembler.py index f3810ab3e..a99d95275 100644 --- a/src/cleveragents/application/services/execute_phase_context_assembler.py +++ b/src/cleveragents/application/services/execute_phase_context_assembler.py @@ -3,7 +3,7 @@ from __future__ import annotations import fnmatch -from pathlib import PurePath +from pathlib import PurePath, PurePosixPath from typing import Any, Protocol import structlog @@ -72,13 +72,53 @@ class ACMSExecutePhaseContextAssembler(ExecutePhaseContextAssembler): @staticmethod def _path_matches(path: str, include: list[str], exclude: list[str]) -> bool: - """Return whether *path* passes include/exclude path globs.""" - pure_path = PurePath(path) - if include and not any(pure_path.full_match(pattern) for pattern in include): - return False - return not ( - exclude and any(pure_path.full_match(pattern) for pattern in exclude) - ) + """Return whether *path* passes include/exclude path globs. + + Normalises absolute paths by stripping a leading ``/`` and then tries each + include/exclude glob against every possible sub-suffix of the normalised path. + This lets relative patterns such as ``src/**/*.py`` match files whose metadata + carries full POSIX paths (e.g. ``/home/user/src/main.py``) emitted by the UKO + indexer / file walker. Paths with a single component are matched directly via + ``full_match()`` to avoid unnecessary suffix enumeration. + """ + # Strip a leading slash so relative globs can match against absolute paths. + normalised = path.removeprefix("/") + + if len(PurePosixPath(normalised).parts) <= 1: + # Single-component path -- match directly via ``full_match()``. + pure_path = PurePath(normalised) + if include and not any( + pure_path.full_match(p) for p in include + ): + return False + return not (exclude and any( + pure_path.full_match(p) for p in exclude + )) + + # Multi-component path: enumerate every sub-suffix by dropping leading + # components one at a time. For ``/home/user/src/main.py`` the suffixes + # are ``src/main.py`` and ``main.py``, so a relative glob like + # ``src/**/*.py`` will find a match on the ``src/main.py`` suffix. + parts = list(PurePosixPath(normalised).parts) + suffixes = [PurePath("/".join(parts[i:])) for i in range(len(parts))] + + if include: + if not any( + sub.full_match(pattern) + for pattern in include + for sub in suffixes + ): + return False + + if exclude: + if any( + sub.full_match(pattern) + for pattern in exclude + for sub in suffixes + ): + return False + + return True @staticmethod def _resource_matches( -- 2.52.0 From 365ac30f8ae01bce0153d3f6e5d4a6694a55970c Mon Sep 17 00:00:00 2001 From: CleverAgents Bot Date: Wed, 10 Jun 2026 20:20:12 -0400 Subject: [PATCH 2/2] ci: stop master workflow on PR updates Remove the stale pull_request trigger from master.yml so PR branch commits do not launch the master workflow. Maintenance patch for PR #11023. --- .forgejo/workflows/master.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.forgejo/workflows/master.yml b/.forgejo/workflows/master.yml index 7c959ba40..ccdede22d 100644 --- a/.forgejo/workflows/master.yml +++ b/.forgejo/workflows/master.yml @@ -3,8 +3,6 @@ name: CI on: push: branches: [master, develop] - pull_request: - branches: [master, develop] vars: docker_prefix: "http://harbor.cleverthis.com/docker/" -- 2.52.0