feat(mcp): client/session-aware runtime ownership and provenance (Closes #948) #968
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#968
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 #948.
Root cause
Two surfaces computed provenance independently and disagreed about one process.
gitea_get_runtime_contextcalled_is_client_managed_process(), which reads the liveos.environ, and reportedserver_provenance="client_managed".mcp_namespace_health.classify_namespace_probederivedis_client_managedfrom_safe_env_summary(process). That summary is filtered throughSAFE_ENV_KEYS, which contains onlyGITEA_MCP_PROFILE,GITEA_PROFILE_NAME,GITEA_SERVICE,GITEA_EXECUTION_ROLE,GITEA_MCP_CONFIG— and none of the three provenance keys it then looked up. Those lookups could only ever returnNone, so this surface was structurally incapable of returning anything butmanual_launch, for any process, ever.An allowlist whose job is deciding what may be echoed was being used to decide what may be believed.
Underneath that, neither model could name which client or which session owned a runtime. Ownership was inferred from a process environment flag, which the launcher sets once and which says nothing about who owns the process now. So a healthy daemon serving a second client could not be distinguished from a duplicate, and the cohort scan walled every process sharing a profile.
Authoritative provenance model
New module
mcp_worker_identity.py, consulted by runtime context, namespace health, namespace attachment, the fleet/cohort scan, capability resolution, and typed reconnect assessment.It splits two claims the old code ran together:
launch_provenancesession_ownershipis_client_managedstays bound to the launch dimension, so unifying the implementations changes which code decides, not what gets decided — nothing previously refused becomes permitted.Invariants enforced:
UNIQUE worker_identity,NOT UNIQUE role,NOT UNIQUE profile,EXCLUSIVE active lease target.<llm-name>-<UTC-timestamp>-<short-sha>, digest oversha256(client + session_id + timestamp_ns + nonce).BEGIN IMMEDIATE) with fencing epochs.Peer processes use a stricter
declared_onlystrategy: their stdin is not ours to inspect and they inheritGITEA_MCP_PROFILEfrom any shell that exported it, so only an explicit declaration counts.Vocabulary change
Absence of proof is now
unproveninstead of assertedmanual_launch. Both fail closed. The old label claimed a hand-launched terminal process the code had no evidence for, which is why remediation pointed operators at the wrong recovery.Other defects closed
DEFAULT_CLIENTbecomesgeneric; an unidentified client gets host-agnostic steps, andgitea_request_mcp_reconnect(client=...)defaults to resolving the client from the live attachment record. Codex callers keep their exact steps.resolve_bound_remotekeeps a bound namespace on its remote rather than falling through to thedadeschoolslibrary default; a request contradicting the binding is refused.Files changed
mcp_worker_identity.pyassess_provenance, cohort classification, failure scoping, remote bindinggitea_mcp_server.py_is_client_managed_processdelegates; runtime context publishes both dimensions; cohort scan keyed on identity; codex literals removedmcp_namespace_health.pyclassify_namespace_probeconsumes the shared verdict instead of the allowlist-derived onemcp_client_reconnect.pyDEFAULT_CLIENTbecomesgeneric;normalize_clientshares alias resolutiontests/test_issue_948_client_session_provenance.pytests/test_issue_686_manual_mcp_provenance.pydocs/remote-mcp/threat-model{,-anchors}.{md,json}Tests
Full suite, run from a
branches/worktree,-p no:randomly:fa510dd8eada1fbdiffof the failing-ID sets is empty — the 28 are pre-existing at the merge base, proven by that comparison rather than assumed. The +43 passing are the new cases.Deployment
Serving daemons run the code loaded at their boot commit, so the new surfaces appear only after the control checkout advances and the MCP namespaces are reconnected by the operator. No process kill, restart loop, raw API call, fallback transport, or configuration edit is required or performed.
The registry auto-creates at
~/.cache/gitea-tools/control-plane/worker_registry.sqlite3(overrideGITEA_WORKER_REGISTRY_DB). Launchers may optionally setGITEA_MCP_CLIENT,GITEA_MCP_CLIENT_INSTANCE,GITEA_MCP_CLIENT_SESSIONto name themselves; unset values are reported as unknown, never guessed.Mutation accounting
No MCP configuration, session-state file, credential, or runtime process was modified. Under pytest the registry is opened only when a test pins a path, so no test run writes to the operator's registry.
Scope
#948 is a large issue. This PR delivers the authoritative provenance model and the surfaces named in the task: identity, ownership, fencing, liveness, cohort scoping, client naming, remote binding. Issue-lease acquisition through
work_issue(AC9-AC16) and the merge-gate criteria (AC19-AC21) build on this model and are not in this change.Scope boundary with #934: #934 defines provenance for a remote, non-stdio transport and is blocked on #931/#932. This PR governs client/session ownership for the local stdio fleet and leaves every stdio guard in force.
Ready for independent review. Not self-reviewed or self-merged.
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: none
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 59450-a817617163f8
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr968-fa510dd2
phase: claimed
candidate_head: none
target_branch: master
target_branch_sha: none
last_activity: 2026-07-29T07:27:20Z
expires_at: 2026-07-29T07:37:20Z
blocker: none
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: none
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 59450-a817617163f8
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr968-fa510dd2
phase: released
candidate_head: none
target_branch: master
target_branch_sha: none
last_activity: 2026-07-29T07:33:31Z
expires_at: 2026-07-29T07:43:31Z
blocker: manual-release
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: #948
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 82756-059259bef0c8
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr968-fa510dd2
phase: claimed
candidate_head:
fa510dd28dtarget_branch: master
target_branch_sha:
8eada1fbe4last_activity: 2026-07-29T07:48:23Z
expires_at: 2026-07-29T07:58:23Z
blocker: none
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: #948
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 82756-515cd5c58ac7
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr968-fa510dd2
phase: claimed
candidate_head:
fa510dd28dtarget_branch: master
target_branch_sha:
8eada1fbe4last_activity: 2026-07-29T07:59:02Z
expires_at: 2026-07-29T08:09:02Z
blocker: none
Canonical PR State
STATE: APPROVED at head fa510dd28dd5f9ca4f81e5b3048ceab584f0b7d7; formal APPROVE review submitted by sysadmin through the gitea-reviewer namespace.
WHO_IS_NEXT: merger
NEXT_ACTION: A merger session (profile prgs-merger) acquires or adopts the PR lease at head
fa510dd28dand merges PR #968 into master, then closes #948 and cleans up branch feat/issue-948-client-session-provenance.NEXT_PROMPT:
WHAT_HAPPENED: Narrow live-state verification of PR #968 was performed through the gitea-reviewer namespace. A prior reviewer session had recorded gitea_mark_final_review_decision (ready_action approve, ready_expected_head_sha
fa510dd28d) and then released its lease without ever submitting the formal verdict, leaving reviews empty and approval_visible false. This session re-verified every gate from live state, re-acquired the reviewer lease at the pinned head, and submitted the missing formal APPROVE.WHY: The recorded final decision was never converted into a native review, so nothing on the PR proved the approval and no merger could act on it. Submitting the formal verdict at the exact head closes that gap without altering the decision that was already validated.
ISSUE: #948
HEAD_SHA:
fa510dd28dREVIEW_STATUS: APPROVE submitted by sysadmin at head
fa510dd28d. No REQUEST_CHANGES verdict is open on this PR.MERGE_READY: yes — open, mergeable true, approved at the current head, no blocking change requests.
BLOCKERS: none
VALIDATION: Targeted suites executed from a branches/ worktree pinned to head
fa510dd28d— tests/test_issue_948_client_session_provenance.py, tests/test_issue_956_threat_model.py, tests/test_issue_686_manual_mcp_provenance.py — 66 passed, 6 subtests passed. Merge base against live prgs master resolves to8eada1fbe4, matching the base stated in the PR body. Changed surface matches the declared scope exactly: 8 files, +2493/-97, with no out-of-scope paths in the diff. The #956 threat-model anchor guard resolves cleanly at this head, confirming the anchor restamp tracks the line movement this change introduces. The #686 manual-provenance wall assertions remain in force under the new vocabulary; moving tounprovenchanges the label, not what is refused.NATIVE_REVIEW_PROOF: this verdict is a native MCP review mutation submitted through gitea_submit_pr_review on the gitea-reviewer namespace, pinned to expected_head_sha
fa510dd28d. Namespace gitea-reviewer on remote prgs; active profile prgs-reviewer; authenticated identity sysadmin; role reviewer. Repository binding Scaled-Tech-Consulting/Gitea-Tools. PR author jcwalker3; reviewer sysadmin; author and reviewer are distinct accounts. Runtime parity: in_parity true, live_stale false, restart_required false, mutation_safe true, at8eada1fbe4. gitea_resolve_task_capability(task='review_pr') returned allowed_in_current_session true, stop_required false. Reviewer lease session 82756-515cd5c58ac7, worktree branches/review-pr968-fa510dd2 pinned to the head above. Live PR state and native review state were read through gitea_view_pr and gitea_get_pr_review_feedback before this verdict.Substantive basis for approval:
LAST_UPDATED_BY: sysadmin (prgs-reviewer), reviewer lease session 82756-515cd5c58ac7
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: #948
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 82756-515cd5c58ac7
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr968-fa510dd2
phase: released
candidate_head:
fa510dd28dtarget_branch: master
target_branch_sha:
8eada1fbe4last_activity: 2026-07-29T08:00:09Z
expires_at: 2026-07-29T08:10:09Z
blocker: manual-release
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: #948
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 13686-d751649482af
worktree: /Users/jasonwalker/Development/Gitea-Tools
phase: claimed
candidate_head:
fa510dd28dtarget_branch: master
target_branch_sha:
8eada1fbe4last_activity: 2026-07-29T08:28:57Z
expires_at: 2026-07-29T08:38:57Z
blocker: none
Stale #332 review-decision lock cleanup (#594)
Status: APPLIED
sysadminprgs-merger2026-07-29T08:29:51.216814+00:00approveon PR feat(mcp): client/session-aware runtime ownership and provenance (Closes #948) (#968)closed(merged=True)956fa15fe3dab82c8669d5b257406e1e4c14929c5prgs-reviewerManual deletion of session-state files is not the workflow.
This path only clears a lock when the referenced PR is merged/closed.
finalized_at: 2026-07-29T08:30:43Z
finalized_by_identity: sysadmin
finalized_by_profile: prgs-merger
finalized_by_session_id: 13686-d751649482af
finalization_outcome: released
finalization_reason: PR #968 merged at
fa510dd2into master as 956fa15f; merger lease finalizedfinalized_lease_comment_id: 18460
repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #968
issue: #948
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 13686-d751649482af
worktree: /Users/jasonwalker/Development/Gitea-Tools
phase: released
candidate_head:
fa510dd28dtarget_branch: master
target_branch_sha:
8eada1fbe4last_activity: 2026-07-29T08:30:43Z
expires_at: 2026-07-29T08:40:43Z
blocker: PR #968 merged at
fa510dd2into master as 956fa15f; merger lease finalized