Fix workflow document picker loading and make workspace documents per-task - #1284
Conversation
…-task Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…k, fix zero retries Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Heads up for reviewers: this PR touches
Also noted while working here, not fixed: |
Fixes #1282
Problem
Two related problems in the workflow builder (personal and group workspaces), on the Tasks step.
1. The workspace document picker never loaded
Choosing a Document action of
Search,Analyze, orComparerevealed the picker but it never initialized — Tags stayed disabled onLoading tags...forever, the Document dropdown stayed empty, and there were no console errors. Since the picker is the only way to choose documents, document-backed workflows could not be created or edited at all, with no workaround.Root cause:
initializeWorkflowDocumentPicker()is the only caller ofsetEffectiveScopes()/ensureDocumentPickerReady(). It ran only fromopenWorkflowModal(), and returned early whenever the action type wasnone— always true for a new workflow. Thechangehandler on#workflow-document-action-typewasupdateDocumentActionFields(), which only toggles visibility. So nothing ever ran, and the tags button simply kept its static markup. Nothing threw, which is why the console stayed clean.Clicking Refresh selected documents then warned
Select one or more <workspace|group> documents in the picker first.— a downstream symptom, since the empty picker offered nothing to select.2. Workspace documents were workflow-level, not per-task
The Workspace documents card lives in the Tasks step but was bound to the workflow. It did not reset when adding a task or restore when switching back to a configured one. At run time,
_execute_workflow_task_sequence()passedinclude_document_action=task_index == 0, so only task 1 ever received the document action and tasks 2..N always ran with{'type': 'none'}.Changes
Picker lifecycle
handleWorkflowDocumentActionSelectionChanged()bound to both#workflow-document-action-typeand#workflow-analysis-target-mode(the picker card is hidden inRecent documentsmode and must reload when switching back).ensureWorkflowDocumentPickerLoaded(options)drives loads from the live form state.workflowDocumentPickerLoadTokenguards overlapping loads so a stale run cannot apply its scopes or selection, or strand the loading flag.loadTagsForScope()now resolves the tags control instead of returning early, so it can never be left in the initialLoading tags...markup.Refresh button
applySelectedWorkspaceDocumentsToWorkflow()reloads the picker (preserving the current selection) before applying it, and reports what it actually observed — including a distinct message when the scope has no documents. Relabeled Refresh selected documents → Refresh documents in both templates.Per-task workspace documents
Every task now owns its full document configuration: action type, target mode, recent window, picker selection, Compare source/targets, per-document toggle, window unit/size/percent, and retries.
createDefaultWorkflowTaskDocumentAction(),normalizeWorkflowTaskDocumentAction(),readWorkflowDocumentActionFromForm(),applyWorkflowDocumentActionToForm(),serializeWorkflowDocumentAction(),buildWorkflowAnalyzeConfig(),validateWorkflowTaskDocumentAction().syncActiveWorkflowTaskFromEditor()writes the task's action,populateWorkflowTaskEditor()restores it. Validation is per task with task-numbered messages that select the offending task. Task cards and the Review step summarize each task's documents._normalize_workflow_tasks()gainedtask_document_action_normalizeranddefault_document_action(same injectable-callable style already used for task runners).save_personal_workflow()/save_group_workflow()now computefile_syncand the workflow-level action before tasks. Group workflows wrap the normalizer with_apply_group_document_action_scope(), so no task can widen scope beyond the owning group._resolve_workflow_task_document_action()uses the task's own action, and_apply_file_sync_context_to_workflow()now rewrites task-level analyze actions with File Sync changed documents.Backward compatibility
document_actiononto task 1 only, matching how it actually executed.noneafterwards.document_action/analyze, mirrored from the first task whose action is notnone, so the workflow list summary, run-resume path, and existing API consumers are unchanged.tasksfrom a save payload leaves stored tasks untouched, so legacy records are not silently rewritten.Coupled fixes
A
code-reviewpass found four issues that only became reachable once more than one task could carry documents. All four are fixed here:_build_workflow_task_execution_workflow()now normalizes inside the retry attempt, so a stored action that stops validating (admin disables Analyze/Compare, or lowers the document limit) fails that task through the normal retry and failure strategy and is recorded as a failed run item, instead of killing the run with no task-level error.{run_id}:task:{task_id}:document:{doc_id}) and recordtask_id/task_name, so a document that failed in one task is no longer displayed as succeeded because a later task processed it. Legacy single-dispatch runs keep the original id.none, falls back to the full failed set for run items recorded before task scoping, and re-forces group scope per task on group resumes.Retries Per Windowof0was rewritten to1on any task other than the one being edited, becausenormalizeText()coerces numeric0to an empty string. Fixed with an explicit nullish helper.Validation
functional_tests/test_workflow_task_document_actions.py— 16/16 passing. Covers the picker load wiring and token guard, the refresh contract, the per-task frontend model, backend normalization with legacy task-1 inheritance, task-numbered validation errors, group scoping, per-task runner execution and the legacy fallback, File Sync propagation, task-scoped run items, retry containment, resume-failed narrowing, and zero-retries preservation.functional_tests/test_workflow_task_sequence.py— 10/10. Extended for the new runner helper; its exact-version assertion was replaced withassert_app_version_at_leastper the repo's versioning instructions (it was already failing onDevelopment).test_workflow_document_picker_recent_targets.pyandtest_workflow_per_document_analysis_mode.py. Both are back to their baseline pass counts.workspace.htmlandgroup_workspaces.htmland confirmed end to end that choosingSearchresolves the tags control and populates the document list, that adding a task resets the fields and returning restores them, and that Refresh documents preserves the selection without warning.test_workflow*sweep: 21 failures, byte-identical to the pre-change baseline (verified against a cleangit archiveexport of the base commit) — one previously failing file now passes and none regressed.functional_tests/route_tests/all pass. No routes were added or changed.Version
0.250.224→0.250.225, with fix documentation, feature documentation, index entries, and release notes.