mirror of
https://github.com/himanshudongre/smriti.git
synced 2026-08-28 05:14:59 +00:00
Render list-valued blocked_by consistently in state --compact
`smriti current` already normalizes a list-valued blocked_by to a clean comma-separated string via the backend CurrentTask validator, but `smriti state` rendered it through an f-string and leaked the raw Python list repr (['a', 'b']) into the state brief — the surface agents read at session start. Add a `_coerce_blocked_by` helper in the CLI formatters mirroring that validator, and apply it in `_normalize_task_item` so every `smriti state` task line renders blocked_by the same way `smriti current` does. Adds regression tests.
This commit is contained in:
parent
c43310caa1
commit
eb60d03f4b
2 changed files with 39 additions and 0 deletions
|
|
@ -120,6 +120,25 @@ def _list_section(heading: str, items: list[str]) -> str:
|
|||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def _coerce_blocked_by(value: object) -> str | None:
|
||||
"""Normalize blocked_by — string, list of dependency labels, or null —
|
||||
to a single display string.
|
||||
|
||||
Real task payloads carry blocked_by as a plain string or as a list (a
|
||||
task blocked by several others). Mirrors the backend CurrentTask
|
||||
validator so `smriti state` and `smriti current` render it identically
|
||||
instead of leaking a raw Python list repr into the state brief.
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, str):
|
||||
return value.strip() or None
|
||||
if isinstance(value, (list, tuple)):
|
||||
labels = [str(item).strip() for item in value if str(item).strip()]
|
||||
return ", ".join(labels) or None
|
||||
return str(value).strip() or None
|
||||
|
||||
|
||||
def _normalize_task_item(item) -> dict:
|
||||
"""Normalize a task to a dict with at least a 'text' key.
|
||||
|
||||
|
|
@ -131,6 +150,8 @@ def _normalize_task_item(item) -> dict:
|
|||
task = dict(item)
|
||||
if not task.get("intent_hint") and task.get("intent_type"):
|
||||
task["intent_hint"] = task["intent_type"]
|
||||
if "blocked_by" in task:
|
||||
task["blocked_by"] = _coerce_blocked_by(task["blocked_by"])
|
||||
return task
|
||||
# Fallback: coerce to string
|
||||
return {"text": str(item)}
|
||||
|
|
|
|||
|
|
@ -504,6 +504,13 @@ def test_normalize_task_item_dict():
|
|||
assert result == task
|
||||
|
||||
|
||||
def test_normalize_task_item_coerces_list_blocked_by():
|
||||
"""A list-valued blocked_by is normalized to a comma-separated string."""
|
||||
task = {"text": "Wire the limiter", "blocked_by": ["middleware", "load-test"]}
|
||||
result = _normalize_task_item(task)
|
||||
assert result["blocked_by"] == "middleware, load-test"
|
||||
|
||||
|
||||
def test_task_section_empty():
|
||||
"""Empty task list produces empty string."""
|
||||
assert _task_section([]) == ""
|
||||
|
|
@ -547,6 +554,17 @@ def test_task_section_structured_with_blocked_by():
|
|||
assert "→ blocked by: freshness-impl" in out
|
||||
|
||||
|
||||
def test_task_section_renders_list_valued_blocked_by():
|
||||
"""A list-valued blocked_by renders as a clean comma-separated string,
|
||||
not a raw Python list repr — consistent with `smriti current`."""
|
||||
tasks = [
|
||||
{"text": "Wire the limiter", "blocked_by": ["middleware", "load-test"]},
|
||||
]
|
||||
out = _task_section(tasks)
|
||||
assert "→ blocked by: middleware, load-test" in out
|
||||
assert "['" not in out # not the raw Python list repr
|
||||
|
||||
|
||||
def test_task_section_structured_with_done_status():
|
||||
"""Task with status=done renders inline marker."""
|
||||
tasks = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue