BUG-HUNT: [Concurrency] Potential race condition in DetailLevelMap due to mutable dictionary exposure #6054

Open
opened 2026-04-09 14:11:41 +00:00 by HAL9000 · 0 comments
Owner

Metadata

  • Branch: fix/bug/detail-level-map-mutable-exposure
  • Commit Message: fix(acms): return MappingProxyType from DetailLevelMap.levels to prevent mutable dictionary exposure
  • Milestone: (backlog — see note below)
  • Parent Epic: #5656

Bug Report: [Concurrency] — Potential race condition in DetailLevelMap due to mutable dictionary exposure

Severity Assessment

  • Impact: If multiple threads modify the module-level DetailLevelMap constants concurrently, it could lead to data corruption and unpredictable behavior.
  • Likelihood: Low, as it depends on the incorrect usage of the module-level constants, which is discouraged in the docstring. However, the lack of enforcement makes it a potential risk.
  • Priority: Medium

Location

  • File: src/cleveragents/domain/models/acms/crp.py (location of DetailLevelMap class, which is not in the provided file but is the root cause)
  • Function/Class: DetailLevelMap.levels property
  • Lines: Unknown

Description

The module cleveragents.acms.uko.detail_level_maps defines several module-level constants (CODE_DETAIL_LEVEL_MAP, OO_DETAIL_LEVEL_MAP, etc.) that are instances of the DetailLevelMap class. The docstring states that these constants should be treated as read-only after initialization.

However, the DetailLevelMap class (defined in cleveragents.domain.models.acms.crp) might be exposing its internal _levels dictionary directly through the levels property. If the property returns the dictionary directly, it is mutable, and external code could modify the dictionary after initialization. This would violate the read-only contract and could lead to race conditions if multiple threads access and modify the map concurrently.

Evidence

The code in detail_level_maps.py relies on the immutability of the DetailLevelMap constants. For example:

# detail_level_maps.py
# ...
# Note: issue #575 describes this as "SIGNATURES_WITH_DOCS at depth 5"
# but the spec (lines 24987-25004) defines VISIBILITY_ANNOTATED as
# the OO-specific insertion.  SIGNATURES_WITH_DOCS already exists in
# the parent uko-code: map.
builder.insert_after("SIGNATURES_WITH_DOCS", "VISIBILITY_ANNOTATED")

If CODE_DETAIL_LEVEL_MAP.levels is mutable, another thread could be modifying it at the same time, leading to unpredictable behavior.

Expected Behavior

The DetailLevelMap.levels property should return a read-only view of the internal dictionary, for example, by returning a types.MappingProxyType or a copy of the dictionary. This would enforce the immutability of the DetailLevelMap instances.

Suggested Fix

In the DetailLevelMap class, change the levels property to return a MappingProxyType:

# In cleveragents/domain/models/acms/crp.py
from types import MappingProxyType

class DetailLevelMap:
    # ...
    @property
    def levels(self) -> MappingProxyType[str, int]:
        return MappingProxyType(self._levels)

Category

concurrency

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be
created for TDD. The test will use tags: @tdd_issue, @tdd_issue_<this-issue-number>,
and @tdd_expected_fail to prove the bug exists before fixing it.

Subtasks

  • Locate DetailLevelMap class in src/cleveragents/domain/models/acms/crp.py and confirm levels property returns raw _levels dict
  • Change levels property to return MappingProxyType(self._levels) with correct type annotation
  • Add from types import MappingProxyType import
  • Update any callers that relied on the mutable dict (e.g., detail_level_maps.py builder logic)
  • Write Behave unit test with @tdd_issue and @tdd_issue_<N> tags verifying levels returns an immutable mapping
  • Ensure all nox stages pass

Definition of Done

  • DetailLevelMap.levels returns a MappingProxyType (read-only view)
  • Attempting to mutate the returned mapping raises TypeError
  • All module-level constants (CODE_DETAIL_LEVEL_MAP, OO_DETAIL_LEVEL_MAP, etc.) are effectively immutable after initialization
  • Behave unit test with @tdd_issue and @tdd_issue_<N> tags is present and passing
  • All nox stages pass (nox -e lint, nox -e typecheck, nox -e unit_tests, nox -e integration_tests)
  • Coverage >= 97%

Backlog note: This issue was discovered during autonomous operation
on milestone v3.2.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: new-issue-creator

## Metadata - **Branch**: `fix/bug/detail-level-map-mutable-exposure` - **Commit Message**: `fix(acms): return MappingProxyType from DetailLevelMap.levels to prevent mutable dictionary exposure` - **Milestone**: *(backlog — see note below)* - **Parent Epic**: #5656 ## Bug Report: [Concurrency] — Potential race condition in DetailLevelMap due to mutable dictionary exposure ### Severity Assessment - **Impact**: If multiple threads modify the module-level `DetailLevelMap` constants concurrently, it could lead to data corruption and unpredictable behavior. - **Likelihood**: Low, as it depends on the incorrect usage of the module-level constants, which is discouraged in the docstring. However, the lack of enforcement makes it a potential risk. - **Priority**: Medium ### Location - **File**: `src/cleveragents/domain/models/acms/crp.py` (location of `DetailLevelMap` class, which is not in the provided file but is the root cause) - **Function/Class**: `DetailLevelMap.levels` property - **Lines**: Unknown ### Description The module `cleveragents.acms.uko.detail_level_maps` defines several module-level constants (`CODE_DETAIL_LEVEL_MAP`, `OO_DETAIL_LEVEL_MAP`, etc.) that are instances of the `DetailLevelMap` class. The docstring states that these constants should be treated as read-only after initialization. However, the `DetailLevelMap` class (defined in `cleveragents.domain.models.acms.crp`) might be exposing its internal `_levels` dictionary directly through the `levels` property. If the property returns the dictionary directly, it is mutable, and external code could modify the dictionary after initialization. This would violate the read-only contract and could lead to race conditions if multiple threads access and modify the map concurrently. ### Evidence The code in `detail_level_maps.py` relies on the immutability of the `DetailLevelMap` constants. For example: ```python # detail_level_maps.py # ... # Note: issue #575 describes this as "SIGNATURES_WITH_DOCS at depth 5" # but the spec (lines 24987-25004) defines VISIBILITY_ANNOTATED as # the OO-specific insertion. SIGNATURES_WITH_DOCS already exists in # the parent uko-code: map. builder.insert_after("SIGNATURES_WITH_DOCS", "VISIBILITY_ANNOTATED") ``` If `CODE_DETAIL_LEVEL_MAP.levels` is mutable, another thread could be modifying it at the same time, leading to unpredictable behavior. ### Expected Behavior The `DetailLevelMap.levels` property should return a read-only view of the internal dictionary, for example, by returning a `types.MappingProxyType` or a copy of the dictionary. This would enforce the immutability of the `DetailLevelMap` instances. ### Suggested Fix In the `DetailLevelMap` class, change the `levels` property to return a `MappingProxyType`: ```python # In cleveragents/domain/models/acms/crp.py from types import MappingProxyType class DetailLevelMap: # ... @property def levels(self) -> MappingProxyType[str, int]: return MappingProxyType(self._levels) ``` ### Category concurrency ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: `@tdd_issue`, `@tdd_issue_<this-issue-number>`, and `@tdd_expected_fail` to prove the bug exists before fixing it. ## Subtasks - [ ] Locate `DetailLevelMap` class in `src/cleveragents/domain/models/acms/crp.py` and confirm `levels` property returns raw `_levels` dict - [ ] Change `levels` property to return `MappingProxyType(self._levels)` with correct type annotation - [ ] Add `from types import MappingProxyType` import - [ ] Update any callers that relied on the mutable dict (e.g., `detail_level_maps.py` builder logic) - [ ] Write Behave unit test with `@tdd_issue` and `@tdd_issue_<N>` tags verifying `levels` returns an immutable mapping - [ ] Ensure all nox stages pass ## Definition of Done - [ ] `DetailLevelMap.levels` returns a `MappingProxyType` (read-only view) - [ ] Attempting to mutate the returned mapping raises `TypeError` - [ ] All module-level constants (`CODE_DETAIL_LEVEL_MAP`, `OO_DETAIL_LEVEL_MAP`, etc.) are effectively immutable after initialization - [ ] Behave unit test with `@tdd_issue` and `@tdd_issue_<N>` tags is present and passing - [ ] All nox stages pass (`nox -e lint`, `nox -e typecheck`, `nox -e unit_tests`, `nox -e integration_tests`) - [ ] Coverage >= 97% > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.2.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: new-issue-creator
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.

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