Repository navigation
long-running: the four start routes cannot create an operation — create_operation gets estimated_items/context it does not accept (TypeError → 500) #17017
Description
Activity
AC verification against merged
main— 3 of 5 met, issue stays OPENVerified from
origin/mainat31310392df. No branch carries this work; it landed and was never
closed.- A test calls each start route as an admin and shows an operation is created.
NOT MET, and deliberately so — recorded here rather than silently dropped.
Two of the five create an operation:/testing/comprehensive
(test_the_test_suite_route_creates_an_operation_that_records_its_creatorasserts a 200 and
metadata["created_by"] == "root") and/migrate/existing
(test_a_migrated_operation_records_its_creator).
The other three answer 501 on purpose —_not_implementedat:94— because the
operation behind each called a method that exists nowhere. That is tracked as long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023
(open), and it is covered by a test that also asserts nothing is queued
(test_a_start_route_with_no_working_operation_answers_501_and_queues_nothing, parametrised
over/codebase/index,/knowledge-base/populate,/security/scan). An honest 501 is a
better answer than a 500, but it is not this criterion. - The create path passes arguments
create_operationaccepts.CreateOperationRequest
(:184-193) carriesestimated_itemsandcontextas fields of the request object, and
created_by, rather than as stray keyword arguments to a call that never accepted them. - The routes call the create handler directly.
await manager._handle_create_operation(create_request)
(:196), with the reason recorded inline: "not routes[0] of an unmounted router".
grep -n 'routes\[0\]'over the module returns nothing. - The creator is recorded, and security: /api/long-running has no authentication — anyone can start test runs, scans and KB population, or cancel any operation #17010's checks admit the creator as well as admins.
created_byis set on both create paths;_may_see(:99) is creator-or-admin;
_owned_operation(:108) 404s rather than 403s so existence is not disclosed; the
progress socket uses_may_see_id(:120). Cross-user tests exist and pass:
test_another_users_or_an_unowned_operation_is_refused_without_disclosing_it,
test_an_admin_reads_and_cancels_anyones,test_a_resumed_operation_keeps_its_original_creator.
An operation with no recorded creator is an admin's alone, which the list test exercises
with alegacyrow. - Non-admins see and control their own, and the frontend panel works for them again, with a
test. HALF MET.
Backend: yes.GET /carries no admin dependency and filters through_may_see
(:310,:316), andtest_a_non_admin_lists_only_their_own_and_an_admin_lists_allpasses.
Frontend: no evidence either way.grep -rn '17018' autobot-frontend/srcreturns
nothing, and neitheruseOperationsApi.tsnorOperationsPanel.test.tsmentions a
non-admin or creator case. The composable has no admin branch to remove, so the panel
plausibly works for a non-admin now — but this criterion asked for a test, and there is
none, so it is not ticked. fix(security): authenticate nine WebSocket endpoints before accept, owner-scope the overseer and workflow sockets, admin-only /api/long-running (#17009, #17010) #17018 is closed, so its 403 is not the blocker.
autobot-backend/api/long_running_operations_17017_test.py— 15 passed locally. Local passes are
not CI (#17144).Verdict: the TypeError-to-500 defect and the ownership model are delivered and verified. What
keeps this open is one criterion superseded by #17023 and one frontend test that was never
written. Neither is provable from this diff, so neither is ticked.- A test calls each start route as an admin and shows an operation is created.
Classification (for work assignment — not a fix proposal)
- Scope:
api(secondaryfrontend) - Primary files/dirs:
autobot-backend/api/long_running_operations.py(verified on main)autobot-backend/api/long_running_operations_17017_test.py(verified on main)autobot-backend/utils/operation_timeout_integration.py(verified on main)autobot-backend/utils/long_running_operations/operation_manager.py(verified on main)autobot-frontend/src/composables/useOperationsApi.ts(verified on main)autobot-frontend/src/components/operations/__tests__/OperationsPanel.test.ts(verified on main)
- Same-file note:
api/long_running_operations.pyandutils/operation_timeout_integration.pyare shared with long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023 and ws: three unreachable WebSocket surfaces would accept unauthenticated if wired — finish or retire each (gateway adapter, /operations router, websocket_heartbeat) #17011, so under the same-file rule the three go to one session. - Umbrella: no (no sub-issues, no parent).
- Blocked by: long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023 for AC1. The three start routes answer 501 until long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023 wires or retires them, and long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023 is itself gated on an owner ruling for the security-scan route. The frontend non-admin test has nothing visible blocking it.
- Read vs inferred: Read the issue body and its 1 comment (the verification of 2026-09-23: 3 of 5 criteria met), and checked that the paths exist on main. The tests were not re-run.
- Undetermined: whether the remaining frontend criterion should be split off so this issue can close, and whether AC1 is meant to be superseded by long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023. Both are owner calls, and neither is recorded.
Generated by Claude Code
- Scope:
Chunking triage — a proposal, not an assignment
- Proposed priority:
priority: low— not applied — and the priority is moot if the recommended move happens first. - triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639 criterion met: none of the five. Placed as misfiled: not blocking and not "landing now". triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639 recommends moving it out of v0.9.0.
- triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639 bucket: 4 — misfiled (not blocking and not "landing now")
- Umbrella / container: no.
- Pre-filter: ⚠ a merged commit references this issue —
abce3e725c fix(ops): a resumed operation's raw checkpoint never reaches the panel. A reference is not a delivery: verify AC coverage before putting it in a chunk, and consider a closure pass first. - Basis: triage(v0.9.0): release criticality of the 123 open issues — 26 blocking, 36 small, 18 umbrellas, 41 misfiled, 2 undetermined #17639's per-issue row, reused rather than re-derived — "TypeError->500 and ownership delivered; remaining AC1 is carried by long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023 (needs-decision; 3 routes answer an honest 501) and a missing frontend test -> v0.10.0 (re-scope AC1 onto long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023)"
Nothing was relabelled, moved or closed by this pass.
- Proposed priority:
Closure pass — 4 of 5 criteria met. The remaining one is not a regression: three of the four start routes now fail cleanly instead of creating anything. Not closed.
Evidence at
origin/main7adaca8c29.AC2 — the create path passes arguments the handler accepts — MET.
api/long_running_operations.py:185-196no longer callscreate_operation(...)with unsupported keywords. It builds aCreateOperationRequest(:185-194) carryingestimated_items(:190),context(:191) andcreated_by(:193) as model fields, then callsmanager._handle_create_operation(create_request)(:196).
Method note, because I got this wrong first:operation_manager.create_operation(utils/long_running_operations/operation_manager.py:192-201) still accepts none ofestimated_items/context— so grepping forestimated_items=next to that signature reads like the original TypeError surviving. It is a different callee. The receiver decides, not the keyword.AC3 — the routes call the create handler directly, not through
router.routes[0]of an unmounted router — MET.:196carries the comment "#17017: not routes[0] of an unmounted…", and the call is tomanager._handle_create_operation.AC4 and AC5 — the creator is recorded, and #17010's checks admit the creator; non-admins see and control their own — MET, with tests.
:193recordscreated_by. Inapi/long_running_operations_17017_test.py:test_the_creator_reads_and_cancels_their_own(:259),test_another_users_or_an_unowned_operation_is_refused_without_disclosing_it(:268),test_an_admin_reads_and_cancels_anyones(:280),test_a_non_admin_lists_only_their_own_and_an_admin_lists_all(:243), plustest_a_migrated_operation_records_its_creator(:319) andtest_a_resumed_operation_keeps_its_original_creator(:332).AC1 — met for one of four routes, and the test says so
"A test calls each start route as an admin and shows an operation is created."
/testing/comprehensive— creates:test_the_test_suite_route_creates_an_operation_that_records_its_creator(:229)./codebase/index,/knowledge-base/populate,/security/scan— the test that covers them istest_a_start_route_with_no_working_operation_answers_501_and_queues_nothing(:221), parametrised over exactly those three.
So the 500 from a TypeError is gone and three routes now answer 501, queueing nothing. That is a strictly better failure — legible, and not a create path that half-runs — but it is not "an operation is created", and the issue's title is "the four start routes cannot create an operation". Three of four still cannot.
What is left is a scope question, not a bug hunt: whether those three routes are supposed to have working operation functions in v0.9.0, or whether 501 is the accepted answer and AC1 should be narrowed to the one route that creates. Not something I can settle from the repository — the test documents the current behaviour deliberately, which reads as a decision already taken by whoever wrote it, but the criterion was never updated to match.
v0.9.1 triage (classification only — not a fix proposal)
Supplements the earlier classification comment (2026-09-28, comment 5864324099). This comment adds only the pre-filter results, the premise check and new observations. Scope, files, the same-file note and the #17023 blocker stand as recorded there.
- Pre-filter — PRs:
- fix(ops): long-running operations — create works and records its creator, creator-or-admin access, the panel reads real data, unimplemented starts answer 501 (#17017) #17027 is CLOSED-unmerged and targets this issue (title ends
(#17017)). Its content landed via the MERGED vehicle chore(vehicle): land WebSocket auth stack — 4 approved PRs (#16891, #16939, #17018, #17027) #17048 ("land WebSocket auth stack — 4 approved PRs (…fix(ops): long-running operations — create works and records its creator, creator-or-admin access, the panel reads real data, unimplemented starts answer 501 (#17017) #17027)"). Commits carrying#17017are on main (below). - fix(security): authenticate nine WebSocket endpoints before accept, owner-scope the overseer and workflow sockets, admin-only /api/long-running (#17009, #17010) #17018 is CLOSED-unmerged. It targets security(ws): nine WebSocket endpoints accept without authentication — PTY execution, workflow control and KB writes among them #17009/security: /api/long-running has no authentication — anyone can start test runs, scans and KB population, or cancel any operation #17010 and only mentions this issue.
- test(api): no route on /api/long-running can be added without an auth gate (#17010) #17344 and test(api): make the LRO route-auth guard read values, and commit its RED case (#17348) #17350 are MERGED. They are security: /api/long-running has no authentication — anyone can start test runs, scans and KB population, or cancel any operation #17010/tech-debt(guard): the LRO route-auth guard matches names, not semantics, and its RED case is not committed #17348 auth-guard tests that mention this issue and do not target it.
- The rest of the 25 hits are MERGED/CLOSED vehicles and unrelated PRs that match the bare number (e.g. docs(release): land the stranded v0.9.0 changelog and its 103 fragments (#16801) #17328 changelog, fix(security): strip the stray line_number field #17067 reintroduced into .secrets.baseline #17083 secrets baseline). None targets this issue.
- fix(ops): long-running operations — create works and records its creator, creator-or-admin access, the panel reads real data, unimplemented starts answer 501 (#17017) #17027 is CLOSED-unmerged and targets this issue (title ends
- Pre-filter — commits since filing:
- Named files:
abce3e725,878fe65c6,fbe3138d3,9c67dbcf5(allfix(ops) … (#17017)) and866babd39(security(ws): nine WebSocket endpoints accept without authentication — PTY execution, workflow control and KB writes among them #17009). --grep '#17017'adds3efc04514and46a1a38b0(changelog fragments) and61bcd1adcandd814eb875(test diagnostics).- No commits touch
useOperationsApi.tsorOperationsPanel.test.tssince filing.
- Named files:
- Files: as in the earlier comment. On this pass I opened
api/long_running_operations.py(:97-218, :405-425),utils/operation_timeout_integration.py(:158-172, :236-383, :700-716) andutils/long_running_operations/operation_manager.py(:192-201, :451-456). - Premise check (code read on main 80b6200):
- The body's "TypeError → 500" is stale (fixed).
create_operationstill has noestimated_items/contextparameters (operation_manager.py:192-201). The caller now folds both intometadatainstead (operation_timeout_integration.py:170). - The body's "routes index
routes[0]" is stale (fixed). The call ismanager._handle_create_operation(...)(long_running_operations.py:196). - Creator recorded: true (
:193,:262,:382). - Three routes answer 501 via
_not_implemented(:97,:136,:212,:218). This matches the earlier verification.
- The body's "TypeError → 500" is stale (fixed).
- New (not in the issue or earlier comments): the internal, unmounted router in
operation_timeout_integration.pystill calls the now-asyncget_operation/list_operationswithoutawaitat:244,:280,:335and:349. The example at:712does the same.878fe65c6fixed the api-level callers only. The api module's WebSocket awaits correctly (long_running_operations.py:419). As far as grep shows, these handlers are reachable only through the unmounted router (ws: three unreachable WebSocket surfaces would accept unauthenticated if wired — finish or retire each (gateway adapter, /operations router, websocket_heartbeat) #17011). They are not live defects on a served route, but they fall under ws: three unreachable WebSocket surfaces would accept unauthenticated if wired — finish or retire each (gateway adapter, /operations router, websocket_heartbeat) #17011's scope. - Blocked by: long-running: wire the indexing, KB-population, security-scan and code-analysis operations to their existing implementations, or retire them — no parallel implementation #17023 for AC1, unchanged. The frontend test remains unblocked.
- Read vs inferred: Read the issue body and all 3 comments, and opened the files above. Unreachability of the unawaited handlers is inferred from grep:
_handle_websocket_connection/_handle_update_progressare called only fromoperation_timeout_integration.py:378,383. Tests were not run. - Undetermined: whether ws: three unreachable WebSocket surfaces would accept unauthenticated if wired — finish or retire each (gateway adapter, /operations router, websocket_heartbeat) #17011 already covers the unawaited calls on the unmounted router. I did not read ws: three unreachable WebSocket surfaces would accept unauthenticated if wired — finish or retire each (gateway adapter, /operations router, websocket_heartbeat) #17011.
- Collisions within v0.9.1: none found — no other issue in this milestone lists a primary file of this one.
Generated by Claude Code
- Pre-filter — PRs:
AC1 is unsatisfiable as worded — the design changed, and the criterion did not
Verified at
2a6c281760. Four of five criteria are ticked. The open one reads:A test calls each start route as an admin and shows an operation is created.
autobot-backend/api/long_running_operations_17017_test.pyshows why that cannot be met and should not be::229test_the_test_suite_route_creates_an_operation_that_records_its_creator— one route genuinely creates.:221test_a_start_route_with_no_working_operation_answers_501_and_queues_nothing, parametrized over the others — they answer 501 and queue nothing, deliberately.
The file's own summary line is "honest start routes, a create that works, creator-scoped access". So three of the four routes are now honest about having no working operation behind them, which is a better outcome than four routes pretending to create. A test asserting all four create would have to make three of them lie.
This is the correct-the-criterion case, not the unmet case. The criterion was written against the original ambition (make all four work); what shipped answers the defect (they silently did nothing) by splitting the routes into one that works and three that refuse loudly.
Suggested rewording, so this can close on evidence rather than stay open on a sentence the code deliberately contradicts:
A test calls each start route as an admin: the routes with a working operation create one and record its creator; the routes without answer 501 and queue nothing. Both are asserted.
Both halves already exist at
:229and:221. I have not edited the body — the rewording is a judgement about original intent, and that is the author's or owner's to make rather than mine.AC1 as worded contradicts a deliberate, tested design. Posting the evidence and a recommendation rather than ticking or rewording unilaterally.
AC1 reads: "A test calls each start route as an admin and shows an operation is created (currently expected to fail, proving this issue)." It was written as a defect pin — note the parenthetical. The defect it pinned is gone, but what replaced it is not "an operation is created" for all four routes.
Verified against merged
origin/main:Three of the four routes answer 501 by design, and a test asserts it.
autobot-backend/api/long_running_operations.py:95-97defines_not_implemented, whose docstring states the intent outright: "501 for a start route with no working operation behind it; nothing is queued (#17017, #17023)." The detail string names #17023 as the issue that will implement them.autobot-backend/api/long_running_operations_17017_test.py:212-226pins exactly that, parametrised over/codebase/index,/knowledge-base/populateand/security/scan— asserting501, asserting#17023appears in the detail, and assertingintegration.operation_manager.operations == {}so nothing is silently queued behind the 501.The fourth route does create an operation, and its test is the one AC1 actually asked for:
test_the_test_suite_route_creates_an_operation_that_records_its_creator, whose docstring records the original failure — "this route raised TypeError inside the create call and answered 500."So this issue's subject is fixed. The title is "create_operation gets estimated_items/context it does not accept (TypeError → 500)". There is no TypeError and no 500 on any of the four routes. What remains is that three routes have no operation behind them yet, which is #17023's scope, not this one's — and the code says so in both the docstring and the response body.
AC1 is therefore unsatisfiable as written while the design is correct. Ticking it would be false; leaving it blocks closure on work that belongs to another issue. The other four criteria are ticked, including creator-recording and the non-admin access path.
Recommendation — reword AC1 to match the delivered design:
A test calls each start route as an admin. The test-suite route creates an operation recording its creator; the other three answer 501 naming #17023 and queue nothing. Both halves are asserted.
That is already true on
main, so the rewording closes the issue rather than opening work.Labelling
needs-decisionrather than applying it. Rewording an acceptance criterion changes what "done" means here, and a criterion deliberately written as a defect pin is exactly the kind whose author may have intended the stricter reading — that all four routes eventually create operations, with closure waiting on #17023. If that was the intent, the correct action is the opposite of mine: keep AC1 and mark this blocked on #17023.The alternative, if rewording is rejected: add a
blocked_byedge to #17023 and leave AC1 untouched. What should not happen is AC1 being ticked against the 501 tests — those assert the absence of the behaviour it describes, and reading a guard as the thing it guards is an error this backlog has produced four times today.- addedneeds-decisionBlocked on an owner decision; options and a recommendation are on the issueBlocked on an owner decision; options and a recommendation are on the issue
on Oct 3, 2026
Found while fixing #17010. The evidence below comes from reading the code; nothing was run.
Problem
The four work-starting routes in
api/long_running_operations.py(/codebase/index,/testing/comprehensive,/knowledge-base/populate,/security/scan) build aCreateOperationRequestand callmanager.router.routes[0].endpoint(create_request). That reachesOperationIntegrationManager._handle_create_operation(utils/operation_timeout_integration.py), which calls:self.operation_managerisLongRunningOperationManager(utils/long_running_operations/operation_manager.py), whosecreate_operationsignature is:It has no
estimated_items, nocontextand no**kwargs. So the call raisesTypeError._handle_create_operationcatches it asExceptionand answers "Internal server error", and the route turns that into "Failed to start operation" (500). Unless something outside these two files adapts the call, none of the four routes can start an operation today.A second point: the routes reach the create handler by indexing
manager.router.routes[0]on a router that is never mounted (#17011). Which route sits at index 0 depends on registration order.Why it matters
This is not a security gap. #17010 makes these routes admin-only. But it is a working-looking feature that cannot work. Once fixed, operations should record their creator (
metadata={"created_by": …}) so #17010's creator-or-admin scoping can replace today's admin-only rule.Acceptance criteria
create_operationaccepts.contextgoes where the operation function needs it, andestimated_itemsis either threaded through or dropped deliberately.router.routes[0]of an unmounted router.useOperationsApi.ts), which fix(security): authenticate nine WebSocket endpoints before accept, owner-scope the overseer and workflow sockets, admin-only /api/long-running (#17009, #17010) #17018 made return 403 to non-admins, works for them again for their own operations, with a test.Related
#17010, #17011, #17009