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
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:
@@ -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
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user