fix(plan-tree): visually mark corrected nodes in build_decision_tree
CI / helm (pull_request) Successful in 36s
CI / build (pull_request) Successful in 53s
CI / lint (pull_request) Successful in 57s
CI / typecheck (pull_request) Successful in 1m23s
CI / quality (pull_request) Successful in 1m34s
CI / security (pull_request) Successful in 1m40s
CI / benchmark-publish (pull_request) Has been skipped
CI / push-validation (pull_request) Successful in 23s
CI / integration_tests (pull_request) Successful in 3m27s
CI / unit_tests (pull_request) Failing after 3m43s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Has been skipped
CI / e2e_tests (pull_request) Successful in 3m57s
CI / status-check (pull_request) Failing after 3s

- Add label key to node dicts in _node_dict
- Append [corrected] marker when decision.is_correction is True
- Add TDD BDD scenario proving corrected nodes are visually marked
This commit is contained in:
2026-04-29 02:21:38 +00:00
parent ab15eec673
commit 10ed6efac4
3 changed files with 182 additions and 0 deletions
@@ -0,0 +1,155 @@
"""Step definitions for tdd_plan_tree_correction_visual.feature.
Tests that corrected nodes (decisions with is_correction=True) are visually
marked in the plan tree output. This is a TDD scenario documenting the gap
where the current implementation does NOT visually distinguish corrected nodes.
"""
from __future__ import annotations
from behave import given, then, when
from behave.runner import Context
from ulid import ULID
from cleveragents.cli.commands.plan import build_decision_tree
from cleveragents.domain.models.core.decision import Decision, DecisionType
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
_PLAN_ID = str(ULID())
# ---------------------------------------------------------------------------
# Given steps
# ---------------------------------------------------------------------------
@given("a set of test decisions with a corrected decision")
def step_decisions_with_correction(context: Context) -> None:
"""Create a set of decisions where one is marked as a correction."""
root_id = str(ULID())
corrected_id = str(ULID())
corrects_id = str(ULID())
context.tdd_decisions = [
# Root decision
Decision(
decision_id=root_id,
plan_id=_PLAN_ID,
sequence_number=0,
decision_type=DecisionType.PROMPT_DEFINITION,
question="What to build?",
chosen_option="REST API",
),
# Original decision that will be corrected
Decision(
decision_id=corrects_id,
plan_id=_PLAN_ID,
parent_decision_id=root_id,
sequence_number=1,
decision_type=DecisionType.STRATEGY_CHOICE,
question="Which framework?",
chosen_option="Django",
),
# Corrected decision (is_correction=True)
Decision(
decision_id=corrected_id,
plan_id=_PLAN_ID,
parent_decision_id=root_id,
sequence_number=2,
decision_type=DecisionType.STRATEGY_CHOICE,
question="Which framework?",
chosen_option="FastAPI",
is_correction=True,
corrects_decision_id=corrects_id,
),
]
context.tdd_corrected_id = corrected_id
# ---------------------------------------------------------------------------
# When steps
# ---------------------------------------------------------------------------
@when("I build the decision tree with default options")
def step_build_tree_default(context: Context) -> None:
"""Build the decision tree from the test decisions."""
context.tdd_tree_data = build_decision_tree(
context.tdd_decisions,
show_superseded=False,
max_depth=0,
)
# ---------------------------------------------------------------------------
# Then steps
# ---------------------------------------------------------------------------
@then("the tree should include a visual marker for the corrected decision")
def step_tree_has_correction_marker(context: Context) -> None:
"""Verify that the tree data includes a marker for the corrected decision."""
tree_nodes: list[dict[str, object]] = context.tdd_tree_data
# The tree_data is a list of root-level node dicts.
# We need to search through it to find the corrected decision node
# and verify it has a visual marker.
def find_corrected_node(
nodes: list[dict[str, object]],
) -> dict[str, object] | None:
"""Recursively search for the corrected decision node."""
for node in nodes:
if node.get("decision_id") == context.tdd_corrected_id:
return node
children = node.get("children", [])
assert isinstance(children, list)
result = find_corrected_node(children)
if result is not None:
return result
return None
corrected_node = find_corrected_node(tree_nodes)
assert corrected_node is not None, (
f"Corrected decision {context.tdd_corrected_id} not found in tree"
)
# Store the node for the next assertion
context.tdd_corrected_node = corrected_node
@then(
'the corrected decision label should contain "[corrected]" or "" or similar marker'
)
def step_corrected_label_has_marker(context: Context) -> None:
"""Verify that the corrected decision's label contains a visual marker.
This assertion is expected to FAIL (via @tdd_expected_fail) because
build_decision_tree does not currently include a 'label' key in its
node dicts, and even if it did, it does not add visual markers for
corrected decisions (is_correction=True). This TDD scenario documents
the gap described in Spec Requirement #7.
"""
corrected_node = context.tdd_corrected_node
# The label should be in the node's label field.
# build_decision_tree currently does NOT include a 'label' key in its
# node dicts -- this assertion will fail with AssertionError, proving
# the bug exists (Spec Requirement #7: corrected nodes must be visually
# marked in the plan tree output).
label = str(corrected_node.get("label", ""))
# Check for common visual markers for corrections
markers = ["[corrected]", "\u270e", "[correction]", "\u270f", "[fix]", "[amended]"]
has_marker = any(marker in label for marker in markers)
assert has_marker, (
f"Corrected decision label '{label}' does not contain any visual marker. "
f"Expected one of: {markers}. "
f"build_decision_tree does not currently add visual markers for "
f"decisions with is_correction=True (Spec Requirement #7 gap)."
)
@@ -0,0 +1,23 @@
@tdd_expected_fail
@tdd_issue
@tdd_issue_8576
Feature: TDD: plan tree visually marks corrected nodes
Spec Requirement #7 states that `agents plan tree` should visually
distinguish corrected nodes (decisions with is_correction=True).
This TDD scenario documents the gap: the current implementation does NOT
visually mark corrected nodes in the tree output. The tree renderer builds
node labels without checking decision.is_correction.
Expected behavior: Corrected nodes should be marked with a visual indicator
such as [corrected], , or similar annotation.
# ------------------------------------------------------------------
# Scenario: Corrected node is visually marked in tree output
# ------------------------------------------------------------------
Scenario: Corrected decision is visually marked in plan tree
Given a set of test decisions with a corrected decision
When I build the decision tree with default options
Then the tree should include a visual marker for the corrected decision
And the corrected decision label should contain "[corrected]" or "" or similar marker
+4
View File
@@ -4878,8 +4878,12 @@ def build_decision_tree(
roots.append(d.decision_id)
def _node_dict(d: Decision) -> dict[str, object]:
label = _get_decision_label(str(d.decision_type), 0)
if d.is_correction:
label = f"{label} [corrected]"
return {
"decision_id": d.decision_id,
"label": label,
"type": str(d.decision_type),
"sequence": d.sequence_number,
"question": d.question,