fix: resolve docs conflict for PR #453 after #452

Merge both audit (#431) and worktree hygiene (#432) route/docs lines.
This commit is contained in:
2026-07-09 09:22:53 -04:00
64 changed files with 5854 additions and 207 deletions
+183
View File
@@ -0,0 +1,183 @@
# Canonical State Comments
Gitea is the durable system of record for workflow continuation. When a
comment changes issue, PR, or discussion state, it should leave enough
information for the next role to continue without private chat history.
Canonical comments answer:
- what state the object is in
- who acts next
- what the next actor should do
- the exact prompt the next actor should run
- which proof, blocker, or dependency matters
Non-workflow discussion comments do not need this template.
## Issue State
Use this when an issue becomes ready, blocked, in progress, PR-open,
superseded, merged, or otherwise changes workflow direction.
```text
## Canonical Issue State
STATE:
<ready-for-author | in-progress | blocked | PR-open | needs-review | ready-to-merge | merged | closed | superseded>
WHO_IS_NEXT:
<controller | author | reviewer | merger | reconciler | user>
NEXT_ACTION:
<specific one-sentence action>
NEXT_PROMPT:
<paste-ready prompt for the next role>
WHAT_HAPPENED:
<latest meaningful event>
WHY:
<decision rationale>
RELATED_DISCUSSION:
<link/reference or none>
RELATED_PRS:
- #...
BRANCH:
<branch or none>
HEAD_SHA:
<40-character SHA or none>
VALIDATION:
<tests/proofs or none>
BLOCKERS:
<blocker and unblock condition, or none>
LAST_UPDATED_BY:
<identity/profile/date>
```
## PR State
Use this when a PR needs review, receives changes requested, is approved,
is stale, is superseded, or becomes ready for merge.
```text
## Canonical PR State
STATE:
<needs-review | changes-requested | approved | stale-approval | ready-to-merge | merged | blocked | superseded>
WHO_IS_NEXT:
<controller | author | reviewer | merger | reconciler | user>
NEXT_ACTION:
<specific one-sentence action>
NEXT_PROMPT:
<paste-ready prompt for the next role>
WHAT_HAPPENED:
<latest meaningful event>
WHY:
<decision rationale>
ISSUE:
#...
BASE:
<branch>
HEAD:
<branch>
HEAD_SHA:
<40-character SHA>
REVIEW_STATUS:
<none | approved | changes-requested | stale | contaminated>
VALIDATION:
<tests/proofs>
BLOCKERS:
<blockers or none>
SUPERSEDES:
<PRs or none>
SUPERSEDED_BY:
<PR or none>
MERGE_READY:
<yes/no and why>
LAST_UPDATED_BY:
<identity/profile/date>
```
## Discussion Summary
Discussions should normally have at least five substantive comments before
conversion into issues. A controller may waive that only for tiny mechanical,
urgent, or explicitly trivial work.
```text
## Canonical Discussion Summary
STATE:
<needs-more-discussion | ready-for-issues | issues-created | closed>
WHO_IS_NEXT:
<controller | author | reviewer | user>
DECISION:
<what was decided>
WHY:
<reasoning and tradeoffs>
SUBSTANTIVE_COMMENTS:
<count and summary>
ISSUES_TO_CREATE_OR_CREATED:
- #...
DEPENDENCY_ORDER:
<order or none>
NON_GOALS:
<non-goals>
OPEN_QUESTIONS:
<questions or none>
NEXT_ACTION:
<specific one-sentence action>
NEXT_PROMPT:
<paste-ready prompt for the next role>
LAST_UPDATED_BY:
<identity/profile/date>
```
## Validation Rules
The final-report validator rejects canonical state update claims when the
report omits the canonical block or when the block lacks:
- `STATE`
- `WHO_IS_NEXT`
- `NEXT_ACTION`
- `NEXT_PROMPT`
It also rejects vague next actions such as `continue`, ready-to-merge states
without approval/head-SHA proof, superseded states without canonical item
proof, and blocked states without an unblock condition.
+142
View File
@@ -0,0 +1,142 @@
# Canonical Thread Handoff (CTH)
**CTH** = **Canonical Thread Handoff**
A CTH comment is the authoritative workflow handoff in a Gitea issue or PR
thread. It records current state, decisions, blockers, proof, and the exact
next prompt/action for the next LLM or person.
CTH comments complement — but do not replace — formal Gitea review state.
A CTH may summarize an APPROVE or REQUEST_CHANGES decision, yet merge gates
still require the live Gitea review verdict.
## CTH comment types
- `CTH: State Handoff`
- `CTH: Controller Decision`
- `CTH: Author Handoff`
- `CTH: Reviewer Handoff`
- `CTH: Merger Handoff`
- `CTH: Supersession Notice`
- `CTH: Blocker`
## Required base template
```md
## CTH: <Type>
Status:
Next owner:
Current blocker:
Decision:
Proof:
Next action:
Ready-to-paste prompt:
```
Extended fields may map to canonical issue/PR state templates from #495 when
that layer is available. Until then, keep the base fields complete.
## Discovery and posting rules
Before acting in an issue or PR thread:
1. **Find the latest CTH comment** before doing work.
2. Treat the **latest valid CTH** as the current handoff state.
3. **Post a new CTH** when you finish, block, skip, supersede, request
changes, approve, or hand off.
4. Do **not** rely on stale non-CTH comments when a newer CTH exists.
5. Casual discussion comments do not need to be CTH comments.
## Examples
### PR approved and ready for merger
```md
## CTH: Reviewer Handoff
Status: approved_at_current_head
Next owner: merger
Current blocker: none
Decision: APPROVE recorded at head abc123...
Proof: gitea_submit_pr_review performed; visible verdict APPROVE
Next action: eligible merger merges PR #N with pinned expected_head_sha
Ready-to-paste prompt: Merge PR #N for issue #M if live head still abc123... and merge gates pass.
```
### PR request-changes back to author
```md
## CTH: Reviewer Handoff
Status: request_changes_at_current_head
Next owner: author
Current blocker: unresolved findings in validation report
Decision: REQUEST_CHANGES at head def456...
Proof: gitea_submit_pr_review performed; blocking review visible
Next action: author fixes findings and pushes; reviewer re-validates fresh head
Ready-to-paste prompt: Fix PR #N review findings, push to feat/issue-M-..., post Author Handoff CTH.
```
### Duplicate / superseded PR closure
```md
## CTH: Supersession Notice
Status: superseded
Next owner: controller
Current blocker: duplicate branch/PR work
Decision: close PR #N; continue on PR #M
Proof: duplicate gate linked open PR #M for issue #K
Next action: controller closes superseded PR and records canonical state
Ready-to-paste prompt: Close superseded PR #N; confirm PR #M remains canonical for issue #K.
```
### Blocked workflow due to dirty root/worktree
```md
## CTH: Blocker
Status: blocked_preflight
Next owner: operator
Current blocker: dirty control checkout / branches worktree mismatch
Decision: stop before mutation
Proof: verify_preflight_purity failed; workspace diagnostics attached
Next action: repair worktree or relaunch MCP from branches/ worktree
Ready-to-paste prompt: Repair dirty workspace, relaunch MCP from branches/review-prN, retry review.
```
### Stale head requiring fresh review
```md
## CTH: Reviewer Handoff
Status: stale_head
Next owner: reviewer
Current blocker: live head differs from pinned review head
Decision: prior approval not valid for current head
Proof: expected_head_sha mismatch at merge gate
Next action: re-run validation and post fresh review decision
Ready-to-paste prompt: Re-validate PR #N at live head, dry-run review gates, submit fresh verdict.
```
### Issue implementation handoff
```md
## CTH: Author Handoff
Status: implementation_complete_pending_review
Next owner: reviewer
Current blocker: none
Decision: PR #N ready for review at head fedcba...
Proof: tests passed in branches/issue-M-...; PR opened with Closes #M
Next action: reviewer acquires lease and validates PR #N
Ready-to-paste prompt: Review PR #N for issue #M; pin head fedcba... before mutations.
```
## Related
- [`llm-workflow-runbooks.md`](llm-workflow-runbooks.md)
- [`../skills/llm-project-workflow/templates/canonical-thread-handoff.md`](../skills/llm-project-workflow/templates/canonical-thread-handoff.md)
- #495 — canonical next-action comment fields
- #496 — fail-closed validation for workflow-changing comments
+12 -1
View File
@@ -22,9 +22,12 @@ launched with exactly one static execution profile:
| Namespace (MCP server name) | Profile (role) | Typical use |
|-----------------------------|----------------|-------------|
| `gitea-author` | an author profile | implement issues, push branches, open PRs, comment |
| `gitea-reviewer` | a reviewer profile | review, approve/request changes, merge |
| `gitea-reviewer` | a reviewer profile | review, approve/request changes |
| `gitea-merger` | a merger profile | merge PRs after approval and verification |
| `gitea-reconciler` | a reconciler profile | close already-landed open PRs after ancestry proof (#304 profile; #310 close tool) |
Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
Properties:
- **One process, one credential.** Each namespace authenticates as exactly
@@ -106,6 +109,14 @@ syntax to the client):
"GITEA_MCP_CONFIG": "<path-to-profiles.json>",
"GITEA_MCP_PROFILE": "<reviewer-profile-name>"
}
},
"gitea-merger": {
"command": "<path-to>/venv/bin/python3",
"args": ["<path-to>/mcp_server.py"],
"env": {
"GITEA_MCP_CONFIG": "<path-to-profiles.json>",
"GITEA_MCP_PROFILE": "<merger-profile-name>"
}
}
}
}
+2 -1
View File
@@ -311,7 +311,8 @@ To make Gitea MCP profile activation and runtime identity state explicit, the fo
### 2. Dual MCP Namespaces Recommendation
For security-sensitive or high-risk tasks, the preferred safety model uses separate, isolated MCP server instances (namespaces/sessions) launched with static profiles:
- `gitea-author`: Exposes tools configured with author permissions; cannot perform approvals or merges.
- `gitea-reviewer`: Exposes tools configured with reviewer permissions; used for PR reviews and merges.
- `gitea-reviewer`: Exposes tools configured with reviewer permissions; used for PR reviews. Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
- `gitea-merger`: Exposes tools configured with merger permissions; used for PR merges.
This layout maintains physical separation of credentials and prevents privilege escalation within a single session.
This is the model accepted in #139; deployment details, rationale, and client
setup live in
+88 -24
View File
@@ -1,34 +1,98 @@
# Label Taxonomy
This document catalogs the issue labels used for MCP workflows, including Jenkins and GlitchTip (observability).
This document defines the canonical issue labels used by MCP workflows.
> **Approval Required:** Do not create or apply new labels in `manage_labels.py` without explicit owner approval of this document.
Every issue should carry:
## Existing Labels
- one `type:*` label
- one `status:*` label
* **`jenkins`**
* Description: Jenkins integration
* Color: `d93f0b`
* Use: Used to mark issues, PRs, or tasks that involve the `jenkins-mcp` boundaries, CI/CD designs, or build failures.
Discussion-only issues must carry `type:discussion`.
* **`glitchtip`**
* Description: GlitchTip integration
* Color: `b60205`
* Use: Used to mark issues related to the `glitchtip-mcp` boundary and observability integration.
## Issue Type Labels
## Proposed / Missing Labels
| Label | Use |
| --- | --- |
| `type:bug` | Bug or defect |
| `type:feature` | Feature or enhancement |
| `type:process` | Process or policy work |
| `type:workflow` | Workflow automation or guidance |
| `type:guardrail` | Safety gate or guardrail |
| `type:docs` | Documentation work |
| `type:test` | Tests or test infrastructure |
| `type:discussion` | Discussion-only issue |
| `type:umbrella` | Umbrella or tracker issue |
| `type:cleanup` | Cleanup or hygiene work |
* **`observability`**
* Proposed Description: Observability, metrics, and monitoring tasks
* Proposed Color: `5319e7`
* Use: Broader than GlitchTip alone; covers logging, metrics, traces, and general observability pipeline improvements.
## Workflow Status Labels
* **`source:glitchtip`**
* Proposed Description: Issue filed automatically by GlitchTip orchestration
* Proposed Color: `b60205`
* Use: Applied automatically by the orchestrator when a GlitchTip error event is converted into a Gitea issue.
Only one `status:*` label should be active on an issue at a time. When an issue
moves forward, tooling must remove the old `status:*` label and apply the new
one.
* **`status:triage`**
* Proposed Description: Issue needs human or orchestrator triage
* Proposed Color: `fbca04`
* Use: Used for incoming issues (especially automated ones like `source:glitchtip`) that have not yet been evaluated for priority or resolution.
| Label | Use |
| --- | --- |
| `status:triage` | Issue needs triage |
| `status:ready` | Issue is ready for work |
| `status:claimed` | Issue is claimed |
| `status:in-progress` | Issue is being worked on |
| `status:blocked` | Issue is blocked |
| `status:needs-review` | Issue work needs review |
| `status:pr-open` | A linked PR is open |
| `status:approved` | Linked PR is approved |
| `status:merged` | Linked PR is merged |
| `status:reconcile` | Issue needs reconciliation |
| `status:done` | Issue workflow is complete |
| `status:duplicate` | Issue is a duplicate |
| `status:wontfix` | Issue will not be fixed |
## Transition Rules
Suggested lifecycle:
1. New issue created: `status:triage` or `status:ready`
2. Issue selected by an author: `status:claimed`
3. Author starts work: `status:in-progress`
4. Work is blocked: `status:blocked`
5. PR opened: `status:pr-open`
6. PR approved: `status:approved`
7. PR merged but issue still needs closure/reconciliation: `status:reconcile`
8. Issue fully complete: `status:done`
9. Duplicate issue: `status:duplicate`
10. Won't-fix issue: `status:wontfix`
The helper module `issue_workflow_labels.py` is the source of truth for the
canonical label specs and status transition replacement behavior.
## Discussion Issues
Discussion issues must be labeled `type:discussion`.
A discussion issue should not be treated as implementation-ready unless it also
has a clear implementation status and next action.
If a discussion produces implementation work, either:
1. convert the discussion issue into an implementation issue by changing labels
and adding acceptance criteria, or
2. create child implementation issues and leave the discussion issue as
`type:discussion`.
## Tooling
- `manage_labels.py --create-labels` creates the canonical `type:*` and
`status:*` labels.
- `gitea_create_issue` recommends `type:*` and `status:*` labels when missing
and can apply supplied label names.
- `gitea_mark_issue(..., action="start")` replaces old `status:*` labels with
`status:in-progress`.
- `gitea_create_pr` fails closed before PR creation if `status:pr-open` cannot
be applied to the locked issue, then applies it after the PR is created.
- `gitea_set_issue_labels` accepts an explicit `worktree_path` so author
sessions can satisfy the branches-only mutation guard while changing labels.
## Existing Non-Workflow Labels
Existing non-workflow labels such as `mcp`, `workflow`, `labels`, `tracker`,
`jenkins`, `glitchtip`, `documentation`, and `testing` remain valid topical
labels. They do not replace the required `type:*` and `status:*` labels.
+116 -10
View File
@@ -7,6 +7,11 @@ package of the MCP Control Plane: creating issues, implementing them, opening
and reviewing pull requests, merging, and closing out — safely and
reproducibly.
Canonical state comments for durable issue/PR/discussion continuation are
documented in [`canonical-state-comments.md`](canonical-state-comments.md).
Use them when a workflow-changing comment needs to leave the next actor, next
action, and paste-ready prompt in Gitea.
> For the **project-agnostic** version of these operating rules (issue-first,
> isolated worktrees, no self-review/merge, profile safety, cleanup, fail-closed)
> that can be copied into any repository, see the reusable skill
@@ -408,6 +413,31 @@ The guard blocks when the **control checkout** (repository root) is:
`branches/...` directories are disposable role worktrees; the root checkout is
the stable orchestration surface only.
## Canonical workflow skill names (#551)
Controller prompts and sessions must load the **same** workflow skill wall
regardless of runtime (Claude, Codex, Gemini):
| Name | Role |
|------|------|
| `gitea-workflow` | Primary controller / Codex skill name |
| `llm-project-workflow` | Portable in-repo package |
| `git-pr-workflows` | Legacy alias |
- Inventory: `mcp_list_project_skills` lists all three.
- Preflight: `mcp_check_workflow_skill_preflight` before mutations.
- Codex install: `scripts/install-codex-workflow-skill.sh`
- Full doc: [`docs/workflow-skill-mount.md`](workflow-skill-mount.md)
If the skill is missing, stop with BLOCKED + DIAGNOSE — do not mutate.
## No direct-import mutation path (#558)
Never `import gitea_mcp_server` or call `gitea_auth.get_auth_header` /
keychain fill from a raw shell to bypass MCP preflight.
Use the official MCP daemon only. See [`docs/mcp-daemon-import-guard.md`](mcp-daemon-import-guard.md).
## Bootstrap Review Path for self-hosted MCP fixes (#557)
When a PR fixes Gitea-Tools MCP workflow code that the **live daemon** still
@@ -634,19 +664,24 @@ loop and do **not** substitute WebFetch/Playwright/manual base64.
- **Profile:** issue-manager or author (any profile allowed to create issues).
- **Steps:** create the parent/roadmap issue; create child issues; apply the
minimal label set; link children to the parent.
- **Labels:** new issues should carry one `type:*` label and one `status:*`
label. Discussion-only issues must carry `type:discussion`. See
[`label-taxonomy.md`](label-taxonomy.md).
- **Prompt:** `Using the issue-manager profile, create issue "<title>" with body
<body>, then create child issues for <list> and link them to the parent.`
### Implement an issue and open a PR
- **Profile:** author.
- **Steps:** claim the issue (`status:in-progress`); create an isolated branch
worktree from latest `master` under `branches/` (`feat/issue-<n>-...` /
- **Steps:** claim the issue (`status:in-progress`, replacing any old
`status:*` label); create an isolated branch worktree from latest `master`
under `branches/` (`feat/issue-<n>-...` /
`fix/...` / `docs/...`); `cd` into that worktree; implement narrowly; add or
update tests if behavior changes; run the full suite; commit with an
issue-linked message; open a PR to `master`. **Do not** review or merge your
own PR. Include an `LLM Handoff Metadata` block (with `LLM-Agent-SHA`) in
the PR body — see [`llm-agent-sha.md`](llm-agent-sha.md).
issue-linked message; open a PR to `master`; move the issue to
`status:pr-open`. **Do not** review or merge your own PR. Include an
`LLM Handoff Metadata` block (with `LLM-Agent-SHA`) in the PR body — see
[`llm-agent-sha.md`](llm-agent-sha.md).
- **Prompt:** `Use an author profile to implement issue #N and open a PR to
master. Do not self-review or self-merge.`
@@ -687,10 +722,10 @@ loop and do **not** substitute WebFetch/Playwright/manual base64.
### Merge a PR
- **Profile:** merger (allowed to merge; must **not** be the PR author).
- **Steps:** confirm eligibility; require explicit confirmation
(`MERGE PR <n>`); optionally pin head SHA / changed-file set; merge only when
Gitea reports the PR mergeable (branch-protection checks satisfied). No force,
no ignore-checks. Verify that remote master contains the merge commit or the expected squashed changes (do not assume a "closed" PR succeeded without verifying the actual landed changes).
- **Steps:**
- Merger workflow starts only after formal approval at current head. Reviewer workflow ends with review decision and separate merger handoff.
- Confirm eligibility; require explicit confirmation (`MERGE PR <n>`); optionally pin head SHA / changed-file set; merge only when Gitea reports the PR mergeable (branch-protection checks satisfied). No force, no ignore-checks. Verify that remote master contains the merge commit or the expected squashed changes (do not assume a "closed" PR succeeded without verifying the actual landed changes).
- Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
- **Prompt:** `Use any eligible merger profile to merge PR #N if checks pass and
it is mergeable. Confirm with "MERGE PR N". Do not force-merge.`
@@ -779,7 +814,7 @@ an author.
|---|---|---|---|---|
| Review PR (`review_pr`) | reviewer (e.g. `sysadmin` / `prgs-reviewer`) | read, gated review verdicts | commits, pushes, file edits, author comments, merge without eligibility | active profile is an author profile — stop immediately; do **not** switch to author-side fixes unless the operator explicitly re-tasks |
| Address PR change requests (`address_pr_change_requests`) | author (e.g. `jcwalker3` / `prgs-author`) | commit/push fixes to the PR branch, PR comment summarizing fixes | review verdicts, approve, request-changes, merge | active profile lacks branch push |
| Merge PR (`merge_pr`) | reviewer/merger | gated merge after eligibility + approval | merging own PR, merging without pinned head match | active profile is an author profile, or any merge gate fails |
| Merge PR (`merge_pr`) | merger (e.g. `sysadmin` / `prgs-merger`) | gated merge after eligibility + approval | merging own PR, merging without pinned head match, reviewing PRs | active profile is an author or reviewer-only profile, or any merge gate fails |
| Comment on issue discussion (`comment_issue`) | any profile with `gitea.issue.comment` | issue thread comments | review verdicts, closing via comment | permission missing (`gitea.pr.comment` does **not** imply it) |
| Comment on PR (`comment_pr`) | any profile with `gitea.pr.comment` | PR thread comments | review verdicts | permission missing |
| Author implementation (`create_branch`/`push_branch`/`create_pr`) | author | branch, commit, push, open PR | self-review, self-merge | profile lacks the author permissions |
@@ -829,6 +864,27 @@ Never imply full-suite success unless the full-suite command itself passed
(`full_suite_passed: true`). A report that hides a failed or skipped check
is worse than a failing report.
## Canonical Thread Handoff (CTH)
**CTH** = **Canonical Thread Handoff** — the authoritative workflow handoff
comment in a Gitea issue or PR thread. See
[`canonical-thread-handoff.md`](canonical-thread-handoff.md) for types,
templates, and examples.
Before acting in an issue or PR thread:
1. **Find the latest CTH comment** before doing work.
2. Treat the **latest valid CTH** as the current handoff state.
3. **Post a new CTH** when you finish, block, skip, supersede, request
changes, approve, or hand off.
4. Do **not** rely on stale non-CTH comments when a newer CTH exists.
A CTH summarizes workflow state for the next session. Formal Gitea review
verdicts remain authoritative for merge gates — a CTH is not merge approval
by itself.
Template: [`../skills/llm-project-workflow/templates/canonical-thread-handoff.md`](../skills/llm-project-workflow/templates/canonical-thread-handoff.md)
## Controller Handoff (required, every task)
Every task — implementation, review, merge, triage, documentation,
@@ -861,6 +917,55 @@ touched release state names the exact tag/commit and why. Design debates
belong in **discussion/RFC issues** (e.g. #100 `profiles.json v2`) — comment
on the issue, create no branches/PRs, and end the comment with this handoff.
## Canonical comment validation (#496)
Workflow-changing issue/PR/review comments must carry durable next-action
state. Casual discussion is still allowed.
The MCP server runs `canonical_comment_validator.assess_canonical_comment`
**before** posting through:
- `gitea_create_issue_comment`
- `gitea_submit_pr_review` / `gitea_dry_run_pr_review` (non-empty review bodies)
- `gitea_reconcile_already_landed_pr` when `post_comment=True`
- internal structured comment helpers (machine lease/heartbeat markers stay exempt)
Detection examples:
- **Allowed:** `Thanks, I will check this.`
- **Rejected:** `Blocked, author should fix.` (workflow trigger without canonical fields)
When validation fails, the tool returns `canonical_comment_validation` with
`allowed: false`, `missing_fields`, `vague_fields`, `correction_message`, and
`suggested_template`. **No Gitea API call is made.**
Minimum workflow comment fields:
```text
STATE:
WHO_IS_NEXT:
NEXT_ACTION:
NEXT_PROMPT:
WHY:
```
`WHO_IS_NEXT` must be one of: `controller`, `author`, `reviewer`, `merger`,
`reconciler`, `user`.
Issue comments also require `RELATED_PRS`, `BLOCKERS`, and `VALIDATION` when
they mention PR work. PR comments/reviews also require `ISSUE`, `HEAD_SHA`,
`REVIEW_STATUS`, `MERGE_READY`, `BLOCKERS`, and `VALIDATION`.
Special states:
- `STATE: blocked` — `BLOCKERS` must name an explicit unblock condition.
- `STATE: superseded` — requires `CANONICAL_ITEM` and `SUPERSEDED_ITEM`.
- `STATE: ready-to-merge` — requires approval proof and head SHA in
`HEAD_SHA`, `REVIEW_STATUS`, `MERGE_READY`, or `VALIDATION`.
Final reports must not claim a comment was posted when
`canonical_comment_validation.allowed` is false (#496 AC14).
## Fail-closed behavior
Before any mutating action the workflow verifies identity, active profile,
@@ -972,6 +1077,7 @@ When posting a Canonical Thread Handoff after a binding blocker:
## Related documents
- [`reviewer-handoff-consistency.md`](reviewer-handoff-consistency.md) — reject contradictory reviewer handoffs (#501).
- [`issue-acceptance-gate.md`](issue-acceptance-gate.md) — controller issue-acceptance audit after PR merge (#500).
- [`../skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md) — portable cross-project LLM workflow skill.
- [`gitea-execution-profiles.md`](gitea-execution-profiles.md) — the profile model.
+23
View File
@@ -0,0 +1,23 @@
# MCP daemon import and keychain guard (#558)
## Problem
During deadlock debugging, agents imported `gitea_mcp_server` / ran credential
helpers from a raw shell, bypassing preflight purity and role gates.
## Rule
Mutation auth and keychain fill require a **sanctioned MCP daemon** process.
| Context | Allowed |
|---------|---------|
| Official MCP entrypoint (`mcp_server.py` / `gitea_mcp_server` `__main__`) sets `GITEA_MCP_SANCTIONED_DAEMON=1` | yes |
| pytest | yes |
| `GITEA_ALLOW_DIRECT_MCP_IMPORT=1` (operator/tests only) | yes |
| bare `python -c 'import gitea_auth; get_auth_header(...)'` | **no** |
| keychain fill without daemon | **no** unless `GITEA_ALLOW_KEYCHAIN_CLI=1` |
## Operator note
LLM sessions must never set the allow-direct-import or allow-keychain-cli
overrides. Those are human-only escape hatches.
+35
View File
@@ -0,0 +1,35 @@
# Reviewer Handoff Consistency
Reviewer and final-review controller handoffs must not contradict themselves.
A narrative that says a merge happened, a review was blocked, or a terminal
mutation budget was consumed must match the mutation ledger fields in the same
handoff.
## What gets validated
`reviewer_handoff_consistency.assess_reviewer_handoff_consistency()` checks:
- merge claims appear under `Merge mutations` or `MCP/Gitea mutations`
- terminal-mutation-budget claims name the exact prior mutation in the ledger
- blocked review submission is not paired with "final decision marked"
- reviewer lease acquisition includes a `Review decision`
- blocked/rejected mutations include proof fields:
- tool called
- mutation attempted
- mutation rejected
- no server-side state changed
`final_report_validator` applies this as `reviewer.handoff_consistency` on
`review_pr` reports and fails closed.
## Blocked review template
When `gitea_submit_pr_review` fails closed, use
`reviewer_handoff_consistency.render_blocked_review_handoff_template()` or the
copy in
[`skills/llm-project-workflow/templates/blocked-review-handoff.md`](../skills/llm-project-workflow/templates/blocked-review-handoff.md).
## Related
- #331 — file-mutation ledger alignment
- #501 — contradictory narrative vs ledger detection
+14 -4
View File
@@ -45,7 +45,8 @@ Optional environment variables:
| `/api/prompts` | JSON prompt export with workflow hashes |
| `/runtime` | MCP runtime health and stale detection (#430) |
| `/api/runtime` | JSON runtime health export |
| `/audit` | Stub — report audit paste (#431) |
| `/audit` | Report audit paste + validator preview (#431) |
| `/api/audit` | JSON validator preview (POST `report_text`, optional `task_kind`) |
| `/worktrees` | Worktree hygiene dashboard (#432) |
| `/api/worktrees` | JSON worktree scan with classifications and anomalies |
| `/leases` | Stub — lease visibility (#433) |
@@ -53,8 +54,17 @@ Optional environment variables:
| `/leases` | Lease and collision visibility (#433) |
| `/api/leases` | JSON lease/collision export |
All routes are GET-only. POST/PUT/PATCH/DELETE return `405` with
`read-only-mvp`.
Most routes are GET-only. POST/PUT/PATCH/DELETE return `405` with
`read-only-mvp`, except `/audit` and `/api/audit` which accept POST for
local validator preview only (no Gitea mutations, no server-side storage).
## Report audit (#431)
Paste an LLM final report at `/audit` or POST JSON to `/api/audit`. The UI
reuses `final_report_validator` and review schema checks to surface missing
proof fields, wrong validation vocabulary, mutation contradictions, and a
suggested next prompt or issue-comment draft. Task kind can be auto-detected
or selected explicitly.
## Project registry (#427)
@@ -116,6 +126,6 @@ no tokens or MCP restart actions are exposed.
## Tests
```bash
pytest tests/test_webui_skeleton.py tests/test_webui_project_registry.py tests/test_webui_prompt_library.py tests/test_webui_queue_dashboard.py tests/test_webui_worktree_hygiene.py -q
pytest tests/test_webui_skeleton.py tests/test_webui_project_registry.py tests/test_webui_prompt_library.py tests/test_webui_queue_dashboard.py tests/test_webui_audit.py tests/test_webui_worktree_hygiene.py -q
pytest tests/test_webui_skeleton.py tests/test_webui_project_registry.py tests/test_webui_prompt_library.py tests/test_webui_queue_dashboard.py tests/test_webui_lease_visibility.py tests/test_webui_runtime_health.py -q
```
+12 -3
View File
@@ -16,12 +16,21 @@ bind an authenticated Gitea identity to an allowed operation set.
- **Allowed:** branch create/push, PR create, issue comment/create/close, repo commit, read.
- **Forbidden:** PR approve, merge, request_changes.
### Reviewer / merger
### Reviewer
- **Profile:** `prgs-reviewer`
- **Typical identity:** `sysadmin`
- **Allowed:** PR review/approve/merge/request_changes, issue comment, read.
- **Forbidden:** branch push, PR create, repo commit.
- **Allowed:** PR review/approve/request_changes, issue comment, read.
- **Forbidden:** branch push, PR create, repo commit, PR merge.
Review and merge are separate workflow roles. A reviewer approval is not merge authorization.
### Merger
- **Profile:** `prgs-merger`
- **Typical identity:** `sysadmin`
- **Allowed:** PR merge, issue comment, read.
- **Forbidden:** branch push, PR create, repo commit, PR approve, PR review, PR request_changes.
## Configuration
+68
View File
@@ -0,0 +1,68 @@
# Workflow skill mount across runtimes (#551)
## Problem
Controller prompts require **`gitea-workflow`**, but:
- Claude may load `~/.claude/skills/gitea-workflow`
- Codex often has **no** `~/.codex/skills/gitea-workflow`
- The portable package in-repo is `skills/llm-project-workflow`
- `mcp_list_project_skills` historically listed operational guides only, not
the workflow router
Sessions then either **block** incorrectly or **proceed without** the workflow
wall.
## Canonical names (must resolve to the same skill)
| Name | Use |
|------|-----|
| `gitea-workflow` | **Primary** controller / Codex skill name |
| `llm-project-workflow` | Portable in-repo package name |
| `git-pr-workflows` | Legacy alias |
Source of truth: `skills/llm-project-workflow/SKILL.md`
In-repo alias stub: `skills/gitea-workflow/SKILL.md`
## Codex install
From a `branches/` worktree (or any clone of the repo):
```bash
./scripts/install-codex-workflow-skill.sh
# optional:
./scripts/install-codex-workflow-skill.sh --dry-run
./scripts/install-codex-workflow-skill.sh --skills-dir "$HOME/.codex/skills"
```
This symlinks the portable package under all three names. **Restart Codex**
after install.
## MCP discovery
- `mcp_list_project_skills` includes `gitea-workflow`, `llm-project-workflow`,
and `git-pr-workflows`.
- `mcp_get_skill_guide("<name>")` returns the same router steps for each.
- `mcp_check_workflow_skill_preflight` proves the in-repo skill file exists and
reports Codex mount status.
## Preflight rule
Before any git or Gitea mutation:
1. Call `mcp_check_workflow_skill_preflight`.
2. If `blocked` / `workflow_skill_ready` is false → **BLOCKED + DIAGNOSE**; do
not mutate.
3. Load the skill by **any** canonical name and follow the router.
Missing Codex mount alone does not block if the in-repo skill is present and
loaded via MCP/docs; operators should still install the Codex symlink so
prompt names resolve natively.
## Controller prompts
Prefer:
> Invoke skill `gitea-workflow` (alias of `llm-project-workflow`).
Do not require a name that is only available on one runtime.