# Plan: Issue-Backed Closeout Guards

## Overview

Add lifecycle guards so issue-backed execution cannot merge or close a
plan-tracking issue while the issue-hosted execution state and dashboard still
say work is in progress.

## Read First

- Primary source: `docs/plans/issue-backed-closeout-guards/issue-backed-closeout-guards-discussion-source.md`
- Source type: discussion-to-implementation-doc
- Open questions carried into execution:
  - Whether `tracking-issue-closeout --repair-closed` should append a missing
    closeout marker or require a separate explicit finalization flag. Default:
    add an explicit one-time finalization flag.

## Execution

- Execution state:
  `docs/plans/issue-backed-closeout-guards/issue-backed-closeout-guards-execution-state.md`
- Tracking issue: [graysurf/agent-kit#273](https://github.com/graysurf/agent-kit/issues/273)

## Scope

- In scope:
  - `skills/workflows/issue/execute-from-tracking-issue/SKILL.md`
  - `skills/workflows/issue/execute-from-tracking-issue/bin/tracking_issue_lifecycle.py`
  - `skills/workflows/issue/execute-from-tracking-issue/scripts/tracking-issue-lifecycle.sh`
  - `skills/workflows/issue/execute-from-tracking-issue/tests/test_workflows_issue_execute_from_tracking_issue.py`
  - `skills/workflows/issue/tracking-issue-closeout/SKILL.md`
  - `skills/workflows/issue/tracking-issue-closeout/bin/tracking_issue_closeout.py`
  - `skills/workflows/issue/tracking-issue-closeout/scripts/tracking-issue-closeout.sh`
  - `skills/workflows/issue/tracking-issue-closeout/tests/test_workflows_issue_tracking_issue_closeout.py`
  - `skills/workflows/pr/github/close-github-pr/SKILL.md`
  - `skills/workflows/pr/github/close-github-pr/scripts/close-github-pr.sh`
  - `skills/workflows/pr/github/close-github-pr/tests/test_workflows_pr_github_close_github_pr.py`
  - `skills/workflows/pr/github/deliver-github-pr/SKILL.md`
  - `skills/workflows/issue/README.md`
  - `CHANGELOG.md`
- Out of scope:
  - `plan-tracking-issue` issue creation or snapshot creation changes.
  - GitLab lifecycle support.
  - Dispatch issue closeout semantics.
  - Generic PR close helpers directly mutating plan-tracking issue comments.
  - Reopening already closed issues.

## Assumptions

1. GitHub issue-backed execution remains the only target for these guards.
2. `execute-from-tracking-issue` owns execution-state creation and complete-state
   repair.
3. `tracking-issue-closeout` owns final readiness checks, final dashboard
   rendering, closeout comments, and issue closure or explicit closed-issue
   finalization.
4. `close-github-pr` can inspect closing issue references but should not become
   the owner of tracking issue state.
5. Optional skipped jobs such as `coverage_badge` are not the root cause of this
   plan; required-check behavior should remain unchanged except for tracking
   issue lifecycle detection.

## Sprint 1: Complete-State Lifecycle Gate

**Goal**: Make `execute-from-tracking-issue` expose a deterministic completion
gate that can be used before PR merge, issue close, or handoff.
**Demo/Validation**:

- Command(s):
  - `scripts/check.sh --tests -- -k execute_from_tracking_issue`
  - `scripts/check.sh --markdown`
- Verify:
  - A state comment with `Status: complete` and all `done`/`deferred` rows
    passes the completion gate.
  - `Status: in-progress` or any pending task row fails the completion gate.
  - Docs state that this gate must pass before issue-backed merge/close.

**PR grouping intent**: group
**Execution Profile**: serial

### Task 1.1: Add lifecycle tests for complete-state readiness

- **Location**:
  - `skills/workflows/issue/execute-from-tracking-issue/tests/test_workflows_issue_execute_from_tracking_issue.py`
- **Description**: Add fixtures modeled on the issue 384 failure mode: source
  and plan snapshots exist, validation and PR evidence exist, but latest state is
  still `in-progress` or contains pending rows.
- **Dependencies**:
  - none
- **Complexity**: 3
- **Acceptance criteria**:
  - A complete ledger fixture passes.
  - An `in-progress` status fixture fails.
  - A `complete` status with one pending row fails.
  - Failure output names the exact incomplete state reason.
- **Validation**:
  - `scripts/check.sh --tests -- -k execute_from_tracking_issue`

### Task 1.2: Implement completion-state reporting

- **Location**:
  - `skills/workflows/issue/execute-from-tracking-issue/bin/tracking_issue_lifecycle.py`
  - `skills/workflows/issue/execute-from-tracking-issue/scripts/tracking-issue-lifecycle.sh`
- **Description**: Extend the lifecycle helper and wrapper with a completion
  readiness check that validates latest state status, task-row statuses, and
  dashboard freshness. Expose it in JSON/report output and through a clear CLI
  flag or default readiness field.
- **Dependencies**:
  - Task 1.1
- **Complexity**: 4
- **Acceptance criteria**:
  - The report includes `completion_ready=true|false`.
  - The report lists incomplete task rows and stale dashboard links.
  - A failed completion gate exits non-zero when requested by the caller.
  - Existing dry-run and body-repair behavior stays compatible.
- **Validation**:
  - `scripts/check.sh --tests -- -k execute_from_tracking_issue`

### Task 1.3: Document the pre-merge and pre-close state checkpoint

- **Location**:
  - `skills/workflows/issue/execute-from-tracking-issue/SKILL.md`
  - `skills/workflows/issue/README.md`
  - `CHANGELOG.md`
- **Description**: Update workflow docs so issue-backed execution explicitly
  requires a complete state checkpoint before PR merge, auto-close, closeout, or
  final success reporting.
- **Dependencies**:
  - Task 1.2
- **Complexity**: 2
- **Acceptance criteria**:
  - Docs name the checkpoint before PR merge/close.
  - Docs state that a plain closeout comment is not a substitute for a complete
    execution-state comment.
  - Changelog records the user-visible lifecycle guard.
- **Validation**:
  - `scripts/check.sh --markdown`

## Sprint 2: Closeout Readiness And Closed-Issue Finalization

**Goal**: Make `tracking-issue-closeout` reject incomplete execution state and
recover already closed tracking issues through an explicit, idempotent path.
**Demo/Validation**:

- Command(s):
  - `scripts/check.sh --tests -- -k tracking_issue_closeout`
  - `scripts/check.sh --markdown`
- Verify:
  - Closeout readiness fails when latest state is incomplete.
  - Closed-issue repair/finalization works only after complete execution state
    exists.
  - Missing closeout marker handling is explicit and non-duplicating.

**PR grouping intent**: group
**Execution Profile**: serial

### Task 2.1: Add closeout tests for incomplete latest state

- **Location**:
  - `skills/workflows/issue/tracking-issue-closeout/tests/test_workflows_issue_tracking_issue_closeout.py`
- **Description**: Add fixtures where PR and validation evidence exist but the
  latest state is still `in-progress` or contains pending task rows.
- **Dependencies**:
  - Task 1.2
- **Complexity**: 3
- **Acceptance criteria**:
  - Normal closeout fails incomplete state.
  - `--repair-closed` also fails incomplete state.
  - Failure output gives a next action: post a complete
    `execute-from-tracking-issue:state:v1` comment first.
- **Validation**:
  - `scripts/check.sh --tests -- -k tracking_issue_closeout`

### Task 2.2: Enforce complete-state readiness in closeout helper

- **Location**:
  - `skills/workflows/issue/tracking-issue-closeout/bin/tracking_issue_closeout.py`
  - `skills/workflows/issue/tracking-issue-closeout/scripts/tracking-issue-closeout.sh`
- **Description**: Parse the latest execution-state comment and make complete
  state a hard readiness gate for normal closeout and closed-issue repair.
- **Dependencies**:
  - Task 2.1
- **Complexity**: 4
- **Acceptance criteria**:
  - Latest state status must be `complete`.
  - Task rows must be `done` or explicitly `deferred`.
  - Readiness JSON identifies incomplete state separately from missing markers,
    missing validation, and unmerged PRs.
  - Existing linked-PR parsing remains precise.
- **Validation**:
  - `scripts/check.sh --tests -- -k tracking_issue_closeout`

### Task 2.3: Add explicit closed-issue finalization for missing closeout marker

- **Location**:
  - `skills/workflows/issue/tracking-issue-closeout/SKILL.md`
  - `skills/workflows/issue/tracking-issue-closeout/bin/tracking_issue_closeout.py`
  - `skills/workflows/issue/tracking-issue-closeout/scripts/tracking-issue-closeout.sh`
  - `skills/workflows/issue/tracking-issue-closeout/tests/test_workflows_issue_tracking_issue_closeout.py`
- **Description**: Add or document a one-time explicit finalization mode for an
  already closed issue that is otherwise complete but lacks
  `<!-- tracking-issue-closeout:v1 -->`. The mode may be a dedicated flag or an
  extension of `--repair-closed`, but it must never duplicate an existing
  closeout marker.
- **Dependencies**:
  - Task 2.2
- **Complexity**: 4
- **Acceptance criteria**:
  - Closed issue finalization requires explicit approval.
  - Existing closeout marker means no duplicate marker is posted.
  - Missing closeout marker can be appended exactly once when the state and PR
    checks pass.
  - Body repair still updates only the mutable dashboard.
  - Reports distinguish `repair_only` from `finalized_closed_issue`.
- **Validation**:
  - `scripts/check.sh --tests -- -k tracking_issue_closeout`

## Sprint 3: GitHub PR Auto-Close Guard

**Goal**: Prevent generic GitHub PR close flows from silently auto-closing an
incomplete plan-tracking issue.
**Demo/Validation**:

- Command(s):
  - `scripts/check.sh --tests -- -k close_github_pr`
  - `scripts/check.sh --tests -- -k deliver_github_pr`
  - `scripts/check.sh --markdown`
- Verify:
  - PR close detects plan-tracking issues in `closingIssuesReferences`.
  - Incomplete tracking issue state blocks or emits the documented hard
    lifecycle stop before merge.
  - Non-tracking issue PRs keep existing behavior.

**PR grouping intent**: group
**Execution Profile**: serial

### Task 3.1: Add close-helper coverage for plan-tracking auto-close

- **Location**:
  - `skills/workflows/pr/github/close-github-pr/tests/test_workflows_pr_github_close_github_pr.py`
- **Description**: Extend the `gh` stub fixtures so a PR can report
  `closingIssuesReferences` and the referenced issue body/comments can identify
  a plan-tracking issue with complete or incomplete state.
- **Dependencies**:
  - Task 1.2
  - Task 2.2
- **Complexity**: 4
- **Acceptance criteria**:
  - A PR closing a non-tracking issue follows existing behavior.
  - A PR closing a tracking issue with incomplete state blocks before merge.
  - A PR closing a tracking issue with complete state may proceed, while
    reminding the caller to run closeout/finalization after merge.
  - Optional skipped checks remain non-blocking only when required checks pass.
- **Validation**:
  - `scripts/check.sh --tests -- -k close_github_pr`

### Task 3.2: Implement plan-tracking issue detection in PR close flow

- **Location**:
  - `skills/workflows/pr/github/close-github-pr/scripts/close-github-pr.sh`
  - `skills/workflows/pr/github/close-github-pr/SKILL.md`
  - `skills/workflows/pr/github/deliver-github-pr/SKILL.md`
- **Description**: Inspect PR closing issue references before merge. For
  plan-tracking issues, require the lifecycle completion gate or stop with a
  deterministic next action that names `execute-from-tracking-issue` and
  `tracking-issue-closeout`.
- **Dependencies**:
  - Task 3.1
- **Complexity**: 5
- **Acceptance criteria**:
  - The close script reads closing issue references through `gh pr view`.
  - Tracking issues are identified by snapshot/state markers, not by title
    heuristics alone.
  - Incomplete tracking issue state prevents `gh pr merge`.
  - Complete tracking issue state permits merge but reports the required
    post-merge closeout/finalization action.
  - Docs warn against accidental `Closes #<issue>` use for issue-backed tracker
    PRs unless the closeout path is planned.
- **Validation**:
  - `scripts/check.sh --tests -- -k close_github_pr`
  - `scripts/check.sh --markdown`

### Task 3.3: Validate delivery composition

- **Location**:
  - `skills/workflows/pr/github/deliver-github-pr/tests/test_workflows_pr_github_deliver_github_pr.py`
  - `skills/workflows/pr/github/deliver-github-pr/SKILL.md`
- **Description**: Confirm `deliver-github-pr` reports tracking issue lifecycle
  stops as blocked workflow state, not partial success, and preserves its
  existing required-check loop.
- **Dependencies**:
  - Task 3.2
- **Complexity**: 3
- **Acceptance criteria**:
  - Delivery docs state that tracking issue lifecycle blocks are real close
    blockers.
  - Tests cover or snapshot the close subcommand's blocked tracking-issue output
    when deliver delegates to close.
  - Existing no-checks and optional-skipped-check tests still pass.
- **Validation**:
  - `scripts/check.sh --tests -- -k deliver_github_pr`

## Sprint 4: Plan And Repository Validation

**Goal**: Validate the plan bundle and the full repository before delivery.
**Demo/Validation**:

- Command(s):
  - `plan-tooling validate --file docs/plans/issue-backed-closeout-guards/issue-backed-closeout-guards-plan.md --format text --explain`
  - `scripts/check.sh --tests -- -k "execute_from_tracking_issue or tracking_issue_closeout or close_github_pr or deliver_github_pr"`
  - `scripts/check.sh --markdown`
  - `git diff --check`
  - `scripts/check.sh --all`
- Verify:
  - The plan remains executable.
  - Focused workflow tests pass.
  - The full repo gate passes.

**PR grouping intent**: group
**Execution Profile**: serial

### Task 4.1: Run focused and full validation

- **Location**:
  - `docs/plans/issue-backed-closeout-guards/issue-backed-closeout-guards-plan.md`
  - `skills/workflows/issue/execute-from-tracking-issue/tests/test_workflows_issue_execute_from_tracking_issue.py`
  - `skills/workflows/issue/tracking-issue-closeout/tests/test_workflows_issue_tracking_issue_closeout.py`
  - `skills/workflows/pr/github/close-github-pr/tests/test_workflows_pr_github_close_github_pr.py`
  - `skills/workflows/pr/github/deliver-github-pr/tests/test_workflows_pr_github_deliver_github_pr.py`
- **Description**: Run plan validation, focused tests, markdown checks,
  whitespace checks, and the full local gate. Fix any in-scope drift before
  opening or updating a PR.
- **Dependencies**:
  - Task 1.3
  - Task 2.3
  - Task 3.3
- **Complexity**: 2
- **Acceptance criteria**:
  - Plan validation passes.
  - Focused workflow tests pass.
  - Markdown checks pass.
  - `git diff --check` passes.
  - `scripts/check.sh --all` passes.
  - Execution-state comments on the tracking issue link the validation evidence.
- **Validation**:
  - `plan-tooling validate --file docs/plans/issue-backed-closeout-guards/issue-backed-closeout-guards-plan.md --format text --explain`
  - `scripts/check.sh --tests -- -k "execute_from_tracking_issue or tracking_issue_closeout or close_github_pr or deliver_github_pr"`
  - `scripts/check.sh --markdown`
  - `git diff --check`
  - `scripts/check.sh --all`

## Risks And Gotchas

- Be precise about ownership: lifecycle helpers can block or render state, but
  only `execute-from-tracking-issue` should create the complete state comment.
- A PR may need to merge before the final closeout marker can honestly say all
  linked PRs are merged. The workflow should either avoid auto-close keywords or
  use the explicit post-merge closed-issue finalization path.
- Do not regress the required-check fix for optional skipped jobs. Keep check
  parsing tests separate from tracking issue lifecycle tests.
- Keep GitHub-only assumptions visible; do not imply GitLab support in these
  helpers.
