docs(10.1): create UAT gap closure plans (08-09)
This commit is contained in:
@@ -51,7 +51,7 @@ Plans:
|
|||||||
|
|
||||||
**Requirements:** MOD-03 (new)
|
**Requirements:** MOD-03 (new)
|
||||||
|
|
||||||
**Plans:** 7 plans
|
**Plans:** 9 plans
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [x] 10.1-01-PLAN.md — Rename sub-workflows, analyze domain boundaries, get user approval
|
- [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-05-PLAN.md — Integration verification and UAT
|
||||||
- [x] 10.1-06-PLAN.md — Gap closure: Extract Matching/Disambiguation sub-workflow
|
- [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
|
- [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:**
|
**Success Criteria:**
|
||||||
1. Main workflow contains only: trigger, auth, keyword routing, sub-workflow dispatch
|
1. Main workflow contains only: trigger, auth, keyword routing, sub-workflow dispatch
|
||||||
@@ -162,7 +164,7 @@ Plans:
|
|||||||
| 8 | Inline Keyboard Infrastructure | v1.1 | Complete |
|
| 8 | Inline Keyboard Infrastructure | v1.1 | Complete |
|
||||||
| 9 | Batch Operations | v1.1 | Complete |
|
| 9 | Batch Operations | v1.1 | Complete |
|
||||||
| 10 | Workflow Modularization | v1.2 | 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) |
|
| 10.2 | Better Logging & Log Management | v1.2 | Pending (INSERTED) |
|
||||||
| 11 | Update All & Callback Limits | v1.2 | Pending |
|
| 11 | Update All & Callback Limits | v1.2 | Pending |
|
||||||
| 12 | Polish & Audit | v1.2 | Pending |
|
| 12 | Polish & Audit | v1.2 | Pending |
|
||||||
@@ -171,4 +173,4 @@ Plans:
|
|||||||
**v1.2 Coverage:** 12+ requirements mapped across 7 phases
|
**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>
|
||||||
Reference in New Issue
Block a user