fix(gate): stop classifying stale-runtime blocks as permission denials (Closes #897) #901

Merged
sysadmin merged 2 commits from fix/issue-897-permission-stale-runtime-classification into master 2026-07-25 06:56:16 -05:00
Owner

Summary

Closes #897.

Stale-runtime and runtime-mode mutation refusals were returned as permission denials: permission_report named a permission the active profile already held and recommended gitea_activate_profile / session switch. That diagnosis is wrong and the recovery is hazardous (#685 reconnect-only; #690/#714 no mid-session role switch).

Changes

  • Typed gate refusals via _build_operation_gate_refusal:
    • blocker_kind=runtime_reconnect_required for master parity staleness (parity heads + reconnect-only action; no permission_report)
    • blocker_kind=runtime_mode_blocked for stable-control runtime blocks (no permission_report)
    • blocker_kind=permission_denied for true profile denials (permission_report retained)
    • Mixed stale + permission: both classes reported under separate fields; still no fabricated missing permission
  • _profile_operation_gate collects all refusal classes (no short-circuit)
  • _profile_permission_block uses the typed builder (covers mark/create/mutation paths)
  • _permission_block_report fails closed as diagnostic_defect when the active profile already holds the op
  • Selected direct gate returns (lease acquire, pr.close, branch.push) updated to the same builder

Tests

pytest tests/test_issue_897_permission_stale_runtime_classification.py tests/test_permission_reports.py -q
# 23 passed, 12 subtests passed

Role matrix: author / reviewer / merger / reconciler — stale+permitted, fresh+forbidden, stale+forbidden, create_issue regression.

Head

  • Branch: fix/issue-897-permission-stale-runtime-classification
  • Commit: 6e6ca9433873056c7a84d2a1ef3590323ea5a636
  • Worktree: branches/issue-897-permission-stale-runtime

Canonical PR state

STATE: author-complete
WHO_IS_NEXT: reviewer
NEXT_ACTION: formal review of head 6e6ca9433873056c7a84d2a1ef3590323ea5a636
## Summary Closes #897. Stale-runtime and runtime-mode mutation refusals were returned as permission denials: `permission_report` named a permission the active profile already held and recommended `gitea_activate_profile` / session switch. That diagnosis is wrong and the recovery is hazardous (#685 reconnect-only; #690/#714 no mid-session role switch). ## Changes - Typed gate refusals via `_build_operation_gate_refusal`: - `blocker_kind=runtime_reconnect_required` for master parity staleness (parity heads + reconnect-only action; **no** `permission_report`) - `blocker_kind=runtime_mode_blocked` for stable-control runtime blocks (**no** `permission_report`) - `blocker_kind=permission_denied` for true profile denials (`permission_report` retained) - Mixed stale + permission: both classes reported under separate fields; still no fabricated missing permission - `_profile_operation_gate` collects all refusal classes (no short-circuit) - `_profile_permission_block` uses the typed builder (covers mark/create/mutation paths) - `_permission_block_report` fails closed as `diagnostic_defect` when the active profile already holds the op - Selected direct gate returns (lease acquire, pr.close, branch.push) updated to the same builder ## Tests ```text pytest tests/test_issue_897_permission_stale_runtime_classification.py tests/test_permission_reports.py -q # 23 passed, 12 subtests passed ``` Role matrix: author / reviewer / merger / reconciler — stale+permitted, fresh+forbidden, stale+forbidden, create_issue regression. ## Head - Branch: `fix/issue-897-permission-stale-runtime-classification` - Commit: `6e6ca9433873056c7a84d2a1ef3590323ea5a636` - Worktree: `branches/issue-897-permission-stale-runtime` ## Canonical PR state ```text STATE: author-complete WHO_IS_NEXT: reviewer NEXT_ACTION: formal review of head 6e6ca9433873056c7a84d2a1ef3590323ea5a636 ```
jcwalker3 added 1 commit 2026-07-25 00:49:06 -05:00
Stale-runtime and runtime-mode mutation refusals previously shared the
permission-denial channel, so permission_report claimed a missing op the
active profile already held and recommended gitea_activate_profile.
Typed blocker_kind payloads report reconnect-only recovery for staleness,
omit permission_report for non-permission gates, and fail closed when a
permission_report would invent a missing permission the profile holds.
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #901
issue: none
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 19262-c1d8c36e6171
worktree: branches/issue-897-permission-stale-runtime
phase: claimed
candidate_head: none
target_branch: master
target_branch_sha: none
last_activity: 2026-07-25T06:04:24Z
expires_at: 2026-07-25T06:14:24Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #901 issue: none reviewer_identity: sysadmin profile: prgs-reviewer session_id: 19262-c1d8c36e6171 worktree: branches/issue-897-permission-stale-runtime phase: claimed candidate_head: none target_branch: master target_branch_sha: none last_activity: 2026-07-25T06:04:24Z expires_at: 2026-07-25T06:14:24Z blocker: none
sysadmin approved these changes 2026-07-25 01:09:16 -05:00
Dismissed
sysadmin left a comment
Owner

Canonical PR State

STATE: reviewer-approved
WHO_IS_NEXT: merger
NEXT_ACTION: merge PR 901 at head 6e6ca94338
NEXT_PROMPT:

Execute sanctioned gitea-merger workflow for PR #901 at head 6e6ca9433873056c7a84d2a1ef3590323ea5a636.

WHAT_HAPPENED: Formal review completed by sysadmin under prgs-reviewer profile. PR #901 correctly addresses #897 by stopping misclassification of stale-runtime and runtime-mode refusals as permission denials.
WHY: All acceptance criteria A-H verified in code and tests. Focused test suite passed cleanly (23 tests).
ISSUE: #897
HEAD_SHA: 6e6ca94338
REVIEW_STATUS: APPROVED
MERGE_READY: true
BLOCKERS: none
VALIDATION: pytest tests/test_issue_897_permission_stale_runtime_classification.py tests/test_permission_reports.py (23 passed)
LAST_UPDATED_BY: sysadmin

NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=4539170d8551c07a


Detailed Review Summary

PR #901 addresses issue #897 by ensuring stale-runtime and runtime-mode refusals are properly classified as system/runtime gate failures rather than profile permission denials.

Key verifications:

  1. Typed blockers: Stale-runtime refusals use blocker_kind=runtime_reconnect_required, runtime-mode refusals use blocker_kind=runtime_mode_blocked, and true profile denials use blocker_kind=permission_denied.
  2. No fabricated permission_report: Stale and runtime-mode refusals do not attach permission_report or claim missing permissions that the active profile already holds.
  3. Sanctioned recovery: Staleness recovery explicitly points to IDE/client session reconnect instead of profile switching.
  4. _permission_block_report integrity: Flags diagnostic_defect: True when active profile holds operation.
  5. Gate collection & cause separation: Stale and permission causes reported distinctly under stale_runtime_reasons and permission_block_reasons.
  6. Regression & Scope: Scoped to gitea_mcp_server.py and tests/test_issue_897_permission_stale_runtime_classification.py. All 23 tests pass cleanly.
## Canonical PR State STATE: reviewer-approved WHO_IS_NEXT: merger NEXT_ACTION: merge PR 901 at head 6e6ca9433873056c7a84d2a1ef3590323ea5a636 NEXT_PROMPT: ```text Execute sanctioned gitea-merger workflow for PR #901 at head 6e6ca9433873056c7a84d2a1ef3590323ea5a636. ``` WHAT_HAPPENED: Formal review completed by sysadmin under prgs-reviewer profile. PR #901 correctly addresses #897 by stopping misclassification of stale-runtime and runtime-mode refusals as permission denials. WHY: All acceptance criteria A-H verified in code and tests. Focused test suite passed cleanly (23 tests). ISSUE: #897 HEAD_SHA: 6e6ca9433873056c7a84d2a1ef3590323ea5a636 REVIEW_STATUS: APPROVED MERGE_READY: true BLOCKERS: none VALIDATION: pytest tests/test_issue_897_permission_stale_runtime_classification.py tests/test_permission_reports.py (23 passed) LAST_UPDATED_BY: sysadmin NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=4539170d8551c07a --- ## Detailed Review Summary PR #901 addresses issue #897 by ensuring stale-runtime and runtime-mode refusals are properly classified as system/runtime gate failures rather than profile permission denials. Key verifications: 1. **Typed blockers**: Stale-runtime refusals use `blocker_kind=runtime_reconnect_required`, runtime-mode refusals use `blocker_kind=runtime_mode_blocked`, and true profile denials use `blocker_kind=permission_denied`. 2. **No fabricated `permission_report`**: Stale and runtime-mode refusals do not attach `permission_report` or claim missing permissions that the active profile already holds. 3. **Sanctioned recovery**: Staleness recovery explicitly points to IDE/client session reconnect instead of profile switching. 4. **`_permission_block_report` integrity**: Flags `diagnostic_defect: True` when active profile holds operation. 5. **Gate collection & cause separation**: Stale and permission causes reported distinctly under `stale_runtime_reasons` and `permission_block_reasons`. 6. **Regression & Scope**: Scoped to `gitea_mcp_server.py` and `tests/test_issue_897_permission_stale_runtime_classification.py`. All 23 tests pass cleanly.
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #901
issue: none
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 19262-c1d8c36e6171
worktree: branches/issue-897-permission-stale-runtime
phase: released
candidate_head: none
target_branch: master
target_branch_sha: none
last_activity: 2026-07-25T06:09:38Z
expires_at: 2026-07-25T06:19:38Z
blocker: manual-release

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #901 issue: none reviewer_identity: sysadmin profile: prgs-reviewer session_id: 19262-c1d8c36e6171 worktree: branches/issue-897-permission-stale-runtime phase: released candidate_head: none target_branch: master target_branch_sha: none last_activity: 2026-07-25T06:09:38Z expires_at: 2026-07-25T06:19:38Z blocker: manual-release
jcwalker3 added 1 commit 2026-07-25 06:42:31 -05:00
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #901
issue: #897
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 18549-06adf7e9875e
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/issue-897-permission-stale-runtime
phase: claimed
candidate_head: 54559aebc3
target_branch: master
target_branch_sha: 715863799f
last_activity: 2026-07-25T11:52:51Z
expires_at: 2026-07-25T12:02:51Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #901 issue: #897 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 18549-06adf7e9875e worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/issue-897-permission-stale-runtime phase: claimed candidate_head: 54559aebc3668f4911943dcad93a3a04a1926789 target_branch: master target_branch_sha: 715863799f7b42521acaa7c2d3636a113bf87cf9 last_activity: 2026-07-25T11:52:51Z expires_at: 2026-07-25T12:02:51Z blocker: none
sysadmin approved these changes 2026-07-25 06:54:08 -05:00
sysadmin left a comment
Owner

Canonical PR State

STATE: reviewer-approved
WHO_IS_NEXT: merger
NEXT_ACTION: merge PR 901 at head 54559aebc3
NEXT_PROMPT:

Execute sanctioned gitea-merger workflow for PR #901 at head 54559aebc3668f4911943dcad93a3a04a1926789 with base master 715863799f7b42521acaa7c2d3636a113bf87cf9.

WHAT_HAPPENED: Fresh independent review at the post-sync head 54559aebc3. The former-head verdict (review 588 at 6e6ca94338) was treated as superseded and was not reused. The update-by-merge was audited, the full effective diff re-read, the focused suite re-run, the full suite run at this head, and its failure set compared against the current master baseline at 715863799f.
WHY: The #897 acceptance criteria hold at this exact head, the branch sync introduced no content of its own, and the full-suite failure set is identical to the master baseline.
ISSUE: #897
HEAD_SHA: 54559aebc3
BASE_SHA: 715863799f
REVIEW_STATUS: APPROVED
MERGE_READY: true
BLOCKERS: none
VALIDATION: focused pytest tests/test_issue_897_permission_stale_runtime_classification.py tests/test_permission_reports.py at 54559aeb -> 23 passed, 12 subtests passed. Full suite at 54559aeb -> 23 failed, 5267 passed, 6 skipped, 926 subtests passed. Master baseline at 715863799f (separate branches/ worktree) -> 23 failed, 5256 passed, 6 skipped, 914 subtests passed. Failure sets compared line-by-line: identical, zero new failures and zero fixed failures; the delta is exactly the 11 new test methods and 12 new subtests this PR adds. Mutation probes: neutering _reason_is_stale_runtime -> 11 failed / 8 passed; restoring the pre-PR short-circuit in _profile_operation_gate -> 1 failed. Live gate probe on gitea_acquire_merger_pr_lease: stale daemon -> blocker_kind=runtime_reconnect_required with no permission_report; runtime-mode block -> blocker_kind=runtime_mode_blocked with no permission_report; profile forbidding gitea.pr.merge -> permission_report with missing_permission=gitea.pr.merge and diagnostic_defect=false.
LAST_UPDATED_BY: sysadmin

NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=3f9d215f6de35cd6


Sync audit (new head)

The head advanced by a merge commit only, with no history rewrite:

  • 54559aeb parents are exactly 6e6ca943 (prior head, first parent) and 715863799f (live base).
  • merge-base --is-ancestor 715863799f 54559aeb succeeds, so the branch contains current base; commits_behind=0, mergeable=true, has_conflicts=false.
  • The merge tree is 7c47ece670a955fa156a0ab31312250d5aa3ca16, byte-identical to git merge-tree --write-tree 6e6ca943 715863799f. The sync therefore carries no conflict-resolution edits and no content of its own.
  • Effective diff versus base is confined to gitea_mcp_server.py and tests/test_issue_897_permission_stale_runtime_classification.py (+749 / -70). Scope matches issue #897; no unrelated files.

Verification of the #897 fix at this head

  1. Typed refusals. _build_operation_gate_refusal emits blocker_kind=runtime_reconnect_required for parity staleness (with startup_head / current_head / live_remote_head / live_stale and reconnect-only recovery), runtime_mode_blocked for stable-control runtime blocks, and permission_denied for genuine profile denials. Verified by live probe against the tool boundary, not only by unit test.
  2. No fabricated missing permission. Stale and runtime-mode refusals attach no permission_report. Mixed causes are separated into stale_runtime_reasons / runtime_mode_reasons and permission_block_reasons, with the full partition under gate_reason_classes.
  3. Reason classifiers match the real strings. Cross-checked every reachable literal: master_parity_gate.parity_block_reasons emits the local-stale text ("started at commit … workspace master is now …; restart the server to load the current capability gates"), the live-stale text ("the daemon is stale relative to live master -- restart/reconnect before mutating"), and the fallback ("server code is stale relative to master (fail closed)") — all classify as stale. stable_control_runtime.assess_runtime_mutation_gate emits unknown-mode, dev-test, dev-worktree-launch, dirty-stable, and alignment texts — all classify as runtime-mode. The two non-blocking parity texts ("startup commit was not captured", "current workspace HEAD could not be read") are unreachable through the gate because parity_block_reasons returns reasons only when stale or live_stale is set.
  4. _permission_block_report integrity. When the active profile already holds the operation it returns missing_permission=None, diagnostic_defect=True, different_mcp_namespace_required=False, and advice that explicitly forbids gitea_activate_profile / role-session switching. A true denial still reports the missing permission with diagnostic_defect=False.
  5. Gate collection. _profile_operation_gate no longer short-circuits; it accumulates parity, runtime-mode, and permission reasons so typed consumers can separate causes, while boolean callers still see a non-empty list.
  6. Recovery direction. The staleness path routes to IDE/client reconnect only, consistent with #685 and with #690/#714 forbidding mid-session role switching.

Non-blocking observations (no change requested)

  • O1 — one gate return in gitea_acquire_merger_pr_lease was not converted. The gitea.pr.merge gate (around gitea_mcp_server.py:14867) still returns the legacy dict with an unconditional permission_report and no blocker_kind, while the gitea.read and gitea.pr.comment gates in the same function were converted. Probed rather than assumed: this path cannot be reached while stale or runtime-mode-blocked, because the preceding gitea.pr.comment gate trips first on those causes and is typed. It is reachable only on a true permission denial, where the legacy payload is semantically correct; the only loss is the blocker_kind / gate_reason_classes labels. No hazardous recovery advice is emitted, so this does not block the merge.
  • O2 — latent classifier gap for namespace re-proof. _reason_is_runtime_mode tests for the substring reproof, but assess_namespace_reproof emits "has not been re-proven since the transport flap …". That text would fall into other and be labelled permission_denied. Currently unreachable: _runtime_mode_block calls runtime_block_reasons(report) without a namespace, so the re-proof branch never contributes reasons on this path. If a future caller passes namespace, the label would be wrong (though _permission_block_report would still mark it diagnostic_defect rather than fabricate a missing permission).
  • O3 — coverage gap on the no-short-circuit change. test_stale_plus_forbidden_op_both_causes_separated patches _profile_operation_gate itself, so it asserts the builder rather than the real accumulation. Restoring the pre-PR short-circuit under mutation left that test green and failed only test_runtime_mode_block_no_permission_report. A test that lets the real gate run with both a stale parity block and a forbidden operation would close this.

Independence and gates

Reviewer identity sysadmin under prgs-reviewer; PR author is jcwalker3, so no self-review. Reviewer namespace parity was green (in_parity=true, mutation_safe=true, startup head 715863799f) both before and after the author phase. Branch protection requires no status checks for master (checks_status=not_required, checks_enabled=false). No unresolved change-requests exist on this PR: the only prior review is 588, an approval at a former head, now correctly reported stale=true with approval_at_current_head=false.

## Canonical PR State STATE: reviewer-approved WHO_IS_NEXT: merger NEXT_ACTION: merge PR 901 at head 54559aebc3668f4911943dcad93a3a04a1926789 NEXT_PROMPT: ```text Execute sanctioned gitea-merger workflow for PR #901 at head 54559aebc3668f4911943dcad93a3a04a1926789 with base master 715863799f7b42521acaa7c2d3636a113bf87cf9. ``` WHAT_HAPPENED: Fresh independent review at the post-sync head 54559aebc3668f4911943dcad93a3a04a1926789. The former-head verdict (review 588 at 6e6ca9433873056c7a84d2a1ef3590323ea5a636) was treated as superseded and was not reused. The update-by-merge was audited, the full effective diff re-read, the focused suite re-run, the full suite run at this head, and its failure set compared against the current master baseline at 715863799f7b42521acaa7c2d3636a113bf87cf9. WHY: The #897 acceptance criteria hold at this exact head, the branch sync introduced no content of its own, and the full-suite failure set is identical to the master baseline. ISSUE: #897 HEAD_SHA: 54559aebc3668f4911943dcad93a3a04a1926789 BASE_SHA: 715863799f7b42521acaa7c2d3636a113bf87cf9 REVIEW_STATUS: APPROVED MERGE_READY: true BLOCKERS: none VALIDATION: focused pytest tests/test_issue_897_permission_stale_runtime_classification.py tests/test_permission_reports.py at 54559aeb -> 23 passed, 12 subtests passed. Full suite at 54559aeb -> 23 failed, 5267 passed, 6 skipped, 926 subtests passed. Master baseline at 715863799f (separate branches/ worktree) -> 23 failed, 5256 passed, 6 skipped, 914 subtests passed. Failure sets compared line-by-line: identical, zero new failures and zero fixed failures; the delta is exactly the 11 new test methods and 12 new subtests this PR adds. Mutation probes: neutering _reason_is_stale_runtime -> 11 failed / 8 passed; restoring the pre-PR short-circuit in _profile_operation_gate -> 1 failed. Live gate probe on gitea_acquire_merger_pr_lease: stale daemon -> blocker_kind=runtime_reconnect_required with no permission_report; runtime-mode block -> blocker_kind=runtime_mode_blocked with no permission_report; profile forbidding gitea.pr.merge -> permission_report with missing_permission=gitea.pr.merge and diagnostic_defect=false. LAST_UPDATED_BY: sysadmin NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; token_fingerprint=3f9d215f6de35cd6 --- ## Sync audit (new head) The head advanced by a merge commit only, with no history rewrite: - `54559aeb` parents are exactly `6e6ca943` (prior head, first parent) and `715863799f` (live base). - `merge-base --is-ancestor 715863799f 54559aeb` succeeds, so the branch contains current base; `commits_behind=0`, `mergeable=true`, `has_conflicts=false`. - The merge tree is `7c47ece670a955fa156a0ab31312250d5aa3ca16`, byte-identical to `git merge-tree --write-tree 6e6ca943 715863799f`. The sync therefore carries no conflict-resolution edits and no content of its own. - Effective diff versus base is confined to `gitea_mcp_server.py` and `tests/test_issue_897_permission_stale_runtime_classification.py` (+749 / -70). Scope matches issue #897; no unrelated files. ## Verification of the #897 fix at this head 1. **Typed refusals.** `_build_operation_gate_refusal` emits `blocker_kind=runtime_reconnect_required` for parity staleness (with `startup_head` / `current_head` / `live_remote_head` / `live_stale` and reconnect-only recovery), `runtime_mode_blocked` for stable-control runtime blocks, and `permission_denied` for genuine profile denials. Verified by live probe against the tool boundary, not only by unit test. 2. **No fabricated missing permission.** Stale and runtime-mode refusals attach no `permission_report`. Mixed causes are separated into `stale_runtime_reasons` / `runtime_mode_reasons` and `permission_block_reasons`, with the full partition under `gate_reason_classes`. 3. **Reason classifiers match the real strings.** Cross-checked every reachable literal: `master_parity_gate.parity_block_reasons` emits the local-stale text ("started at commit … workspace master is now …; restart the server to load the current capability gates"), the live-stale text ("the daemon is stale relative to live master -- restart/reconnect before mutating"), and the fallback ("server code is stale relative to master (fail closed)") — all classify as stale. `stable_control_runtime.assess_runtime_mutation_gate` emits unknown-mode, dev-test, dev-worktree-launch, dirty-stable, and alignment texts — all classify as runtime-mode. The two non-blocking parity texts ("startup commit was not captured", "current workspace HEAD could not be read") are unreachable through the gate because `parity_block_reasons` returns reasons only when `stale` or `live_stale` is set. 4. **`_permission_block_report` integrity.** When the active profile already holds the operation it returns `missing_permission=None`, `diagnostic_defect=True`, `different_mcp_namespace_required=False`, and advice that explicitly forbids `gitea_activate_profile` / role-session switching. A true denial still reports the missing permission with `diagnostic_defect=False`. 5. **Gate collection.** `_profile_operation_gate` no longer short-circuits; it accumulates parity, runtime-mode, and permission reasons so typed consumers can separate causes, while boolean callers still see a non-empty list. 6. **Recovery direction.** The staleness path routes to IDE/client reconnect only, consistent with #685 and with #690/#714 forbidding mid-session role switching. ## Non-blocking observations (no change requested) - **O1 — one gate return in `gitea_acquire_merger_pr_lease` was not converted.** The `gitea.pr.merge` gate (around `gitea_mcp_server.py:14867`) still returns the legacy dict with an unconditional `permission_report` and no `blocker_kind`, while the `gitea.read` and `gitea.pr.comment` gates in the same function were converted. Probed rather than assumed: this path cannot be reached while stale or runtime-mode-blocked, because the preceding `gitea.pr.comment` gate trips first on those causes and is typed. It is reachable only on a true permission denial, where the legacy payload is semantically correct; the only loss is the `blocker_kind` / `gate_reason_classes` labels. No hazardous recovery advice is emitted, so this does not block the merge. - **O2 — latent classifier gap for namespace re-proof.** `_reason_is_runtime_mode` tests for the substring `reproof`, but `assess_namespace_reproof` emits "has not been re-proven since the transport flap …". That text would fall into `other` and be labelled `permission_denied`. Currently unreachable: `_runtime_mode_block` calls `runtime_block_reasons(report)` without a `namespace`, so the re-proof branch never contributes reasons on this path. If a future caller passes `namespace`, the label would be wrong (though `_permission_block_report` would still mark it `diagnostic_defect` rather than fabricate a missing permission). - **O3 — coverage gap on the no-short-circuit change.** `test_stale_plus_forbidden_op_both_causes_separated` patches `_profile_operation_gate` itself, so it asserts the builder rather than the real accumulation. Restoring the pre-PR short-circuit under mutation left that test green and failed only `test_runtime_mode_block_no_permission_report`. A test that lets the real gate run with both a stale parity block and a forbidden operation would close this. ## Independence and gates Reviewer identity `sysadmin` under `prgs-reviewer`; PR author is `jcwalker3`, so no self-review. Reviewer namespace parity was green (`in_parity=true`, `mutation_safe=true`, startup head `715863799f`) both before and after the author phase. Branch protection requires no status checks for `master` (`checks_status=not_required`, `checks_enabled=false`). No unresolved change-requests exist on this PR: the only prior review is 588, an approval at a former head, now correctly reported `stale=true` with `approval_at_current_head=false`.
Owner

adopted_at: 2026-07-25T11:55:56Z
adopted_by_identity: sysadmin
adopted_by_profile: prgs-merger
adopted_from_session_id: 18549-06adf7e9875e
adopted_from_profile: prgs-reviewer
adopted_from_reviewer_identity: sysadmin
adopted_from_comment_id: 16641
adoption_reason: merger-handoff-approved-head

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #901
issue: #897
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 18556-15564104d8f4
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/issue-897-permission-stale-runtime
phase: adopted
candidate_head: 54559aebc3
target_branch: master
target_branch_sha: 715863799f
last_activity: 2026-07-25T11:55:56Z
expires_at: 2026-07-25T12:05:56Z
blocker: none

<!-- mcp-review-lease-adoption:v1 --> adopted_at: 2026-07-25T11:55:56Z adopted_by_identity: sysadmin adopted_by_profile: prgs-merger adopted_from_session_id: 18549-06adf7e9875e adopted_from_profile: prgs-reviewer adopted_from_reviewer_identity: sysadmin adopted_from_comment_id: 16641 adoption_reason: merger-handoff-approved-head <!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #901 issue: #897 reviewer_identity: sysadmin profile: prgs-merger session_id: 18556-15564104d8f4 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/issue-897-permission-stale-runtime phase: adopted candidate_head: 54559aebc3668f4911943dcad93a3a04a1926789 target_branch: master target_branch_sha: 715863799f7b42521acaa7c2d3636a113bf87cf9 last_activity: 2026-07-25T11:55:56Z expires_at: 2026-07-25T12:05:56Z blocker: none
sysadmin merged commit 76f293eb28 into master 2026-07-25 06:56:16 -05:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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