Defect A - invariants:
- task_capability_map.ROLE_EXCLUSIVE_TASKS is now the single shared
definition of role-exclusive tasks; the resolver's inline copy is gone
(AC1/AC5 drift surface removed).
- tests: every role-exclusive task must exist in the capability map;
formal-review tasks stay role-exclusive; canonical merger satisfies
merge_pr; canonical reconciler satisfies branch-cleanup tasks
(extends the #722 break-glass invariant suite).
Defect B - unactionable internal_error:
- AC3: gitea_resolve_task_capability records the capability purity
baseline first but stamps _preflight_resolved_role/_task only for an
ALLOWED resolve; a denied resolve clears any stale stamp
(_clear_resolved_capability_stamp) so later mutation preflights key
off the real profile role.
- AC4: _evaluate_pr_review_submission converts
_verify_role_mutation_workspace failures (role binding, stale
runtime) into result reasons with blocker_kind=workspace_role_binding
instead of letting RuntimeError escape as a generic internal_error.
- AC5: _build_runtime_task_capabilities applies the resolver's
role-exclusive filter when given the active role kind and labels each
entry role_filtered/permission_only; matching_configured_profiles
honors declared profile roles for role-exclusive tasks.
Validation: focused suites 22 passed (+48 subtests); adjacent resolver/
runtime/review suites 72 passed; full suite 2929 passed, 6 skipped,
221 subtests (single pre-existing Starlette warning, #682).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
EXCEPTIONAL OPERATOR-AUTHORIZED BREAK-GLASS RECOVERY - incident #722.
Commit 970e68b ("fix: adopt_merger_pr_lease requires merger role") was an
unreviewed direct push that flipped 11 task_capability_map.py entries to
role="merger" instead of the intended 1. Merger profiles forbid the review
permissions, so no configured profile could resolve review_pr / approve_pr /
request_changes_pr (matching_configured_profile was empty repository-wide)
and no fix PR could be formally reviewed. The operator resolved the catch-22
with a one-time break-glass authorization recorded on issue #722
(comment 11918); this commit is the authorized minimum and nothing more.
Changes:
- task_capability_map.py restored to blob 02826af (the preserved intended
correction, local commit c071f8a1): the 10 regressive entries return to
role="reviewer"; adopt_merger_pr_lease keeps role="merger"; merge_pr is
untouched.
- tests/test_task_capability_role_invariants.py added (#723 AC1/AC2):
profile-coverage invariant for formal review tasks, map/router agreement,
merger-only adopt_merger_pr_lease and merge_pr, merger profiles cannot
hold review permissions.
Validation: focused role-mapping tests 72 passed (+22 subtests); full suite
2900 passed, 6 skipped, 1 known warning, 195 subtests.
Recovery step 1 for incident #722; code-defect follow-ups tracked in #723.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EnHNSVQvJ8nCk7KZ9kL4Ym