Skip to content

V2 workflow alerts: require acknowledgment, repeating sound, size options and team delivery (0.261.235) - #1636

Merged
Paul Lizer (paullizer) merged 6 commits into
microsoft:paullizer-react-v2-uifrom
paullizer:paullizer-workflow-alert-acknowledgment
Oct 5, 2026
Merged

Paul Lizer (paullizer) merged 6 commits into
microsoft:paullizer-react-v2-uifrom
paullizer:paullizer-workflow-alert-acknowledgment

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Workflow alert rules can now require acknowledgment. Such an alert keeps coming back after a refresh, in every tab and on every device, until someone selects Acknowledge or opens it. Closing it only shrinks it: V2 keeps a notice under My Workspace (in room of its own, never covering the rail items), classic keeps a banner with Review. Mark read, Dismiss and Mark all read never acknowledge. Alerts that need acknowledgment are shown before any others.
  • A rule can play a sound once or repeat it every five seconds until acknowledged. Three locally bundled tones (chosen by severity) are generated by a stdlib-only script. One tab per browser sounds (shared Web Lock between classic and V2); several repeating alerts sound as one tone; Play once chimes once per browser, and alerts that arrive together chime once in the loudest tone. When autoplay is blocked the alert offers Enable sound until a sound plays. Admins control this with Enable Workflow Alert Sounds (on by default) and each device has a Play alert sounds switch.
  • A rule can choose a size (small notice, medium opens the full alert, large is a full-screen takeover for wall displays), and in a group workflow can alert everyone in the group: one shared alert, one acknowledgment for everyone, "Acknowledged by name at time" in the bell, and a simpler member view (severity, workflow, matched rules, Open to what the run created in the group).
  • V2 Preferences adds an Alert monitor switch for operations screens: checks every 30 s without backing off, even in a background tab. While an alert waits for acknowledgment, V2 re-checks every 20 s so an acknowledgment elsewhere stops it.

New route POST /api/notifications/<notification_id>/acknowledge (recipients only, 404 otherwise). GET /api/notifications/workflow-alerts also returns pending must-acknowledge alerts (no recency window) and team alerts from the caller's groups, with complete and sounds_enabled. Read, dismiss and acknowledge writes are now ETag-conditional with retry, so concurrent writes to a shared alert can't drop each other.

Commits after the feature

  • Two review rounds. The second commit fixes 11 frontend review findings (sound follows what the store holds, Open leaves other pending alerts up, one chime per browser, pending alerts lead, the pending notice no longer covers rail items, the large dialog fills the screen, classic gives up the lock on refusal and retries refused chimes, Mark as read for ordinary alerts without links). The third fixes two more: "play once" alerts arriving together raced for the lock so a newer low alert could chime instead of an older critical one, and a V2 flyout that stepped aside could hide the next alert needing acknowledgment.
  • Merged paullizer-react-v2-ui and renumbered to 0.261.235. Clearer saved-result error messages and repaired workflow test harnesses #1635 merged first as 0.261.234; this PR's release notes section, VERSION, docs and test headers now say 0.261.235.
  • CodeQL notes. Removed the unused find_group_by_id import, the unused stopAllWorkflowAlertSounds helper and an unused test variable.

About the remaining CodeQL py/cyclic-import note

It reports functions_notifications → functions_group → functions_settings → content_screening.service → functions_notifications. That chain predates this PR (the base already imports functions_group at the top of functions_notifications); CodeQL reports it here because this PR edited that import line. py/cyclic-import is a recommendation-level maintainability rule that also counts imports made inside functions, and both links that close this chain are function-local (functions_settings.py lines 2254 and 2370, content_screening/service.py line 1234), so nothing can fail while modules load (py/unsafe-cyclic-import did not fire). Moving this PR's imports into functions wouldn't clear the note and would break the stub-loaded tests. New functional_tests/test_workflow_alert_notifications_import_cycle.py keeps any module-level cycle out of functions_notifications and loads the real modules cold and offline in each order the app reaches them. It can be dismissed as "won't fix", or left for a separate cleanup of the settings and screening imports.

Linked issue

Refs #1634

Release Notes & Latest Features

  • New Feature
  • Bug Fix
  • UI Enhancement
  • Breaking Change
  • Internal only

Is this visible to end users?

  • Yes
  • No

Is this admin-facing (Admin Settings, governance, deployment, config)?

  • Yes
  • No

Should this become a Latest Feature card?

  • Yes
  • No
  • Already added

Screenshot needed for the card?

  • Yes
  • No
  • Attached

Version bump

Testing / validation

After merging the base and the CodeQL changes (head 8f39dafad):

  • python -m pytest functional_tests/test_workflow_alert_notifications_import_cycle.py — 16 passed. Mutation-checked: hoisting the two function-local imports to module level fails the static guard and the group-first cold import.
  • python -m pytest on the workflow alert, notification, editor, docs-bell and route-policy functional files (the 24 files listed in the earlier run plus the new import test) — 444 passed, 1 failed: test_chat_completion_notifications.py::test_version_updated_for_feature, which requires exactly VERSION = "0.250.047" (stale, unrelated).
  • python -m pytest ui_tests/test_workflow_alert_classic_acknowledgment.py ui_tests/test_v2_workflow_alerts.py — 48 passed
  • node --check application/single_app/static/js/notifications.js — passed
  • python scripts/check_xss_sinks.py --base-sha efee70775 --head-sha HEAD <63 changed files> — passed; python scripts/check_broken_access_control.py --base-sha efee70775 --head-sha HEAD <33 changed .py files> — passed; python scripts/check_swagger_routes.py <3 changed route files> — passed
  • python functional_tests/test_docs_app_surface_coverage.py — 7/7 passed; python functional_tests/test_docs_site_quality.py — 6/6 passed

Earlier, at c78092a28 (no V2 source has changed since):

  • npm --prefix application/v2_ui run typecheck and npm --prefix application/v2_ui run build — passed
  • python -m pytest ui_tests/test_v2_workflow_alert_notices.py ui_tests/test_v2_notifications_bell.py ui_tests/test_v2_workflow_alerts.py — 132 passed
  • python -m pytest ui_tests/test_workflow_alert_classic_acknowledgment.py — 18 passed (three consecutive runs)
  • Regression tests for each review finding were mutation-checked: the 9 V2 and 4 classic tests from the second commit fail against the first, and the 4 V2 and 2 classic tests from the third fail against the second.

Not run, or failing for reasons unrelated to this change:

  • Live UI tests that need SIMPLECHAT_UI_BASE_URL (a running, signed-in app) were skipped.
  • test_notification_polling_redirect_guard.py is stale on the base branch too: it expects the notifications comment directly after {% if session.get('user') %} and a notifications.js tag without ?v=, and the base already has completion-audio-cues.js between them and the cache-buster.
  • test_workflow_priority_alerts.py (CosmosClient credentials when config.py is imported) and test_group_notification_context.py (needs live Cosmos DB) need Azure configuration.
  • Earlier OpenSSL failures (module 'lib' has no attribute 'GEN_EMAIL') came from a cryptography 50 / pyOpenSSL 25.3 mismatch in my local Python, not from the app; with a compatible cryptography those tests pass.

Known risks and limitations:

  • After each page load, sound waits for a click or key press unless the browser policy allows the site to autoplay (AutoplayAllowlist in Edge and Chrome, documented). The alert itself always shows.
  • Each of the alert reads is capped (V2 asks for 10, classic for 5). If more must-acknowledge alerts are pending than one read returns, the rest wait their turn: complete keeps them from being retired, and they appear as the others are acknowledged.
  • A group manager's rule can make every member's browser sound. Admins can turn sounds off and each device can mute; there is no per-member opt-out from team alerts yet.
  • Members other than the owner see a simplified alert by design (the full alert describes the owner's side of the run).

Documentation

  • Release notes updated, or not needed
  • Feature documentation updated, or not needed
  • Fix documentation updated, or not needed

New docs/explanation/features/WORKFLOW_ALERT_ACKNOWLEDGMENT.md; updated WORKFLOW_ALERT_RULES.md, V2_WORKFLOW_ALERT_NOTICES.md, V2_WORKFLOW_ALERT_EDITING.md, WORKFLOW_PRIORITY_ALERTS.md, the create-a-workflow, manage-notifications and update-profile-preferences guides, docs/admin/workflow.md, docs/_data/features.yml and docs/_data/app_surface.yml, and a v0.261.235 release notes section.

Security checklist

  • New Flask routes include @swagger_route(security=get_auth_security())
  • Settings sent to non-admin frontends use sanitize_settings_for_user()
  • Browser JavaScript is served from local SimpleChat static assets only; no CDN-hosted JS
  • No secrets, keys, connection strings, or local-only artifacts are included

Paul Lizer (paullizer) and others added 3 commits October 3, 2026 17:39
… (0.261.234)

Each workflow alert rule can now require acknowledgment, play a sound once or
repeat it until acknowledged, choose a small, medium or large size, and in a
group workflow alert everyone in the group with one shared acknowledgment.

- Rules store the new options only when not the default; the server validates
  them with reviewed messages, and both editors mirror them.
- Matched rules merge options strongest-wins; a model-evaluated rule that asks
  for a stronger option is still evaluated.
- Team alerts are one group-scoped notification; current members acknowledge
  it for everyone through POST /api/notifications/<id>/acknowledge, and
  members other than the owner read a simpler alert.
- Read, dismiss and acknowledge writes are ETag-conditional with retry.
- The pop-up read returns pending must-acknowledge alerts regardless of age or
  read state, plus team alerts, with complete and sounds_enabled.
- V2 and classic re-show must-acknowledge alerts until acknowledged, play
  locally bundled tones in one tab per browser, and share a BroadcastChannel.
- New admin setting enable_workflow_alert_sounds (on), per-device Play alert
  sounds switch, and a V2 Alert monitor switch for operations screens.

Refs microsoft#1634

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
V2
- The sound follows the alerts the store holds (syncWorkflowAlertSound), so an
  alert acknowledged while it waited, in another tab or by the bell stops
  sounding, and a refused sound is never retried for an acknowledged alert.
- Acknowledged ids are never re-presented by a read that left earlier.
- Open acknowledges only the alert opened; other pending alerts stay in the
  notice and keep sounding. Acknowledging one keeps the loop going for the rest.
- Play once chimes once per browser through a shared soundedOnce record,
  checked and written under the Web Lock.
- Alerts that need acknowledgment lead the notice and card.
- A pending notice takes its own room in the full rail instead of covering the
  items below, and a flyout steps aside from focus it covers (WCAG 2.4.11).
- The full-size dialog is no longer capped at 85vh.
- Enable sound stays until a retried sound plays.

Classic
- One repeating loop in the loudest tone; a refused tab gives up the lock;
  refused one-off chimes are retried; the shared soundedOnce record.
- Mark as read is offered again for ordinary alerts without links.

Tests: V2 and classic regressions for each finding (mutation-checked against the
previous commit), and a classic/V2 sound contract parity test.

Refs microsoft#1634

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Found in review of the previous commit:

- Each "play once" alert took the Web Lock on its own, so when several arrived
  together the first in server order (newest) won and the rest were dropped:
  a newer low alert's chime could play instead of an older critical alert's
  alarm. V2 and classic now gather the chimes asked for in one task into a
  batch, take the lock once, play the loudest that hasn't chimed in the browser
  and record all of them. Enable sound retries refused chimes the same way.
- A V2 flyout that had stepped aside could keep that flag while an ordinary
  alert led and focus moved elsewhere, so the next alert needing
  acknowledgment arrived invisible. Every focus move is now measured whatever
  leads, and the record belongs to one lead in one placement, so a new lead is
  shown.

Tests: V2 and classic regressions for both, mutation-checked against the
previous commit.

Refs microsoft#1634

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread application/single_app/static/js/notifications.js Fixed
Comment thread application/single_app/functions_notifications.py Fixed
Comment thread application/single_app/functions_notifications.py Fixed
Comment thread ui_tests/test_v2_workflow_alerts.py Fixed
Paul Lizer (paullizer) and others added 3 commits October 5, 2026 13:16
microsoft#1635 took 0.261.234, so this PR's release notes section moves to v0.261.235,
above microsoft#1635's section.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
microsoft#1635 merged into paullizer-react-v2-ui as 0.261.234 first. Moves VERSION, the
feature and guide docs, and this PR's test headers and version floors to
0.261.235.

Refs microsoft#1634

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Remove the unused find_group_by_id import from functions_notifications and
  the unused stopAllWorkflowAlertSounds helper from notifications.js.
- Drop an unused variable in the V2 editor UI test.
- py/cyclic-import reports functions_notifications -> functions_group ->
  functions_settings -> content_screening.service -> functions_notifications.
  The chain predates this PR and closes only through imports made inside
  functions (the rule counts those too), so nothing can fail while modules
  load. New test_workflow_alert_notifications_import_cycle.py keeps any
  module-level cycle out of functions_notifications and loads the real modules
  cold and offline in each order the app reaches them, with and without -O.

Refs microsoft#1634

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer Paul Lizer (paullizer) changed the title V2 workflow alerts: require acknowledgment, repeating sound, size options and team delivery (0.261.234) V2 workflow alerts: require acknowledgment, repeating sound, size options and team delivery (0.261.235) Oct 5, 2026
Comment thread application/single_app/functions_notifications.py
@paullizer
Paul Lizer (paullizer) marked this pull request as ready for review October 5, 2026 17:52
@paullizer
Paul Lizer (paullizer) merged commit 5be1d84 into microsoft:paullizer-react-v2-ui Oct 5, 2026
11 checks passed
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 5, 2026
V2 moved to 5be1d84 (VERSION 0.261.235) when #1636 merged: must-acknowledge
workflow alerts, alert sounds, sizes and team delivery.

Conflicts:
- config.py: keep this branch's 0.261.238, still above V2's 0.261.235.
- release_notes.md: keep both sections, 0.261.238 above 0.261.235. This also
  restores V2's 0.261.234 entry exactly: the previous merge (ab87e79) left
  extra spaces in its Ref line and dropped the blank line before 0.261.233.

admin_settings_fields.py, functions_personal_workflows.py, functions_settings.py,
route_frontend_admin_settings.py and docs/_data/features.yml auto-merged.
docs/_data/app_surface.yml auto-merged with capabilities: 125, because both
sides raised the same count by one. Regenerated with
scripts/build_docs_inventory.py: 126, for enable_chat_orchestration_workflow_handoff
and enable_workflow_alert_sounds.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 5, 2026
paullizer-react-v2-ui merged #1636 (workflow alert acknowledgment) and
published v0.261.235, which this branch used for Phase 1.

The integration branch's sections are kept exactly as published. This
branch's ten sections shift up one, to v0.261.236 through v0.261.245,
and config.py becomes 0.261.245. Every file only this branch changed is
checked to equal its previous content with those versions shifted, every
file only the integration branch changed is byte-identical to it, and
the release notes are the integration branch's file plus this branch's
ten sections.

Ten files changed on both sides. config.py and the release notes
conflicted on versions only. The other eight merged cleanly; in
docs/guides/create-a-workflow.md only this branch's six lines about its
own versions were shifted, and #1636's line about 0.261.235 is kept.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 5, 2026
Brings in #1636 (must-acknowledge workflow alerts, sounds, sizes and team
delivery), which also used 0.261.235 and changed the alert notice this
branch moves from My Workspace to the bell.

- WorkflowAlertNotice.tsx: kept the bell anchor. #1636 gave an alert that
  needs acknowledgment room of its own below My Workspace in the full
  rail; that room is now WorkflowAlertRowSlot, a row under the rail's
  header whose notch is measured to point at the bell. It pushes New chat
  and the navigation down and sits outside the chat scroll region. The
  bell's overlay slot stands aside while it is in use; the flyout keeps
  #1636's step-aside behaviour.
- Feature docs and the notifications guide describe the row instead of
  My Workspace; both sides' text is kept.
- Renumbered this PR to 0.261.236: config.py, this PR's tests and docs,
  and its release-notes section, now above #1636's 0.261.235 entry.
- Tests: the in-flow test also checks the row hangs from the bell, comes
  after the header controls and survives collapse/expand; the scrolled
  chat rail test covers a must-acknowledge alert; the functional test
  guards the row.

Refs #1642.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 5, 2026
PR #1636 took 0.261.235, so the settings fix moves to 0.261.236 and the
Microsoft 365 orchestration fix to 0.261.237. This merge resolves the
version and release notes conflicts; the next commit renumbers the rest.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 5, 2026
PR #1636 took 0.261.235 on paullizer-react-v2-ui. The settings document
type fix is now 0.261.236, and the Microsoft 365 orchestration fix is
0.261.237, in code headers, tests and documentation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 6, 2026
V2 is still at 0.261.233. microsoft#1635, microsoft#1636, microsoft#1637 and microsoft#1638 claim .234 to .236,
so this branch takes .237. Every 0.261.234 reference moves to 0.261.237:
config.py, the release notes header, the feature docs, the chat-controls
reference and the test headers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 6, 2026
Brings in microsoft#1636 (V2 workflow alerts: require acknowledgment, repeating
sound, size options and team delivery, released as 0.261.235). Three
conflicts:

- config.py: VERSION kept at 0.261.237, which is still above V2's
  0.261.235.
- release_notes.md: both sides added a section at the top. Both are kept
  intact under their own headings, v0.261.237 above v0.261.235, so
  against V2 the file only gains 6b-2's section.
- ui_tests/test_v2_workflow_alert_notices.py: the last line of
  test_open_run_goes_to_the_run_in_its_workspace keeps 6b-2's
  read_calls == ["o1", "o2", "o4"], and every must-acknowledge test
  microsoft#1636 appended after it is kept unchanged.

Refs microsoft#1546

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 6, 2026
microsoft#1636 changed BootstrapPayload.features to BootstrapFeatures, which allows undefined values, so App.tsx and MessageList.tsx no longer typechecked against workflowRunTrackerShouldRun's Record<string, boolean> parameter after the merge. The gate already compares each flag with === true, so only the parameter type widens; the tracker test now also covers an explicit undefined flag.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 6, 2026
Sets config.py VERSION to 0.261.238, one above the versions claimed by the open V2 PRs (microsoft#1636 0.261.234, microsoft#1637 0.261.235, microsoft#1638 0.261.236, 6b-2 next), and moves the hand-off modules' and tests' Version, Implemented in, MINIMUM_VERSION and assert_app_version_at_least literals to it. The off-golden fixture keeps its factual capture note (f1aeef1, 0.261.233).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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