Skip to content

fix(specs): _STATUS_VALUE_RE accepts both **Status**: and **Status:**#57

Merged
silversurfer562 merged 2 commits into
mainfrom
fix/status-regex-both-formats
May 23, 2026
Merged

fix(specs): _STATUS_VALUE_RE accepts both **Status**: and **Status:**#57
silversurfer562 merged 2 commits into
mainfrom
fix/status-regex-both-formats

Conversation

@silversurfer562
Copy link
Copy Markdown
Member

Summary

_STATUS_RE and _STATUS_VALUE_RE in sidecar/attune_gui/routes/cowork_specs.py previously only matched **Status**: (colon outside the asterisks). Real specs in this repo overwhelmingly use **Status:** (colon inside) — a quick grep -h "Status" specs/*/requirements.md docs/specs/*/decisions.md returned ~7 of 8 status lines in that form.

Net result: the dashboard's Status column and the new MCP gui_get_spec_status tool were silently returning None for the majority of specs in the wild.

The fix

Tiny alternation in both regexes:

# old:
_STATUS_VALUE_RE = re.compile(r"\*\*Status\*\*:\s*(\S+)")

# new:
_STATUS_VALUE_RE = re.compile(r"\*\*Status(?:\*\*:|:\*\*)\s*(\S+)")

The (?:\*\*:|:\*\*) matches **: or :** — covering both legitimate markdown emphasis styles. Manual confirmation:

Input Captured
**Status**: approved approved
**Status:** approved approved
**Status:** Closed — final Closed
**Status**: pending pending
**Status: (no match — correct)
**Status: approved (no match — correct)
**Statuss**: approved (no match — correct)
## Status: approved (no match — correct)

Tests

  • test_cowork_specs.py — 8 new parametrized tests:
    • test_status_regex_accepts_both_markdown_emphasis_styles (4 happy paths covering both formats, the common dashed-phrase form, and indented lines)
    • test_status_regex_rejects_malformed_lines (4 negative cases proving the looser regex still rejects look-alikes)
  • test_mcp_tools.py — 1 new test (test_get_spec_reads_colon_inside_status_format) locking in the fix on the MCP path

What's NOT changed

The PUT-status route's substitution still rewrites in the **Status**: form (line ~442 of cowork_specs.py). That's a separate normalization choice — when the route rewrites a **Status:** line, it'll convert it to **Status**:. Could be revisited later but out of scope here.

Test plan

  • pytest sidecar/tests/test_cowork_specs.py sidecar/tests/test_mcp_tools.py sidecar/tests/test_mcp_integration.py — 40/40 green
  • Full sidecar suite: 543 passed (+9 new), 1 pre-existing unrelated fail (version == 'dev' worktree quirk)
  • ruff check sidecar/ — clean

Provenance

Surfaced during #52's MCP Phase 2 work, when the test fixtures had to use the rare **Status**: form to work around this latent bug. Flagged via a follow-up chip at the time; this PR closes the chip's intent.

🤖 Generated with Claude Code

silversurfer562 and others added 2 commits May 23, 2026 11:38
The regex previously only matched `**Status**:` (colon outside
asterisks). Real specs in this repo overwhelmingly use `**Status:**`
(colon inside) — a quick grep showed ~7 of 8 status lines in that
form. The dashboard's Status column and the MCP gui_get_spec_status
tool were silently returning None for those specs.

  _STATUS_RE       — old: r"^\s*\*\*Status\*\*:.*$"
                   — new: r"^\s*\*\*Status(?:\*\*:|:\*\*).*$"

  _STATUS_VALUE_RE — old: r"\*\*Status\*\*:\s*(\S+)"
                   — new: r"\*\*Status(?:\*\*:|:\*\*)\s*(\S+)"

The alternation accepts either order of the closing asterisks and
colon. Malformed look-alikes (`**Status:`, `**Status: foo` without
closing asterisks, `**Statuss**: foo`, `## Status: foo`) still get
correctly rejected.

Tests:
  - test_cowork_specs.py:
      • test_status_regex_accepts_both_markdown_emphasis_styles
        (4 parametrized happy paths covering both formats, the
        dashed-phrase form, and indented lines)
      • test_status_regex_rejects_malformed_lines (4 parametrized
        negative cases)
  - test_mcp_tools.py:
      • test_get_spec_reads_colon_inside_status_format — covers the
        MCP path, not just the FastAPI route

The PUT-status route's substitution still rewrites in the
`**Status**:` form; that's a separate normalization choice and
isn't changed here. Surfaced during PR #52's MCP Phase 2 work and
flagged via a follow-up chip; this closes the chip's intent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
source_hash drift only — no narrative change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@silversurfer562 silversurfer562 merged commit 30cc722 into main May 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant