fix: make cross-role allocations consumable by independent workers (Closes #843) #845
Open
jcwalker3
wants to merge 2 commits from
fix/issue-843-cross-role-allocation-handoff into master
pull from: fix/issue-843-cross-role-allocation-handoff
merge into: :master
:master
:fix/issue-844-exclude-epic-containers
:fix/issue-842-conflict-fix-lease-lifecycle
:feat/issue-646-policy-guardrail-visibility
:fix/issue-843-cross-role-allocation-handoff
:fix/issue-790-slice-a-heartbeat-policy
:feat/issue-628-autonomous-handoffs-orchestration
:feat/issue-634-readonly-system-health-api
:feat/issue-638-webui-app-shell-phase1
:fix/issue-840-cross-role-queue-allocation
:feat/issue-822-atomic-install-authority-kernel
:feat/issue-633-console-authz-audit-model
:feat/issue-636-inventory-api
:fix/issue-815-preflight-worktree-forwarding
:feat/issue-812-publish-unpublished-commit
:feat/issue-635-project-registry-api
:feat/issue-798-worker-registry-schema
:feat/issue-610-live-remote-parity
:docs/issue-632-web-console-architecture
:fix/issue-760-exact-owner-renewal
:fix/issue-787-kill-segment-separators
:chore/issue-681-preserve-review-session-wip
Labels
Clear labels
allocator
anti-stomp
architecture
bug
chore
codex
concurrency
contamination
control-plane
dashboard
database
design
documentation
enhancement
gitea
glitchtip
important
incident
incident-bridge
integration
jenkins
labels
leases
mcp
mcp-health
mcp-menu
multi-project
mutating
nice-to-have
observability
portability
preflight
protected-branch
queue
read-only
reconnect
recovery
refactor
release
reliability
resumable-review
reviewer
roadmap
safety
security
self-hosted
sentry
stale-runtime
status:blocked
status:in-progress
status:pr-open
status:ready
terminal-lock
testing
tracker
type:bug
type:feature
type:feature
type:guardrail
visibility
workflow
workflow-hardening
workflow-hardening
Controller-owned work allocator
Prevent concurrent LLM session stomping
Architecture / structural design
OpenAI Codex client / workflow session surface
Concurrent session safety
Workflow or session contamination incident
MCP control-plane coordination and allocation authority
MCP operational dashboard/queue view
Internal coordination storage (SQLite/Postgres)
Design / investigation, no implementation
Docs / runbooks
New feature or improvement
Gitea MCP workflow
GlitchTip integration
Operational or process incident requiring durable audit trail
Sentry-to-Gitea incident bridging
Integration testing
Jenkins integration
Label taxonomy management
Lease adopt/release/expire lifecycle
MCP server / tooling
MCP namespace and runtime health
MCP menu surface
Work spanning multiple monitoring projects or Gitea repos
Mutating action; requires gating
Observability, metrics, traces, error reporting
Cross-platform / portability
Shared preflight gates before mutation
Protected branch / stable-branch policy concern
Work queue visibility and allocation
Read-only, no mutation
MCP client reconnect/reload recovery path
Recovery paths for stale/foreign leases
Code refactor / restructure
Release / versioning
Reliability / failure handling
Persist and resume prepared review verdicts across sessions
Reviewer workflow tooling
Roadmap / umbrella issue
Safety rails and fail-closed mutation guards
Security / trust boundary
Self-hosted infrastructure integration
Sentry error monitoring integration
Stale backend daemon / runtime-vs-master parity failures
Issue is blocked
Issue is being worked on
Issue has an open pull request
Issue is ready for work
Terminal review lock (#332) path
Tests / test coverage
Issue tracker hygiene / meta
Bug or defect
Feature or enhancement
Feature or enhancement
Safety gate or guardrail
Workflow state visibility for LLMs/operators
Cross-tool workflow
LLM workflow coordination hardening
LLM workflow coordination hardening
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Scaled-Tech-Consulting/Gitea-Tools#845
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #843
Summary
Controller-created cross-role allocations (e.g.
role=author) remained owned by the allocating controller session. Independent author workers had no sanctioned consume path; when the controller exited the lease becamestale_dead_processand required abandon/reassign instead of a usable handoff.Handoff behavior implemented
apply=trueallocations are marked with durable provenance (cross_role_handoff,handoff_status=pending,required_role, allocating session).gitea_adopt_workflow_leasewithout sharing the controller session identity.stale_dead_process).adopted_by_session_idwith read-after-write evidence.process_work_queue/ allocate results includeconsume_allocationidentifiers and instructions.Remediation for review #515 (F1)
Head
5eb89f8addresses the blocking finding ona6c15af:gitea_adopt_workflow_leaseno longer trusts a caller-suppliedrole((role or active_role)removed). The adopter role is derived authoritatively from the active authenticated profile; a suppliedrolethat does not exactly match the profile-derived role is rejected (no silent accept or reinterpretation), and an underivable profile role fails closed instead of defaulting toauthor.lease_lifecycle.adopt_lease, which now validates handoff provenancerequired_profile/required_namespaceagainst that caller context (fail closed on mismatch).role="author", a supplied-role mismatch is rejected, a foreignrequired_profileis rejected, and the legitimateprgs-authorprofile still consumes the handoff.Files
control_plane_db.py— atomic cross-role handoff consume pathlease_lifecycle.py— sanctioned consume policy + provenance required_profile/required_namespace validation + inspect next-actionallocator_service.py— handoff provenance + consume payloadgitea_mcp_server.py— authoritative profile-derived role binding at the adopt tool boundarytests/test_issue_843_cross_role_handoff.py— focused regression suite incl. MCP-boundary role-binding testsValidation
Scope
Defect A only. Epic/container queue exclusion is recorded as #844 and is not implemented in this PR.
Canonical PR State
Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #845
issue: #843
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 27430-647309de43e2
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-845
phase: claimed
candidate_head:
a6c15afec1target_branch: master
target_branch_sha:
4f3a464a90last_activity: 2026-07-23T06:49:08Z
expires_at: 2026-07-23T06:59:08Z
blocker: none
Review verdict: REQUEST_CHANGES — PR #845 (Closes #843)
Reviewer sysadmin / prgs-reviewer (independent of author jcwalker3). Reviewed the pinned head only.
Most of the implementation is sound: the two-layer consume (
lease_lifecycle.adopt_lease→control_plane_db.adopt_lease) is provenance-driven (no title/session heuristics); the DB CAS transfer runs inside oneBEGIN IMMEDIATEtransaction with rollback-on-exception, so a failed assignment transfer after the lease CAS rolls back cleanly (no partial transfer); second/terminal/expired adoptions fail closed;adopted_by_session_idread-after-write evidence is produced; same-role and genuine-abandonment recovery remain compatible. Scope is clean — no #844 epic/container exclusion is implemented and allocator changes are limited to handoff provenance and the consume payload.BLOCKING FINDING F1 — consume role/profile not authoritatively bound to the caller
gitea_mcp_server.py::gitea_adopt_workflow_lease(~L21148):The cross-role handoff consume gate (
lease_lifecycle.is_pending_cross_role_handoff+control_plane_db.adopt_lease) decides solely onadopter_role == required_role, andadopter_roleis this caller-suppliedrole. Gaps: (1) callerroleoverrides the profile-derivedactive_rolewith no equality assertion; (2) the tool self-gates only on_profile_operation_gate("gitea.read")— it does not enforce therole: "author"thattask_capability_map.py:360declares forgitea_adopt_workflow_lease(contrastdelete_branch, which enforcesrequired_role), nor validate provenancerequired_profile/required_namespaceagainst the caller.Failure scenario: every namespace (prgs-reviewer, prgs-merger, …) holds
gitea.read, so any can callgitea_adopt_workflow_lease(lease_id=<author handoff>, role="author");adopter_rolebecomesauthor, both gates pass, and a non-author session consumes an author allocation — hijacking assignment+lease from the legitimate author (then the second-adoption guard rejects the real author). Defeats #843 AC6 ("wrong role/profile cannot consume") and the "do not trust caller-supplied role/profile/namespace" contract.Missing test:
test_wrong_role_adoption_rejectedonly calls the libraryadopt_lease(role=ROLE_REVIEWER)directly; nothing asserts the MCP boundary rejects a wrong-profile caller supplyingrole="author".Required correction: derive the handoff adopter role authoritatively from the active profile (reject a mismatching caller
role); enforce the capability-map role and/or validate provenancerequired_profile/required_namespaceagainst the caller; add MCP-boundary regression that a reviewer/merger profile cannot consume an author handoff viarole="author".Canonical PR State
STATE: changes-requested
WHO_IS_NEXT: author
NEXT_ACTION: Author binds the cross-role consume role/profile to the authenticated profile at the gitea_adopt_workflow_lease boundary, enforces required-role/profile/namespace, adds the missing wrong-profile MCP-boundary test, then requests fresh review.
NEXT_PROMPT:
WHAT_HAPPENED: Independent reviewer inspected the full diff and surrounding implementation at the pinned head, ran the prescribed validation suite (93 passed), verified atomicity/concurrency/terminal/second-adoption/scope, and found one blocking security + missing-test defect (F1).
WHY: The consume path trusts a caller-supplied
roleand gates only ongitea.read, so a wrong-profile worker can consume an author cross-role handoff, violating #843 AC6 role/profile isolation; the failure mode is untested at the MCP boundary.ISSUE: #843
HEAD_SHA:
a6c15afec1REVIEW_STATUS: REQUEST_CHANGES
MERGE_READY: no
BLOCKERS: F1 — gitea_adopt_workflow_lease does not authoritatively bind consume role/profile to the caller (security role-isolation defect + missing MCP-boundary test)
VALIDATION: pytest tests/test_issue_843_cross_role_handoff.py tests/test_lease_lifecycle.py tests/test_cross_role_queue_allocation.py tests/test_allocator_service.py tests/test_allocator_foreign_lease_exclusion.py → 93 passed (at reviewed head
a6c15afe)LAST_UPDATED_BY: prgs-reviewer (sysadmin)
[THREAD STATE LEDGER]
a6c15afec1Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]
CTH: Author Handoff — remediation for review #515 (F1) complete
Author jcwalker3 / prgs-author, independent of reviewer sysadmin. Review #515 (REQUEST_CHANGES on
a6c15afec1ff3c154541bf65ecc196a317256c72) was confirmed current against the then-live head before remediation; it is now stale against the new head after the remediation push.F1 remediation (consume role/profile not authoritatively bound to the caller)
gitea_mcp_server.py::gitea_adopt_workflow_lease: the(role or active_role)caller-override is removed. The adopter role is derived authoritatively from the active authenticated profile; any suppliedrolethat does not exactly match the profile-derived role is refused fail-closed withoutcome: blocked(no silent accept or reinterpretation), and an underivable profile role fails closed instead of defaulting toauthor.lease_lifecycle.adopt_lease: handoff provenancerequired_profile/required_namespaceare now checked against the authoritative caller context passed from the MCP boundary; a mismatch fails closed. Wrong-role, terminal, second-adoption, CAS atomicity, same-role recovery, and genuine-abandonment recovery behavior are unchanged.MCPBoundaryAdoptRoleBindingTest): reviewer and merger profiles cannot consume an author handoff by supplyingrole="author"; a mismatching supplied role is refused; a foreignrequired_profile(dadeschools-author) is refused; the legitimateprgs-authorprofile consumes the handoff with read-after-write ownership evidence.Verification runs (in
branches/fix-issue-843-cross-role-allocation-handoff)Re-review request
Please perform a fresh independent review of PR #845 at the new pinned head
5eb89f883074cf8ab56461767188e9454ad04a98against issue #843 acceptance criteria and the F1 remediation above.Canonical PR State
[THREAD STATE LEDGER] PR #845 — F1 remediation pushed; fresh review requested
What is true now:
What changed:
a6c15afec1→5eb89f8830(feature-branch push); PR body updated via gitea_edit_prWhat is blocked:
Who/what acts next:
5eb89f8830Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.