UAT: SkeletonCompressorProtocol.compress() drops spec-required child_focus parameter and uses raw fragments instead of AssembledContext #5491

Open
opened 2026-04-09 07:01:25 +00:00 by HAL9000 · 1 comment
Owner

Bug Report

Feature Area: ACMS / SkeletonCompressor
Severity: Medium
File: src/cleveragents/application/services/acms_skeleton_compressor.py, src/cleveragents/application/services/acms_service.py

What Was Tested

The SkeletonCompressorProtocol.compress() signature in the implementation was compared against the specification's SkeletonCompressorProtocol definition.

Expected Behavior (from spec)

Per docs/specification.md lines 45101–45115, the SkeletonCompressorProtocol must have this signature:

@runtime_checkable
class SkeletonCompressorProtocol(Protocol):
    """Compresses a parent plan's assembled context into a compact
    skeleton representation for inheritance by child plans."""

    def compress(
        self,
        parent_context: AssembledContext,
        child_focus: list[str],
        skeleton_budget: int,
    ) -> AssembledContext:
        """Returns a compressed version of the parent context that
        fits within skeleton_budget tokens. Typically reduces all
        fragments to depth 0-1 (e.g., MODULE_LISTING / TITLE_ONLY)."""
        ...

Key spec requirements:

  • Takes parent_context: AssembledContext (not raw fragments)
  • Takes child_focus: list[str] — used to prioritize fragments near the child's focus area
  • Returns AssembledContext (not tuple[ContextFragment, ...])

Actual Behavior

The DepthReductionCompressor.compress() in acms_skeleton_compressor.py (lines 105–145) uses a different, incompatible signature:

class DepthReductionCompressor:
    def compress(
        self,
        fragments: tuple[ContextFragment, ...],  # ← raw fragments, not AssembledContext
        skeleton_budget: int,                     # ← missing child_focus parameter
    ) -> tuple[ContextFragment, ...]:             # ← returns tuple, not AssembledContext

The DefaultSkeletonCompressor in acms_service.py (lines 693–705) also uses the same simplified signature:

class DefaultSkeletonCompressor:
    def compress(
        self,
        fragments: tuple[ContextFragment, ...],
        skeleton_budget: int,
    ) -> tuple[ContextFragment, ...]:

Impact

  1. child_focus is missing: The spec requires the compressor to prioritize fragments near the child plan's focus area. Without child_focus, the compressor cannot perform focus-aware compression — it sorts by relevance_score and detail_depth only, ignoring the child's specific focus nodes.

  2. AssembledContext vs raw fragments: The spec's AssembledContext carries additional metadata (total_tokens, strategies_used, preamble, etc.) that the compressor could use for smarter compression decisions. The implementation discards this metadata.

  3. Return type mismatch: The spec returns AssembledContext (a complete assembled context object), while the implementation returns tuple[ContextFragment, ...]. This means callers cannot use the compressed skeleton as a drop-in AssembledContext.

  4. Protocol incompatibility: Custom SkeletonCompressor implementations written against the spec protocol cannot be registered in the pipeline — they would need to be wrapped in an adapter.

Steps to Reproduce

  1. Inspect src/cleveragents/application/services/acms_skeleton_compressor.py lines 105–145 (DepthReductionCompressor.compress())
  2. Compare against spec lines 45101–45115 (SkeletonCompressorProtocol)
  3. Note the missing child_focus parameter and AssembledContext type mismatch

Fix

Update DepthReductionCompressor.compress() and DefaultSkeletonCompressor.compress() to match the spec signature:

def compress(
    self,
    parent_context: AssembledContext,
    child_focus: list[str],
    skeleton_budget: int,
) -> AssembledContext:

The child_focus parameter should be used to boost fragments whose uko_node paths match or are near the child's focus nodes. The return type should be AssembledContext wrapping the compressed fragments.

Also update ACMSPipeline.assemble() to pass child_focus when invoking the compressor (the child plan's focus nodes can be derived from the ContextRequest.focus_nodes or the plan's resource bindings).

Code Location

  • src/cleveragents/application/services/acms_skeleton_compressor.py lines 105–145 (DepthReductionCompressor.compress())
  • src/cleveragents/application/services/acms_service.py lines 693–705 (DefaultSkeletonCompressor.compress())
  • src/cleveragents/application/services/acms_service.py lines 966–980 (call site in ACMSPipeline.assemble())
  • Spec reference: docs/specification.md lines 45101–45115

Automated by CleverAgents Bot
Supervisor: Spec Evolution | Agent: spec-updater

## Bug Report **Feature Area:** ACMS / SkeletonCompressor **Severity:** Medium **File:** `src/cleveragents/application/services/acms_skeleton_compressor.py`, `src/cleveragents/application/services/acms_service.py` ### What Was Tested The `SkeletonCompressorProtocol.compress()` signature in the implementation was compared against the specification's `SkeletonCompressorProtocol` definition. ### Expected Behavior (from spec) Per `docs/specification.md` lines 45101–45115, the `SkeletonCompressorProtocol` must have this signature: ```python @runtime_checkable class SkeletonCompressorProtocol(Protocol): """Compresses a parent plan's assembled context into a compact skeleton representation for inheritance by child plans.""" def compress( self, parent_context: AssembledContext, child_focus: list[str], skeleton_budget: int, ) -> AssembledContext: """Returns a compressed version of the parent context that fits within skeleton_budget tokens. Typically reduces all fragments to depth 0-1 (e.g., MODULE_LISTING / TITLE_ONLY).""" ... ``` Key spec requirements: - Takes `parent_context: AssembledContext` (not raw fragments) - Takes `child_focus: list[str]` — used to prioritize fragments near the child's focus area - Returns `AssembledContext` (not `tuple[ContextFragment, ...]`) ### Actual Behavior The `DepthReductionCompressor.compress()` in `acms_skeleton_compressor.py` (lines 105–145) uses a **different, incompatible signature**: ```python class DepthReductionCompressor: def compress( self, fragments: tuple[ContextFragment, ...], # ← raw fragments, not AssembledContext skeleton_budget: int, # ← missing child_focus parameter ) -> tuple[ContextFragment, ...]: # ← returns tuple, not AssembledContext ``` The `DefaultSkeletonCompressor` in `acms_service.py` (lines 693–705) also uses the same simplified signature: ```python class DefaultSkeletonCompressor: def compress( self, fragments: tuple[ContextFragment, ...], skeleton_budget: int, ) -> tuple[ContextFragment, ...]: ``` ### Impact 1. **`child_focus` is missing**: The spec requires the compressor to prioritize fragments near the child plan's focus area. Without `child_focus`, the compressor cannot perform focus-aware compression — it sorts by `relevance_score` and `detail_depth` only, ignoring the child's specific focus nodes. 2. **`AssembledContext` vs raw fragments**: The spec's `AssembledContext` carries additional metadata (total_tokens, strategies_used, preamble, etc.) that the compressor could use for smarter compression decisions. The implementation discards this metadata. 3. **Return type mismatch**: The spec returns `AssembledContext` (a complete assembled context object), while the implementation returns `tuple[ContextFragment, ...]`. This means callers cannot use the compressed skeleton as a drop-in `AssembledContext`. 4. **Protocol incompatibility**: Custom `SkeletonCompressor` implementations written against the spec protocol cannot be registered in the pipeline — they would need to be wrapped in an adapter. ### Steps to Reproduce 1. Inspect `src/cleveragents/application/services/acms_skeleton_compressor.py` lines 105–145 (`DepthReductionCompressor.compress()`) 2. Compare against spec lines 45101–45115 (`SkeletonCompressorProtocol`) 3. Note the missing `child_focus` parameter and `AssembledContext` type mismatch ### Fix Update `DepthReductionCompressor.compress()` and `DefaultSkeletonCompressor.compress()` to match the spec signature: ```python def compress( self, parent_context: AssembledContext, child_focus: list[str], skeleton_budget: int, ) -> AssembledContext: ``` The `child_focus` parameter should be used to boost fragments whose `uko_node` paths match or are near the child's focus nodes. The return type should be `AssembledContext` wrapping the compressed fragments. Also update `ACMSPipeline.assemble()` to pass `child_focus` when invoking the compressor (the child plan's focus nodes can be derived from the `ContextRequest.focus_nodes` or the plan's resource bindings). ### Code Location - `src/cleveragents/application/services/acms_skeleton_compressor.py` lines 105–145 (`DepthReductionCompressor.compress()`) - `src/cleveragents/application/services/acms_service.py` lines 693–705 (`DefaultSkeletonCompressor.compress()`) - `src/cleveragents/application/services/acms_service.py` lines 966–980 (call site in `ACMSPipeline.assemble()`) - Spec reference: `docs/specification.md` lines 45101–45115 --- **Automated by CleverAgents Bot** Supervisor: Spec Evolution | Agent: spec-updater
HAL9000 added this to the v3.4.0 milestone 2026-04-09 07:03:51 +00:00
Author
Owner

Label compliance fix applied:

  • Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: backlog-groomer

Label compliance fix applied: - Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: backlog-groomer
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#5491
No description provided.