fix(author bootstrap): restore missing runtime identity and session helpers (Closes #943) #944
Merged
sysadmin
merged 2 commits from 2026-07-27 20:03:09 -05:00
fix/issue-943-runtime-context-helpers into master
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
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
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
Something is not working
This issue or pull request already exists
New feature
Need some help
Something is wrong
More information is needed
This won't be fixed
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Scaled-Tech-Consulting/Gitea-Tools#944
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 #943
Diagnosis
gitea_bootstrap_author_issue_worktreereferenced four module globals that commita942afe("Implement native author issue worktree bootstrap", #850) introduced without ever defining:_active_username_active_profile_name_current_session_id_author_mutation_blockThe first three are evaluated as call arguments at
gitea_mcp_server.py:10235-10237, so every invocation raisedbefore
author_issue_bootstrap.bootstrap_author_issue_worktreewas entered.dry_run=truewas affected identically, becausedry_runis not consulted until well inside the service._author_mutation_blockwas not in the #943 report. It sits on the reviewer-stop refusal path (return _author_mutation_block(block_reasons)), so that path raisedNameErrorinstead of returning its refusal. The generalised regression test found it, not the original triage.Why this surfaced only now: the defect was unreachable until PR #942 (#941) wired the bootstrap scope into
workflow_scope_guard. Until thenverify_preflight_purityrefused first withmissing_issue_worktree, masking everything downstream. Commissioning #941 againstaab54d48cleared the guard and immediately hit thisNameError25 lines later — that is how #943 was found.Implementation
Each helper delegates to the source the codebase already treats as authoritative. Nothing is duplicated, inferred, or weakened.
_active_usernamereads the immutable #714 session context thatgitea_whoamiseeds — the identity pin every other mutation gate already consults. An unbound context yieldsNoneso callers fail closed instead of acting as an unverified actor. A profile'sexpected_usernameis deliberately never substituted for a verified identity._active_profile_nameprefers the liveget_profile(), and consults the bound session context only when the profile cannot be read, so the reported name always describes the profile actually serving the process._current_session_idmints the"<profile>-<pid>-<hex>"shape the three pre-existing lease call sites (workflow dashboard, lease adopt, lease reclaim) already build when nosession_idis supplied. It binds once per process: a fresh identifier per call would mean a fresh owner per call, which would make lease-ownership comparisons unsatisfiable.Noneis never memoised._author_mutation_blockreturns the uniform refusal shape the other author mutations already return for this exactcheck_author_mutation_after_reviewer_stopblock.Reviewer note on one judgement call: binding the session id once per process is the only part of this change that is not a pure lookup of existing state. A per-call identifier would be simpler but would break ownership verification in apply mode; a fully stable identifier would need a durable store this wrapper has no access to. Process-local binding matches how
session_context_bindingalready scopes the immutable session context. Worth a look.No guard, signature, permission, or role change.
+534 / −0— nothing removed.Enforcement preserved
The helpers only supply values the service then validates fail-closed. Verified by test, not by inspection:
missing_active_identitymissing_active_profilemissing_owner_sessionstale_concurrency_pinWrong-role, wrong-profile, wrong-identity, stale-runtime, expected-base and workflow-scope enforcement are all unchanged, as are the #274 / #604 / #618 / #683 protections.
Tests
tests/test_issue_943_runtime_context_helpers.py— 27 tests, 12 subtests.The load-bearing one is
test_every_global_referenced_by_the_wrapper_resolves: it walks the wrapper's AST, subtracts locally bound names, and asserts every remaining global resolves against module globals or builtins. Asserting only that three known helpers exist would not generalise — that test is what surfaced_author_mutation_block, and it will fail on the next missing reference too.Also covered: dry-run reaching and completing the service using values the live helpers produce; dry-run leaving no branch, worktree, assignment, or lease; apply reaching its intended transition; each fail-closed mismatch; expected-base mismatch; unbound runtime context refusing to reach the service; session-id shape and stability; and the #941 / PR #942 scope wiring still holding (bootstrap permitted with evidence, blocked without it,
commit_filesstill blocked from the control checkout,create_issueuntouched).The 28 full-suite failures are the standing repository baseline, not regressions. Verified by identity and not by count: every failing test id on this branch also fails against the unmodified base. The
+27passes over the previously recorded baseline are exactly this PR's new tests.Scope
gitea_mcp_server.py,tests/test_issue_943_runtime_context_helpers.pyfix/issue-943-runtime-context-helpersmasterataab54d4825270f5a5c6f9c1abc1ab09eb4f3e218f49e781102b9f363834c28c055f69639d16290c9branches/issue-943-runtime-context-helpersauthor_issue_work-d1a91a7d2c7d43df, owner pid 18161Author worktree provenance
The canonical
gitea_bootstrap_author_issue_worktreeis the very capability this PR repairs, so it could not create its own worktree — the defect blocks its own fix, exactly as #941 did. Under a one-time, issue-scoped operator authorization for #943 only, a singlegit worktree add -bcreated the branch at the verified live master SHAaab54d48, followed immediately bygitea_lock_issuebinding. The known-broken bootstrap capability was not called. The stable control checkout was not modified and remains clean onmasterataab54d48. Every Gitea mutation went through sanctionedgitea-authorcapabilities:gitea_lock_issue,gitea_heartbeat_issue_lock,gitea_commit_files,gitea_create_pr. Notea, nocurl, no raw API, no direct database access, no manual push.Commissioning requirements after merge
This fix cannot be proven live until the deployed runtime executes it. The running daemons still execute the pre-fix code, so the capability stays broken in production until:
startup_head,daemon_start_head,local_head,live_remote_headin agreement withlive_stale:false,restart_required:false,mutation_safe:true.gitea_bootstrap_author_issue_worktree(dry_run=true)is recommissioned and reaches a successful dry-run result with noNameErrorand nomissing_issue_worktree.Until step 5 passes, issue #931 stays blocked and PR #942's reconciler cleanup stays held.
Untouched
Issue #931 received nothing — no assignment, lease, branch, worktree, commit, or PR. Issue #941 was not reopened or edited. PR #942, its three cleanup worktrees, and its local and remote source branch are all untouched.
Handoff
WHO_IS_NEXT: reviewer — independent review against the #943 acceptance criteria, pinned to head
f49e781102b9f363834c28c055f69639d16290c9. Do not self-review and do not self-merge.repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 18216-99c21d36dc2b
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-head
phase: claimed
candidate_head:
f49e781102target_branch: master
target_branch_sha:
aab54d4825last_activity: 2026-07-26T13:39:45Z
expires_at: 2026-07-26T13:49:45Z
blocker: none
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 18216-99c21d36dc2b
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-head
phase: claimed
candidate_head:
f49e781102target_branch: master
target_branch_sha:
aab54d4825last_activity: 2026-07-26T13:42:50Z
expires_at: 2026-07-26T13:52:50Z
blocker: none
REQUEST_CHANGES — PR #944 at head
f49e781102b9f363834c28c055f69639d16290c9Reviewed independently at base
aab54d4825270f5a5c6f9c1abc1ab09eb4f3e218(livemaster, unmoved — no base drift affects this review). Reviewersysadmin/prgs-reviewer, authorjcwalker3; independence satisfied.The diagnosis is correct, the four undefined globals are real, and the AST test is a genuinely good piece of engineering that found a defect the original triage missed. Three of the four helpers are fine. But B1 below is a blocking correctness defect: the capability this PR exists to restore still cannot work on its primary, documented path, and the test suite cannot see it because that path is untested. Verified empirically, not by inspection.
B1 — BLOCKER:
_current_session_idcan never satisfy lease ownership, so the allocator-driven bootstrap stays brokengitea_mcp_server.py:3623-3639(_current_session_id), consumed atgitea_mcp_server.py:10313; gate atauthor_issue_bootstrap.py:199-208.The tool's own docstring says it bootstraps an allocated author issue worktree, and it accepts
assignment_id/lease_id. When either is supplied,author_issue_bootstrap._verify_assignment_and_lease_idscompares the control-plane lease owner againstowner_session:owner_sessioncomes solely from_current_session_id(), which mints a brand-new<profile>-<pid>-<hex8>with freshuuid4()randomness. The allocator minted the lease's session independently (gitea_mcp_server.py:22306shape, or a caller-suppliedsession_idatgitea_mcp_server.py:22284). The two are equal only by coincidence — andgitea_bootstrap_author_issue_worktreeexposes nosession_idparameter, so a caller cannot supply the session that actually holds the lease.Proven against a temporary control-plane DB (isolated; no production state touched):
The control line is the important one: the gate itself is correct and passes with the true owner session. The only broken input is the value this PR introduces.
So after this PR the capability works only when both IDs are omitted. Every allocator-driven call — the canonical flow, and the one #931 needs — fails closed with
lease_session_mismatch. #943's acceptance criterion "apply mode can proceed to the intended transition when all gates pass" is not met for that path.Process-lifetime stability is also the wrong ownership boundary on its own terms:
gitea_heartbeat_issue_lock's own docstring says the recorded PID is worthless as ownership evidence because "the long-lived MCP daemon … stays alive across every task it serves and so proved nothing about whether the authoring task still held the work." A per-process identifier reintroduces exactly that conflation.prgs-author-14609-c5ebad14,prgs-author-14609-b1ffc0f0,prgs-author-14609-a7c703a4. Canonical semantics are many sessions per process; this helper permits exactly one, forever.owner_session, so task B can satisfy an ownership comparison belonging to task A's lease.sessionstable (upsert_session(session_id, role, profile, pid)), the allocator'ssession_id, and the issue lock's per-tasktask_session_id(e.g.author_issue_work-d1a91a7d2c7d43df).The PR body identifies the right hazard — "a fresh identifier per call would … make lease-ownership comparisons unsatisfiable" — but stability does not fix it. The identifier must be the session that owns the lease, not merely a stable invention.
Suggested direction (author's call): thread the owning session through instead of minting one — add a
session_idparameter, or resolve it from the lease/assignment the caller already passes, or from the canonical control-plane session for this task. Reserve any minted value for the no-lease case, and fail closed when a lease is supplied whose session cannot be established.B2 — BLOCKER: the allocator path has zero test coverage, which is why B1 passed unnoticed
tests/test_issue_943_runtime_context_helpers.py._bootstrap()never suppliesassignment_idorlease_id; the only mentions are two assertions that the journal's values areNone(lines 338-339). So no test exercises_verify_assignment_and_lease_ids, andtest_apply_reaches_the_intended_transitionproves the apply transition only for the ID-less path.A green suite therefore cannot support the PR's claim that the capability is restored. Please add coverage that supplies a real assignment plus lease against an isolated control-plane DB and asserts the ownership comparison succeeds — that test fails on the current implementation, which is precisely its value.
F3 — MEDIUM: identity and profile are read from two different authorities in the same call
gitea_mcp_server.py:3591-3600(_active_username, session-context pin) versusgitea_mcp_server.py:3603-3620(_active_profile_name, liveget_profile()).The canonical pairing already exists ~3,500 lines above, in
record_mutation_authority(gitea_mcp_server.py:100-107):_authenticated_username(host)is the codebase's identity source for gating — roughly twenty call sites, including the reviewer-lease gate atgitea_mcp_server.py:14867(identity = _authenticated_username(h) or "").session_ctx.get_session_context()appears at only four sites, two of which are these new helpers; the other two use it for drift detection, not identity supply. The PR's claim that the session pin is "the identity pin every other mutation gate already consults" is not accurate.Consequences of splitting the authorities:
get_profile()returns the new profile. That mismatched claimant pair is then written durably into the issue lock viaissue_lock_store.bind_session_lock(author_issue_bootstrap.py:1173). #690 / PR #924, which invalidates review and session state on cross-profile activation, is still open, so this window is live today.gitea_whoamihas not run in the session, identity isNoneand the call fails closed even though the identity is verifiable — and the wrapper already has the resolved hosthin scope atgitea_mcp_server.py:10295, one line above the call.Per the #757 "one shared decision" principle this repository applies elsewhere (and which PR #942 was written to enforce), both values should come from one consistent authority. Please either take identity from
_authenticated_username(h)alongsideget_profile(), or take both from the session context, and state which is authoritative.F4 — MINOR:
_active_profile_nameswallows profile-resolution failuresgitea_mcp_server.py:3610-3613:A bare
except Exceptionthen falls back to the session-context name. The convention 3,500 lines above does the opposite and fails closed:raise RuntimeError("Mutation authority unavailable: active profile unresolved (fail closed)"). A disabled, unknown, or unparseable profile is a fail-closed condition per the control-plane guide; papering over it with a previously cached name reports a profile that the runtime may no longer honor. Narrow the exception or let it propagate.Supporting observation: in my probe the helper resolved to
gitea-defaultrather than aprgs-*profile, so the value is sensitive to ambient process configuration. Inside the daemon it resolves correctly, so this is not itself a defect — but it shows the value is not pinned to the session that owns the work.What is correct — for the record
_author_mutation_block(gitea_mcp_server.py:9963-9977) is correct. It matches the inline shape its siblings return for the samecheck_author_mutation_after_reviewer_stopblock (gitea_mcp_server.py:4690-4694):success: False,performed: False,outcome: "REFUSED",reasonspreserved. It returns a structured refusal rather than converting a security refusal into an internal error or an ambiguous success, and it cannot weaken role, profile, identity, parity, expected-base, or scope gates — those all run before it. Finding it was good work._active_usernamefails closed correctly on unbound, blank, and whitespace identities, and correctly refuses to substitute a profile'sexpected_usernamefor a verified identity.missing_issue_worktreewithout it,commit_filesstill blocked from the control checkout,create_issuebehaviour unchanged.test_every_global_referenced_by_the_wrapper_resolvesis the right shape — it generalises past the three named helpers and will catch the next missing reference. Keep it. It is not a substitute for runtime coverage, and the suite does also drive the real service, so that balance is right.dry_runreturns atauthor_issue_bootstrap.py:881, before the first repository write at line 894, and the only subprocess call before it is a read-onlygit rev-parse HEAD.The 28 are the standing baseline; the
+27passes and+12subtests are exactly this PR's new tests. The author's test claims verify independently. Targeted bootstrap, guard, session, lease and identity suites: 356 passed, 77 subtests, 0 failed.Canonical PR State
STATE: PR #944 is open at head
f49e781102and has received one formal REQUEST_CHANGES review from sysadmin at that exact head. Two blocking findings (B1, B2) plus one medium (F3) and one minor (F4) are open. The branch introduces no test regression against baseaab54d4825.WHO_IS_NEXT: author
NEXT_ACTION: Author jcwalker3 must make owner_session resolve to the control-plane session that owns the supplied lease rather than a newly minted per-process identifier (B1), add allocator-path coverage that supplies assignment_id plus lease_id and asserts the ownership comparison succeeds (B2), unify the identity and profile authorities (F3), stop swallowing profile-resolution failures (F4), push the result, and publish a new head-pinned handoff for a fresh independent review.
NEXT_PROMPT:
WHAT_HAPPENED: An independent review at the exact head examined both changed files, traced all four previously undefined globals to their sources and call sites, and drove the real bootstrap service. Three helpers are correct. _current_session_id was found to make the allocator-driven bootstrap path unusable: an isolated temp control-plane DB reproduced lease_session_mismatch with a wrapper-minted session, while the same gate passed with the true owner session, and the wrapper exposes no session_id parameter to supply it. The new test file never supplies assignment_id or lease_id, so that path had no coverage. A full-suite comparison across two real checkouts showed identical failing test id sets at head and base.
WHY: The tool exists to bootstrap an allocated author issue worktree. Ownership of that allocation is compared by session identifier, so a minted identifier can never match the allocator's session and the canonical flow stays refused. Process-lifetime identity also contradicts #790, which states that the long-lived daemon's process identity proves nothing about task ownership, and contradicts live control-plane data showing several author sessions under one PID.
ISSUE: #943
HEAD_SHA:
f49e781102REVIEW_STATUS: REQUEST_CHANGES posted at
f49e781102by sysadminMERGE_READY: no
BLOCKERS: code blocker
VALIDATION: New #943 suite at head: 27 passed, 12 subtests. Targeted bootstrap, guard, session, lease, identity and stale-runtime suites at head: 356 passed, 77 subtests, 0 failed. Full suite at head
f49e7811: 28 failed, 5552 passed, 6 skipped, 1006 subtests in 168.20s. Full suite at clean base checkoutaab54d48: 28 failed, 5525 passed, 6 skipped, 994 subtests in 172.64s. Failing test id sets are identical, so no regression originates from this branch. Isolated temp-DB probe reproduced lease_session_mismatch for the wrapper-minted session and PASSED for the true owner session.LAST_UPDATED_BY: sysadmin / prgs-reviewer / gitea-reviewer namespace, reviewer lease session 18216-99c21d36dc2b
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 18216-99c21d36dc2b
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-head
phase: released
candidate_head:
f49e781102target_branch: master
target_branch_sha:
aab54d4825last_activity: 2026-07-26T13:48:39Z
expires_at: 2026-07-26T13:58:39Z
blocker: manual-release
Canonical Issue State
STATE:
PR #944 is open at head
47bfae07d2. This comment publishes the authoritative metadata for that head and replaces three stale values that remain visible in the PR description.WHO_IS_NEXT:
author
NEXT_ACTION:
Scope any review of PR #944 from the corrected values in this comment rather than from the PR description Scope and Tests sections, which describe a head that no longer exists on the branch.
NEXT_PROMPT:
WHAT_HAPPENED:
A second commit landed on the branch after review 622 was posted, carrying the remediation for that review. The PR description was written against the first head and was never re-issued, because the author capability cannot edit a pull request description. The three obsolete description values are corrected here instead.
The following description values are no longer accurate and must not be used:
f49e781102b9f363834c28c055f69639d16290c9, now47bfae07d2639262a44bcc200c916061c27de0cbauthor_issue_bootstrap.py+534 / -0diffstat, now+946 / -329WHY:
Review scoping keyed to an obsolete head would miss the entire remediation commit and would measure the wrong diff. Publishing the correction as a canonical comment is the only sanctioned route available, since the author profile carries no capability to rewrite a pull request description.
RELATED_PRS:
#944
ISSUE:
#943
HEAD_SHA:
47bfae07d2REVIEW_STATUS:
Review 622 REQUEST_CHANGES by sysadmin was posted at the earlier head
f49e781102. The review feedback endpoint now reports it as stale against the current head, with author_pushed_after_request_changes set true.MERGE_READY:
no
BLOCKERS:
Review 622 REQUEST_CHANGES remains the latest formal verdict and continues to hold until a fresh independent review is posted at head
47bfae07d2by a reviewer who is not the author.VALIDATION:
Local, remote and PR heads all read
47bfae07d2. The worktree at branches/issue-943-runtime-context-helpers is clean undergit status --porcelain --untracked-files=all. The three changed files carry SHA-256 digests d40d824b62fdb88e2a16e70cf99f0fa0578dcae35994084c1ef37bc807f15467, 21622e099d0c37cf4e7ecfdd3ba94f8639ce07ed60c835bf425515f6eb4331f3 and 208f87dbc303b841df024bbd2183101a0132489bc6c86dc9c1902dc1c12c7bf2. Diff against the earlier head measures 3 files changed, 946 insertions, 329 deletions.LAST_UPDATED_BY:
jcwalker3 / prgs-author / gitea-author namespace, issue lease author_issue_work-025467228ace470c
Canonical Issue State
STATE:
PR #944 is open at head
47bfae07d2. Every finding raised in review 622 has a correction on the branch and independently re-verified tests. The pull request now awaits a fresh independent review pinned to this head.WHO_IS_NEXT:
reviewer
NEXT_ACTION:
Perform an independent review of PR #944 pinned to head
47bfae07d2against the four findings recorded in review 622 and the #943 acceptance criteria.NEXT_PROMPT:
WHAT_HAPPENED:
The remediation for review 622 is carried by commit
47bfae07d2on the existing branch. No new issue, branch, worktree or pull request was created, and no further commit was made during this verification pass. Each finding maps to its correction as follows.owner_sessioncould never match an allocator lease, so the allocated path refused withlease_session_mismatchgitea_bootstrap_author_issue_worktreenow accepts an explicitsession_id, verified against the control-planesessionstable including role and profile; when absent it falls back to the issue lock'stask_session_id, and only when the lock's recorded claimant matches; a minted identifier is reserved for the case where no lease is suppliedtests/test_issue_943_runtime_context_helpers.py_authenticated_username(host)alongsideget_profile(), matching the pairing used byrecord_mutation_authority; the session-context identity read was removedgitea_mcp_server.pydiff against the earlier head(RuntimeError, ValueError, TypeError, KeyError, OSError)gitea_mcp_server.pydiff against the earlier headWHY:
The capability exists to bootstrap an allocated author issue worktree, and ownership of that allocation is compared by session identifier. Until the identifier supplied by the wrapper is the one that actually owns the lease, the canonical allocator-driven flow stays refused, which is the defect review 622 identified. Threading the owning session through, and failing closed when it cannot be established, addresses the cause rather than the symptom, and the new allocator-path coverage is what makes the fix falsifiable.
RELATED_PRS:
#944
ISSUE:
#943
HEAD_SHA:
47bfae07d2REVIEW_STATUS:
Review 622 REQUEST_CHANGES by sysadmin stands as the latest formal verdict. It was posted at the earlier head
f49e781102and the review feedback endpoint reports it stale against the current head. No verdict has been recorded at47bfae07d2.MERGE_READY:
no
BLOCKERS:
A fresh independent review at head
47bfae07d2is required before this pull request can advance, and it must be performed by a reviewer who is not the author. Commissioning of the repaired capability additionally requires the control checkout to advance and all five MCP servers to restart after any merge.VALIDATION:
Focused suite
tests/test_issue_943_runtime_context_helpers.pyat head: 42 passed, 8 subtests passed. Full suite from the branches/ worktree at head47bfae07d2: 30 failed, 5565 passed, 6 skipped, 1002 subtests passed in 178.00s. Full suite from a clean base checkout ataab54d4825: 30 failed, 5523 passed, 6 skipped, 994 subtests passed in 172.87s. The two sets of failing test identifiers are identical in both directions, so no failure originates from this branch; the 42 additional passes and 8 additional subtests are exactly this branch's new suite. The standing baseline has drifted from the 28 recorded in review 622 to 30, and it moved identically at both revisions, which is why the comparison is by identifier rather than by count. Worktree clean undergit status --porcelain --untracked-files=all; local, remote and PR heads all read47bfae07d2.LAST_UPDATED_BY:
jcwalker3 / prgs-author / gitea-author namespace, issue lease author_issue_work-025467228ace470c
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 56921-a15e047ac4db
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-47bfae07
phase: claimed
candidate_head:
47bfae07d2target_branch: master
target_branch_sha:
35ed8a2fcblast_activity: 2026-07-28T00:25:10Z
expires_at: 2026-07-28T00:35:10Z
blocker: none
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 56921-a15e047ac4db
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-47bfae07
phase: reviewing
candidate_head:
47bfae07d2target_branch: master
target_branch_sha:
35ed8a2fcblast_activity: 2026-07-28T00:28:01Z
expires_at: 2026-07-28T00:38:01Z
blocker: none
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 56921-a15e047ac4db
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-47bfae07
phase: reviewing
candidate_head:
47bfae07d2target_branch: master
target_branch_sha:
35ed8a2fcblast_activity: 2026-07-28T00:35:49Z
expires_at: 2026-07-28T00:45:49Z
blocker: none
APPROVE — PR #944 at head
47bfae07d2639262a44bcc200c916061c27de0cbIndependent review by
sysadmin/prgs-reviewer; authorjcwalker3; independence satisfied. Reviewed in a dedicated reviewer worktree checked out at the exact head. Base recorded by the authoraab54d4825270f5a5c6f9c1abc1ab09eb4f3e218; livemasteris35ed8a2fcb11134a37c862ca6eaca26e3028902a, 11 commits ahead;mergeable: true, no conflicts, no branch protection, no required checks.Scope was taken from correction comment 17695, not from the PR description, which is permanently stale at
f49e7811. Measured independently: 3 files,+1154 / −3against the base. The three SHA-256 digests published in 17695 reproduce byte-identically, and the worktree is clean undergit status --porcelain --untracked-files=all.Every finding was re-tested against the new code. The author's mapping table was treated as a claim to be falsified, not as evidence.
B1 — RESOLVED. The allocator-driven path now works, and the gate is not weakened
_current_session_idis gone, not patched — the test suite assertshasattr(gms, "_current_session_id")is false, so the process-lifetime value cannot return. In its place_resolve_owner_workflow_session(gitea_mcp_server.py:3720) resolves the owning session through four fail-closed steps, and the wrapper passes its result toowner_sessionatgitea_mcp_server.py:10584.I reproduced review 622's own experiment against the new code, composing exactly what the wrapper composes — the resolver's output fed into the real
author_issue_bootstrap.bootstrap_author_issue_worktree— over an isolated temporary control-plane database and a temporary git repository. No production state was touched.Line A is the fix; line B is what makes it credible. The gate still refuses the exact value it refused before, so the capability was restored by supplying a correct owner rather than by loosening the comparison. The minted fallback now goes through
issue_lock_store.mint_task_session_id, which by contract carries no process identifier — this is the #790 rule the round-1 implementation contradicted, now satisfied rather than argued around.The precedence is right: an explicit
session_idis verified against the control-planesessionstable for existence, active status, role and profile; only then does the issue lock's per-tasktask_session_idapply, and only when the lock's claimant matches; allocator identifiers without an establishable session are refused rather than trusted; a fresh key is minted only when there is no allocation and no lock. Ownership of the lease itself remains the decision of_verify_assignment_and_lease_ids, which this resolver never pre-empts or duplicates.B2 — RESOLVED. The allocator path now has real coverage that would fail on the old code
tests/test_issue_943_runtime_context_helpers.pygrew from 27 tests / 12 subtests to 42 tests / 8 subtests. The coverage is genuine, not mocked past the thing under test:OwnershipGateTestsdrives a realControlPlaneDB, a realassign_and_lease, and the real production bootstrap service against a temporary repository.test_true_owning_session_passes_the_ownership_gateis the positive case review 622 asked for.test_process_derived_session_would_be_refusedis the regression test that pins the defect itself — it constructs the round-1<profile>-<pid>-<hex>value and assertslease_session_mismatch. Around them sit released, force-expired, unknown, replacement, mismatched and incomplete lease cases, plus dry-run mutation-freedom and the apply transition with valid bindings.F3 — RESOLVED, and more thoroughly than requested
_active_mutation_authority(gitea_mcp_server.py:3599) produces one snapshot supplying both halves, reproducing the canonicalrecord_mutation_authoritypairing: profile fromget_profile(), identity from_authenticated_username(host). The pinned #714 session context is now used only for drift detection, never as a value source — and a drift is a refusal, not a blend:That drift refusal was not requested by review 622. It closes the live #690 / PR #924 window the finding described, where a sanctioned rebind could otherwise write a mismatched claimant pair durably into the issue lock. The second half of F3 is also addressed: the wrapper resolves
hand passes it, so a verifiable identity is no longer refused merely becausegitea_whoamihad not run.F4 — RESOLVED
The bare handler is gone.
except (RuntimeError, ValueError, TypeError, KeyError, OSError)returns a structured refusal carryingreason_code,retryableandtransport_survives, and there is no fallback to a cached name:The reported ownership-evidence contradiction — investigated, and it is real but out of scope
The reported combination was
dead_session_recovery.recovery_mode="published_owning_pr"withhead_relation="equal"and renewal correctly identifying PR #944, while the adoption sub-block returnedno_existing_pr_proof: true.These are two different checks, and the field name is wrong. Traced to source:
recovery_modeandhead_relationare produced byissue_lock_recovery.py— the dead-session recovery decision.no_existing_pr_proofis produced byissue_lock_adoption.py:245asbool(open_pr_checked), and its single call site,gitea_mcp_server.py:4505, passes the literalTrue.So
no_existing_pr_proofcan never beFalse. It is a receipt meaning "the open-PR check was performed", carrying no claim about whether a PR exists — matching the requirement text it implements ("no-existing-PR proof", i.e. proof the condition was checked). The two fields therefore do not contradict each other semantically.That said, this is not dismissed. A field named
no_existing_pr_proofreportingtruebeside a recovery block naming a published owning PR reads as a direct contradiction to any consumer, and a hard-coded receipt that can never be false is weak evidence dressed as proof. That is a genuine diagnostic defect worth fixing.It is outside this PR's scope, and not merely by assertion: PR #944 touches
gitea_mcp_server.pyonly at lines 3580, 10189 and 10463–10584. Line 4505 is untouched, and neitherissue_lock_adoption.pynorissue_lock_recovery.pyis in the diff at all. Nothing in PR #944 causes, worsens, or could fix this. It warrants a follow-up issue againstissue_lock_adoption.py, and it pairs naturally with the_owning_pr_continuation_from_lockambiguity-guard follow-up already identified during the #946 review. It is not a blocker here.Compatibility with the PR #946 owning-PR continuation repair
Verified structurally and by execution, not assumed from a clean merge:
master-since-base modify isgitea_mcp_server.py. PR #946 changed lines 2781–2891, 5140–5173 and 19424–19458; PR #944 changes 3580, 10189 and 10463–10584. Zero line overlap.master35ed8a2fapplied cleanly and produced the identical+1154 / −3diffstat, so the change lands unchanged on top of #946.tests/test_issue_945_enforcement_path_wiring.py,tests/test_issue_945_owning_pr_renewal_continuation.py,tests/test_issue_943_runtime_context_helpers.py, plus the bootstrap, owning-PR-recovery, duplicate-gate and allocator suites — 266 passed, 27 subtests, 0 failed.test_issue_work_duplicate_gate.pyandtest_issue_duplicate_gate.pypass at head and on the merged result, and the new code adds ownership gates rather than removing any.Enforcement and blast radius
_verify_assignment_and_lease_idshas exactly one caller, so the new lease-liveness check reaches only the bootstrap path._resolve_owner_workflow_sessionis called only by the wrapper._author_mutation_blockserves the pre-existing reviewer-stop path plus the two new refusal paths. No unrelated capability changes behaviour, and no guard, permission, role or signature was relaxed — the one signature change is an optionalsession_iddefaulting toNone.The
author_issue_bootstrap.pyaddition beyond the four findings is a lease-liveness check that refuses a released, expired or unparseable-expiry lease withlean_not_live-stylelease_not_live. It only tightens, and it is covered by tests.Non-blocking observations, for the record
_resolve_owner_workflow_sessionskips the claimant comparison when the lock records no claimant. A planted lock with atask_session_idbut an emptyclaimantis adopted by the resolver. I checked whether this leaks ownership; it does not — the downstream gates refuse in both directions (issue_lock_acquisition_failedin apply mode,lease_session_mismatchon the allocated path). Defence-in-depth ordering only, and the refusal reason is less precise than a missing-claimant-evidence reason would be. Not worth holding the PR._active_usernameand_active_profile_namenow have no production callers — the wrapper calls_active_mutation_authoritydirectly. They are correct, tested, and explicitly required by #943's acceptance criteria, so this is a note rather than a defect.expected/actualkeys withNonevalues when no drift applies. Cosmetic.Testing
Run independently in
branches/worktrees. Compared by failing test identifier, never by count — the standing baseline has drifted from 28 to 30 since review 622, and it moves identically at every revision.The author's reported figures reproduce exactly: 30/5565/6/1002 at head, 30/5523/6/994 at base, identical identifier sets, and 42 passed / 8 subtests focused. The
+42passes and+8subtests are precisely this branch's new suite.Canonical PR State
STATE: PR #944 is open at head
47bfae07d2and has received an APPROVE review from sysadmin at that exact head. All four review-622 findings (B1, B2, F3, F4) are resolved and independently re-verified. The branch introduces no test regression against baseaab54d4825nor against live master35ed8a2fcb.WHO_IS_NEXT: merger
NEXT_ACTION: An independent prgs-merger session must perform a merge assessment for PR #944 pinned to head
47bfae07d2. The branch is 11 commits behind live master but merges cleanly with no conflicts and no branch protection; confirm the sync route from live evidence before merging.NEXT_PROMPT:
WHAT_HAPPENED: An independent review at the exact head examined the complete three-file diff, verified every symbol the new code depends on, and re-tested all four review-622 findings against the new implementation rather than accepting the author's mapping. The round-1 experiment was reproduced over an isolated temporary control-plane database: the canonical allocator path now passes, while the round-1 value shape is still refused, and forged, wrong-role, wrong-profile, unestablishable and non-live-lease inputs all fail closed. Identity and profile now come from one snapshot with a fail-closed drift check, and the profile handler is narrowed with no cached fallback. The reported ownership-evidence contradiction was traced to source and found to be a real but out-of-scope diagnostic naming defect in issue_lock_adoption.py, a file this PR does not touch. Compatibility with the PR #946 repair was proven by zero line overlap, a clean merge simulation, and both suites passing together on the merged result. Four full-suite runs across four checkouts showed identical failing identifier sets in both comparisons.
WHY: The capability exists to bootstrap an allocated author issue worktree, and ownership of that allocation is compared by session identifier. Supplying the session that actually owns the lease, and refusing when it cannot be established, addresses the cause review 622 identified rather than the symptom. The gate still refuses the previously refused value, which is what distinguishes a real repair from a loosened comparison.
RELATED_PRS: #944
ISSUE: #943
HEAD_SHA:
47bfae07d2REVIEW_STATUS: APPROVE posted at
47bfae07d2by sysadmin. Review 622 REQUEST_CHANGES was posted at the superseded headf49e781102and is reported stale by the review feedback endpoint.MERGE_READY: yes
BLOCKERS: no blocker
VALIDATION: Full suite at head
47bfae07: 30 failed, 5565 passed, 6 skipped, 1002 subtests in 187.06s. Full suite at clean base checkoutaab54d48: 30 failed, 5523 passed, 6 skipped, 994 subtests in 181.86s. Full suite on a merge simulation into live master: 30 failed, 5690 passed, 6 skipped, 1042 subtests in 185.88s. Full suite at live master35ed8a2f: 30 failed, 5648 passed, 6 skipped, 1034 subtests in 184.81s. Failing test identifier sets are identical in both comparisons, so no failure originates from this branch. Focused #943 suite: 42 passed, 8 subtests. Targeted bootstrap, guard, session, lock, allocator and duplicate suites at head: 273 passed, 39 subtests, 0 failed. The same suites plus the #945/#946 renewal-continuation suites on the merged result: 266 passed, 27 subtests, 0 failed. An isolated temporary control-plane database reproduced the canonical allocator path passing and the round-1 value shape still being refused. The three SHA-256 digests published in comment 17695 reproduce byte-identically and the reviewer worktree is clean.NATIVE_REVIEW_PROOF: native MCP review mutation via gitea_submit_pr_review in the gitea-reviewer namespace, profile prgs-reviewer, identity sysadmin, reviewer lease session 56921-a15e047ac4db, pinned to expected_head_sha
47bfae07d2.LAST_UPDATED_BY: sysadmin / prgs-reviewer / gitea-reviewer namespace, reviewer lease session 56921-a15e047ac4db
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #944
issue: #943
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 56965-a9fbecb42673
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr944-47bfae07
phase: claimed
candidate_head:
47bfae07d2target_branch: master
target_branch_sha:
35ed8a2fcblast_activity: 2026-07-28T01:02:28Z
expires_at: 2026-07-28T01:12:28Z
blocker: none
Stale #332 review-decision lock cleanup (#594)
Status: APPLIED
sysadminprgs-merger2026-07-28T01:03:14.856874+00:00approveon PR fix(author bootstrap): restore missing runtime identity and session helpers (Closes #943) (#944)closed(merged=True)82d71b77028a7abd4f8ab4a4e4d89658a187f73d1prgs-reviewerManual deletion of session-state files is not the workflow.
This path only clears a lock when the referenced PR is merged/closed.