Separate PR submission outcomes from task done #777

Closed
opened 2026-07-09 07:41:17 +00:00 by coilyco-ops · 4 comments
Member

Problem

PR workflows currently let the engineer post WARD-OUTCOME: done after opening a pull request. That encodes the wrong state. The issue task is not done while the change is only proposed in a PR. This caused recovery confusion in ward#735 and PR #773: the worker opened a PR, posted done, then CI failed.

The same problem applies to both PR-shaped workflows:

  • pr / pull-requests - the engineer has submitted work for review, but the task is not done.
  • pull-requests-and-merge - the engineer has submitted merge-eligible work, but the task is not done until the director merge lane lands it on main.

Desired model

Separate engineer boundary states from task completion states. A worker that only opens a PR should report a non-done state such as submitted, pending, or ready-for-merge. The exact spelling is an implementation choice, but it must not map to done in the backlog ledger.

Suggested shape:

WARD-OUTCOME: submitted - PR opened, waiting for human merge
workflow: pr; review summary: ...

For pull-requests-and-merge, the worker should report a non-done merge-ready state after PR creation and review. The director merge sweep, not the engineer, should mark the task done after the PR merge reaches main.

Requirements

  • Update the seed text so PR-only engineers are never told to post WARD-OUTCOME: done for PR creation.
  • Update the seed text so pull-requests-and-merge engineers also do not claim done at the engineer boundary.
  • Extend the outcome parser and director ledger with an explicit nonterminal PR-submitted state instead of treating unknown statuses as blocked by accident.
  • Update the director merge policy to use the new merge-ready state for pull-requests-and-merge, then have the director post or otherwise record the final done outcome only after merge.
  • Keep direct-main behavior unchanged: a direct-main worker may still post done only after the commit is on main.
  • Update docs and tests around headlessReflection, parseBacklogOutcome, and directorMergeDecision.
  • ward#706 - make PR workflow create, wait, and merge pull requests.
  • ward#698 - standardize structured outcome comments.
  • ward#735 / PR #773 - concrete incident where a PR-only worker claimed done before CI failed.

Acceptance

  • A workflow pr run that opens a PR no longer produces a WARD-OUTCOME: done comment.
  • A workflow pull-requests-and-merge run that opens a PR no longer produces a WARD-OUTCOME: done comment from the engineer.
  • The director can still distinguish blocked/failed runs from PR-submitted runs.
  • The director merge lane can still find merge-eligible PRs.
  • Only after the PR merge reaches main does ward mark the issue done.
  • ward exec test passes.

Filed from the read-only director surface during the 2026-07-09 recovery pass.

Codex, via ward agent

## Problem PR workflows currently let the engineer post `WARD-OUTCOME: done` after opening a pull request. That encodes the wrong state. The issue task is not done while the change is only proposed in a PR. This caused recovery confusion in `ward#735` and PR `#773`: the worker opened a PR, posted done, then CI failed. The same problem applies to both PR-shaped workflows: * `pr` / `pull-requests` - the engineer has submitted work for review, but the task is not done. * `pull-requests-and-merge` - the engineer has submitted merge-eligible work, but the task is not done until the director merge lane lands it on `main`. ## Desired model Separate engineer boundary states from task completion states. A worker that only opens a PR should report a non-done state such as submitted, pending, or ready-for-merge. The exact spelling is an implementation choice, but it must not map to done in the backlog ledger. Suggested shape: ```text WARD-OUTCOME: submitted - PR opened, waiting for human merge workflow: pr; review summary: ... ``` For `pull-requests-and-merge`, the worker should report a non-done merge-ready state after PR creation and review. The director merge sweep, not the engineer, should mark the task done after the PR merge reaches `main`. ## Requirements * Update the seed text so PR-only engineers are never told to post `WARD-OUTCOME: done` for PR creation. * Update the seed text so `pull-requests-and-merge` engineers also do not claim done at the engineer boundary. * Extend the outcome parser and director ledger with an explicit nonterminal PR-submitted state instead of treating unknown statuses as blocked by accident. * Update the director merge policy to use the new merge-ready state for `pull-requests-and-merge`, then have the director post or otherwise record the final done outcome only after merge. * Keep `direct-main` behavior unchanged: a direct-main worker may still post done only after the commit is on `main`. * Update docs and tests around `headlessReflection`, `parseBacklogOutcome`, and `directorMergeDecision`. ## Related * `ward#706` - make PR workflow create, wait, and merge pull requests. * `ward#698` - standardize structured outcome comments. * `ward#735` / PR `#773` - concrete incident where a PR-only worker claimed done before CI failed. ## Acceptance * A `workflow pr` run that opens a PR no longer produces a `WARD-OUTCOME: done` comment. * A `workflow pull-requests-and-merge` run that opens a PR no longer produces a `WARD-OUTCOME: done` comment from the engineer. * The director can still distinguish blocked/failed runs from PR-submitted runs. * The director merge lane can still find merge-eligible PRs. * Only after the PR merge reaches `main` does ward mark the issue done. * `ward exec test` passes. Filed from the read-only director surface during the 2026-07-09 recovery pass. <!-- ward-agent-signature --> Codex, via `ward agent`
Author
Member

🔒 Reserved by ward agent --harness codex — container engineer-codex-ward-777 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-09T07:41:24Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (1h TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/ward#777 · branch issue-777 · harness codex · workflow pr
  • Run: engineer-codex-ward-777 · ward v0.480.0 · dispatched 2026-07-09T07:41:24Z
  • Comment thread: 0 included in the pre-flight read, 0 stripped (ward's own automated comments).

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.480.0).

— Codex, via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --harness codex` — container `engineer-codex-ward-777` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-09T07:41:24Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (1h TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/ward#777` · branch `issue-777` · harness `codex` · workflow `pr` - **Run:** `engineer-codex-ward-777` · ward `v0.480.0` · dispatched `2026-07-09T07:41:24Z` - **Comment thread:** 0 included in the pre-flight read, 0 stripped (ward's own automated comments). Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.480.0). </details> <!-- ward-agent-signature --> — Codex, via `ward agent`
Author
Member

WARD-RESERVATION: held 🔒

reservation details

Holder: container engineer-codex-ward-777 on host kais-macbook-pro-2.local.

Reserved by ward agent --harness codex (reserved 2026-07-09T17:55:42Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (1h TTL). --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/ward#777 · branch issue-777 · harness codex · workflow pull-request-and-merge
  • Run: engineer-codex-ward-777 · ward v0.493.0 · dispatched 2026-07-09T17:55:42Z
  • Comment thread: 0 included in the pre-flight read, 1 stripped (ward's own automated comments).

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.493.0).

— Codex, via ward agent

<!-- ward-agent-reservation --> WARD-RESERVATION: held 🔒 <details><summary>reservation details</summary> Holder: container `engineer-codex-ward-777` on host `kais-macbook-pro-2.local`. Reserved by `ward agent --harness codex` (reserved 2026-07-09T17:55:42Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (1h TTL). `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh**. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/ward#777` · branch `issue-777` · harness `codex` · workflow `pull-request-and-merge` - **Run:** `engineer-codex-ward-777` · ward `v0.493.0` · dispatched `2026-07-09T17:55:42Z` - **Comment thread:** 0 included in the pre-flight read, 1 stripped (ward's own automated comments). - stripped: @coilyco-ops (2026-07-09T07:41:25Z) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.493.0). </details> </details> <!-- ward-agent-signature --> — Codex, via `ward agent`
Author
Member

WARD-RESERVATION: held 🔒

reservation details

Holder: container engineer-codex-ward-777 on host kais-macbook-pro-2.local.

Reserved by ward agent --harness codex (reserved 2026-07-09T21:54:06Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (1h TTL). --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/ward#777 · branch issue-777 · harness codex · workflow direct-to-main
  • Run: engineer-codex-ward-777 · ward v0.522.0 · dispatched 2026-07-09T21:54:06Z
  • Comment thread: 0 included in the pre-flight read, 2 stripped (ward's own automated comments).

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.522.0).

— Codex, via ward agent

<!-- ward-agent-reservation --> WARD-RESERVATION: held 🔒 <details><summary>reservation details</summary> Holder: container `engineer-codex-ward-777` on host `kais-macbook-pro-2.local`. Reserved by `ward agent --harness codex` (reserved 2026-07-09T21:54:06Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (1h TTL). `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh**. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/ward#777` · branch `issue-777` · harness `codex` · workflow `direct-to-main` - **Run:** `engineer-codex-ward-777` · ward `v0.522.0` · dispatched `2026-07-09T21:54:06Z` - **Comment thread:** 0 included in the pre-flight read, 2 stripped (ward's own automated comments). - stripped: @coilyco-ops (2026-07-09T07:41:25Z), @coilyco-ops (2026-07-09T17:55:44Z) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.522.0). </details> </details> <!-- ward-agent-signature --> — Codex, via `ward agent`
Author
Member

WARD-OUTCOME: done

details

workflow: pull-requests-and-merge; review summary: skipped (review gate skipped by ~/.ward/config.yaml default)
retrospective: the boundary split held, and the only friction was cache churn in this container
confidence: high
surprises: none beyond the repeated Go build scratch pressure
follow-ups: none

WARD-OUTCOME: done <details><summary>details</summary> workflow: pull-requests-and-merge; review summary: skipped (review gate skipped by ~/.ward/config.yaml default) retrospective: the boundary split held, and the only friction was cache churn in this container confidence: high surprises: none beyond the repeated Go build scratch pressure follow-ups: none </details>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#777
No description provided.