Entry point B of #812 is the state where an author's work has already advanced to a local commit: the worktree is registered, clean, on the issue branch, and carries the only copy of the implementation, but the branch has never been published. Two individually correct predicates close a cycle around it: exact-owner lease renewal refuses without an observable remote head, and every publication path is lock-derived under #618, so nothing can create that remote head without first holding the lock renewal would grant.
This adds the missing operation. gitea_publish_unpublished_issue_branch publishes an already-committed local head to its remote branch, so exact-owner renewal has the evidence its model requires. Publication is the whole of its authority: it renews, reclaims, rebinds, and clears nothing.
Why this is not a lock bypass: the operation can only publish a branch whose durable issue-lock record already names the caller as claimant. Ownership is read from the lock file, never asserted by the caller. Guard strictness is unchanged (AC15): a dirty tree, an untracked file the commit does not carry, an unregistered worktree, a non-issue or stable branch, a changed local HEAD, a remote head that is not an ancestor of the commit, a competing open PR for the same issue on another branch, and any declared-hash mismatch each fail closed. The refspec names the commit SHA explicitly and never forces.
Record separation (AC23): the durable issue-lock file and the control-plane workflow lease are distinct records. This reads the former as ownership evidence and writes neither.
Truthful process evidence (AC24): the recorded owner pid's liveness is never consulted or asserted. A regression pins the recorded pid to a live process, proves publication still succeeds, and proves expired-lock reclaim still refuses for that same pid.
Scope is AC20 only. AC21 cannot unblock on its own, so the two are separable and only the smaller one is implemented here.
Tests: 36 new cases against synthetic fixtures only, using a real git repository with a real local bare remote so publication and read-after-write verification are genuinely executed rather than mocked. AC17 is honoured and a regression asserts the protected worktree is never referenced.
Full suite: 11 failed, 4354 passed, 6 skipped, 533 subtests passed. The 11 failures are the documented pre-existing drift baseline at 9eb0f29, unchanged in count and identity.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
174 lines
5.9 KiB
Markdown
174 lines
5.9 KiB
Markdown
# Registered MCP tool inventory
|
|
|
|
This is the canonical list of tools the Gitea-Tools MCP server registers. It
|
|
exists because documentation and the registered inventory drifted: the workflow
|
|
documented a `gitea_edit_issue` tool that no namespace had ever registered, so a
|
|
mutation could be planned against a tool that did not exist and only fail at
|
|
execution time (#781).
|
|
|
|
## The rule
|
|
|
|
**Documentation must never name a tool an actor cannot reach.**
|
|
|
|
Two guards enforce it, both in `tests/test_issue_781_edit_issue_tool.py`:
|
|
|
|
1. The list below must equal the registered tool set exactly — sorted, no
|
|
duplicates, nothing missing in either direction. Adding a tool without
|
|
documenting it fails, and documenting a tool without registering it fails.
|
|
2. Every backticked `gitea_*` / `mcp_*` identifier in `skills/**/*.md` must be a
|
|
registered tool. Module and script names that share the prefix are listed
|
|
explicitly in `mcp_tool_inventory.NON_TOOL_IDENTIFIERS` rather than being
|
|
waved through by a looser pattern.
|
|
|
|
## Updating this file
|
|
|
|
When you add or remove an `@mcp.tool()`, regenerate the block below:
|
|
|
|
```bash
|
|
PYTEST_CURRENT_TEST=1 venv/bin/python -c "
|
|
import mcp_server, mcp_tool_inventory
|
|
print(mcp_tool_inventory.render_inventory_block(
|
|
mcp_server.mcp._tool_manager._tools))
|
|
"
|
|
```
|
|
|
|
Replace everything between the markers with that output. Do not hand-edit
|
|
individual entries — the generator and the guard share one ordering rule.
|
|
|
|
## Registered tools
|
|
|
|
Namespaces (`gitea-tools`, `gitea-reviewer`, `gitea-merger`, `gitea-reconciler`)
|
|
register the same tool set; what differs per namespace is the execution profile
|
|
that gates each call, not which tools exist.
|
|
|
|
<!-- BEGIN REGISTERED TOOL INVENTORY -->
|
|
|
|
- `gitea_abandon_workflow_lease`
|
|
- `gitea_acquire_conflict_fix_lease`
|
|
- `gitea_acquire_merger_pr_lease`
|
|
- `gitea_acquire_reviewer_pr_lease`
|
|
- `gitea_activate_profile`
|
|
- `gitea_adopt_merger_pr_lease`
|
|
- `gitea_adopt_workflow_lease`
|
|
- `gitea_allocate_next_work`
|
|
- `gitea_assess_already_landed_reconciliation`
|
|
- `gitea_assess_conflict_fix_classification`
|
|
- `gitea_assess_conflict_fix_push`
|
|
- `gitea_assess_gitea_operation_path`
|
|
- `gitea_assess_master_parity`
|
|
- `gitea_assess_mcp_namespace_health`
|
|
- `gitea_assess_pr_sync_status`
|
|
- `gitea_assess_review_merge_state_machine`
|
|
- `gitea_assess_reviewer_pr_lease`
|
|
- `gitea_assess_terminal_label_hygiene`
|
|
- `gitea_assess_work_issue_duplicate`
|
|
- `gitea_assess_worktree_cleanup_integrity`
|
|
- `gitea_audit_config`
|
|
- `gitea_audit_runtime_recovery_contamination`
|
|
- `gitea_audit_stable_branch_contamination`
|
|
- `gitea_audit_worktree_cleanup`
|
|
- `gitea_authorize_reconciliation_cleanup_phase`
|
|
- `gitea_authorize_review_correction`
|
|
- `gitea_capability_stop_terminal_report`
|
|
- `gitea_capture_branches_worktree_snapshot`
|
|
- `gitea_check_pr_eligibility`
|
|
- `gitea_cleanup_merged_pr_branch`
|
|
- `gitea_cleanup_obsolete_reviewer_comment_lease`
|
|
- `gitea_cleanup_post_merge_moot_lease`
|
|
- `gitea_cleanup_stale_claims`
|
|
- `gitea_cleanup_stale_review_decision_lock`
|
|
- `gitea_cleanup_terminal_pr_labels`
|
|
- `gitea_close_issue`
|
|
- `gitea_commit_files`
|
|
- `gitea_consume_irrecoverable_decision_lock_provenance`
|
|
- `gitea_create_issue`
|
|
- `gitea_create_issue_comment`
|
|
- `gitea_create_label`
|
|
- `gitea_create_pr`
|
|
- `gitea_delete_branch`
|
|
- `gitea_diagnose_review_decision_lock`
|
|
- `gitea_diagnose_reviewer_pr_lease_handoff`
|
|
- `gitea_diagnose_terminal`
|
|
- `gitea_dry_run_pr_review`
|
|
- `gitea_edit_issue`
|
|
- `gitea_edit_pr`
|
|
- `gitea_expire_workflow_leases`
|
|
- `gitea_get_authenticated_user`
|
|
- `gitea_get_current_user`
|
|
- `gitea_get_file`
|
|
- `gitea_get_pr_review_feedback`
|
|
- `gitea_get_profile`
|
|
- `gitea_get_runtime_context`
|
|
- `gitea_get_shell_health`
|
|
- `gitea_heartbeat_reviewer_pr_lease`
|
|
- `gitea_inspect_workflow_lease`
|
|
- `gitea_issue_irrecoverable_provenance_authorization`
|
|
- `gitea_list_dependency_edges`
|
|
- `gitea_list_issue_comments`
|
|
- `gitea_list_issues`
|
|
- `gitea_list_labels`
|
|
- `gitea_list_profiles`
|
|
- `gitea_list_prs`
|
|
- `gitea_list_workflow_leases`
|
|
- `gitea_load_review_workflow`
|
|
- `gitea_lock_issue`
|
|
- `gitea_mark_final_review_decision`
|
|
- `gitea_mark_issue`
|
|
- `gitea_merge_pr`
|
|
- `gitea_mirror_refs`
|
|
- `gitea_observability_link_issue`
|
|
- `gitea_observability_list_projects`
|
|
- `gitea_observability_reconcile_incident`
|
|
- `gitea_post_heartbeat`
|
|
- `gitea_publish_unpublished_issue_branch`
|
|
- `gitea_quarantine_contaminated_review`
|
|
- `gitea_reclaim_expired_workflow_lease`
|
|
- `gitea_reconcile_already_landed_pr`
|
|
- `gitea_reconcile_issue_claims`
|
|
- `gitea_reconcile_merged_cleanups`
|
|
- `gitea_reconcile_superseded_by_merged_pr`
|
|
- `gitea_record_daemon_process_kill_attempt`
|
|
- `gitea_record_irrecoverable_decision_lock_provenance`
|
|
- `gitea_record_pre_review_command`
|
|
- `gitea_record_shell_spawn_outcome`
|
|
- `gitea_record_stable_branch_push_attempt`
|
|
- `gitea_release_merger_pr_lease`
|
|
- `gitea_release_reviewer_pr_lease`
|
|
- `gitea_release_workflow_lease`
|
|
- `gitea_resolve_task_capability`
|
|
- `gitea_resume_review_draft`
|
|
- `gitea_review_pr`
|
|
- `gitea_route_task_session`
|
|
- `gitea_save_review_draft`
|
|
- `gitea_scan_already_landed_open_prs`
|
|
- `gitea_sentry_get_issue_events`
|
|
- `gitea_sentry_link_gitea_issue`
|
|
- `gitea_sentry_list_issues`
|
|
- `gitea_sentry_reconcile_issue`
|
|
- `gitea_sentry_watchdog`
|
|
- `gitea_set_issue_labels`
|
|
- `gitea_submit_pr_review`
|
|
- `gitea_update_pr_branch_by_merge`
|
|
- `gitea_validate_review_final_report`
|
|
- `gitea_view_issue`
|
|
- `gitea_view_pr`
|
|
- `gitea_whoami`
|
|
- `gitea_workflow_dashboard`
|
|
- `mcp_check_workflow_skill_preflight`
|
|
- `mcp_get_control_plane_guide`
|
|
- `mcp_get_skill_guide`
|
|
- `mcp_list_project_skills`
|
|
|
|
<!-- END REGISTERED TOOL INVENTORY -->
|
|
|
|
## Issue-content editing
|
|
|
|
`gitea_edit_issue` is the only path that changes an issue's title or body. It
|
|
PATCHes the issue endpoint, refuses a pull-request number, sends only the fields
|
|
the caller named, and proves the result by read-after-write — including that
|
|
state, labels, assignees, and milestone did not move.
|
|
|
|
`gitea_edit_pr` remains pull-request-only. The two paths never merge: a single
|
|
tool that accepted either kind would make the narrower capability reachable
|
|
through the wider one.
|