review-state update creates the card when none exists #715

Closed
opened 2026-10-05 07:49:38 +00:00 by claude · 1 comment
Member

Problem

A workflow step that records a state on the review-state card must today choose between review-state update (card exists) and review-state write (no card). kanon's instructions do this with an if [ -f <path> ] branch in the agent's shell code. Since IW-702 the card lives outside the work tree, so the agent cannot know where it is or whether it exists. A branch that still tracks its card in the tree makes it worse: review-state path (IW-710, never moves) reports no card at the core location, the agent runs write, write moves the tracked card and then overwrites it whole, and phase_checkpoints, artifacts and badges are lost.

The agent must not decide this. It states the state it wants, and the tool decides whether the card exists and where it lives.

Change

iw review-state update creates the card when none exists for the key.

  • Resolve the card as now (withCardPath: core location, after the one-time move of a tracked in-tree card).
  • When no card exists, merge the update onto an empty card that holds only the key (version, issue_id, artifacts: []) instead of failing with "Review state file not found". When a card exists, merge as now.
  • Validate the merged result as now.
  • Update the declaration: exit 1 no longer covers "the file does not exist"; the does text says it creates the card when missing.

update already takes --workflow-type, and --append-artifact is keyed by label, so one update call covers what the create branch passed to write (an appended artifact whose label exists replaces it, no duplicate).

write stays as it is, for a full replace (--from-stdin).

Acceptance

  • update --issue-id K ... with no card for K writes a valid card with the given fields.
  • update on an existing card keeps checkpoints, badges and artifacts it did not touch (unchanged behaviour).
  • update on a branch that still tracks its card in the tree moves it and merges into it; nothing is lost.
  • An explicit --input path that does not exist: decide and document (create, or keep failing).

Context

Consumer: kanon DEVDOCS-439 Phase 2 (agent instructions call one update per state, no if, no path). kanon raises its // REQUIRES: headers to the release that ships this; DEVDOCS-439's final PR waits for that release.
Known risk: a wrong key creates a stray card (required fields are only version/issue_id/artifacts/last_updated). The key comes from the branch or --issue-id and is parsed as a WorktreeKey.


Type: feature
Filed from: /home/mph/ops/kanon-DEVDOCS-439 on branch DEVDOCS-439

## Problem A workflow step that records a state on the review-state card must today choose between `review-state update` (card exists) and `review-state write` (no card). kanon's instructions do this with an `if [ -f <path> ]` branch in the agent's shell code. Since IW-702 the card lives outside the work tree, so the agent cannot know where it is or whether it exists. A branch that still tracks its card in the tree makes it worse: `review-state path` (IW-710, never moves) reports no card at the core location, the agent runs `write`, `write` moves the tracked card and then overwrites it whole, and `phase_checkpoints`, artifacts and badges are lost. The agent must not decide this. It states the state it wants, and the tool decides whether the card exists and where it lives. ## Change `iw review-state update` creates the card when none exists for the key. - Resolve the card as now (`withCardPath`: core location, after the one-time move of a tracked in-tree card). - When no card exists, merge the update onto an empty card that holds only the key (`version`, `issue_id`, `artifacts: []`) instead of failing with "Review state file not found". When a card exists, merge as now. - Validate the merged result as now. - Update the declaration: exit 1 no longer covers "the file does not exist"; the `does` text says it creates the card when missing. `update` already takes `--workflow-type`, and `--append-artifact` is keyed by label, so one `update` call covers what the create branch passed to `write` (an appended artifact whose label exists replaces it, no duplicate). `write` stays as it is, for a full replace (`--from-stdin`). ## Acceptance - `update --issue-id K ...` with no card for K writes a valid card with the given fields. - `update` on an existing card keeps checkpoints, badges and artifacts it did not touch (unchanged behaviour). - `update` on a branch that still tracks its card in the tree moves it and merges into it; nothing is lost. - An explicit `--input` path that does not exist: decide and document (create, or keep failing). ## Context Consumer: kanon DEVDOCS-439 Phase 2 (agent instructions call one `update` per state, no `if`, no path). kanon raises its `// REQUIRES:` headers to the release that ships this; DEVDOCS-439's final PR waits for that release. Known risk: a wrong key creates a stray card (required fields are only version/issue_id/artifacts/last_updated). The key comes from the branch or `--issue-id` and is parsed as a WorktreeKey. --- **Type:** feature **Filed from:** `/home/mph/ops/kanon-DEVDOCS-439` on branch `DEVDOCS-439`
Author
Member

Correction to the issue body, and two additions to scope.

  1. The body says --append-artifact is keyed by label. That is wrong. In core/model/ReviewStateUpdater.scala:151-156 the artifacts merge passes no keyField; only available_actions (by id) and badges (by label) are keyed. Without a key, every one-command update that appends Analysis adds a duplicate artifact. Scope addition: key artifact appends by label (mergeArray(..., keyField = Some("label"))), so an appended artifact whose label exists replaces it. Acceptance: two update --append-artifact "Analysis:..." runs leave one Analysis artifact.
  2. update has no --version flag. The empty card that update creates must set version: 2 itself, as well as issue_id, so the merged result passes validation. Acceptance: update --issue-id K --status x with no card for K writes a card that review-state validate accepts.
Correction to the issue body, and two additions to scope. 1. The body says `--append-artifact` is keyed by label. That is wrong. In `core/model/ReviewStateUpdater.scala:151-156` the artifacts merge passes no `keyField`; only `available_actions` (by `id`) and `badges` (by `label`) are keyed. Without a key, every one-command update that appends `Analysis` adds a duplicate artifact. **Scope addition:** key artifact appends by `label` (`mergeArray(..., keyField = Some("label"))`), so an appended artifact whose label exists replaces it. Acceptance: two `update --append-artifact "Analysis:..."` runs leave one `Analysis` artifact. 2. `update` has no `--version` flag. The empty card that `update` creates must set `version: 2` itself, as well as `issue_id`, so the merged result passes validation. Acceptance: `update --issue-id K --status x` with no card for K writes a card that `review-state validate` accepts.
mph closed this issue 2026-10-05 12:17:52 +00:00
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
iterative-works/iw-cli#715
No description provided.