docs(10.1): create UAT gap closure plans (08-09)

This commit is contained in:
Lucas Berger
2026-02-08 09:35:34 -05:00
parent b74fb3c19c
commit f3ab7cf312
3 changed files with 370 additions and 3 deletions
+5 -3
View File
@@ -51,7 +51,7 @@ Plans:
**Requirements:** MOD-03 (new)
**Plans:** 7 plans
**Plans:** 9 plans
Plans:
- [x] 10.1-01-PLAN.md — Rename sub-workflows, analyze domain boundaries, get user approval
@@ -61,6 +61,8 @@ Plans:
- [x] 10.1-05-PLAN.md — Integration verification and UAT
- [x] 10.1-06-PLAN.md — Gap closure: Extract Matching/Disambiguation sub-workflow
- [x] 10.1-07-PLAN.md — Gap closure: Code node classification + contract documentation
- [ ] 10.1-08-PLAN.md — UAT gap closure: Fix action result statusCode handling (n8n-actions.json)
- [ ] 10.1-09-PLAN.md — UAT gap closure: Fix batch keyboard, cancel routing, /list command (n8n-workflow.json)
**Success Criteria:**
1. Main workflow contains only: trigger, auth, keyword routing, sub-workflow dispatch
@@ -162,7 +164,7 @@ Plans:
| 8 | Inline Keyboard Infrastructure | v1.1 | Complete |
| 9 | Batch Operations | v1.1 | Complete |
| 10 | Workflow Modularization | v1.2 | Complete |
| 10.1 | Aggressive Workflow Modularization | v1.2 | Complete |
| 10.1 | Aggressive Workflow Modularization | v1.2 | In Progress (7/9 plans) |
| 10.2 | Better Logging & Log Management | v1.2 | Pending (INSERTED) |
| 11 | Update All & Callback Limits | v1.2 | Pending |
| 12 | Polish & Audit | v1.2 | Pending |
@@ -171,4 +173,4 @@ Plans:
**v1.2 Coverage:** 12+ requirements mapped across 7 phases
---
*Updated: 2026-02-08 — Phase 10.1 COMPLETE (7/7 plans)*
*Updated: 2026-02-08 — Phase 10.1 UAT gap closure plans created (08-09)*
@@ -0,0 +1,153 @@
---
phase: 10.1-aggressive-workflow-modularization
plan: 08
type: execute
wave: 1
depends_on: []
files_modified: [n8n-actions.json]
autonomous: true
gap_closure: true
must_haves:
truths:
- "Stopping an already-stopped container returns helpful 'already stopped' message"
- "Starting an already-started container returns helpful 'already started' message"
- "Container not found returns clear error message"
- "Server errors are handled gracefully with descriptive messages"
artifacts:
- path: "n8n-actions.json"
provides: "Format Stop Result, Format Start Result, Format Restart Result nodes with statusCode handling"
contains: "statusCode"
key_links:
- from: "n8n-actions.json Format Stop Result"
to: "HTTP 304/404/500 detection"
via: "response.statusCode check"
pattern: "statusCode.*304|404|500"
---
<objective>
Fix container action result formatting to properly handle Docker API HTTP status codes (304, 404, 500) in addition to existing message-based detection.
Purpose: Close UAT gap where stopping an already-stopped container showed a failure message instead of "already stopped"
Output: Updated n8n-actions.json with comprehensive status code handling
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/10.1-aggressive-workflow-modularization/10.1-UAT.md
@.planning/phases/10.1-aggressive-workflow-modularization/10.1-CONTEXT.md
@n8n-actions.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Add statusCode checks to Format Stop/Start/Restart Result nodes</name>
<files>n8n-actions.json</files>
<action>
Update three Code nodes in n8n-actions.json:
- **Format Stop Result** (id: code-format-stop-result)
- **Format Start Result** (id: code-format-start-result)
- **Format Restart Result** (id: code-format-restart-result)
Each node currently checks `response.message` and `response.error` patterns. Add statusCode checks BEFORE the existing checks:
```javascript
const response = $input.item.json;
const containerName = response.containerName;
// Check HTTP status codes first (Docker API with onError:continueRegularOutput)
if (response.statusCode) {
if (response.statusCode === 304) {
// Already in desired state
return {
success: true,
message: `${containerName} is already {stopped|started}`
};
} else if (response.statusCode === 404) {
return {
success: false,
message: `❌ Container ${containerName} not found`
};
} else if (response.statusCode >= 500) {
return {
success: false,
message: `❌ Server error {stopping|starting|restarting} ${containerName}: ${response.statusMessage || 'Unknown error'}`
};
}
}
// Then fall through to existing message-based checks...
```
**Per-action text variations:**
- Stop: "already stopped", "stopping"
- Start: "already started", "starting"
- Restart: "already started" (Docker restart endpoint returns 304 for already-running containers)
**Note:** HTTP 204 is handled by existing `!response.message && !response.error` success check.
</action>
<verify>
1. Read n8n-actions.json and verify all three Format nodes have statusCode checks
2. Verify 304 returns success: true with "already {state}" message
3. Verify 404 returns success: false with "not found" message
4. Verify >= 500 returns success: false with "server error" message
</verify>
<done>All three Format Result nodes check response.statusCode for 304, 404, and 500+ before falling through to existing message-based checks. Status code checks use appropriate per-action messaging.</done>
</task>
<task type="auto">
<name>Task 2: Deploy updated sub-workflow via n8n API</name>
<files>n8n-actions.json</files>
<action>
Deploy updated n8n-actions.json to n8n instance:
```bash
source .env.n8n-api
curl -X PUT "$N8N_HOST/api/v1/workflows/fYSZS5PkH0VSEaT5" \
-H "X-N8N-API-KEY: $N8N_API_KEY" \
-H "Content-Type: application/json" \
--data @n8n-actions.json
```
Verify deployment success (returns 200 with workflow object).
</action>
<verify>
curl returns 200 status code and JSON response containing workflow ID fYSZS5PkH0VSEaT5
</verify>
<done>Updated n8n-actions.json deployed to n8n instance successfully</done>
</task>
</tasks>
<verification>
## Manual Test Cases
After deployment, test using Telegram bot:
1. **Already stopped:** Find a stopped container → send "stop {name}" → expect "✅ {name} is already stopped" (not failure message)
2. **Already started:** Find a running container → send "start {name}" → expect "✅ {name} is already started"
3. **Not found:** Send "stop nonexistent123" → expect "❌ Container nonexistent123 not found"
All three should show success/error indicators instead of generic failure messages.
</verification>
<success_criteria>
- Format Stop/Start/Restart Result nodes check response.statusCode before message patterns
- HTTP 304 treated as success with "already {stopped|started}" message
- HTTP 404 returns clear "not found" error
- HTTP 500+ returns clear "server error" message
- Updated sub-workflow deployed via n8n API
- UAT gap "Stopping an already-stopped container returns helpful message" is closed
</success_criteria>
<output>
After completion, create `.planning/phases/10.1-aggressive-workflow-modularization/10.1-08-SUMMARY.md`
</output>
@@ -0,0 +1,212 @@
---
phase: 10.1-aggressive-workflow-modularization
plan: 09
type: execute
wave: 1
depends_on: []
files_modified: [n8n-workflow.json]
autonomous: true
gap_closure: true
must_haves:
truths:
- "Multiple container matches show disambiguation keyboard with correct action in button text"
- "Cancel button on confirmation dialog returns to container status view"
- "/list command shows container list (or documented as /status)"
artifacts:
- path: "n8n-workflow.json"
provides: "Build Batch Keyboard with correct actionType reference"
contains: "$json.actionType"
- path: "n8n-workflow.json"
provides: "Build Cancel Return Submenu with dynamic input reference"
contains: "$input.item.json"
- path: "n8n-workflow.json"
provides: "Keyword Router with list command handling"
contains: "list"
key_links:
- from: "Build Batch Keyboard"
to: "actionType field"
via: "$json.actionType (not $json.action)"
pattern: "\\$json\\.actionType"
- from: "Build Cancel Return Submenu"
to: "dynamic predecessor data"
via: "$input.item.json (not hardcoded node reference)"
pattern: "\\$input\\.item\\.json"
---
<objective>
Fix three data flow bugs in main workflow: Build Batch Keyboard reading wrong field, Build Cancel Return Submenu referencing wrong predecessor, and Keyword Router missing /list command.
Purpose: Close UAT gaps for disambiguation keyboard, confirmation cancel, and /list command
Output: Updated n8n-workflow.json with corrected node logic
</objective>
<execution_context>
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
@/home/luc/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/10.1-aggressive-workflow-modularization/10.1-UAT.md
@.planning/phases/10.1-aggressive-workflow-modularization/10.1-CONTEXT.md
@.planning/phases/10.1-aggressive-workflow-modularization/10.1-02-SUMMARY.md
@.planning/phases/10.1-aggressive-workflow-modularization/10.1-04-SUMMARY.md
@n8n-workflow.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Fix Build Batch Keyboard to use actionType field</name>
<files>n8n-workflow.json</files>
<action>
Update **Build Batch Keyboard** Code node (id: code-build-batch-keyboard) in n8n-workflow.json:
**Current code reads:**
```javascript
const action = $json.action; // This is "multiple" - the routing label
```
**Change to:**
```javascript
const action = $json.actionType; // This contains the actual action: stop/start/restart/update
```
**Why:** When the matching sub-workflow returns `action: "multiple"` (indicating multiple matches found), it also includes `actionType` with the user's requested action (e.g., "stop"). The keyboard builder needs the actual action for:
1. Button callback_data: `bexec:{action}:{containerId}:all`
2. Message text: "Found multiple containers matching '{term}'. Select containers to {action}:"
Using `$json.action` produces "multiple all?" as button text and `bexec:multiple:...` callbacks which won't be recognized.
**Location:** Find node with `"id": "code-build-batch-keyboard"` and update its JavaScript code parameter.
</action>
<verify>
1. Read n8n-workflow.json and find node with id "code-build-batch-keyboard"
2. Verify code contains `const action = $json.actionType;`
3. Verify no other references to `$json.action` in the action variable assignment
</verify>
<done>Build Batch Keyboard node reads actionType field instead of action field for constructing disambiguation keyboard</done>
</task>
<task type="auto">
<name>Task 2: Fix Build Cancel Return Submenu to use dynamic input</name>
<files>n8n-workflow.json</files>
<action>
Update **Build Cancel Return Submenu** Code node (id: code-build-cancel-return-submenu) in n8n-workflow.json:
**Current code reads:**
```javascript
const data = $('Prepare Cancel Return').item.json;
```
**Change to:**
```javascript
const data = $input.item.json;
```
**Why:** This node has two incoming paths:
1. From "Prepare Cancel Return" (batch cancel path)
2. From "Prepare Cancel From Confirm" (confirmation dialog cancel path)
The hardcoded node reference `$('Prepare Cancel Return')` only works for path 1. When user cancels from confirmation dialog, the data flows through "Prepare Cancel From Confirm" instead, causing the node reference to fail.
Both predecessors output the same data structure (containerId, containerName, chatId, messageId, queryId, page), so using `$input.item.json` works for both paths.
**Location:** Find node with `"id": "code-build-cancel-return-submenu"` and update its JavaScript code parameter.
</action>
<verify>
1. Read n8n-workflow.json and find node with id "code-build-cancel-return-submenu"
2. Verify code contains `const data = $input.item.json;`
3. Verify the node has connections from both "Prepare Cancel Return" and "Prepare Cancel From Confirm"
</verify>
<done>Build Cancel Return Submenu node uses dynamic $input reference instead of hardcoded predecessor, allowing it to work with both cancel paths</done>
</task>
<task type="auto">
<name>Task 3: Add /list command to Keyword Router</name>
<files>n8n-workflow.json</files>
<action>
Update **Keyword Router** Switch node (id: switch-keyword-router) in n8n-workflow.json:
**Current routes:** status, restart, start, stop, update, update all, logs, (default to "Show Menu")
**Decision:** Add "list" as an alias that routes to the same output as "status".
**Implementation:** Find the switch node rules array and add a new rule:
```json
{
"type": "string",
"value": "list",
"output": 0
}
```
Where `output: 0` matches the same output index as the "status" rule (both should route to the same node - likely "Prepare Status Input" or similar).
**Rationale:** The "status" command with no arguments already correctly displays the container list (per UAT note "Accessed via 'status' command (no args), not /list. Pagination works."). Adding "list" as an alias provides the user-expected command while leveraging existing functionality.
**Alternative if routing proves complex:** Instead of adding the route, document in verification that "/status" is the correct command for listing containers, and suggest updating any user-facing help text to clarify this.
**Location:** Find node with `"id": "switch-keyword-router"` and update its routing rules.
</action>
<verify>
1. Read n8n-workflow.json and find node with id "switch-keyword-router"
2. Verify routing rules include "list" with same output as "status" rule
3. Check what output index "status" routes to and confirm "list" routes to same
</verify>
<done>Keyword Router accepts "list" command as alias for "status", routing to the same container list display path</done>
</task>
<task type="auto">
<name>Task 4: Deploy updated main workflow via n8n API</name>
<files>n8n-workflow.json</files>
<action>
Deploy updated n8n-workflow.json to n8n instance:
```bash
source .env.n8n-api
curl -X PUT "$N8N_HOST/api/v1/workflows/HmiXBlJefBRPMS0m4iNYc" \
-H "X-N8N-API-KEY: $N8N_API_KEY" \
-H "Content-Type: application/json" \
--data @n8n-workflow.json
```
Verify deployment success (returns 200 with workflow object).
</action>
<verify>
curl returns 200 status code and JSON response containing workflow ID HmiXBlJefBRPMS0m4iNYc
</verify>
<done>Updated n8n-workflow.json deployed to n8n instance successfully</done>
</task>
</tasks>
<verification>
## Manual Test Cases
After deployment, test using Telegram bot:
1. **Disambiguation keyboard:** Send "stop plex" (assuming multiple containers match "plex") → expect keyboard showing containers with "Select containers to stop:" and buttons with correct action callbacks
2. **Confirmation cancel:** From container status view → tap Stop → confirmation dialog appears → tap Cancel → expect return to container status view (not failure)
3. **List command:** Send "/list" → expect container list with pagination (same as "/status" with no args)
All three should now work correctly per UAT expectations.
</verification>
<success_criteria>
- Build Batch Keyboard reads $json.actionType for correct action in disambiguation keyboards
- Build Cancel Return Submenu uses $input.item.json to support both cancel paths
- Keyword Router accepts "list" command routing to status handler
- Updated main workflow deployed via n8n API
- Three UAT gaps closed: disambiguation keyboard text/callbacks, confirmation cancel, /list command
</success_criteria>
<output>
After completion, create `.planning/phases/10.1-aggressive-workflow-modularization/10.1-09-SUMMARY.md`
</output>