Author mutation tools now resolve workspace via explicit worktree_path,
env bindings, or the active author issue lock — never silent fallback to
the control checkout/master. Missing configured bindings fail closed with
operator recovery; create_issue and create_issue_comment agree.
Recovered onto 0568f44 from preserved candidate cbf56ccd (AUTHOR_RECOVERY).
LLM_LOCK_ID=author-618-recovery-508eb3162d01-1784569919
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
571 lines
15 KiB
Python
571 lines
15 KiB
Python
"""Worked examples for the two-comment workflow (#507)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
HEAD_SHA = "08202f7eaa6d09b2eca8f2960126994a4b22646b"
|
|
|
|
EXAMPLES: list[tuple[str, str, str]] = []
|
|
|
|
|
|
def _example(name: str, handoff: str, ledger: str) -> tuple[str, str, str]:
|
|
return (name, handoff.strip(), ledger.strip())
|
|
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"approved_review_posted",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #487 / Issue #485 — review approved
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_submit_pr_review → APPROVED review posted to Gitea (comment id 6566)
|
|
|
|
Blockers:
|
|
- none
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] PR #487 — APPROVED review posted to Gitea
|
|
|
|
What is true now:
|
|
- PR state: open
|
|
- Current head SHA: {HEAD_SHA}
|
|
- Server-side decision state: APPROVED review posted to Gitea
|
|
- Local verdict/state: APPROVE verdict prepared locally
|
|
- Latest known validation: tests passed locally
|
|
|
|
What changed:
|
|
- APPROVED review posted to Gitea at pinned head
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: merger
|
|
- Required action: merge on explicit operator command
|
|
- Do not do: re-post APPROVE
|
|
- Resume from: PR #487 review feedback
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"approve_blocked_before_posting",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #487 / Issue #485 — approve blocked
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- process/rule blocker: MCP process root still control checkout
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] PR #487 — APPROVE verdict prepared locally; post blocked
|
|
|
|
What is true now:
|
|
- PR state: open
|
|
- Current head SHA: {HEAD_SHA}
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: APPROVE verdict prepared locally
|
|
- Latest known validation: tests passed locally
|
|
|
|
What changed:
|
|
- Review validation completed locally; APPROVE not posted
|
|
|
|
What is blocked:
|
|
- Blocker classification: process/rule blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: operator
|
|
- Required action: reconnect reviewer MCP to branches worktree
|
|
- Do not do: retry APPROVE from root-bound session
|
|
- Resume from: lease + mark_final_review_decision + submit
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"request_changes_posted",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #200 — request changes
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_submit_pr_review → REQUEST_CHANGES posted to Gitea
|
|
|
|
Blockers:
|
|
- none
|
|
""",
|
|
"""
|
|
[THREAD STATE LEDGER] PR #200 — REQUEST_CHANGES posted to Gitea
|
|
|
|
What is true now:
|
|
- PR state: open
|
|
- Server-side decision state: REQUEST_CHANGES posted to Gitea
|
|
- Local verdict/state: REQUEST_CHANGES prepared locally
|
|
- Latest known validation: tests passed locally
|
|
|
|
What changed:
|
|
- REQUEST_CHANGES posted to Gitea
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: author
|
|
- Required action: address review feedback and push fixes
|
|
- Do not do: merge
|
|
- Resume from: PR review comments
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"merge_completed",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #487 — merge performed
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_merge_pr → merge performed
|
|
|
|
Blockers:
|
|
- none
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] PR #487 — merge performed
|
|
|
|
What is true now:
|
|
- PR state: merged
|
|
- Current head SHA: {HEAD_SHA}
|
|
- Server-side decision state: merge performed
|
|
- Local verdict/state: merge not attempted locally before MCP merge
|
|
- Latest known validation: full suite not rerun
|
|
|
|
What changed:
|
|
- merge performed via gitea_merge_pr
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: reconciler
|
|
- Required action: verify linked issue closure policy
|
|
- Do not do: re-merge
|
|
- Resume from: post-merge cleanup checklist
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"merge_blocked",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #487 — merge not performed
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_merge_pr attempted → merge not performed (stale approval gate)
|
|
|
|
Blockers:
|
|
- stale head blocker: approval not at current head
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] PR #487 — merge not performed
|
|
|
|
What is true now:
|
|
- PR state: open
|
|
- Current head SHA: {HEAD_SHA}
|
|
- Server-side decision state: merge not performed
|
|
- Local verdict/state: merge not performed
|
|
- Latest known validation: tests passed locally
|
|
|
|
What changed:
|
|
- merge attempt blocked by stale-head gate
|
|
|
|
What is blocked:
|
|
- Blocker classification: stale head
|
|
|
|
Who/what acts next:
|
|
- Next actor: reviewer
|
|
- Required action: re-review at current head
|
|
- Do not do: merge until approval_at_current_head is true
|
|
- Resume from: gitea_get_pr_review_feedback
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"reconciler_closure",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #99 — reconciler closure
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_reconcile_already_landed_pr → PR closed on Gitea
|
|
|
|
Blockers:
|
|
- none
|
|
""",
|
|
"""
|
|
[THREAD STATE LEDGER] PR #99 — reconciler closure complete
|
|
|
|
What is true now:
|
|
- PR state: closed
|
|
- Server-side decision state: server-side state changed
|
|
- Local verdict/state: no server-side state changed locally before MCP close
|
|
- Latest known validation: ancestor proof passed
|
|
|
|
What changed:
|
|
- superseded PR closed by reconciler
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: controller
|
|
- Required action: verify queue has no duplicate open PR
|
|
- Do not do: reopen without canonical PR proof
|
|
- Resume from: queue inventory
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"environment_tooling_blocker",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #487 — tooling blocker
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- environment/tooling blocker: gitea-reviewer MCP process root mismatch
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] PR #487 — lease attempt blocked
|
|
|
|
What is true now:
|
|
- PR state: open
|
|
- Current head SHA: {HEAD_SHA}
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: APPROVE verdict prepared locally
|
|
- Latest known validation: tests passed locally
|
|
|
|
What changed:
|
|
- lease attempt blocked by workspace guard
|
|
|
|
What is blocked:
|
|
- Blocker classification: environment/tooling blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: operator
|
|
- Required action: set GITEA_AUTHOR_WORKTREE and /mcp reconnect
|
|
- Do not do: acquire lease from control checkout
|
|
- Resume from: gitea_get_runtime_context
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"stale_head_blocker",
|
|
f"""
|
|
[CONTROLLER HANDOFF] PR #300 — stale head
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- stale head blocker: live head differs from pinned reviewed head
|
|
""",
|
|
"""
|
|
[THREAD STATE LEDGER] PR #300 — stale approval
|
|
|
|
What is true now:
|
|
- PR state: open
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: approval_at_current_head is false (stale head)
|
|
- Latest known validation: full suite not rerun
|
|
|
|
What changed:
|
|
- author pushed after approval
|
|
|
|
What is blocked:
|
|
- Blocker classification: stale head
|
|
|
|
Who/what acts next:
|
|
- Next actor: reviewer
|
|
- Required action: fresh review at current head
|
|
- Do not do: merge with stale approval
|
|
- Resume from: gitea_get_pr_review_feedback
|
|
""",
|
|
)
|
|
)
|
|
|
|
# ── Stable control runtime states (#615) ─────────────────────────────────────
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"runtime_healthy",
|
|
"""
|
|
[CONTROLLER HANDOFF] Runtime check — stable control runtime healthy
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- none
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] Runtime — stable control runtime healthy
|
|
|
|
What is true now:
|
|
- Runtime mode: stable-control
|
|
- Runtime git SHA: {HEAD_SHA}
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: runtime reported real_mutations_allowed=true
|
|
- Latest known validation: gitea_get_runtime_context read in this session
|
|
|
|
What changed:
|
|
- nothing; this is a read-only runtime observation
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: author
|
|
- Required action: proceed with the allocated workflow phase
|
|
- Do not do: restart or relaunch the stable runtime
|
|
- Resume from: gitea_workflow_dashboard
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"transport_flap_recovered",
|
|
"""
|
|
[CONTROLLER HANDOFF] Runtime check — transport flap recovered
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- environment/tooling blocker: MCP transport dropped mid-session and recovered
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] Runtime — transport flap recovered, namespaces re-proven
|
|
|
|
What is true now:
|
|
- Runtime mode: stable-control
|
|
- Runtime git SHA: {HEAD_SHA}
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: all four namespaces re-proven after the flap
|
|
- Latest known validation: whoami + runtime context + capability resolve per namespace
|
|
|
|
What changed:
|
|
- author, reviewer, merger, and reconciler namespaces each re-proven independently
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: author
|
|
- Required action: resume the interrupted workflow phase from its last durable state
|
|
- Do not do: treat author proof as proof of the other namespaces
|
|
- Resume from: the phase handoff that preceded the flap
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"namespace_not_yet_reproven",
|
|
"""
|
|
[CONTROLLER HANDOFF] Runtime check — reviewer namespace not re-proven
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- environment/tooling blocker: reviewer namespace not re-proven since the transport flap
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] Runtime — reviewer namespace not re-proven after flap
|
|
|
|
What is true now:
|
|
- Runtime mode: stable-control
|
|
- Runtime git SHA: {HEAD_SHA}
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: reviewer namespace unproven; mutation gate fails closed
|
|
- Latest known validation: author namespace re-proven; reviewer not attempted
|
|
|
|
What changed:
|
|
- reviewer mutations blocked with namespace_not_reproven_after_flap
|
|
|
|
What is blocked:
|
|
- Blocker classification: environment/tooling blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: reviewer
|
|
- Required action: run whoami, runtime context, and capability resolve in the reviewer namespace
|
|
- Do not do: substitute author proof for reviewer proof
|
|
- Resume from: docs/stable-runtime-promotion-runbook.md section 5
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"promotion_completed",
|
|
"""
|
|
[CONTROLLER HANDOFF] Runtime promotion — completed
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_create_issue_comment on #615 with the promotion record
|
|
|
|
Blockers:
|
|
- none
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] Runtime — promotion completed and re-proven
|
|
|
|
What is true now:
|
|
- Runtime mode: stable-control
|
|
- Runtime git SHA: {HEAD_SHA}
|
|
- Server-side decision state: server-side state changed
|
|
- Local verdict/state: promotion record carries every required field
|
|
- Latest known validation: assess_promotion_record valid=true; all namespaces re-proven
|
|
|
|
What changed:
|
|
- stable control runtime advanced to the promoted SHA and reloaded by the operator
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: author
|
|
- Required action: resume normal workflow phases on the promoted runtime
|
|
- Do not do: promote again without a fresh record
|
|
- Resume from: docs/stable-runtime-promotion-runbook.md section 4
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"rollback_required",
|
|
"""
|
|
[CONTROLLER HANDOFF] Runtime promotion — rollback required
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_create_issue_comment on #615 with the rollback evidence
|
|
|
|
Blockers:
|
|
- environment/tooling blocker: promoted runtime unhealthy, rollback required
|
|
""",
|
|
f"""
|
|
[THREAD STATE LEDGER] Runtime — promoted runtime unhealthy, rollback required
|
|
|
|
What is true now:
|
|
- Runtime mode: unknown
|
|
- Runtime git SHA: {HEAD_SHA}
|
|
- Server-side decision state: no server-side state changed after the promotion record
|
|
- Local verdict/state: promoted runtime failed namespace health; mutations blocked
|
|
- Latest known validation: namespace health probe reported EOF after reload
|
|
|
|
What changed:
|
|
- all PR/review/merge work stopped pending rollback to the previous runtime SHA
|
|
|
|
What is blocked:
|
|
- Blocker classification: environment/tooling blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: controller
|
|
- Required action: operator rolls back to the previous runtime SHA and re-proves every namespace
|
|
- Do not do: route around the unhealthy runtime or mutate from a dev/test runtime
|
|
- Resume from: docs/stable-runtime-promotion-runbook.md section 6
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"duplicate_canonicalization_blocker",
|
|
f"""
|
|
[CONTROLLER HANDOFF] Issue filing — duplicate found
|
|
|
|
Server-side mutation ledger:
|
|
- gitea_create_issue_comment on #505 with missing acceptance criteria
|
|
|
|
Blockers:
|
|
- duplicate/canonicalization blocker: #505 tracks CTH umbrella
|
|
""",
|
|
"""
|
|
[THREAD STATE LEDGER] Issue #507 — filed as focused split from #505
|
|
|
|
What is true now:
|
|
- Issue state: open
|
|
- Server-side decision state: server-side state changed
|
|
- Local verdict/state: no server-side state changed before issue create
|
|
- Latest known validation: duplicate search completed
|
|
|
|
What changed:
|
|
- new issue #507 created after duplicate assessment
|
|
|
|
What is blocked:
|
|
- Blocker classification: no blocker
|
|
|
|
Who/what acts next:
|
|
- Next actor: author
|
|
- Required action: implement #507 two-comment validator
|
|
- Do not do: recreate duplicate CTH issue
|
|
- Resume from: issue #507 body
|
|
""",
|
|
)
|
|
)
|
|
|
|
EXAMPLES.append(
|
|
_example(
|
|
"bound_worktree_missing_blocker",
|
|
"""
|
|
[CONTROLLER HANDOFF] Issue #618 — author mutation blocked
|
|
|
|
Server-side mutation ledger:
|
|
- none — no server-side state changed
|
|
|
|
Blockers:
|
|
- environment/tooling blocker: bound worktree missing; operator must recreate or repoint the worktree and reconnect
|
|
""",
|
|
"""
|
|
[THREAD STATE LEDGER] Issue #618 — author worktree binding unhealthy
|
|
|
|
What is true now:
|
|
- Issue state: open
|
|
- Server-side decision state: no server-side state changed
|
|
- Local verdict/state: author mutation tools fail closed consistently
|
|
- Latest known validation: runtime context reports workspace_healthy=false
|
|
- Role/profile: prgs-author
|
|
- Configured worktree path: branches/mcp-author-clean-ns (via GITEA_AUTHOR_WORKTREE)
|
|
- path_exists: false
|
|
- in_git_worktree_list: false
|
|
- inspected_git_root: null
|
|
|
|
What changed:
|
|
- nothing server-side; local env still points at a deleted role-bound worktree
|
|
|
|
What is blocked:
|
|
- Blocker classification: environment/tooling blocker
|
|
- Blocker detail: bound worktree missing; operator must recreate or repoint the worktree and reconnect
|
|
- create_issue and create_issue_comment (and other author mutations) agree: fail closed before API mutation
|
|
|
|
Who/what acts next:
|
|
- Next actor: operator
|
|
- Required action: recreate the worktree under branches/ (scripts/worktree-start or git worktree add), set GITEA_AUTHOR_WORKTREE / GITEA_ACTIVE_WORKTREE to that path (or pass worktree_path), keep control checkout clean on master, reconnect the author MCP session, then re-run the mutation
|
|
- Do not do: retry mutations hoping create_issue_comment will still work while create_issue blocks; do not fall back to the control checkout or master
|
|
- Resume from: healthy author worktree binding + gitea_whoami + gitea_resolve_task_capability
|
|
""",
|
|
)
|
|
) |