Repository navigation
Gate personal workflow instruction drafting on the AI workflow assistant setting (N9) - #1596
Merged
Paul Lizer (paullizer) merged 2 commits intoOct 1, 2026
Conversation
…ant setting POST /api/workflows/draft-instructions now refuses personal-scope requests with 403 workflow_assistant_disabled when the Enable AI Workflow Assistant setting is off for the signed-in user. The check runs after the existing personal workflow availability and WorkflowUser role checks, so those responses are unchanged, and no model client is created when it refuses. Group scope keeps following the group workflow settings. The classic personal workspace no longer renders the Task Brief box and Draft Workflow Instructions button when the assistant isn't available to the user. The group workspace is unchanged. VERSION 0.261.215. Refs #1548. Part of #1543. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Brings in paullizer-react-v2-ui at 520132d (Phase 6a, VERSION 0.261.214). Conflicts resolved by hand, without rerere: - config.py: keep VERSION 0.261.215, one above 6a's 0.261.214. - release_notes.md: the v0.261.215 section sits above 6a's v0.261.214 section, which is unchanged byte for byte. route_backend_workflows.py and docs/admin/workflow.md merged cleanly; the diff against V2 is still only this PR's hunks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
marked this pull request as ready for review
October 1, 2026 16:59
Paul Lizer (paullizer)
merged commit Oct 1, 2026
86f3f36
into
paullizer-react-v2-ui
11 checks passed
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 1, 2026
Brings in N9 (the AI workflow assistant gate on personal workflow instruction drafting) so the harness fixes on this branch are rerun against the updated workflows route and workspace template. Refs microsoft#1543 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
14 of 24 tasks
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 1, 2026
Resolves the two conflicts with 0.261.214: - config.py keeps VERSION 0.261.216. - release_notes.md puts the v0.261.216 section above the new v0.261.214 section. Every V2 section is unchanged. route_backend_workflows.py merged without conflicts. Its sanitize_log_message wraps and the extended functions_appinsights import are unchanged. N9 (microsoft#1596, 0.261.215) has not landed on V2 yet. When it does, its release-notes section will need one more merge. 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 1, 2026
Resolves the two conflicts with 0.261.215: - config.py keeps VERSION 0.261.216. - release_notes.md puts the v0.261.216 section above the new v0.261.215 section. Every V2 section is unchanged. route_backend_workflows.py merged without conflicts. N9's import and draft-instructions gate sit above this branch's hunks, so the seven sanitize_log_message wraps moved down 10 lines unchanged, and the extended functions_appinsights import is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
14 of 24 tasks
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 1, 2026
Docs-only status update to the chat orchestration workflows roadmap at paullizer-react-v2-ui 0.261.216: - 6a done in microsoft#1592 (v0.261.214), with where it differs from the plan - workflow_results capability and 6b (6b-1 server, 6b-2 V2) in progress; Retry uses the durable runtime/resume, not /resume-failed; run deep link reuses P's query form through one scope-aware helper - N9 follow-up microsoft#1596 (v0.261.215) and microsoft#1597 log injection fix (v0.261.216) - new follow-ups: microsoft#1598 in review, non_group_invitee product bug, stale base assertions, and the verified cold-import cycle - section 10: branch from paullizer-react-v2-ui, not only base on it Refs microsoft#1543 microsoft#1546 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This was referenced Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
POST /api/workflows/draft-instructionsnow refuses a personal request with 403 when Enable AI Workflow Assistant isn't available to the signed-in user.workflow_assistant_requireddecorator's exact body:{"error": "The AI workflow assistant is not available.", "code": "workflow_assistant_disabled"}._assert_personal_workflow_draft_access(settings), so personal workflows being off (400) and a missingWorkflowUserrole (403) keep today's answers.workspace.html) no longer renders the Task Brief box or the Draft Workflow Instructions button when the assistant isn't available.route_frontend_workspace.pysets one role-aware boolean,enable_workflow_ai_assistant, on the already-sanitizedpublic_settings, using the same helper (is_workflow_assistant_enabled_for_user).group_workspaces.htmlkeep following the group workflow settings, because the setting is documented as personal-only.70c255508and again on the merged head544aed9a3:WorkflowEditorDialog.tsxL261 reads the bootstrap flagfeatures.enable_workflow_ai_assistant === true.askAiAvailable = askAiEnabled && scope.type === 'personal' && !readOnly.draftWithAiis passed only whenaskAiAvailableis true (L587 and L966).WorkflowTaskFields.tsxL1086 renders Draft with AI only whendraftWithAiis set.route_backend_v2.pyL711 on the merged head, L710 on70c255508.Linked issue
Refs #1548
Part of #1543
Release Notes & Latest Features
Is this visible to end users?
When the assistant is off, users no longer see the classic personal Task Brief box or the Draft Workflow Instructions button.
Is this admin-facing (Admin Settings, governance, deployment, config)?
Enable AI Workflow Assistant now governs personal AI drafting on every surface.
Should this become a Latest Feature card?
Screenshot needed for the card?
Version bump
application/single_app/config.pyVERSIONthird segment bumped, or not needed because this is docs-only0.261.214→0.261.215.0.261.214is V2 after Phase 6a (Phase 6a: workflow results reader and Follow up in chat #1592), which has landed; the branch started from0.261.213. The log-injection PR is planned as .216.deployers/version.txtbumped, or not needed becausedeployers/was not changeddeployers/wasn't changed.Testing / validation
Runner. I used the pinned venv
python.exe(Flask 3.1.3) withPYTHONPATH=application/single_app;functional_testsandPYTHONDONTWRITEBYTECODE=1, running one process at a time. The global Python has Flask 2.2.5 with Werkzeug 3.1.4, which can't runtest_client().Post-merge validation (head
544aed9a3)544aed9a3mergesorigin/paullizer-react-v2-uiat520132dc2(the merge of #1592, Phase 6a, VERSION0.261.214) into2bed2f26c.git -c rerere.enabled=false merge, committed with rerere off and pushed as a fast-forward (2bed2f26c..544aed9a3). There was no rebase or force-push, and rerere resolved nothing.config.py: keptVERSION = "0.261.215".docs/explanation/release_notes.md: the v0.261.215 section now sits directly above 6a's v0.261.214. A scripted check confirmed the file equals the V2 tip's file plus this PR's 11-line section, so every existing section, including 6a's, is byte-identical.route_backend_workflows.pyanddocs/admin/workflow.mdmerged automatically. Only this PR's hunks differ from V2: the import (now L122), the gate (about L1621–1630) and the assistant paragraph (L103–110).git diff --shortstat origin/paullizer-react-v2-ui...HEADgives 11 files changed, 825 insertions(+), 15 deletions(-). Only this PR's files appear.544aed9a3. Where a table has two columns, it shows the results from both heads.route_tests/test_workflow_result_context_policy.pypasses.520132dc2.New test
functional_tests/test_workflow_draft_instructions_assistant_gate.pyhas 12 tests.draft_workflow_instructionsandworkspaceroute code is loaded from source withast, registered on a test Flask app and called throughtest_client().workspace.htmlandgroup_workspaces.htmlis rendered with Jinja.2bed2f26c544aed9a3(merged)python -u functional_tests/test_workflow_draft_instructions_assistant_gate.pypython -u -O functional_tests/test_workflow_draft_instructions_assistant_gate.pypython -u -m pytest functional_tests/test_workflow_draft_instructions_assistant_gate.py -q -p no:cacheproviderpython -u -O -m pytest functional_tests/test_workflow_draft_instructions_assistant_gate.py -q -p no:cacheproviderPytestConfigWarningfor-O)Under
-Othe 49 plain asserts are stripped. The harness's 10 explicitraise AssertionErrorchecks still run, including therefuse()fakes that fail the test if the model client or any other unexpected collaborator is created.Coverage:
workflow_assistant_disabled, and the model client is never created or calledWorkflowUserstill needs the assistantworkflow_assistant_requiredMutation checks
The session helper
run_n9_mutations.pyruns each mutation through the test's__main__runner and restores the files afterwards. Result: 15/15 killed, no survivors, files restored byte-identical, on2bed2f26cand again on544aed9a3. The unmutated baseline was 12/12 both times.workflow_assistant_requiredRoute policy
The route already existed, and this PR doesn't change these files.
2bed2f26c544aed9a3(merged)python -u functional_tests/route_tests/test_route_blueprint_policy_inventory.pypython -u functional_tests/route_tests/test_route_unauthenticated_policy_contract.pypython -u functional_tests/route_tests/test_route_policy_test_coverage.pypython -u -m pytest functional_tests/route_tests/test_workflow_result_context_policy.py -q -p no:cacheproviderRelated suites (all pass on both heads)
python -u -m pytest functional_tests/route_tests/test_workflow_assist_policy.py functional_tests/route_tests/test_workflow_flow_inspection_policy.py functional_tests/test_workflow_loop_inputs.py -q -p no:cacheprovider→ 117 passed, 6 subtests passedtest_workflow_assist_limits_runtime.py→ 93 passedtest_group_agent_drafting.py→ 8 passedui_tests/test_workspace_supported_file_types_modal.py(static Jinja parse) → 6 passedtest_v2_documents_explorer.py20/20test_v2_workspace_sections.py8/8test_v2_workflow_ask_ai.py7/7test_agent_modal_instructions_step_order.py6/6test_agent_draft_instructions_context.py8/8test_voice_assisted_authoring.pyOKtest_v2_documents_explorer.pyandtest_v2_workflow_ask_ai.pyskip their TypeScript type-check step, because this worktree has nonode_modules. This PR changes no TypeScript.Docs
2bed2f26c544aed9a3(merged)python .\scripts\build_docs_inventory.pydocs/_data/app_surface.yml; restored, no content changepython -u functional_tests/test_docs_app_surface_coverage.pypython -u functional_tests/test_docs_site_quality.pypython -u functional_tests/test_docs_link_integrity.py70c255508(known base failure)520132dc2; this PR's 2 new links resolvepython -u functional_tests/test_docs_release_notes_integrity.pytest_docs_release_notes_integrity.pyis a known base failure. The generated release-notes pages are stale on base and weren't regenerated here, so the stale list now also names v0.261.215 (151 releases missing from the generated pages, against 150 on the V2 tip).Pre-existing failures
Each one fails identically on temporary detached worktrees at base
70c255508and at the V2 tip520132dc2. I removed both worktrees afterwards.functional_tests/test_workflow_instruction_drafting.py(pytest): L49 expects the wordingworkflow or task instructions.functional_tests/test_workflow_access_controls.py(script): expects 14@enabled_required('allow_user_workflows')route gates.functional_tests/test_model_endpoint_capacity_save_validation.py(pytest):test_capacity_save_routes_fail_safely_before_persistence[True]and[False]fail.functional_tests/test_governance_route_and_wiring_coverage.py(script): 3/4. It expects a literalworkspace_governance = {inroute_frontend_workspace.py.functional_tests/test_v2_admin_workflow_parity.py(script):AttributeError: 'list' object has no attribute 'get'. It's on the known base-failure list.Not run:
ui_tests/test_voice_assisted_form_inputs.py(Playwright; needs a live server).#workflow-task-briefas optional, which is consistent with this change.Workflow or Task Instructions, but base rendersTask Instructions, so that line is stale on base whenever the brief renders.Guardrails
On
544aed9a3, I ranrun_v2_guardrails.py <worktree> 520132dc2323367d61e9455ecc50e82f0d7f5fa1 HEAD n9. It exited 0:Before the merge, the same command against
70c255508also exited 0 with every check passing; python-syntax compiled 488 files then.The malicious-PR report reviewed
520132dc2toHEAD(11 files). Its verdict is "Needs investigation", with no blockers. It has 181 advisory keyword findings, the same set as before the merge:workflow_assistant_disabled), plus test and doc text.ast.literal_eval,getattr,exec(compile(...))andre.compile.exec(compile(...))is the harness pattern that 236 existing functional tests use.Documentation
### **(v0.261.215)**section under Bug Fixes, directly above Phase 6a's v0.261.214. Existing sections are untouched.docs/admin/workflow.md: only the paragraph after the assistant description. The settings-table row and the troubleshooting table are untouched.WORKFLOW_AI_ASSISTANT.md,CHAT_ORCHESTRATION_WORKFLOWS_ROADMAP.md,VOICE_ASSISTED_WORKFLOW_ACTION_CREATION.mddocs/explanation/fixes/WORKFLOW_DRAFT_INSTRUCTIONS_ASSISTANT_GATE_FIX.mdSecurity checklist
@swagger_route(security=get_auth_security())sanitize_settings_for_user()public_settings.Decisions made autonomously
workspace_workflows.jsandform-voice-input.js).enable_workflow_ai_assistantkey on the classic page.allow_user_workflowsandenable_url_access, and the V2 bootstrap uses the same key.CHAT_ORCHESTRATION_WORKFLOWS_ROADMAP.md, about L950) as settled for personal scope, and added notes toVOICE_ASSISTED_WORKFLOW_ACTION_CREATION.md.WORKFLOW_AI_ASSISTANT.md's title version at v0.261.213.git push originattempt succeeded instead of returning the expected 403. The branch is on microsoft/simplechat, so this is a same-repository PR, and nothing was pushed to the fork.CodeQL
CodeQLcheck run on the merged head544aed9a3concluded success: "No new alerts in code changed by this pull request", with 0 annotations.Analyze (python),Analyze (javascript-typescript)andAnalyze (actions)all passed.2bed2f26chad the same result.code-scanning/alerts?pr=1596&state=open) returned none, so there was nothing to fix, and nothing was dismissed.paullizer-react-v2-uiin files this PR touches. I re-checked these against the V2 tip after the merge. All are on lines this PR doesn't change; they aren't fixed here and nothing was dismissed.route_backend_workflows.py:py/stack-trace-exposureAdd Microsoft 365 external tab for chat context and sync #956 and Auto-select Microsoft Graph endpoints from environment settings #957 are this route's existingexcept ValueError/except (LookupError, PermissionError)handlers, which returnstr(exc). They're at L1624 and L1626 on the V2 tip; this PR moves them down 10 lines, to L1634 and L1636, without changing them. The new refusal returns a constant body, so it adds no exposure.py/stack-trace-exposurealerts are in other routes in the file (numbered between Create SimpleChat FAQ agent seeded from official docs #958 and #2896).py/log-injection#2120–#2126 are thelogging.exceptioncalls the log-injection PR (.216) targets.route_frontend_workspace.py:py/polluting-importExtend the XSS PR guardrail to the V2 React/TypeScript UI #1576, Phase 3b: workflow assist endpoint (POST /api/user/workflows/assist) #1577 and #3350 (the existing wildcard imports).config.py: 47py/unused-import, 2py/unused-local-variable, 1py/multiple-definition(#1866) and 1py/import-of-mutable-attribute(#3579). This PR changes only theVERSIONline.templates/workspace.htmland the new test file have no alerts.Follow-ups
test_workflow_instruction_drafting.pyL49 wordingtest_workflow_access_controls.py14-gate counttest_governance_route_and_wiring_coverage.pyworkspace_governance = {markertest_model_endpoint_capacity_save_validation.py(2 cases)test_v2_admin_workflow_parity.pyWorkflow or Task Instructionslabel inui_tests/test_voice_assisted_form_inputs.pyL97 (andtest_workflow_instruction_drafting.pyL60)544aed9a3; see Post-merge validation. The roadmap edit merged without a conflict.config.py, the test header and its version check, the docs' "0.261.215" mentions, the fix doc and the release-notes heading.