diff --git a/src/attune_forms/markdown_surface.py b/src/attune_forms/markdown_surface.py index f8bf5be..be75a4f 100644 --- a/src/attune_forms/markdown_surface.py +++ b/src/attune_forms/markdown_surface.py @@ -117,12 +117,15 @@ def _progress_lines(q: FormQuestion) -> list[str]: for item in q.progress_items or []: label = item.get("label", "") status = item.get("status", "") - detail = f" — {item['detail']}" if item.get("detail") else "" if q.progress_style == "report": - lines.append(f"- `{status}` {label}{detail}") + head = f"- `{status}` {label}" else: icon = PROGRESS_STATUS_ICONS.get(status, "•") - lines.append(f"- {icon} {label}{detail}") + head = f"- {icon} {label}" + # _item_row keeps a single-line detail inline (unchanged render) + # and moves a multi-line one below the bullet — the same fix the + # other item-bearing constructs got in the #61 batch. + lines.extend(_item_row(head, item.get("detail"))) if q.options: head = ( "Pick one to go deeper:" diff --git a/src/attune_forms/theme.py b/src/attune_forms/theme.py index ade384d..d17de8e 100644 --- a/src/attune_forms/theme.py +++ b/src/attune_forms/theme.py @@ -28,7 +28,9 @@ excerpt — keep its newlines instead of collapsing inside a flex row, across triage / assumption_review / progress / confirm at once; a trim to fit under 10 KB was offered and declined) — no fonts, no icon -fonts, no images, no @import. +fonts, no images, no @import. Bar for the next raise (chair-ruled at +the 2026-08-28 retro): raises buy FAMILIES, not rules — a single rule +that fits after a trim does not clear it. Copyright 2026 Smart-AI-Memory Licensed under Apache 2.0 diff --git a/tests/test_markdown_surface.py b/tests/test_markdown_surface.py index bb51d5e..6c01f45 100644 --- a/tests/test_markdown_surface.py +++ b/tests/test_markdown_surface.py @@ -288,3 +288,35 @@ def test_multiline_detail_keeps_the_skeleton_round_tripping() -> None: form = form_from_dict(_hunk_board()) skeleton = _skeleton(form_to_markdown(form)) assert skeleton["answers"] == {"hunks": {"src/bridge.py@a1b2c3d:88-96": None}} + + +def test_progress_multiline_detail_stays_inside_its_row() -> None: + """PROGRESS rows route detail through _item_row like the other + item-bearing constructs (retro probe 2026-08-29: the #61 batch + missed this fourth site).""" + md = form_to_markdown( + form_from_dict( + { + "title": "T", + "fields": [ + { + "id": "p", + "type": "progress", + "text": "Status?", + "progress_items": [ + { + "label": "migrate", + "status": "done", + "detail": "a\n- old\n+ new", + }, + {"label": "ship", "status": "blocked", "detail": "one-liner"}, + ], + "options": ["ship"], + } + ], + } + ) + ) + assert " - old" in md + assert not any(ln.startswith("- old") for ln in md.splitlines()) + assert "- ✕ ship — one-liner" in md