Authoritative cross-role generic queue allocation for controller #840

Closed
opened 2026-07-22 22:58:33 -05:00 by jcwalker3 · 0 comments
Owner

Problem

Controller-owned queue allocation is not authoritative across roles. Observed defects:

  1. gitea_allocate_next_work invoked through gitea-controller binds allocation to role=controller and returns selected=null even when the authoritative dashboard contains eligible author, reviewer, merger, or reconciler work.

  2. gitea_route_task_session does not recognize the generic task type process_work_queue and returns ambiguous_task_stop.

  3. Controller role metadata is inconsistent:

    • gitea_whoami: role=controller
    • control-plane guide: role_kind=reconciler
    • task router: active_role=reconciler
    • allocator: role=controller

Root cause (current code)

  • allocator_service.classify_skip for ROLE_CONTROLLER only accepts reconciler-needed / blocked diagnosis targets, so normal author/reviewer/merger candidates are skipped as "does not require controller".
  • role_session_router.TASK_REQUIRED_ROLE has no process_work_queue entry → fail-closed ambiguous route.
  • Control-plane guide and some paths derive role from permission inference (_role_kind) instead of the declared profile role, so a controller profile can be mislabeled reconciler.

Required behavior

  1. Canonical controller-owned cross-role allocation mode

    • Default when the allocator runs as controller (or with explicit allocation_mode=cross_role).
    • Inspect the complete candidate inventory (pagination completeness already required).
    • Apply canonical ordering and eligibility rules (deps, leases, blocked, terminal path, head_sha pins, ready-gate).
    • Return exactly one authoritative selection containing:
      • selected item (kind, number, title, labels, priority)
      • selected action
      • required role
      • required profile / namespace
      • pinned issue/PR/head identifiers where applicable
      • allocation/lease evidence (preview reasons or apply lease proof)
    • Role isolation: controller routes only — does not perform author, reviewer, merger, or reconciler mutations. Allowed controller actions remain allocate/diagnose/comment; forbidden remain approve/merge/push/create_pr.
  2. Generic queue task type

    • Document and implement process_work_queue (and hyphen alias) in gitea_route_task_session with required_role=controller.
    • Map capability for the task so controller sessions get allowed_current_session.
  3. Normalize controller role metadata to controller

    • gitea_whoami profile.role, control-plane guide role_kind, task router active_role, and allocator role must agree on controller when the active profile declares controller (or profile name contains controller).
    • Do not silently reclassify controller as reconciler from permission inference when the profile declares controller.
  4. Dashboard remains explanatory

    • gitea_workflow_dashboard stays read-only and must never replace allocator selection. Update controller prompt text only if needed to point at cross-role allocate / process_work_queue.

Acceptance criteria

  • Controller cross-role allocate (dry-run) returns a non-null selection when eligible author work exists.
  • Same for eligible reviewer, merger, and reconciler work (each role covered by tests).
  • No eligible work → structured no_safe_work / wait outcome with selected=null.
  • Leased/foreign-owned work is not selected; ownership evidence is present.
  • Dependency-unmet candidates are skipped; next eligible item may win.
  • Reporting limit truncates skip lists only; selection ranks complete inventory (pagination unaffected).
  • Selection payload includes selected item, action, required_role, required_profile/namespace, pins, and lease/preview evidence.
  • gitea_route_task_session(task_type="process_work_queue") under controller returns allowed_current_session (not ambiguous_task_stop).
  • Controller role metadata is consistently controller across whoami, control-plane guide, router active_role, and allocator role.
  • Dashboard remains non-authoritative for assignment.
  • Role isolation preserved: controller allocation does not grant author/reviewer/merger/reconciler mutation rights to the controller session.
  • Focused unit tests cover the cases above.

Affected areas

  • allocator_service.py
  • role_session_router.py
  • task_capability_map.py
  • gitea_mcp_server.py (gitea_allocate_next_work, control-plane guide, role helpers)
  • namespace_workspace_binding.py (controller role kind normalization)
  • workflow_dashboard.py (prompt only if needed)
  • tests/

Non-goals

  • Dashboard self-selection of work
  • Controller performing review/merge/implement mutations
  • Changing role isolation between author/reviewer/merger/reconciler workers

Safety

Fail closed on incomplete inventory, unknown roles, and ownership ambiguity. Never assign raw monitoring incidents.

## Problem Controller-owned queue allocation is not authoritative across roles. Observed defects: 1. `gitea_allocate_next_work` invoked through **gitea-controller** binds allocation to `role=controller` and returns `selected=null` even when the authoritative dashboard contains eligible author, reviewer, merger, or reconciler work. 2. `gitea_route_task_session` does not recognize the generic task type `process_work_queue` and returns `ambiguous_task_stop`. 3. Controller role metadata is inconsistent: - `gitea_whoami`: `role=controller` - control-plane guide: `role_kind=reconciler` - task router: `active_role=reconciler` - allocator: `role=controller` ## Root cause (current code) - `allocator_service.classify_skip` for `ROLE_CONTROLLER` only accepts reconciler-needed / blocked diagnosis targets, so normal author/reviewer/merger candidates are skipped as "does not require controller". - `role_session_router.TASK_REQUIRED_ROLE` has no `process_work_queue` entry → fail-closed ambiguous route. - Control-plane guide and some paths derive role from permission inference (`_role_kind`) instead of the declared profile role, so a controller profile can be mislabeled reconciler. ## Required behavior 1. **Canonical controller-owned cross-role allocation mode** - Default when the allocator runs as controller (or with explicit `allocation_mode=cross_role`). - Inspect the **complete** candidate inventory (pagination completeness already required). - Apply canonical ordering and eligibility rules (deps, leases, blocked, terminal path, head_sha pins, ready-gate). - Return **exactly one** authoritative selection containing: - selected item (kind, number, title, labels, priority) - selected action - required role - required profile / namespace - pinned issue/PR/head identifiers where applicable - allocation/lease evidence (preview reasons or apply lease proof) - Role isolation: controller **routes** only — does not perform author, reviewer, merger, or reconciler mutations. Allowed controller actions remain allocate/diagnose/comment; forbidden remain approve/merge/push/create_pr. 2. **Generic queue task type** - Document and implement `process_work_queue` (and hyphen alias) in `gitea_route_task_session` with `required_role=controller`. - Map capability for the task so controller sessions get `allowed_current_session`. 3. **Normalize controller role metadata to `controller`** - `gitea_whoami` profile.role, control-plane guide `role_kind`, task router `active_role`, and allocator `role` must agree on `controller` when the active profile declares controller (or profile name contains controller). - Do not silently reclassify controller as reconciler from permission inference when the profile declares controller. 4. **Dashboard remains explanatory** - `gitea_workflow_dashboard` stays read-only and must never replace allocator selection. Update controller prompt text only if needed to point at cross-role allocate / process_work_queue. ## Acceptance criteria - [ ] Controller cross-role allocate (dry-run) returns a non-null selection when eligible author work exists. - [ ] Same for eligible reviewer, merger, and reconciler work (each role covered by tests). - [ ] No eligible work → structured no_safe_work / wait outcome with `selected=null`. - [ ] Leased/foreign-owned work is not selected; ownership evidence is present. - [ ] Dependency-unmet candidates are skipped; next eligible item may win. - [ ] Reporting `limit` truncates skip lists only; selection ranks complete inventory (pagination unaffected). - [ ] Selection payload includes selected item, action, required_role, required_profile/namespace, pins, and lease/preview evidence. - [ ] `gitea_route_task_session(task_type="process_work_queue")` under controller returns `allowed_current_session` (not `ambiguous_task_stop`). - [ ] Controller role metadata is consistently `controller` across whoami, control-plane guide, router active_role, and allocator role. - [ ] Dashboard remains non-authoritative for assignment. - [ ] Role isolation preserved: controller allocation does not grant author/reviewer/merger/reconciler mutation rights to the controller session. - [ ] Focused unit tests cover the cases above. ## Affected areas - `allocator_service.py` - `role_session_router.py` - `task_capability_map.py` - `gitea_mcp_server.py` (`gitea_allocate_next_work`, control-plane guide, role helpers) - `namespace_workspace_binding.py` (controller role kind normalization) - `workflow_dashboard.py` (prompt only if needed) - `tests/` ## Non-goals - Dashboard self-selection of work - Controller performing review/merge/implement mutations - Changing role isolation between author/reviewer/merger/reconciler workers ## Safety Fail closed on incomplete inventory, unknown roles, and ownership ambiguity. Never assign raw monitoring incidents.
jcwalker3 added the status:readytype:bug labels 2026-07-22 22:58:34 -05:00
jcwalker3 added status:pr-open and removed status:ready labels 2026-07-22 23:21:17 -05:00
sysadmin removed the status:pr-open label 2026-07-23 00:37:57 -05:00
Sign in to join this conversation.
No labels type:bug
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#840