Files
2026-02-08 18:56:44 -05:00

16 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, gap_closure, must_haves
phase plan type wave depends_on files_modified autonomous gap_closure must_haves
10.1-aggressive-workflow-modularization 06 execute 1
n8n-matching.json
n8n-workflow.json
false true
truths artifacts key_links
Matching/disambiguation logic is encapsulated in a dedicated sub-workflow
Container name matching works for text commands (action, update)
Batch container matching works for batch operations
Disambiguation, suggestion, and not-found flows work correctly
All 6 Telegram/HTTP response nodes remain in main workflow (sub-workflow returns data only)
path provides contains
n8n-matching.json Container matching and disambiguation sub-workflow Execute Workflow Trigger
path provides
n8n-workflow.json Main workflow with matching extracted
path provides
n8n-workflow.json.backup-matching Pre-extraction backup
from to via pattern
n8n-workflow.json n8n-matching.json 3 Execute Workflow nodes (Action, Update, Batch) Execute.*Match
from to via pattern
n8n-matching.json main workflow Route *Match Result switches action return field from last node in each exit path action
Extract the Matching/Disambiguation domain (12 logic nodes) from the main workflow into a new n8n-matching.json sub-workflow. This is the 4th extractable domain identified in the 10.1-01 domain analysis that was deferred during initial extraction.

Purpose: Close Gap 1 from VERIFICATION.md (node count target). While the 115-125 target is structurally unachievable (86 nodes are locked to main), extracting matching completes the extraction of all viable domains and reduces main workflow complexity.

Output: n8n-matching.json sub-workflow + updated n8n-workflow.json

<execution_context> @/home/luc/.claude/get-shit-done/workflows/execute-plan.md @/home/luc/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/10.1-aggressive-workflow-modularization/10.1-01-domain-analysis.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 @n8n-actions.json Task 1: Create n8n-matching.json sub-workflow n8n-matching.json Create a new n8n-matching.json sub-workflow that encapsulates container matching and disambiguation logic. Follow the exact same patterns used in n8n-confirmation.json, n8n-batch-ui.json, and n8n-status.json (action-based return pattern).

Sub-workflow structure:

  1. Execute Workflow Trigger — Entry point receiving inputs

  2. Input contract:

    • action: one of "match_action", "match_update", "match_batch"
    • containerList: JSON array of containers from Docker API
    • searchTerm: container name to match (for action/update)
    • selectedContainers: CSV of selected containers (for batch)
    • chatId, messageId: for context passing
  3. Route Action (Switch node) — Routes by action field to appropriate matching logic

  4. 12 logic nodes to extract from main workflow:

    Matching nodes (Code):

    • Match Container — Fuzzy matches container name against list for action commands
    • Match Update Container — Fuzzy matches for update commands
    • Match Batch Containers — Matches batch-selected containers against Docker list

    Routing nodes (Switch/If):

    • Check Match Count — Routes by match count (0, 1, 2+)
    • Check Update Match Count — Routes by update match count
    • Check Suggestion — Checks if suggestion is close enough
    • Needs Disambiguation — Checks if batch has ambiguous matches
    • Has Not Found — Checks if batch has not-found containers

    Result-building nodes (Code):

    • Find Closest Match — Finds closest match for suggestions
    • Build Suggestion Keyboard — Builds inline keyboard for suggestion
    • Build Disambiguation Message — Builds disambiguation text
    • Build Not Found Message — Builds not-found message text
  5. 6 response nodes that MUST NOT be extracted (stay in main workflow per locked decision):

    • Send Disambiguation (n8n-nodes-base.httpRequest)
    • Send Suggestion (n8n-nodes-base.httpRequest)
    • Send No Match (n8n-nodes-base.telegram)
    • Send Not Found Message (n8n-nodes-base.httpRequest)
    • Send Update No Match (n8n-nodes-base.telegram)
    • Delete Suggestion Message (n8n-nodes-base.httpRequest)

    Note: 4 of these 6 are HTTP Request type (not Telegram type). Only Send No Match and Send Update No Match are Telegram nodes.

  6. Return mechanism (how data gets back to main workflow):

    In n8n sub-workflows, the last node executed in each code path automatically becomes the return data. There is no explicit "return" node. Each exit path must end with a Code node (or Set node) that outputs a JSON object with an action field.

    Add a Format Return Code node at each exit path that produces the return object. For paths that already end with a Code node (e.g., Build Suggestion Keyboard), modify that node to include the action field in its output. For paths that end with Switch/If nodes, add a small Code node after them.

    Exit path return values:

    • Single action match found: { action: "matched", containerId, containerName }
    • Single update match found: { action: "matched_update", containerId, containerName }
    • Multiple update matches: { action: "multiple_update", matches }
    • Close match suggestion: { action: "suggestion", keyboard, text }
    • No match, no suggestion: { action: "no_match" }
    • Disambiguation needed: { action: "disambiguation", text }
    • Batch not-found: { action: "not_found", text, keyboard }
    • Batch matched OK: { action: "batch_matched", matchedContainers }
    • Docker list error: { action: "error", errorMessage }
    • No update match: { action: "no_match_update" }

CRITICAL: Copy the actual JavaScript code from each Code node in n8n-workflow.json. Do NOT rewrite or approximate the logic. Read the jsCode property from each node's parameters and transplant it exactly, adjusting only input references (change $json or $('Node Name').item.json references to use the sub-workflow's input data).

Follow existing sub-workflow patterns:

  • Use typeVersion that matches existing sub-workflows (check n8n-confirmation.json for reference)
  • Include proper metadata (name: "Container Matching", tags, etc.)
  • Position nodes in a readable layout (increment x/y coordinates) Verify with Python script:
  1. n8n-matching.json is valid JSON
  2. Has Execute Workflow Trigger node
  3. Has Switch/Route node for action routing
  4. Contains all 12 logic nodes by name: Match Container, Match Update Container, Match Batch Containers, Check Match Count, Check Update Match Count, Find Closest Match, Check Suggestion, Build Suggestion Keyboard, Build Disambiguation Message, Build Not Found Message, Needs Disambiguation, Has Not Found
  5. All Code nodes have non-empty jsCode
  6. None of these 6 response nodes appear in sub-workflow:
    • "Send Disambiguation" (httpRequest)
    • "Send Suggestion" (httpRequest)
    • "Send No Match" (telegram)
    • "Send Not Found Message" (httpRequest)
    • "Send Update No Match" (telegram)
    • "Delete Suggestion Message" (httpRequest)
  7. At least one node in each exit path outputs a JSON object with an action field (check Code node jsCode for action: or "action") n8n-matching.json exists with 14-16 nodes (12 logic + trigger + router + any Format Return nodes), valid JSON, all matching logic transplanted, every exit path returns an action-typed JSON object
Task 2: Update main workflow to call matching sub-workflow n8n-workflow.json, n8n-workflow.json.backup-matching **Step 1: Create backup** Copy n8n-workflow.json to n8n-workflow.json.backup-matching before any modifications.

Step 2: Remove the 12 extracted logic nodes Remove ONLY these 12 nodes from n8n-workflow.json (the logic nodes now living in n8n-matching.json):

  • Match Container, Match Update Container, Match Batch Containers
  • Check Match Count, Check Update Match Count
  • Find Closest Match, Check Suggestion
  • Build Suggestion Keyboard, Build Disambiguation Message, Build Not Found Message
  • Needs Disambiguation, Has Not Found

Do NOT remove these 6 response nodes (they stay in main per locked decision):

  • Send Disambiguation (httpRequest)
  • Send Suggestion (httpRequest)
  • Send No Match (telegram)
  • Send Not Found Message (httpRequest)
  • Send Update No Match (telegram)
  • Delete Suggestion Message (httpRequest)

Step 3: Add 9 integration nodes

The matching domain has 3 distinct entry points. Create integration for each:

Entry 1: Action matching (text command like "stop nginx")

  • Add Prepare Action Match Input (Code node) — Takes output from Docker List for Action, prepares: action="match_action", containerList, searchTerm from parsed command, chatId, messageId
  • Add Execute Action Match (Execute Workflow node) — Calls n8n-matching.json with TODO_DEPLOY_MATCHING_WORKFLOW placeholder. Use typeVersion 1.2 with workflowId: { "__rl": true, "mode": "list", "value": "TODO_DEPLOY_MATCHING_WORKFLOW" }
  • Add Route Action Match Result (Switch node) — Routes by returned action field:
    • "matched" -> Prepare Text Action Input (existing)
    • "suggestion" -> Send Suggestion (existing httpRequest node, stays in main)
    • "no_match" -> Send No Match (existing telegram node, stays in main)
    • "disambiguation" -> Send Disambiguation (existing httpRequest node, stays in main)
    • "error" -> Send Docker Error (existing)

Entry 2: Update matching (text command like "update nginx")

  • Add Prepare Update Match Input (Code node) — Takes output from Docker List for Update, prepares: action="match_update", containerList, searchTerm, chatId, messageId
  • Add Execute Update Match (Execute Workflow node) — Calls n8n-matching.json
  • Add Route Update Match Result (Switch node) — Routes by returned action:
    • "matched_update" -> Prepare Text Update Input (existing)
    • "multiple_update" -> Handle Update Multiple (existing)
    • "no_match_update" -> Send Update No Match (existing telegram node, stays in main)
    • "error" -> Send Update Error (existing)

Entry 3: Batch matching

  • Add Prepare Batch Match Input (Code node) — Takes output from Get Containers for Batch, prepares: action="match_batch", containerList, selectedContainers, chatId, messageId
  • Add Execute Batch Match (Execute Workflow node) — Calls n8n-matching.json
  • Add Route Batch Match Result (Switch node) — Routes by returned action:
    • "batch_matched" -> Build Batch Keyboard (existing) or equivalent downstream
    • "disambiguation" -> Send Disambiguation (existing httpRequest node, stays in main)
    • "not_found" -> Send Not Found Message (existing httpRequest node, stays in main) then -> Route Batch Action (existing)

Step 4: Rewire connections

  • Docker List for Action -> Prepare Action Match Input -> Execute Action Match -> Route Action Match Result -> (existing targets)
  • Docker List for Update -> Prepare Update Match Input -> Execute Update Match -> Route Update Match Result -> (existing targets)
  • Get Containers for Batch -> Prepare Batch Match Input -> Execute Batch Match -> Route Batch Match Result -> (existing targets)
  • Remove old connections from Docker List nodes to removed matching nodes
  • Preserve all connections from the 6 response nodes (Send Disambiguation, etc.) to their downstream targets

Step 5: Update Answer Action Query connection Currently Answer Action Query -> Delete Suggestion Message. This connection stays as-is since Delete Suggestion Message remains in main workflow.

Node count math:

  • Starting count: 168 nodes
  • Removed: 12 logic nodes
  • Added: 9 integration nodes (3 Prepare + 3 Execute + 3 Route)
  • Remaining in main: 6 response nodes (not removed, per locked decision)
  • Net reduction: 3 nodes (168 -> 165)

IMPORTANT: Maintain exact connection format used in existing workflow. Check existing Execute Workflow nodes (e.g., Execute Confirmation, Execute Batch UI) for correct connection structure, parameter format, and typeVersion. Verify with Python script:

  1. n8n-workflow.json is valid JSON
  2. Backup file exists at n8n-workflow.json.backup-matching
  3. Node count is 165 or fewer (168 - 12 removed + 9 added = 165)
  4. None of the 12 extracted logic nodes exist in main workflow: Match Container, Match Update Container, Match Batch Containers, Check Match Count, Check Update Match Count, Find Closest Match, Check Suggestion, Build Suggestion Keyboard, Build Disambiguation Message, Build Not Found Message, Needs Disambiguation, Has Not Found
  5. 3 Execute Workflow nodes reference TODO_DEPLOY_MATCHING_WORKFLOW (or actual ID)
  6. All 6 response nodes still exist in main workflow:
    • "Send Disambiguation" (httpRequest)
    • "Send Suggestion" (httpRequest)
    • "Send No Match" (telegram)
    • "Send Not Found Message" (httpRequest)
    • "Send Update No Match" (telegram)
    • "Delete Suggestion Message" (httpRequest)
  7. No orphan nodes (every node has at least one connection in or out, except trigger)
  8. All existing Execute Workflow nodes for other sub-workflows still present (14 original) Main workflow updated: 12 logic nodes removed, 9 integration nodes added (net -3, 168 -> 165), 6 response nodes preserved in main, backup created, all connections properly wired
Task 3: Verify matching sub-workflow runtime behavior Matching/disambiguation domain extracted into n8n-matching.json sub-workflow. Main workflow now calls it via 3 Execute Workflow nodes (action match, update match, batch match). All 6 response nodes remain in main workflow. 1. Import n8n-matching.json into n8n (note the workflow ID) 2. Update the 3 TODO_DEPLOY_MATCHING_WORKFLOW placeholders in n8n-workflow.json with the actual workflow ID 3. Import updated n8n-workflow.json into n8n 4. Test action matching: Send a text command like "stop nginx" — should match container and show action buttons 5. Test no match: Send "stop nonexistent" — should show "not found" message 6. Test disambiguation: Send a partial name that matches multiple containers — should show disambiguation options 7. Test update matching: Send "update nginx" — should match and show update confirmation 8. Test batch matching: Enter batch mode, select containers, confirm — batch should execute correctly 9. Verify all response messages appear correctly in Telegram (proves response nodes stayed in main) Type "approved" if all matching flows work, or describe which flow(s) failed 1. `python3 -c "import json; wf=json.load(open('n8n-matching.json')); print(f'Matching nodes: {len(wf[\"nodes\"])}')"` shows 14-16 nodes 2. `python3 -c "import json; wf=json.load(open('n8n-workflow.json')); print(f'Main nodes: {len(wf[\"nodes\"])}')"` shows ~165 nodes 3. Both files are valid JSON 4. No matching logic nodes remain in main workflow 5. All 6 response nodes preserved in main workflow (4 httpRequest + 2 telegram) 6. Execute Workflow connections properly structured 7. Sub-workflow exit paths return action-typed JSON objects

<success_criteria>

  • n8n-matching.json exists with all 12 matching logic nodes transplanted
  • Every exit path in sub-workflow returns a JSON object with an action field
  • Main workflow reduced from 168 to ~165 nodes (12 removed, 9 added)
  • All 3 matching entry paths (action, update, batch) routed through sub-workflow
  • 6 response nodes remain in main workflow per locked decision (4 httpRequest + 2 telegram)
  • Backup file created before modification
  • Both workflow files are valid JSON with no orphan nodes
  • Runtime verification confirms matching flows work end-to-end </success_criteria>
After completion, create `.planning/phases/10.1-aggressive-workflow-modularization/10.1-06-SUMMARY.md`