22
33## Goal
44
5- Fix work-prepare parseRawArguments treating the CAT agent ID UUID as a bare issue name, causing NO_ISSUES
6- when issues are available. When cat: work-agent invokes work-prepare via ` --arguments "${ARGUMENTS}" ` , the
7- $ARGUMENTS string includes the agent ID UUID as the first token. parseRawArguments matches this UUID against
8- the bare name pattern ` ^[a-zA-Z][a-zA-Z0-9_-]*$ ` (UUIDs start with a letter, contain only alphanumeric
9- chars and hyphens), sets Scope.BARE_NAME, and resolveBareNameToIssueId finds no matching directory →
10- returns NO_ISSUES. The fix strips the leading UUID-format token before processing remaining args as an issue
11- name or filter.
5+ Add E2E regression test coverage for the bug fix already present in the codebase: ` parseRawArguments ` no
6+ longer treats a UUID-format CAT agent ID as a bare issue name. The source fix is already implemented in
7+ ` WorkPrepare.java ` — ` CAT_AGENT_ID_TOKEN ` strips the leading UUID before processing remaining arguments.
8+ Unit tests for ` parseRawArguments() ` already cover UUID stripping directly. This issue adds E2E tests that
9+ call ` WorkPrepare.run() ` end-to-end with ` --arguments "<UUID>" ` and ` --arguments "<UUID> <issue-name>" `
10+ to verify READY is returned with the correct issue selected (not NO_ISSUES), confirming the full execution
11+ pipeline works correctly for both invocation patterns.
12+
13+ ## Research Findings
14+
15+ The source fix is already implemented in the codebase:
16+
17+ - ` client/src/main/java/io/github/cowwoc/cat/hooks/util/WorkPrepare.java ` (lines 73-75): ` CAT_AGENT_ID_TOKEN `
18+ regex pattern already defined
19+ - ` WorkPrepare.java ` (lines 1866-1906): ` parseRawArguments() ` already strips the UUID prefix via
20+ ` CAT_AGENT_ID_TOKEN.lookingAt() ` and throws ` IllegalArgumentException ` when rawArguments is non-blank
21+ but does not start with a valid UUID
22+ - ` client/src/test/java/io/github/cowwoc/cat/hooks/test/WorkPrepareTest.java ` (lines 2619-2683): 5 unit
23+ tests already cover UUID stripping for ` parseRawArguments() ` directly (UUID-only, UUID+issue-id,
24+ UUID+subagent-id, UUID+resume-keyword, UUID+skip-keyword)
25+
26+ Missing coverage: no end-to-end test calls ` WorkPrepare.run() ` with ` --arguments "<UUID>" ` to verify the
27+ READY response from the full execution pipeline (required by post-conditions 2 and 7).
1228
1329## Pre-conditions
1430
@@ -25,7 +41,87 @@ name or filter.
2541- [ ] UUID stripping is format-specific: only tokens matching
2642 ` [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12} ` at position 0 are
2743 stripped; bare issue names containing hyphens are unaffected
28- - [ ] All existing WorkPrepareTest tests pass with no regressions (mvn -f client/pom.xml test exits 0)
44+ - [x ] All existing WorkPrepareTest tests pass with no regressions (mvn -f client/pom.xml verify exits 0)
2945- [ ] No new issues introduced
3046- [ ] E2E verification: invoking /cat: work with no explicit issue argument (where ARGUMENTS contains only
3147 the agent UUID) correctly returns the next available issue rather than NO_ISSUES
48+
49+ ## Execution Steps
50+
51+ ### Step 1: Add E2E test for run() with UUID-only --arguments
52+
53+ File to modify: ` client/src/test/java/io/github/cowwoc/cat/hooks/test/WorkPrepareTest.java `
54+
55+ Insert the following test method after the ` parseRawArgumentsStripsUuidThenParsesSkip ` test (around line
56+ 2683). Place it at the end of the ` parseRawArguments — CAT agent ID prefix stripping ` section, before
57+ the ` globToRegexHandlesMetacharacters ` test:
58+
59+ ``` java
60+ /**
61+ * Verifies that when {@code --arguments } contains only a CAT agent ID UUID (no trailing issue name),
62+ * {@code run() } strips the UUID and returns READY for the next available issue (not NO_ISSUES).
63+ * <p >
64+ * This is the end-to-end regression test for the bug where UUIDs were matched as bare issue names.
65+ *
66+ * @throws IOException if an I/O error occurs
67+ */
68+ @Test
69+ public void runReturnsReadyWhenArgumentsContainsOnlyUuid() throws IOException
70+ {
71+ Path projectPath = createTempGitCatProject(" v2.1" );
72+ Path worktreePath = null ;
73+ try (JvmScope scope = new TestJvmScope (projectPath, projectPath))
74+ {
75+ createIssue(projectPath, " 2" , " 1" , " my-feature" , " open" );
76+ GitCommands . runGit(projectPath, " add" , " ." );
77+ GitCommands . runGit(projectPath, " commit" , " -m" , " planning: add issue my-feature" );
78+
79+ ByteArrayOutputStream buffer = new ByteArrayOutputStream ();
80+ PrintStream out = new PrintStream (buffer, true , StandardCharsets . UTF_8 );
81+
82+ String sessionId = UUID . randomUUID(). toString();
83+ // Pass UUID as the sole --arguments token — simulates /cat:work invocation with no explicit issue
84+ String uuid = " 92289cdd-76a1-4d7e-8cf3-be5618ec270a" ;
85+ WorkPrepare . run(scope, new String []{" --session-id" , sessionId, " --arguments" , uuid}, out);
86+
87+ String output = buffer. toString(StandardCharsets . UTF_8 ). strip();
88+ requireThat(output, " output" ). isNotBlank();
89+
90+ JsonMapper mapper = scope. getJsonMapper();
91+ JsonNode node = mapper. readTree(output);
92+ requireThat(node. path(" status" ). asString(), " status" ). isEqualTo(" READY" );
93+
94+ worktreePath = Path . of(node. path(" worktree_path" ). asString());
95+ }
96+ finally
97+ {
98+ cleanupWorktreeIfExists(projectPath, worktreePath);
99+ TestUtils . deleteDirectoryRecursively(projectPath);
100+ }
101+ }
102+ ```
103+
104+ Note on imports: ` ByteArrayOutputStream ` and ` PrintStream ` are likely already imported in the test file.
105+ Verify existing imports before adding duplicates. The test file already uses ` UUID ` , ` ByteArrayOutputStream ` ,
106+ ` PrintStream ` , ` StandardCharsets ` , ` JsonMapper ` , ` JsonNode ` , ` TestJvmScope ` , ` GitCommands ` , ` TestUtils ` ,
107+ ` WorkPrepare ` , ` createTempGitCatProject ` , ` createIssue ` , and ` cleanupWorktreeIfExists ` — no new imports
108+ needed.
109+
110+ ### Step 2: Run full build verification
111+
112+ Run from within the worktree directory (the subagent's working directory is already the worktree root):
113+
114+ ``` bash
115+ mvn -f client/pom.xml verify
116+ ```
117+
118+ All tests must pass (exit code 0) before proceeding. If any test fails, fix the failure before continuing.
119+
120+ ### Step 3: Commit the new test
121+
122+ Stage and commit only the test file (index.json is updated by the work-confirm/merge phases):
123+
124+ ``` bash
125+ git add client/src/test/java/io/github/cowwoc/cat/hooks/test/WorkPrepareTest.java
126+ git commit -m " test: add E2E regression test for UUID-only --arguments in work-prepare"
127+ ```
0 commit comments