Add canonical issue/PR/discussion state comment templates and validators,
final-report rules for STATE/WHO_IS_NEXT/NEXT_ACTION/NEXT_PROMPT, and
queue-controller guidance. Posting enforcement remains in #496.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Add templates, validators, and documentation for discussion/issue/PR state
comments and final-report next-action handoff fields. Wire enforcement into
assess_final_report_validator across all workflow task kinds.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Introduce root_checkout_guard helper and enforce it in verify_preflight_purity
so author, reviewer, and merger mutations fail closed when the stable control
checkout is on the wrong branch, detached, dirty, or diverged from prgs/master.
Isolated branches/... worktrees and reconciler paths remain allowed.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Normal author work is unchanged: gitea_lock_issue still requires the worktree
to be base-equivalent to master/main/dev, and gitea_create_pr still targets a
normal base branch. A *stacked* PR (based on another unmerged PR's branch) is a
new explicit, proof-backed path — it never bypasses the issue lock.
- stacked_pr_support.py: pure policy. Approve a non-master base only when it is
declared AND owned by a live OPEN PR whose number matches; reject arbitrary,
mismatched, or stale (merged/closed) branches; require the PR body to document
the stack (base branch, stacked-on PR, merge ordering).
- issue_lock_worktree.py: read_worktree_git_state / _find_matching_base_ref gain
an opt-in extra_bases arg so an approved stacked base can anchor
base-equivalence in addition to master/main/dev (empty by default = unchanged).
- gitea_mcp_server.py:
- gitea_lock_issue gains stacked_base_branch + stacked_base_pr. When declared,
it verifies the open PR owns the branch, anchors base-equivalence to it, and
records approved_stacked_base = {branch, pr_number, verified_open} on the lock.
- gitea_create_pr validates a non-master base against the lock's approved
stacked base, re-checks the dependency PR is still open, and enforces the
stacked-PR body fields. Master-based path untouched.
- Docs: llm-workflow-runbooks.md and work-issue.md document when stacked PRs are
allowed and the required PR-body wording.
Tests: test_stacked_pr_support.py (18 policy cases), stacked base-equivalence in
test_issue_lock_worktree.py, approved_stacked_base persistence round-trip in
test_issue_lock_store.py. Existing lock/create_pr regressions still pass.
The #482 -> #479/#478 case motivates this: create_pr previously could not open a
stacked PR because the lock required a master-equivalent worktree.
Closes#484.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
When gitea_lock_issue adopts an existing own branch, the live tool
response now carries explicit, citable adoption-proof fields so #473-style
recovery sessions can quote the lock output directly instead of inferring
adoption from separate offline checks.
- issue_lock_adoption.py: add DECISION_LABELS + decision_label()/
safe_next_action() helpers; extend build_adoption_proof() with
adoption_decision, adopted, adopted_branch, adopted_branch_head,
matcher_summary (boundary-safe reason), competing_branch_check, and
safe_next_action for all outcomes; add build_non_adoption_lock_proof()
for adoption-free NO_MATCH metadata.
- gitea_mcp_server.py: attach adoption-free adoption_check block to normal
(non-adopt) lock responses so they cannot be misread as claiming adoption.
- docs/llm-workflow-runbooks.md: document the adoption/adoption_check
response blocks and instruct recovery reports to cite them directly.
- tests: explicit-field proof for ADOPT/BLOCK_COMPETING/NO_MATCH,
substring-collision boundary safety (issue-42 vs issue-420), non-adoption
proof, and MCP-level live-response assertions.
BLOCK_COMPETING lock attempts still fail closed (raise); no raw API
fallback, branch deletion, force-push, or manual lock seeding introduced.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Store per remote/org/repo/issue locks under GITEA_ISSUE_LOCK_DIR with
atomic writes and per-session binding. Integrate own-branch adoption for
lock recovery, update worktree-start and cleanup reconcile, and add tests
documenting the ban on manual global lock seeding.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Add lock_provenance metadata on gitea_lock_issue writes and fail closed at
gitea_create_pr when provenance is missing. Final-report validation now
requires explicit External-state mutations disclosure for issue-lock
read/write/delete and blocks mixed author PR creation with reviewer approval.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Adds canonical pr-queue-cleanup workflow, report verifier, reviewer-only task
routing, and runbook guidance so operators can drain open PRs one canonical
review at a time with fail-closed boundaries on batching and unauthorized merges.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Introduce a dedicated reconciler role with gitea_reconcile_already_landed_pr,
which closes open PRs only after live fetch and ancestor proof against a fresh
target branch. Document the gitea-reconciler namespace and extend task routing.
Document default tool-call and wall-time budgets for deterministic MCP
work, forbid subagent commit delegation when gitea_commit_files is
available, and pin the rules in runbooks, portable skill, operator guide,
and doc-contract tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Document MCP-native gitea_commit_files as the only approved commit path when
gitea.repo.commit is allowed; ban WebFetch, Playwright, and manual base64
workarounds in runbooks and safety model. Add doc tests.
Closes#260.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Add runbook section, root-level .gitignore patterns, and detection helper
for _encode_/_emit_/_inline_ throwaway scripts. Surface non-blocking
warnings from assess_preflight_status and gitea_lock_issue.
Closes#261
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Add runbook guidance for deleting throwaway _encode/_emit/_inline commit
helpers after MCP commit attempts, ignore those patterns in .gitignore,
and cross-link the worktree-cleanup template.
Closes#261.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Require mutations only from branches/ worktrees after proving project
root, cwd, branch, stable main-checkout branch, and session worktree
path. Surface in portable skill, runbooks, wiki, operator guide, and
start-issue template.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Require lease verification (open PRs, branches, worktrees, leases,
merged completion) before any issue or PR work. Surface the rule in
the portable skill, Gitea runbooks, operator guide, and start-issue
template; add doc-contract tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- Add gitea_get_pr_review_feedback: read-only MCP-native discovery of
formal PR review verdicts (APPROVED / REQUEST_CHANGES / COMMENT) with
latest-state-per-reviewer, blocking change-request and approval
summaries, reviewed-head vs current-head staleness, dismissed/PENDING
handling, credential redaction of review bodies, no endpoint URLs
without the reveal opt-in, and a fail-closed gitea.read gate that
returns feedback_not_attempted with a structured #142 permission
report and zero API calls.
- Add task/role guards to gitea_resolve_task_capability: new
stop_required and task_role_guidance outputs, and a distinct
address_pr_change_requests author task, so a review/merge request
under an author profile returns explicit STOP guidance instead of
silently degrading into author-side mutations, and author-side
remediation is explicitly barred from review verdicts and merges.
- Add build_validation_report: validation reporting helper that
distinguishes passed / failed / skipped / not-run, requires the exact
output for failures, rejects vague statuses, and never implies
full-suite success unless the full-suite command passed.
- Document task/role alignment (review vs author-fix vs merge vs
comment workflows with required identity, allowed/forbidden actions,
and stop conditions), MCP-native review feedback discovery, and
validation reporting discipline in docs/llm-workflow-runbooks.md.
- Add tests/test_review_feedback.py (22 tests) covering discovery,
staleness, redaction, URL hiding, fail-closed gating, role guards for
author/reviewer profiles, and validation report semantics.
Closes#167
Co-Authored-By: Claude Fable 5 <[email protected]>
Record the #139 accepted decision as a deployment doc: two static
per-role MCP namespaces (gitea-author, gitea-reviewer), one credential
per process, with dynamic profile switching and dispatcher routing
explicitly rejected for now. Covers rationale (audit clarity, credential
concentration, two-party review boundary, fail-closed behavior),
reference-only client setup via GITEA_MCP_CONFIG/GITEA_MCP_PROFILE,
the 'Auth unsupported' client-badge caveat, and reconnect/reload
requirements after profile/config/code changes. Cross-linked from the
execution-profiles model doc and the workflow runbooks; guarded by
docs-content tests.
Closes#143
Co-Authored-By: Claude Fable 5 <[email protected]>
Add three read-only capability-discovery tools so new LLM sessions can
learn the workflow rules and available project skills from the MCP
server instead of long pasted operator prompts:
- mcp_get_control_plane_guide: active profile, authenticated identity
(fail-soft; unresolved identity returns STOP instructions),
allowed/forbidden operations, profile-aware guidance (author profiles
are told review/approve/merge is forbidden; reviewer profiles are told
review/merge requires eligibility checks and a pinned head SHA; mixed
profiles get a misconfiguration warning), and the standing rules: hard
stops, fail-closed behavior, head-SHA pinning, merge confirmation,
redaction, author/reviewer/merger separation, profile switching, and
identity verification.
- mcp_list_project_skills: registry of ten project workflows (issue
authoring, PR creation, PR review, PR merge, issue comments, profile
switching, redaction/security review, Jenkins read-only, GlitchTip
read-only, release/operator) with description, when-to-use, required
operations, status, and per-profile availability. Unimplemented
services are listed as designed-not-implemented rather than omitted.
- mcp_get_skill_guide: step-by-step guide per skill; unknown names fail
closed with the list of valid names.
All three are read-only and change no existing gate or permission.
Normal output contains no endpoint URLs or keychain IDs; the guide
includes the server host only under GITEA_MCP_REVEAL_ENDPOINTS=1.
Tests (tests/test_operator_guide.py, 17 new): profile-aware guidance
for author/reviewer, unresolved-identity STOP, read-only behavior,
redaction defaults and reveal opt-in, rules coverage, registry
completeness and profile awareness, unimplemented-service marking,
fail-closed unknown skill names.
Docs: llm-workflow-runbooks.md now tells new sessions to call the guide
tools first.
Closes#128
Co-Authored-By: Claude Fable 5 <[email protected]>
Make the nine-line compact Controller Handoff the default end-of-task
format; reserve the long Controller Handoff Summary for high-risk/complex
tasks (merge/tag/release, failed validation, blocked gates, secrets/prod,
complicated owner decisions, cross-repo state, or explicit owner request).
Compact form is for controller-LLM readability, safety confirmations are
never omitted, and PR bodies still carry full review detail.
Updates SKILL.md §K, llm-workflow-runbooks.md, and the start-issue /
review-pr templates. Documentation only.
Refs #101. Closes#108.
Co-Authored-By: Claude Fable 5 <[email protected]>
Automate the documented release-tag checklist (#48) without bypassing safety
gates.
scripts/release-tag:
- Requires a SemVer tag (vMAJOR.MINOR.PATCH); validates before any git/network.
- Fetch/prune first, then refuses: dirty worktree, non-master branch, local
master != remote master, HEAD not on remote master, and an existing local or
remote tag of the same name.
- Runs the full suite by default; --skip-tests is an explicit opt-out that warns.
- Creates an ANNOTATED tag (git tag -a), never lightweight.
- Safe by default: no push unless --push; --dry-run prints planned actions and
changes nothing. Supports --notes-file <path> for the annotation message.
- Prints: commit, tag, tests_run, tag_created, tag_pushed.
- Env injection points for testing/CI: RELEASE_TAG_REMOTE, RELEASE_TAG_TEST_CMD.
tests/test_release_tag.py (14 cases): valid SemVer dry-run; invalid version;
dirty worktree; non-master; master/remote mismatch; existing tag; missing
notes-file; annotated-not-lightweight; no-push-without-flag; push-only-with-flag;
notes-file message; --skip-tests warns; default runs tests (fail blocks tag,
pass tags). Each test builds a throwaway repo with a LOCAL bare remote (cloned,
not pushed) and stubs the test command — no network, no real tags, no pushing
from the project repo.
Docs: reference scripts/release-tag from the runbook, SKILL, and the release-tag
template (script preferred; manual steps are the fallback).
Full suite 305 passed / 0 failures; bash -n clean; git diff --check clean; no
secrets.
Closes#50. Refs #48.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Documents and enforces rules for closed-not-merged PR reconciliation, direct-master-push prevention, and issue label cleanup.
Rules added:
- Explicit definitions for Merged, Landed, Closed-not-merged, and Reconciled.
- A PR is done only when Gitea reports it merged or reconciliation proves content is present on master.
- Direct push to master is forbidden except as a documented recovery exception.
- PRs closed but not merged trigger the reconciliation process.
- Branch and worktree cleanup is forbidden until merge or reconciliation is confirmed.
- Final reports require PR metadata and Git content verification.
Closes#51.
Formalize the branch↔issue relationship and add a release/version-tagging policy.
Branch/issue linkage:
- scripts/worktree-start now validates branch names: implementation branches
must match (fix|feat|docs|chore)/issue-<number>-<slug>; review branches
review/pr-<number>-<slug>. Untraceable names are rejected with a clear error
(exit 2). New --allow-unlinked override for genuine exceptions. --dry-run
preserved.
- Documented issue → branch → worktree → PR → cleanup traceability in the
runbook and the portable SKILL, including the claim-comment convention and
Closes #n / Refs #n PR-body usage.
- Noted that Gitea exposes no native issue→branch API field (only a PR head
branch), so linkage is enforced via branch name + claim comment + PR body +
cleanup.
Versioning / tagging policy (docs only; no release automation yet):
- SemVer vMAJOR.MINOR.PATCH (v0.x.y while unstable) with PATCH/MINOR/MAJOR bump
rules.
- Annotated tags only, from the exact commit on remote master, only after the
full suite passes, with release notes referencing merged PRs/issues. Never tag
feature branches, dirty worktrees, unreviewed/self-authored work, or commits
not on remote master.
- Release runbook in the runbook + SKILL, plus a new
skills/llm-project-workflow/templates/release-tag.md prompt template.
Tests: worktree-start branch validation — accepts fix/feat/docs/chore/issue-*
and review/pr-*, rejects fix/random-name / my-branch / non-numeric issue,
honors --allow-unlinked, preserves --dry-run. Full suite 291 passed / 0 failures;
bash -n clean; git diff --check clean; no secrets.
Release-tag automation (a scripts/release-tag helper) intentionally deferred to a
later issue to keep this diff narrow and testable.
Closes#48. Refs #38, #39, #46.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Extract the project's operating rules into a reusable, project-agnostic skill
so any repo can adopt the same safe LLM workflow.
- skills/llm-project-workflow/SKILL.md: issue-first; isolated branch worktrees
(main checkout = orchestration only); distinct author/reviewer identities and
profile safety (secrets by reference only; stop if authenticated user == PR
author); branch naming; start/review/merge/cleanup workflows; fail-closed
cases; recovery patterns; and an "Adapting to a project" table for the
forge-specific names.
- templates/: copy/paste prompts for start-issue, review-pr, merge-pr,
recover-bad-state, worktree-cleanup.
- Link the skill from README.md and docs/llm-workflow-runbooks.md (the runbook
is framed as the Gitea-specific application of the portable skill).
Docs-only; no code, no secrets, safe placeholder examples only. No change to
MCP runtime, Gitea API, credential storage, or worktree helpers.
Checks: full suite 287 passed / 0 failures; git diff --check clean; secret scan
of skills/ clean.
Closes#46. Refs #38, #39.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Finishes the isolated-worktree standard begun in #38 (which merged the
branches/ gitignore, runbook, and scripts/worktree-start). Adds the two
remaining helpers and their tests.
- scripts/worktree-review: isolated DETACHED review worktree under
branches/review-<branch> (fetch/prune first, refuse to overwrite, print path,
--dry-run). Detached so a reviewer cannot accidentally commit and review work
never blocks the author's implementation folder.
- scripts/worktree-clean: the only deleting helper — removes a branches/
worktree after merge/close, refuses a dirty worktree (no --force), optionally
safe-deletes a merged branch (git branch -d), fetch/prune first, --dry-run.
Deletes nothing unless explicitly invoked.
- tests/test_worktrees.py: path generation + refuse-to-overwrite for all three
helpers via --dry-run (no real worktrees/branches/network/deletions).
- runbook: reference worktree-review / worktree-clean and the --dry-run flag.
Checks: bash -n clean on all three scripts; git diff --check clean; full suite
286 passed, 0 failures.
Closes#39. Follow-up to #38.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Make the interactive profile menu feel like a real terminal menu, via a new
injectable MenuIO abstraction (no menu logic change, no auth/secret-storage
change).
- Single-key top-level actions in a TTY (termios/tty raw read); no Enter
needed. Non-TTY / test runs fall back to line input.
- Enter backs out: Enter (or 0) on the main menu quits; Enter cancels any
submenu/profile prompt and returns.
- Profile chooser: everywhere a profile is needed, show a numbered list and
pick by key (1-9), with an explicit 'm) type a name manually' path and Enter
to cancel. Empty config handled gracefully.
- Clear screen before redrawing the main menu and chooser — TTY only; never
emits clear codes in non-TTY/test runs.
- Result actions (validate/test-auth/whoami/eligibility) print a concise result
then pause for a keypress in a TTY; non-TTY never blocks.
Helpers: read_key (via default_io) / choose_menu_option / choose_profile /
clear_screen / pause_for_key, plus MenuIO(is_tty, clear_enabled). TTY detected
with sys.stdin.isatty() and sys.stdout.isatty(); stdlib only.
Safety unchanged: no tokens/passwords printed, no raw config dumps, no
.env.personal, no change to auth behavior or secret storage.
Tests: rewrote menu tests around a scripted _FakeIO (no real terminal): single-
key select + clear, main-menu Enter/0 quit, submenu Enter cancel (no change),
chooser lists/selects/no-profiles/manual/out-of-range, non-TTY line fallback,
clear-only-when-enabled, pause never hangs non-TTY, and add-flow proving the
token value never reaches disk or stdout.
Docs: runbook note on single-key nav / Enter back-out / numbered chooser.
scripts/gitea-config-menu unchanged.
Closes#36. Refs #31, #34.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>