refactor(opencode): use $1 substitution, drop BASE_BRANCH and arg parsing

The workflow command was asking the model to parse $ARGUMENTS into
positional tokens (issue ID, optional base branch). Opencode supports
$1, $2, $3, ... for direct positional substitution at template-load
time — the model never needs to see or parse a joined argument string.
Two simplifications:

1. Replace $ARGUMENTS-parsing with $1. Every reference to the issue ID
   in commands/workflow.md is now $1, which opencode substitutes
   literally before the prompt loads. Eliminates a class of parsing
   errors (whitespace edge cases, mis-splits, hallucinated extra args)
   and removes the orchestrator's need to "remember" an ISSUE_ID
   variable across phases.

2. Drop BASE_BRANCH entirely. It was used in three places:
   - Phase 1 "branch != base" check — actual concern is "don't run on
     a protected branch." Replace with refusal on main/master/develop/
     any matching protected name.
   - Phase 8 `git diff "$BASE_BRANCH"...HEAD` — anchor the diff to
     START_SHA captured at Phase 1 instead. With one-task-per-run
     (ADR-21), the run produces a small bounded diff from a known
     starting point; START_SHA is more accurate than diffing against
     a separate branch tip that may have moved.
   - Failure Handler recovery procedure — user-facing instructions;
     name "your usual integration branch" instead of $BASE_BRANCH.

The command signature collapses from `/workflow <ISSUE-ID> [base-branch]`
to just `/workflow <ISSUE-ID>` — single positional, zero parsing.

Routing matrix Phase 1 row updated for the protected-branch refusal;
ADR-14's recovery-procedure paragraph no longer names BASE_BRANCH.

Refs: config/opencode/workflow-design.md ADR-14, ADR-21
This commit is contained in:
Harald Hoyer 2026-05-08 15:39:22 +02:00
parent e440bf39fd
commit 1094facb1e
2 changed files with 26 additions and 30 deletions

View file

@ -135,7 +135,7 @@ Every observed `(phase, signal) → action`. Empty cells are gaps. Walking this
| Phase | Signal source | Signal | Action |
|---|---|---|---|
| 1 | Sanity checks | Bare repo / detached HEAD / branch == base | Stop with error |
| 1 | Sanity checks | Bare repo / detached HEAD / branch is a protected name (`main`/`master`/`develop`/...) | Stop with error |
| 1 | Sanity checks | Working tree dirty (`git status --porcelain` non-empty) | Stop with error (ADR-20) |
| 2 | `@pm` (Validate run prerequisites) | `ok: true` | Capture `issue_file_path` and full issue context; proceed |
| 2 | `@pm` (Validate run prerequisites) | `error_code: tracker_missing` | Stop with error using `@pm`'s message verbatim (ADR-22) |
@ -289,7 +289,7 @@ ADR-flavoured. New decisions append at the end. If a decision is later reversed
### ADR-14 (2026-05-08) — Workflow is non-resumable
**Context:** Phase 9 has multiple sub-steps (code commit → `@pm` status update → file follow-ups → TODO commit → summary). Crashing between any two sub-steps leaves the worktree in a state that earlier docs called "partial." The original Failure Handler did not flip status back, did not recognize partial-Phase-9 separately from earlier-phase crashes, and re-running `/workflow` after a crash could append new comments and re-do work indefinitely.
**Decision:** declare the workflow non-resumable. On any failure (Failure Handler invocation), the recovery procedure is: `git worktree remove` the failed worktree, delete the feature branch, re-create the worktree from `$BASE_BRANCH`, then re-run `/workflow`. Document this explicitly in the Failure Handler section. The throwaway-worktree model means there is no in-place resume state to corrupt — the user discards the worktree and starts fresh.
**Decision:** declare the workflow non-resumable. On any failure (Failure Handler invocation), the recovery procedure is: `git worktree remove` the failed worktree, delete the feature branch, re-create the worktree from the user's usual integration branch (typically `main`), then re-run `/workflow`. Document this explicitly in the Failure Handler section. The throwaway-worktree model means there is no in-place resume state to corrupt — the user discards the worktree and starts fresh.
**Alternatives:** (a) smarter Failure Handler that cleans up partial state idempotently; (b) transactional Phase 9 via a state file; (c) idempotent sub-steps so re-runs auto-resume.
**Consequences:** simplest possible recovery model. Phase 9 sub-step ordering doesn't need to be defended against partial failures — partial state is acceptable because the recovery is "discard everything and re-run." User-initiated cancellation (Ctrl-C) follows the same procedure.