Skip to content

Fix orchestration settings race and Microsoft 365 action steps - #1644

Merged
Paul Lizer (paullizer) merged 7 commits into
microsoft:paullizer-react-v2-uifrom
paullizer:paullizer-orchestration-retained-result-error
Oct 5, 2026
Merged

Paul Lizer (paullizer) merged 7 commits into
microsoft:paullizer-react-v2-uifrom
paullizer:paullizer-orchestration-retained-result-error

Conversation

@paullizer

Copy link
Copy Markdown
Contributor

Summary

Fixes two V2 chat orchestration bugs found while investigating a "what are my latest emails" plan that showed every step completed but ended Partially completed.

  • Finished plans no longer fail with "A required retained result is unavailable or changed" (0.261.237). Orchestration rechecks kept results against current settings and requires exactly a dict. Settings served from Redis were a dict, but settings served from Cosmos DB came back as the SDK's CosmosDict. Cosmos serves the read while any settings save is in flight (the Cosmos throughput autoscale saves often), when the cache is repaired, and on every read when Redis is off, so runs failed intermittently at finalization. app_settings_store now returns a plain dict from every read and write; the orchestration check is unchanged.
  • Microsoft 365 actions now work in plan steps (0.261.238). Each action step runs in a fresh bridged request context, and orchestration never installed the M365ExecutionContext that chat and workflows create. Every Microsoft 365 call was refused with m365_context_required before reaching Microsoft Graph, the plugin returned the refusal as data, and the step reported completed. An action step now gets its own Microsoft 365 request as the signed-in user. It selects only that step's saved action and checks delegated sign-in before the model or Graph is called.
  • Microsoft 365 refusals stop the step with a failure that says what to do (m365_sign_in_required, m365_approval_required, m365_unavailable, m365_shared_conversation, m365_read_only) instead of becoming findings. The V2 run details offer Connect Microsoft 365 (the existing Profile reconnect flow, in a pop-up), then Retry from failed step. Approval stops link to Approvals.
  • Telemetry: [MS_GRAPH_PLUGIN] Microsoft 365 operation could not complete. now logs the refusal code and source as text instead of only the code's length. A stopped step logs [ORCHESTRATION_M365] A Microsoft 365 step stopped.

Deliberate limits worth a look in review:

  • Plans only read Microsoft 365. send_mail, create_calendar_invite and mark_message_as_read are removed from a plan step even when the action enables them.
  • Shared conversations are refused before any Microsoft 365 work, because their source-sharing approvals resume chat requests, not plan steps.
  • The step's Microsoft 365 request ID is derived from the plan's first attempt and the step, so Retry from failed step reuses the request and any approval given after the stop. Deciding an approval doesn't resume a plan; the user retries.
  • Sign-in is checked at the step, before any model or Graph call, not before the run starts.
  • Ask an agent steps don't get Microsoft 365, because plans already refuse the local agents that load those actions. Classic Call agent delegation is unchanged: the same bridge runs inside workflows, which must use their Run as account.

Linked issue

N/A (no tracking issue)

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

  • application/single_app/config.py VERSION third segment bumped, or not needed because this is docs-only
  • deployers/version.txt bumped, or not needed because deployers/ was not changed

VERSION is 0.261.238. The settings fix is recorded as 0.261.237 and the Microsoft 365 fix as 0.261.238, renumbered after #1636 and #1643 took 0.261.235 and 0.261.236.

Testing / validation

Functional tests ran from functional_tests with PYTHONPATH=application/single_app, one file per process:

  • python -m pytest test_orchestration_m365_actions.py -q -p no:cacheprovider (new): 14 passed. It runs the real action runner, step scope, Microsoft 365 runtime, approval service and Email plugin through a real Flask bridge, with storage, tokens, Graph and the model doubled and network blocked. Each of 10 deliberate breaks of the fix fails at least one test.
  • python -m pytest test_app_settings_store_plain_dict_reads.py -q -p no:cacheprovider (new): 21 passed. 17 of them fail without the fix.
  • Same command for test_orchestration_action_runtime.py (50 passed), test_m365_runtime_adapters.py (14 passed), test_m365_execution_preflight.py (23 passed), test_m365_approvals_execution.py (42 passed) and test_m365_loader_preflight.py (29 passed).
  • Regression sweep of 78 related files (m365_*, msgraph_*, orchestration action, adapter, dependency, external, executor and recovery suites, app_settings_*, agent_delegation_entrypoints), run before merging V2: Scroll the chat rail as one panel and pop workflow alerts from the bell #1643, which changed only VERSION in Python application code: 63 pass, 6 of them on a lower-parallelism rerun after timing out under machine load. The other 15 also fail on the base branch:
    • 14 fail with the same failing tests on both branches. Causes seen include missing Cosmos credentials in this environment, a copy_action_manifest NameError in test_agent_delegation_entrypoints.py, and an assert_group_role ImportError in test_m365_routes.py.
    • test_orchestration_dependency_imports.py: cold-import probes hit their 180 s timeout under heavy machine load on both branches.

Docs and logging, from the repo root:

  • python .\functional_tests\test_docs_site_quality.py: 6/6 passed.
  • python .\functional_tests\test_docs_app_surface_coverage.py: 7/7 passed.
  • python .\functional_tests\test_logging_tag_standardization.py: fails on nonstandard tags that already exist in workflow modules this PR doesn't touch ([Workflows], [WorkflowResults], [WorkflowAssist], ...). The new [ORCHESTRATION_M365] tag is detected and documented.

V2 UI:

  • npm --prefix .\application\v2_ui run build -- --outDir ..\..\ui_tests\artifacts\orchestration-plan-editor (includes tsc -b): passed.
  • python -m pytest .\ui_tests\test_v2_orchestration_m365_recovery.py -q -p no:cacheprovider (new, Chromium): 6 passed. Removing the notice from the recovery view fails 5 of them, and dropping m365_sources when a failure is read fails the connect test.
  • python -m pytest .\ui_tests\test_v2_orchestration_recovery.py -v -p no:cacheprovider (existing; its RecoveryApi failure is now configurable, with the same default): 32 passed.

Not run: a plan against a live Microsoft 365 tenant. The real sign-in pop-up and Microsoft Graph calls are doubled in these tests.

Documentation

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

Fix docs: ORCHESTRATION_SETTINGS_DOCUMENT_TYPE_FIX.md and ORCHESTRATION_M365_ACTION_CONTEXT_FIX.md. Also updated: the admin orchestration page (Microsoft 365 actions in plans, troubleshooting rows), the Microsoft 365 data guide (Use Microsoft 365 in a plan) and the logging tag reference. No new feature doc.

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

No routes were added or changed. No settings are sent to the browser; step failures carry only allowlisted m365_sources. The connect pop-up navigates to the HTTPS sign-in URL issued by the existing connect route. Tests use placeholder keys.

Paul Lizer (paullizer) and others added 7 commits October 5, 2026 13:52
Settings read from Cosmos DB came back as the SDK's CosmosDict type, while
reads from the shared Redis copy were plain dicts. Orchestration rechecks a
retained external result's access with the current settings and requires
exactly a dict, so a run whose steps all completed could still finish as
partially completed with "A required retained result is unavailable or
changed." Cosmos serves the read whenever another worker is saving settings
(for example the Cosmos throughput autoscale), on cache repair or Redis
fallback, and on every read when Redis is off.

AppSettingsStore now copies Cosmos reads and writes into plain dicts. The
strict orchestration check is unchanged.

Version 0.261.235.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Every Microsoft 365 call from a chat orchestration action step was refused
with m365_context_required before reaching Microsoft Graph. Each step runs
in its own bridged request context, and orchestration never installed the
M365ExecutionContext that chat and workflows create. The plugin returned
the refusal as a function result, so the step reported completed and the
model described the refusal as findings.

An action step for a Microsoft 365 action now gets its own Microsoft 365
request as the signed-in user. It selects only the step's saved action,
removes send, invitation and mark-as-read functions, refuses shared
conversations, and runs the delegated sign-in preflight before the model
or Microsoft Graph is called. The request ID is stable across retries of
the step, so an approval given after a stop applies on retry, and the
retried step's outcome is reported on that approval as a resumed chat's
is.

Sign-in, approval and authorization refusals now stop the step with new
m365_* failures that carry the affected sources. The V2 run details offer
Connect Microsoft 365 for a sign-in stop and link to Approvals for an
approval stop. The Microsoft Graph failure event now logs the refusal code
and source as text.

Version 0.261.236.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
PR microsoft#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>
PR microsoft#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>
The new UI test mounts the real recovery notice and connect flow with
mocked HTTP. It checks that a sign-in stop connects only known sources
with the Microsoft 365 CSRF header and leaves retrying to the user. A
sign-in window closed without a saved sign-in reports it, and one that
cannot report is confirmed by the saved connection. Sign-in stops
without sources link to Profile, approval stops link to Approvals, and
other failures show neither.

RecoveryApi's step failure is now configurable, with the same default,
so the new test reuses the existing harness.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
PR microsoft#1643 took 0.261.236, so the settings fix moves to 0.261.237 and the
Microsoft 365 orchestration fix to 0.261.238. 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>
PR microsoft#1643 took 0.261.236 on paullizer-react-v2-ui. The settings document
type fix is now 0.261.237, and the Microsoft 365 orchestration fix is
0.261.238, in code headers, tests and documentation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer
Paul Lizer (paullizer) merged commit 4f3eacb into microsoft:paullizer-react-v2-ui Oct 5, 2026
9 of 10 checks passed
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 5, 2026
V2 moved to 4f3eacb (VERSION 0.261.238) when #1644 merged: the
orchestration settings store returns plain dicts, which fixes the settings
race, and Microsoft 365 actions now work as chat orchestration plan steps.

Conflicts:
- release_notes.md: keep both sections. This branch's hand-off section sits
  above #1644's; both are headed 0.261.238 until the renumber commit that
  follows moves this branch to 0.261.239.

config.py auto-merged: both sides were at 0.261.238.
functions_orchestration_adapters.py, functions_orchestration_schema.py and
docs/admin/orchestration.md auto-merged; each side's changed lines are kept
unchanged. The merged tree differs from 6fdef66 only in #1644's files;
every file outside those three and the release notes is identical to V2's.
docs/_data/app_surface.yml is unchanged after re-running
scripts/build_docs_inventory.py.

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
V2 reached 0.261.238 when #1644 merged, so this branch moves one above it.
Sets config.py VERSION to 0.261.239 and moves this branch's own 0.261.238
lines to 0.261.239: the hand-off modules' and tests' Version, Implemented in,
MINIMUM_VERSION and assert_app_version_at_least literals, the two route-test
coverage notes, the run adapter test's hand-off refusal note, the two
hand-off rows in docs/admin/orchestration.md, the feature doc and this
branch's release-notes header. #1644's own 0.261.238 lines (its schema
docstring, its Microsoft 365 section and troubleshooting row in
orchestration.md, its fix docs and its release-notes section) are unchanged.
The open V2 PRs claim 0.261.234 (#1639), 0.261.235 (#1637), 0.261.236
(#1638) and 0.261.246 (#1641), none of them 0.261.239.

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 #1644 (orchestration retained-result and
Microsoft 365 action fixes) and published v0.261.237 and v0.261.238,
which this branch used for Phases 1 and 2.

The integration branch's sections are kept exactly as published. This
branch's ten sections shift up two, to v0.261.239 through v0.261.248,
and config.py becomes 0.261.248. 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.

Five files changed on both sides. config.py and the release notes
conflicted on versions only. functions_orchestration_adapters.py,
functions_orchestration_schema.py and docs/admin/orchestration.md
merged cleanly; in the admin page only this branch's five lines about
its own versions were shifted, and #1644's lines about 0.261.237 and
0.261.238 are kept. #1644's new failure codes and build_failure
argument are additive and don't touch the merge capabilities.

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 V2 4f3eacb (0.261.237 orchestration settings document type
fix and 0.261.238 Microsoft 365 actions in orchestration plans).

Conflicts resolved:
- config.py: keep this branch's version; it is renumbered above V2's
  0.261.238 in the next commit.
- release_notes.md: this branch's section on top, then V2's 0.261.238
  and 0.261.237 sections unchanged.

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 0.261.238 after microsoft#1644, which also used 0.261.237. Moves this
branch's version, release-notes heading and every 0.261.237 line it adds
to 0.261.239. V2's own 0.261.237 section and files are unchanged.

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.

1 participant