docs(09): create phase plan
Phase 09: Batch Operations - 4 plans in 4 waves - 3 autonomous, 1 with checkpoint - Ready for execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
---
|
||||
phase: 09-batch-operations
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified: [n8n-workflow.json]
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "User can type 'update plex sonarr radarr' and bot recognizes multiple containers"
|
||||
- "Fuzzy matching finds containers even with partial names"
|
||||
- "Exact match gets priority (plex matches plex, not jellyplex)"
|
||||
- "Ambiguous matches show disambiguation prompt"
|
||||
artifacts:
|
||||
- path: "n8n-workflow.json"
|
||||
provides: "Batch command parsing and container matching"
|
||||
contains: "Parse Batch Command"
|
||||
key_links:
|
||||
- from: "Parse Batch Command node"
|
||||
to: "Match Containers node"
|
||||
via: "Parsed action and container names array"
|
||||
pattern: "containerNames.*split"
|
||||
- from: "Match Containers node"
|
||||
to: "disambiguation or execution path"
|
||||
via: "Switch based on match results"
|
||||
pattern: "needsDisambiguation"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Parse multi-container batch commands and match container names with fuzzy matching and exact-match priority.
|
||||
|
||||
Purpose: Enable batch operations by recognizing commands like "update plex sonarr radarr" and resolving container names accurately.
|
||||
Output: Workflow nodes that parse batch commands and match containers, with disambiguation for ambiguous matches.
|
||||
</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/09-batch-operations/09-CONTEXT.md
|
||||
@.planning/phases/09-batch-operations/09-RESEARCH.md
|
||||
@.planning/phases/08-inline-keyboard-infrastructure/08-01-SUMMARY.md
|
||||
@n8n-workflow.json
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add batch command detection and parsing</name>
|
||||
<files>n8n-workflow.json</files>
|
||||
<action>
|
||||
Add a new branch in the command routing logic to detect batch commands (multiple container names after action keyword).
|
||||
|
||||
1. In the existing command matching flow (after "Extract Keywords" or equivalent), add a Code node "Detect Batch Command":
|
||||
- Input: message text
|
||||
- Check if command matches pattern: `{action} {name1} {name2} ...` where action is update/start/stop/restart
|
||||
- Parse action and container names array (split by spaces after action keyword)
|
||||
- Output: `{ isBatch: boolean, action: string, containerNames: string[], originalMessage: string }`
|
||||
- Single container = not batch (handled by existing flow)
|
||||
- Two or more containers = batch
|
||||
|
||||
2. Add an IF node "Is Batch Command" that routes:
|
||||
- TRUE: To new batch processing flow (Plan 01-02 nodes)
|
||||
- FALSE: To existing single-container flow (preserve current behavior)
|
||||
|
||||
3. The batch flow should NOT trigger for:
|
||||
- "status" (always shows list)
|
||||
- "logs {name} {count}" (second word is line count, not container)
|
||||
- Commands with only one container name
|
||||
|
||||
Callback format from context: Existing callbacks use colon-separated format. Batch text commands use space-separated. Keep them distinct.
|
||||
</action>
|
||||
<verify>
|
||||
Test via n8n execution:
|
||||
- "update plex sonarr" -> isBatch: true, action: "update", containerNames: ["plex", "sonarr"]
|
||||
- "update plex" -> isBatch: false (single container, use existing flow)
|
||||
- "logs plex 50" -> isBatch: false (logs has line count parameter)
|
||||
- "status" -> Not routed to batch flow
|
||||
</verify>
|
||||
<done>Batch commands detected and parsed into action + container names array; single-container commands continue to existing flow</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add container name matching with exact-match priority</name>
|
||||
<files>n8n-workflow.json</files>
|
||||
<action>
|
||||
Add container matching logic that resolves user-provided names to actual container names.
|
||||
|
||||
1. Add Code node "Match Batch Containers":
|
||||
- Input: `containerNames` array from batch parser, `containers` array from Docker API (reuse existing "Get All Containers" HTTP node)
|
||||
- For each user-provided name:
|
||||
a. Normalize: lowercase, trim whitespace
|
||||
b. Check exact match first: `containers.find(c => c.Names[0].replace('/', '').toLowerCase() === normalized)`
|
||||
c. If no exact match, check substring match: `containers.filter(c => c.Names[0].toLowerCase().includes(normalized))`
|
||||
d. Record match result: { input: "plex", matched: "plex", type: "exact" } or { input: "plex", matches: ["plex", "jellyplex"], type: "ambiguous" }
|
||||
- Aggregate results into: `{ allMatched: Container[], needsDisambiguation: { input, matches }[], notFound: string[] }`
|
||||
|
||||
2. Add IF node "Needs Disambiguation":
|
||||
- TRUE (any ambiguous matches): Route to disambiguation message
|
||||
- FALSE (all matched or some not found): Continue to batch execution or error
|
||||
|
||||
3. Add Code node "Build Disambiguation Message" for ambiguous matches:
|
||||
- Format: "Multiple matches found:\n- 'plex' could match: plex, jellyplex\nPlease be more specific."
|
||||
- Include inline keyboard with exact container names as buttons for user to select
|
||||
|
||||
4. Add Code node "Build Not Found Message" for completely unmatched names:
|
||||
- Format: "Container not found: {name}"
|
||||
- Only show if notFound array is not empty and no disambiguation needed
|
||||
|
||||
Decision from context: "if 'plex' matches both 'plex' and 'jellyplex', user should be able to specify they want only 'plex'" - this is why exact match has priority. If user types exact name, it wins.
|
||||
</action>
|
||||
<verify>
|
||||
Test via n8n execution with mock container list ["plex", "jellyplex", "sonarr", "radarr"]:
|
||||
- Input ["plex"] -> exact match "plex", no disambiguation
|
||||
- Input ["jelly"] -> ambiguous, matches ["jellyplex"], could ask if they meant jellyplex
|
||||
- Input ["plex", "sonarr"] -> both exact match, no disambiguation
|
||||
- Input ["notacontainer"] -> notFound: ["notacontainer"]
|
||||
</verify>
|
||||
<done>Container names resolved with exact-match priority; ambiguous matches show disambiguation; not-found names reported clearly</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Wire batch routing and add "batch stop" confirmation</name>
|
||||
<files>n8n-workflow.json</files>
|
||||
<action>
|
||||
Complete the batch command routing and add confirmation for batch stop operations.
|
||||
|
||||
1. Wire the routing from "Is Batch Command" TRUE output:
|
||||
- Connect to "Get All Containers" (reuse existing node or create duplicate for batch)
|
||||
- Then to "Match Batch Containers"
|
||||
- Then to "Needs Disambiguation" IF node
|
||||
- Disambiguation TRUE -> "Build Disambiguation Message" -> "Send Disambiguation" (HTTP editMessageText or sendMessage)
|
||||
- Disambiguation FALSE -> Check action type
|
||||
|
||||
2. Add Switch node "Route Batch Action":
|
||||
- update: Continue to batch execution (Plan 02)
|
||||
- start/restart: Continue to batch execution (Plan 02) - immediate, no confirmation
|
||||
- stop: Route to confirmation flow (batch stop is dangerous per context)
|
||||
|
||||
3. Add confirmation flow for batch stop (per context: "Batch stop confirms due to fuzzy matching risk"):
|
||||
- Code node "Build Batch Stop Confirmation": "Stop {N} containers?\n\n{list names}\n\n[Confirm] [Cancel]"
|
||||
- Callback format: `bstop:confirm:{comma-separated-names}:{timestamp}` or `bstop:cancel`
|
||||
- HTTP node to send confirmation message with inline keyboard
|
||||
- Add to Route Callback node: handle `bstop:` prefix callbacks
|
||||
- On confirm: check 30-second timeout, then continue to batch execution
|
||||
- On cancel: return to container list
|
||||
|
||||
4. Named batch update/start/restart run immediately without confirmation (per context: "Named batches run immediately without confirmation").
|
||||
</action>
|
||||
<verify>
|
||||
Test via n8n execution:
|
||||
- "update plex sonarr" -> Matches containers, routes to batch update (output waits for Plan 02)
|
||||
- "stop plex sonarr" -> Shows confirmation "Stop 2 containers? plex, sonarr [Confirm] [Cancel]"
|
||||
- "start plex sonarr" -> Routes to batch start immediately (no confirmation)
|
||||
- Disambiguation keyboard buttons work and re-route correctly
|
||||
</verify>
|
||||
<done>Batch commands route correctly; batch stop shows confirmation; other batch actions proceed immediately; disambiguation allows user selection</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. Workflow imports successfully in n8n
|
||||
2. Batch command detection works for all action types
|
||||
3. Container matching prioritizes exact matches
|
||||
4. Disambiguation shows when multiple fuzzy matches exist
|
||||
5. Batch stop shows confirmation dialog
|
||||
6. Existing single-container commands still work unchanged
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- "update plex sonarr" parses into batch update for two containers
|
||||
- "stop plex sonarr" shows confirmation before executing
|
||||
- "plex" exactly matches "plex" even when "jellyplex" exists
|
||||
- Ambiguous input like "jelly" prompts for clarification
|
||||
- Single-container commands route to existing flow (no regression)
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/09-batch-operations/09-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user