issue comment write broken: shadow passes -body to ward-kdl-write which doesn't define it, so no comment posts (also edit --labels) #613

Closed
opened 2026-07-05 22:08:17 +00:00 by coilysiren · 2 comments
Owner

Summary

Posting an issue comment through ward ops forgejo issue comment fails in (at least) the director-surface container build: the shadow wrapper hands -body to an inner ward-kdl-write invocation that does not define that flag, so no comment is ever created. Confirmed live from an eco-ops read-only director session (2026-07-05).

Symptom

$ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body "..."
... --output json: exit status 1: Incorrect Usage: flag provided but not defined: -body
ward-kdl-write: flag provided but not defined: -body

$ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body-file comment.json
... same: ward-kdl-write: flag provided but not defined: -body

Both --body and --body-file fail identically. Verified the comment did not post (comment count on the target issue unchanged across attempts).

Scope / contrast

  • ward ops forgejo issue comment help advertises --body string and --body-file string, so the surface flag exists - the break is in the shadow -> ward-kdl-write translation, which emits -body to a binary that does not define it. Looks like a version skew between the comment shadow and the ward-kdl-write build shipped in this container.
  • ward ops forgejo issue edit --body-file <json> works (used it to append to a body successfully), because it PATCHes the JSON body directly without the per-flag translation.
  • ward ops forgejo issue edit --labels fails the same way (flag provided but not defined: -labels) - same translation class of bug.
  • ward ops forgejo issue reopen / edit --state work.

Impact

From a director surface, the sanctioned way to add context to an issue (comment) is dead. The workaround is to append into the issue body via edit --body-file, which is acceptable for reaching a headless engineer (it reads the body, not comments) but wrong for human-facing threads and for the advisor role, whose whole output contract is "post the answer as a comment." An advisor that cannot comment cannot deliver.

Ask

Fix the issue comment shadow so --body / --body-file reach ward-kdl-write as a flag it defines (or pin the shadow and ward-kdl-write to the same build). Same fix class covers edit --labels. Add a regression test that actually posts a comment through the shadow and asserts it lands.

Refs

Found from an eco-ops director session, 2026-07-05, while reviving ward#547. Related: the label-add path is separately out of the director broker's write tier (create/edit/comment/close/reopen only), so labels could not be set at all from that seat. Origin: eco-ops director session.


Likely root cause (Kai's read, 2026-07-06): build-time vs run-time ward-kdl asset skew

Kai's diagnosis: this is a release-asset version skew, not a flag typo. At any given run there are multiple ward binaries each carrying their own embedded ward-kdl, and they do not match:

  • host ward (with its embedded/generated ward-kdl assets)
  • container ward (with its own embedded ward-kdl assets)

So up to four ward-kdl variants can be live at once (host-ward-embedded, host dev-tree, container-ward-embedded, container dev-tree). The issue comment shadow is defined by one ward-kdl generation, and it hands -body to a ward-kdl-write invocation built from a different generation that does not define that flag — hence flag provided but not defined: -body. edit --labels fails the same way; edit --body-file (which bypasses the per-flag translation) works, which fits: the break is in the flag surface the shadow emits vs the flag surface the embedded ward-kdl-write accepts, not in the HTTP call.

Direction

Pin the shadow definition and the ward-kdl-write it drives to the same build/generation, so a released ward binary cannot ship a comment shadow whose -body the embedded ward-kdl-write rejects. Treat the embedded ward-kdl as a versioned release asset that must match the binary that embeds it (build-time), and make a host-ward / container-ward mismatch a detectable, loud condition rather than a silent flag-parse error at run time. Add a regression that actually posts a comment through the shadow end to end.

## Summary Posting an issue comment through `ward ops forgejo issue comment` fails in (at least) the director-surface container build: the shadow wrapper hands `-body` to an inner `ward-kdl-write` invocation that does not define that flag, so **no comment is ever created**. Confirmed live from an eco-ops read-only director session (2026-07-05). ## Symptom ``` $ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body "..." ... --output json: exit status 1: Incorrect Usage: flag provided but not defined: -body ward-kdl-write: flag provided but not defined: -body $ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body-file comment.json ... same: ward-kdl-write: flag provided but not defined: -body ``` Both `--body` and `--body-file` fail identically. Verified the comment did **not** post (comment count on the target issue unchanged across attempts). ## Scope / contrast - `ward ops forgejo issue comment` help advertises `--body string` and `--body-file string`, so the surface flag exists - the break is in the **shadow -> `ward-kdl-write`** translation, which emits `-body` to a binary that does not define it. Looks like a version skew between the comment shadow and the `ward-kdl-write` build shipped in this container. - `ward ops forgejo issue edit --body-file <json>` **works** (used it to append to a body successfully), because it PATCHes the JSON body directly without the per-flag translation. - `ward ops forgejo issue edit --labels` fails the same way (`flag provided but not defined: -labels`) - same translation class of bug. - `ward ops forgejo issue reopen` / `edit --state` work. ## Impact From a director surface, the sanctioned way to add context to an issue (comment) is dead. The workaround is to append into the issue **body** via `edit --body-file`, which is acceptable for reaching a headless engineer (it reads the body, not comments) but wrong for human-facing threads and for the advisor role, whose whole output contract is "post the answer as a comment." An advisor that cannot comment cannot deliver. ## Ask Fix the `issue comment` shadow so `--body` / `--body-file` reach `ward-kdl-write` as a flag it defines (or pin the shadow and `ward-kdl-write` to the same build). Same fix class covers `edit --labels`. Add a regression test that actually posts a comment through the shadow and asserts it lands. ## Refs Found from an eco-ops director session, 2026-07-05, while reviving ward#547. Related: the label-add path is separately out of the director broker's write tier (create/edit/comment/close/reopen only), so labels could not be set at all from that seat. Origin: eco-ops director session. --- ## Likely root cause (Kai's read, 2026-07-06): build-time vs run-time ward-kdl asset skew Kai's diagnosis: this is a **release-asset version skew**, not a flag typo. At any given run there are **multiple ward binaries each carrying their own embedded ward-kdl**, and they do not match: - host ward (with its embedded/generated ward-kdl assets) - container ward (with its own embedded ward-kdl assets) So up to **four** ward-kdl variants can be live at once (host-ward-embedded, host dev-tree, container-ward-embedded, container dev-tree). The `issue comment` shadow is defined by one ward-kdl generation, and it hands `-body` to a `ward-kdl-write` invocation built from a **different** generation that does not define that flag — hence `flag provided but not defined: -body`. `edit --labels` fails the same way; `edit --body-file` (which bypasses the per-flag translation) works, which fits: the break is in the **flag surface the shadow emits vs the flag surface the embedded ward-kdl-write accepts**, not in the HTTP call. ## Direction Pin the shadow definition and the `ward-kdl-write` it drives to the **same build/generation**, so a released ward binary cannot ship a comment shadow whose `-body` the embedded ward-kdl-write rejects. Treat the embedded ward-kdl as a versioned release asset that must match the binary that embeds it (build-time), and make a host-ward / container-ward mismatch a detectable, loud condition rather than a silent flag-parse error at run time. Add a regression that actually posts a comment through the shadow end to end.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-613 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-06T01:43:36Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s 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#613 · branch issue-613 · driver claude · workflow direct-main
  • Run: engineer-claude-ward-613 · ward v0.406.0 · dispatched 2026-07-06T01:43:36Z
  • Comment thread: 0 included in the pre-flight read, 0 stripped (ward's own automated comments).

Issue body as seeded:

## Summary

Posting an issue comment through `ward ops forgejo issue comment` fails in (at least) the director-surface container build: the shadow wrapper hands `-body` to an inner `ward-kdl-write` invocation that does not define that flag, so **no comment is ever created**. Confirmed live from an eco-ops read-only director session (2026-07-05).

## Symptom

` ` `
$ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body "..."
... --output json: exit status 1: Incorrect Usage: flag provided but not defined: -body
ward-kdl-write: flag provided but not defined: -body

$ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body-file comment.json
... same: ward-kdl-write: flag provided but not defined: -body
` ` `

Both `--body` and `--body-file` fail identically. Verified the comment did **not** post (comment count on the target issue unchanged across attempts).

## Scope / contrast

- `ward ops forgejo issue comment` help advertises `--body string` and `--body-file string`, so the surface flag exists - the break is in the **shadow -> `ward-kdl-write`** translation, which emits `-body` to a binary that does not define it. Looks like a version skew between the comment shadow and the `ward-kdl-write` build shipped in this container.
- `ward ops forgejo issue edit --body-file <json>` **works** (used it to append to a body successfully), because it PATCHes the JSON body directly without the per-flag translation.
- `ward ops forgejo issue edit --labels` fails the same way (`flag provided but not defined: -labels`) - same translation class of bug.
- `ward ops forgejo issue reopen` / `edit --state` work.

## Impact

From a director surface, the sanctioned way to add context to an issue (comment) is dead. The workaround is to append into the issue **body** via `edit --body-file`, which is acceptable for reaching a headless engineer (it reads the body, not comments) but wrong for human-facing threads and for the advisor role, whose whole output contract is "post

… (truncated to 2000 chars; full body is on this issue)

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

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-613` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-06T01:43:36Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s 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#613` · branch `issue-613` · driver `claude` · workflow `direct-main` - **Run:** `engineer-claude-ward-613` · ward `v0.406.0` · dispatched `2026-07-06T01:43:36Z` - **Comment thread:** 0 included in the pre-flight read, 0 stripped (ward's own automated comments). **Issue body as seeded:** ``` ## Summary Posting an issue comment through `ward ops forgejo issue comment` fails in (at least) the director-surface container build: the shadow wrapper hands `-body` to an inner `ward-kdl-write` invocation that does not define that flag, so **no comment is ever created**. Confirmed live from an eco-ops read-only director session (2026-07-05). ## Symptom ` ` ` $ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body "..." ... --output json: exit status 1: Incorrect Usage: flag provided but not defined: -body ward-kdl-write: flag provided but not defined: -body $ ward ops forgejo issue comment coilyco-flight-deck ward 547 --body-file comment.json ... same: ward-kdl-write: flag provided but not defined: -body ` ` ` Both `--body` and `--body-file` fail identically. Verified the comment did **not** post (comment count on the target issue unchanged across attempts). ## Scope / contrast - `ward ops forgejo issue comment` help advertises `--body string` and `--body-file string`, so the surface flag exists - the break is in the **shadow -> `ward-kdl-write`** translation, which emits `-body` to a binary that does not define it. Looks like a version skew between the comment shadow and the `ward-kdl-write` build shipped in this container. - `ward ops forgejo issue edit --body-file <json>` **works** (used it to append to a body successfully), because it PATCHes the JSON body directly without the per-flag translation. - `ward ops forgejo issue edit --labels` fails the same way (`flag provided but not defined: -labels`) - same translation class of bug. - `ward ops forgejo issue reopen` / `edit --state` work. ## Impact From a director surface, the sanctioned way to add context to an issue (comment) is dead. The workaround is to append into the issue **body** via `edit --body-file`, which is acceptable for reaching a headless engineer (it reads the body, not comments) but wrong for human-facing threads and for the advisor role, whose whole output contract is "post ``` … (truncated to 2000 chars; full body is on this issue) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.406.0). </details> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - broker CommentIssue now shells issue comment (the real leaf) instead of the nonexistent comment create; regression walks argv against the generated tree.

Honest read: the diagnosis in the issue (four-way ward-kdl asset skew) sent me looking for a version mismatch, but the actual bug was smaller and dumber - CommentIssue in broker_exec.go just shelled the wrong verb path. There is no comment resource, only the ward#380 issue comment shadow, so urfave/cli read comment create as bare args to forgejo and let --body fall through as undefined. FileIssue/EditIssue used the right issue create/issue edit paths all along; comment was the lone typo.

What fought back a little: nothing technically, but the existing unit test had frozen the bug in place - it asserted the comment create argv against a fake runner that never parses argv, so it stayed green while the real binary rejected the flag. That's the thing that let this ship. The new regression walks each executor's argv against the actual generated forgejo command tree (buildForgejoOps), so a wrong verb path or an undefined flag now fails at go test time. I verified it: flip the argv back to comment create and it fails with the exact runtime error; flip it forward and it passes. Confident in the fix.

One divergence worth flagging: edit --labels is not the same fix class. Forgejo's edit endpoint has no labels field - labels live in the issue-label sub-collection, which the broker write tier doesn't serve at all. That's a missing capability, not a verb typo, so I filed it separately as #615 rather than half-implement a label-write tier here.

WARD-OUTCOME: done - broker CommentIssue now shells `issue comment` (the real leaf) instead of the nonexistent `comment create`; regression walks argv against the generated tree. Honest read: the diagnosis in the issue (four-way ward-kdl asset skew) sent me looking for a version mismatch, but the actual bug was smaller and dumber - `CommentIssue` in `broker_exec.go` just shelled the wrong verb path. There is no `comment` resource, only the ward#380 `issue comment` shadow, so urfave/cli read `comment create` as bare args to `forgejo` and let `--body` fall through as undefined. `FileIssue`/`EditIssue` used the right `issue create`/`issue edit` paths all along; comment was the lone typo. What fought back a little: nothing technically, but the *existing* unit test had frozen the bug in place - it asserted the `comment create` argv against a fake runner that never parses argv, so it stayed green while the real binary rejected the flag. That's the thing that let this ship. The new regression walks each executor's argv against the actual generated forgejo command tree (buildForgejoOps), so a wrong verb path or an undefined flag now fails at `go test` time. I verified it: flip the argv back to `comment create` and it fails with the exact runtime error; flip it forward and it passes. Confident in the fix. One divergence worth flagging: `edit --labels` is **not** the same fix class. Forgejo's edit endpoint has no labels field - labels live in the `issue-label` sub-collection, which the broker write tier doesn't serve at all. That's a missing capability, not a verb typo, so I filed it separately as #615 rather than half-implement a label-write tier here.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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#613
No description provided.