Repository navigation
fix(orchestrator): repair TestOrchestratorPerformance patch target and the empty plan it was hiding (#13699) - #13731
Conversation
…ask fields (#13699) WorkflowStep has aliased autobot_shared.workflow.WorkflowTask since #6951 Phase 2A, but plan_workflow_steps still passed the retired `id` and `expected_duration_ms` kwargs. Every invocation therefore raised TypeError, was swallowed by the broad handler, and returned an empty plan — the method has produced no steps for any caller since the alias landed. Repoint the three construction sites at `task_id` / `estimated_duration_seconds` (restoring the invariant workflow_templates/ types.py already documents) and log the guard with exc_info so the next such breakage is diagnosable rather than a one-line mystery.
…rtions (#13699) The class patched `orchestrator.config_manager`, which the module does not define — it imports `get_config_manager` and takes an injectable `config_manager` (#13162). Both nodes therefore errored in setup_method and have never run. Inject the config double via the constructor instead, as dependency_injection_test.py does. Two further reasons the bodies would have measured nothing once they ran: GemmaClassificationAgent() raises unless a classification provider is configured and __init__ swallows that into classification_agent = None, so classify_request_complexity short-circuited; and isinstance(steps, list) passes on the empty list plan_workflow_steps was returning. Bind a classification double so the measured path is environment-independent, and assert a real TaskComplexity and a non-empty plan.
✅ SSOT Configuration Compliance: Passing🎉 No hardcoded values detected that have SSOT config equivalents! |
ReviewSelf-review — GitHub refuses an approving review from the PR author, and VerifiedUnit conversion is correct and matches the canonical convention. The four rewrites No caller can regress from the behaviour change. The strengthened assertions hold on both branches. No stale patch targets remain. The only surviving
One risk, accepted deliberately
Not addressed here, by designThe caller-side migration (#13730). Bundling it would mean four modules, missing CI59 checks, 0 failures. All 10 required contexts green or correctly skipped Verdict: merge. |
Closes #13699
Thinking Path
The reported symptom was a bad patch target:
TestOrchestratorPerformance.setup_methodpatches
orchestrator.config_manager, which the module does not define. It importsget_config_manager, andOrchestrator.__init__takes an injectableconfig_manager(#13162) — so the fix is constructor injection, matching
dependency_injection_test.py.That made both nodes run. But the issue's real concern was fake coverage, so I checked
whether the bodies now measure anything. They did not, for two further reasons:
GemmaClassificationAgent()raisesAgentConfigurationErrorunless a classificationprovider is configured, and
_init_classification_agentswallows that intoclassification_agent = None.classify_request_complexitythen short-circuits on theNone branch — so the benchmark timed an early return, and timed a different path
depending on the environment.
assert isinstance(steps, list)passes on the empty list. Asserting a non-empty planinstead turned the test red and exposed a live production bug:
plan_workflow_stepsreturned[]on every call.WorkflowStephas aliasedautobot_shared.workflow.WorkflowTasksince refactor: unify 5 duplicate WorkflowStep/Task/Plan definitions + add first-class prompt/tools fields #6951 Phase 2A (task_id/estimated_duration_seconds), but the method still passed the retiredid/expected_duration_ms, so each invocation raisedTypeErrorinto the broad handler.workflow_templates/types.py:29-31documents the invariant that "everyWorkflowStep(task_id=..., ...)call site constructs a realWorkflowTask" — this wasthe one site never migrated.
So the issue was two layers deep: the tests could not run, and the method they cover
produced nothing.
What Changed
autobot-backend/orchestrator.pyplan_workflow_steps: three construction sites repointed fromid/expected_duration_msto the canonicaltask_id/estimated_duration_seconds.exceptguard now logsexc_info=True, so a future constructor mismatch isdiagnosable rather than a one-line mystery that silently empties every plan.
autobot-backend/performance_benchmarks_test.pysetup_method: injects the config double through the constructor instead of patching anabsent module attribute.
never reaches a provider.
TaskComplexityand a non-empty plan; the concurrent test asserts stepcounts are
> 0rather than merely integer-shaped.#13162comment claiming these entry points route throughllm_service— they do not; the double stays only as a provider guard.Verification
Before — both nodes error at setup, so neither body ever ran:
After:
AC 2 — assertions execute, proven by deliberate failure, not by a green run. Each of
the four assertions was inverted in turn and each fired:
The strongest evidence is unsynthetic: the new
assert stepsfailed for real against thepre-fix orchestrator, which is how the empty-plan bug was found:
AC 3 — no non-existent patch target. The only remaining
patchin the class ispatch.object(self.orchestrator, "llm_service"), an attribute set in_init_core_components.Whole module under the marker CI selects, plus a regression sweep over every area the
orchestrator change touches:
Note: local Python is 3.10 and 19/69 backend deps are absent, so this is not a CI proxy —
CI is the authority on the full suite.
Discovered — out of scope, filed as #13730
Fixing the method exposed that every remaining caller of it is still broken, two ways:
all four production call sites invoke the async planning API without
await(the benchmarkrepaired here is the only awaited caller in the tree), and they read
step.id/step.user_approval_required, whichWorkflowTaskdoes not define. Alsoorchestration/plan_steps_e2e_test.pyhas no assertions and swallows every exception — itpassed throughout the entire period the method returned nothing.
That is a caller-side migration across four modules with real behavioural blast radius, so
it is not bundled here. Chat-request workflow planning is dead end-to-end until #13730
lands; this PR fixes the planner itself and the tests that cover it.
Model Used
Claude Opus 5 (1M context)