Skip to content

Fixes #70: Rework /esb-status Slack command as an interactive modal#73

Merged
jantman merged 3 commits into
mainfrom
issue-70-status-modal
Jul 3, 2026
Merged

Fixes #70: Rework /esb-status Slack command as an interactive modal#73
jantman merged 3 commits into
mainfrom
issue-70-status-modal

Conversation

@jantman

@jantman jantman commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Reworks the /esb-status Slack command (issue #70) from an ephemeral text reply into an interactive Block Kit modal, fixing two UX problems: the confusing "Only visible to you" ephemerals, and the bot's inability to post into channels it is not a member of.

  • Summary modal (views_open): one section per non-empty area, each with a "View details" button accessory (in a distinct block_id) that swaps the modal in place (views_update) to that area's detail view, which has a "Back to summary" button.
  • Text-arg deep-link preserved: area name wins over equipment search; a single equipment match opens its area's detail; ambiguous / no-match / archived-area targets land on the summary. Archived-area deep-links are routed to the summary inline (AreaArchived), not surfaced as an error.
  • Error fallback now replies via the slash command's response_url (Bolt's respond), which works even when the bot is not a channel member — the exact limitation this feature fixes. Button-action failures swap to an in-modal error view.
  • Adds build_status_summary_modal / build_area_status_modal builders plus the shared _area_summary_mrkdwn helper; removes the now-dead text formatters (format_status_summary, format_equipment_status_detail, format_equipment_list).
  • Bumps version to 0.16.0.

Testing

  • make lint — clean
  • make test1805 passed
  • New/updated: TestEsbStatusCommand (modal assertions), TestEsbStatusActions, TestBuildStatusSummaryModal, TestBuildAreaStatusModal (incl. Block Kit ≤100-block / ≤3000-char guards).

Implemented via the BMAD quick-dev workflow; an adversarial review pass was run and its findings resolved (see _bmad-output/implementation-artifacts/tech-spec-esb-status-modal.md → Review Notes).

🤖 Generated with Claude Code

https://claude.ai/code/session_01QzHqw96wXCi9i6aK349yZa

jantman and others added 2 commits July 3, 2026 15:29
Reworks /esb-status to open a Block Kit modal (summary + per-area "View
details" buttons + area detail with back navigation) instead of an
ephemeral message, so it works in channels the bot isn't a member of and
avoids confusing "Only visible to you" replies. Spec produced via the
quick-spec workflow and hardened through two adversarial review passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzHqw96wXCi9i6aK349yZa
Replace the ephemeral /esb-status reply with a Block Kit modal opened via
views_open, fixing the confusing "Only visible to you" UX and the bot's
inability to post into channels it is not a member of.

- Summary modal: one section per non-empty area, each with a "View details"
  button accessory (distinct block_id) that swaps the modal in place
  (views_update) to that area's detail view, which has a "Back to summary"
  button.
- Preserve the text-arg deep-link: area name wins over equipment search; a
  single equipment match opens its area's detail; ambiguous/no-match/archived
  targets land on the summary. Archived-area deep-links are routed to the
  summary inline (AreaArchived), not surfaced as an error.
- Error fallback replies via the slash command's response_url (Bolt's
  respond), which works even when the bot is not a channel member; action
  handlers swap to an in-modal error view.
- Add build_status_summary_modal / build_area_status_modal builders and the
  shared _area_summary_mrkdwn helper; remove the now-dead text formatters
  (format_status_summary, format_equipment_status_detail, format_equipment_list).
- Bump version to 0.16.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzHqw96wXCi9i6aK349yZa
@jantman

jantman commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@claude please review this change

@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @jantman's task in 2m 35s —— View job


Review: /esb-status interactive modal (#73)

  • Gather context (PR diff, changed files)
  • Review esb/slack/forms.py (modal builders)
  • Review esb/slack/handlers.py (command + action handlers)
  • Review test changes
  • Post final review feedback

Overall this is a solid, well-documented rework. The deep-link resolution (area name → single equipment match → archived-area fallback to summary) in handle_esb_status (esb/slack/handlers.py:622-679) is handled carefully, and I traced AreaArchived/AreaNotFound through status_service.get_single_area_status_dashboard (esb/services/status_service.py:288-310) to confirm the fallback-to-summary behavior is correct rather than accidental. The response_url-based error fallback (via Bolt's respond) is the right fix for the "bot not a channel member" problem this PR targets.

One correctness gap worth addressing:

No enforcement of Slack's Block Kit modal limits — only tested against small fixtures.
format_area_status_detail() (esb/slack/forms.py:69-106, used by build_area_status_modal) renders every equipment item's issue_description in full, with no truncation. RepairRecord.description is an unbounded db.Text column (esb/models/repair_record.py:34), and the Slack modal's plain_text_input for description (build_problem_report_modal/build_repair_create_modal) sets no max_length. So an area with several non-green items, or just a couple of long descriptions, can push a single section's mrkdwn text past Slack's ~3000-char modal section limit. Similarly, build_status_summary_modal (esb/slack/forms.py:109-160) adds one block per non-empty area with no cap, so a large number of areas could exceed the 100-block modal limit.

The new tests (TestBuildStatusSummaryModal, TestBuildAreaStatusModal in tests/test_slack/test_forms.py:590-710) assert len(modal['blocks']) <= 100 and per-section len(text) <= 3000 — but only against small fixture data that trivially satisfies those bounds. There's no actual truncation/capping logic in the builders themselves, so these read as tests of today's fixtures rather than guarantees. In production this would surface as views_open/views_update failing and falling through to the generic error modal (or, from the button handlers, _update_esb_status_error_modal) for a busy area — the opposite of what the feature is meant to show.

Suggested fix: truncate format_area_status_detail's per-item issue_description the same way _area_summary_mrkdwn already does via _truncate() (esb/slack/forms.py:56-64), and/or cap the total assembled text length defensively before returning from both formatter functions, and consider capping the number of area sections built in build_status_summary_modal.

Fix this →

Minor / non-blocking:

  • handle_esb_status_view_area (esb/slack/handlers.py:680-696) catches all exceptions generically and shows the close-only error modal, including for AreaArchived (e.g. if an area is archived between the summary render and the button click) — unlike the slash-command path, it doesn't special-case that to route back to the summary. Probably fine as-is (the modal is already open, so an explicit error is arguably clearer), but flagging for consistency with the initial command's "archived is not an error" philosophy.

I was not able to run make lint / make test in this session (no venv / dependencies installed and no DB container running), so this review is based on manual code reading rather than executing the suite — the PR description's reported "1805 passed" / clean lint should still be trusted unless CI says otherwise.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reworks the /esb-status Slack slash command from posting ephemeral channel messages into opening a Block Kit modal with per-area navigation, addressing the “Only visible to you” confusion and the bot-not-in-channel posting limitation described in issue #70.

Changes:

  • Replaces /esb-status output with views_open summary modal and adds button action handlers that views_update to area detail and back.
  • Adds modal builder functions in esb/slack/forms.py and removes now-dead legacy text formatter tests.
  • Updates Slack handler and form unit tests to assert modal structure/behavior; bumps project version to 0.16.0.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
esb/slack/handlers.py Opens /esb-status as a modal and adds action handlers for in-modal navigation + error fallback via respond.
esb/slack/forms.py Introduces build_status_summary_modal, build_area_status_modal, and _area_summary_mrkdwn for modal content generation.
tests/test_slack/test_handlers.py Rewrites /esb-status tests to assert views_open/views_update behavior and response_url fallback.
tests/test_slack/test_forms.py Removes legacy formatter tests and adds modal builder tests (structure + Block Kit constraint assertions).
pyproject.toml Version bump to 0.16.0.
_bmad-output/implementation-artifacts/tech-spec-esb-status-modal.md Adds implementation tech spec and review notes artifact for the modal rework.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread esb/slack/forms.py Outdated
Comment thread esb/slack/forms.py Outdated
Block Kit caps a section's text at 3000 chars; a single unbounded
RepairRecord.description (db.Text) can exceed it and make
views_open/views_update fail with invalid_blocks. Truncate the per-area
summary sections and the area-detail section to _SECTION_TEXT_LIMIT so the
modal always opens. Addresses Copilot review feedback on PR #73.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzHqw96wXCi9i6aK349yZa

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@jantman
jantman merged commit 33e6ce7 into main Jul 3, 2026
11 checks passed
@jantman
jantman deleted the issue-70-status-modal branch July 3, 2026 20:39
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.

2 participants