Archive v1.2 Modularization & Polish milestone:
- Archive ROADMAP.md, REQUIREMENTS.md, and audit to milestones/
- Evolve PROJECT.md with v1.2 validated requirements and decisions
- Reorganize ROADMAP.md with collapsed milestone groupings
- Delete REQUIREMENTS.md (fresh for next milestone)
- Update STATE.md and MILESTONES.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- File written during Phase 10-05 for 3 sub-workflows (now 7)
- References 199 nodes (now 166 in main workflow)
- Fully superseded by DEPLOY-SUBWORKFLOWS.md (725 lines, current)
- README now links only to DEPLOY-SUBWORKFLOWS.md for technical details
- Remaining references in .planning/ are historical records (expected)
BATCH-04 and BATCH-05 UAT passed. 9 bugs fixed during testing.
All 12 v1.2 requirements now complete. Phase 13 (docs overhaul) next.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes discovered during BATCH-04/BATCH-05 UAT testing:
- Convert confirmation to HTTP Request (editMessageText for inline kb,
sendMessage for text command) with dynamic endpoint selection
- Fix data chain breaks: use named node refs ($('Parse Callback Data'),
$('Get Update All Data')) instead of $json after API calls
- Add infrastructure container exclusion (n8n, socket-proxy) by image
and container name to prevent bot self-destruction during updates
- Add batch responseMode to update sub-workflow (skip Telegram messages)
- Reorder infra check before :latest filter so sha256-digest images
appear in skipped list
- Add onError:continueRegularOutput to Answer Update All Start for
expired callback queries
- Show "Back to List" button in batch summary for update-all flow
- Add Prepare Update All Batch fallback in Prepare Batch Loop
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Known Limitations section to DEPLOY-SUBWORKFLOWS.md
- Document UNR-01: Unraid shows "apply update" after bot updates a container
- Explain root cause: bot bypasses Unraid's XML template system
- Provide workaround: click Apply Update in Unraid (instant, image cached)
- Clarify "Check for Updates" does NOT clear badge, may create new ones
- Mark UNR-01 as complete (documented limitation with workaround)
- Update README to document docker-socket-proxy architecture instead of direct socket mount
- Clarify TELEGRAM_BOT_TOKEN needs both n8n credential AND env var
- Clarify user ID is hardcoded in IF nodes (no env var needed)
- Add missing commands to usage table (update all, /list)
- Document all 8 workflow files (main + 7 sub-workflows)
- Mark ENV-01, ENV-02, DEBT-01, DEBT-02 as complete in REQUIREMENTS.md
- Verify DEBT-02 is fixed (single --max-time 600 flag, no duplicates)
Research found Unraid badge issue is architectural (bot bypasses
Unraid's XML template system). Updated plans to document limitation
with workaround instead of attempting programmatic fix. Plan 01
covers docs/env/debt, Plan 02 covers deferred Update All UAT.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UAT results: tests 1-3,6 pass (bitmap, long names, batch exec, regression).
Tests 4-5 (Update All UAT) deferred to after Phase 12.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Is Bitmap Batch Stop and Resolve Batch Stop Names were checking $json.bitmap
which contains the Telegram API response, not the parsed callback data. Changed
both to reference $("Parse Callback Data").item.json directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three bugs from plan 11-01 execution:
1. Parse Callback Data bstop return missing bitmap/isBitmapBatchStop fields
2. Is Bitmap Batch Stop wired to expired branch [0] instead of not-expired [1]
3. Is Bitmap Batch Stop false branch went to Initialize Batch State, bypassing Prepare Batch Stop Exec
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'Update All :latest' button to Build Container List and Build Paginated List
- Add uall:start parser to Parse Callback Data (sets isUpdateAllStart flag)
- Add updateallstart rule to Route Callback (index 2)
- Add Answer Update All Start node with 'Checking for updates...' callback response
- Wire Route Callback [updateallstart] -> Answer Update All Start -> Get All Containers For Update All
- Fix Check Available Updates to support both text and callback origins (try/catch for Keyword Router vs Parse Callback Data)
- Created 10.2-03-SUMMARY.md documenting scope reduction and platform limitation
- Updated STATE.md: Phase 10.2 complete (3/3 plans)
- Documented critical finding: n8n static data does not persist between executions
- Final state: 170 nodes (168 baseline + 2 correlation ID generators)
- Correlation ID infrastructure and structured error returns retained
n8n $getWorkflowStaticData only reliably tracks top-level property changes.
Deep nested mutations (staticData.errorLog.debug.enabled = true) are not
persisted between executions. Fix: serialize errorLog as JSON string in
staticData._errorLog — every read does JSON.parse, every write does
JSON.stringify as a top-level assignment.
Fixed in: Process Debug Command, Log Error, Log Trace, 6 inline trace
nodes, Parse Callback Data callback routing trace.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Plan 02 executor placed correlationId outside the json object in all
Prepare Input code nodes, creating "Unexpected token '}'" syntax errors.
Moved correlationId inside the json return object in all 19 affected nodes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two bugs: (1) connection array had old fallback at index [9] shifting debug
connections off-by-one, so /errors routed to Show Menu. (2) /debug status
matched rule 1 (contains "status") before rule 11 (startsWith /debug).
Fix: move startsWith debug rules [1-4] before contains rules [5-12].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Part A - Correlation ID Generation:
- Added Generate Correlation ID node for text command path
- Added Generate Callback Correlation ID node for callback path
- Wired between authentication and routing nodes
- Uses timestamp + random string pattern (no external dependencies)
Part B - Correlation ID Propagation:
- Modified 19 Prepare Input nodes to pass correlationId to sub-workflows
- Uses $input.item.json.correlationId pattern for flexibility
- Supports both text and callback paths
Part C - Error Capture Infrastructure:
- Added 2 error detection IF nodes for high-value paths:
* Check Execute Container Action Success
* Check Execute Inline Action Success
- Error path: success === false → Log Error node
- Success path: continues to original result handling
- Log Error node receives error data from sub-workflows
- Pass-through design preserves data for downstream handlers
Main workflow: 172 → 176 nodes (+4)
- 2 correlation ID generators
- 2 error detection IF nodes
Error ring buffer now captures:
- Container action failures (Docker API errors)
- Sub-workflow errors with full diagnostic context
- Correlation IDs for request tracing
- Workflow name, node, HTTP codes, raw responses
- Create Log Error code node with ring buffer write logic
- Create Log Trace code node with debug mode check and auto-disable
- Both nodes implement ring buffer (max 50 entries) with auto-rotation
- Log Error: accepts error data, truncates large fields (stack 500, raw 1000)
- Log Error: passes through input data with _errorLogged flag
- Log Trace: checks debug.enabled before logging, passes through unchanged
- Log Trace: auto-disables debug mode after 100 executions
- Both nodes positioned at utility area (2600, -200/-400)
- Nodes are standalone (no connections) - ready for Plan 02 wiring
- Node count: 170 -> 172 (+2 utility nodes)
The list keyword rule was added to Keyword Router but its connection
pointed to Show Menu (fallback) instead of Prepare Status Input.
Added proper connection at index 8 and shifted fallback to index 9.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added 'list' route with same output as 'status'
- Both /list and /status now show paginated container list
- Provides user-expected /list command while leveraging existing functionality
- Add HTTP 304 detection for 'already in desired state' (success: true)
- Add HTTP 404 detection for 'container not found' (success: false)
- Add HTTP 500+ detection for server errors (success: false)
- Apply to Format Stop/Start/Restart Result nodes
- StatusCode checks run before existing message-based fallback logic
- Changed $('Prepare Cancel Return').item.json to $input.item.json
- Allows node to work with both cancel paths (batch cancel and confirmation cancel)
- Fixes confirmation dialog cancel button returning to container status view
- Gap 1: Format Stop/Start/Restart missing statusCode 304 check
- Gap 2: Build Batch Keyboard reads action instead of actionType
- Gap 3: /list not implemented in Keyword Router (minor)
- Gap 4: Build Cancel Return Submenu references wrong predecessor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Code Node Classification section to DEPLOY-SUBWORKFLOWS.md
- Classify each Code node into 6 categories with evidence
- 58 nodes confirmed as orchestration infrastructure (must stay)
- 2 domain-logic candidates identified but extraction is net-negative
- Summary proves no further extraction is viable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added "Prepare Batch Execution" Code node between Route Batch Match Result
and Route Batch Action to transform matching sub-workflow output:
- matchedContainers -> allMatched (field name expected by downstream nodes)
- action from Detect Batch Command (stop/start/restart) instead of
"batch_matched" routing label from sub-workflow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Text commands like "status book" should show plain text status without
inline keyboard buttons. Added "Strip Status Keyboard" Code node that
removes reply_markup before sending via Send Container Submenu Direct.
Callback-based status (with messageId) still gets the full UI with buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Prepare Text Action Input now reads action (stop/start/restart) from
Parse Action Command instead of matching sub-workflow's actionType field
- Added "Has Status Message ID" If node to route status_direct results:
messageId > 0 → Edit Container List (callback), messageId == 0 →
Send Container Submenu Direct (text command)
- Pre-existing bug: text "status <name>" routed to editMessageText with
messageId 0, causing Telegram API error
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Updated 3 Execute Workflow nodes: Execute Action Match, Execute Update Match, Execute Batch Match
- Deployed n8n-matching.json as workflow kL4BoI8ITSP9Oxek
- Pushed main workflow to n8n API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract 12 matching/disambiguation logic nodes into sub-workflow
- 23 nodes total: trigger + router + 12 logic + 9 format-return nodes
- Three action paths: match_action, match_update, match_batch
- Every exit path returns JSON with action field per established pattern
- Adapted input references to use trigger data instead of main workflow refs
- No response nodes included (stay in main per locked decision)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 10.1 verification found 3 gaps:
- Gap 1: Node count 168 vs 115-125 target (needs user decision)
- Gap 2: Code node analysis incomplete (documentation task)
- Gap 3: Sub-workflow contracts not documented (documentation task)
Plan 10.1-06 addresses gaps with:
- Task 1: Document all 6 sub-workflow input/output contracts
- Task 2: Classify all 62 Code nodes by purpose
- Task 3: User decision checkpoint on node count approach
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created 10.1-05-SUMMARY.md documenting verification and UAT
- Updated STATE.md to reflect phase completion (5/5 plans)
- Updated ROADMAP.md to mark phase 10.1 complete
- Updated DEPLOY-SUBWORKFLOWS.md with deployed workflow IDs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Docker logs API returns multiplexed stream with 8-byte headers per frame,
not just newline-separated text. The old code split on \n which missed
frames that weren't newline-terminated.
Now properly parses the binary stream format:
- Reads 8-byte header (stream type + frame size)
- Extracts frame data based on size
- Splits frame content by newlines
- Correctly counts and displays requested number of lines
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Text-based batch commands (e.g., /start container1 container2) were
failing because Send Batch Start Message always used editMessageText,
but you can't edit the user's message.
Fixed by:
- Conditionally use sendMessage vs editMessageText based on fromKeyboard
- Capture new message_id from sendMessage response for progress updates
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The batch action (stop/start/restart) was being lost because:
1. Parse Callback Data extracted action: "stop"
2. Prepare Batch UI Input overwrote it with action: "exec" (the UI action type)
3. Handle Exec tried to parse callbackData which was empty
Fixed by:
- Adding batchAction field to Prepare Batch UI Input
- Adding batchAction to Batch UI trigger schema
- Updating Handle Exec to use triggerData.batchAction and selectedCsv
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The n8n Telegram node's inlineKeyboard parameter doesn't work reliably
with editMessageText operation. Switched to HTTP Request node calling
Telegram API directly, which properly passes reply_markup.
Changed nodes:
- Send Confirmation Dialog
- Send Stop Result
- Send Expired Message
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The n8n Telegram node's inlineKeyboard parameter expects the keyboard
rows array directly, not the full {inline_keyboard: [...]} object.
Fixed nodes:
- Send Confirmation Dialog
- Send Stop Result
- Send Expired Message
Changed from: JSON.stringify($json.reply_markup)
Changed to: JSON.stringify($json.reply_markup.inline_keyboard)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The batch rule was added at index 4 but connections weren't updated,
causing all subsequent rules to route to wrong handlers:
- select → Answer List Callback (wrong)
- list → Answer Action Callback (wrong)
- action → Answer Noop Callback (wrong)
- noop → nothing (missing)
Fixed by correcting outputs 5-8 to connect to proper handlers.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch node connections must use "main" array format with indices,
not named output keys. Changed from:
{ "list": [...], "status": [...] }
to:
{ "main": [ [...], [...], [...] ] }
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Execute Workflow nodes need mode: "once" to properly pass input
data to sub-workflows. Added to:
- Execute Container Status
- Execute Select Status
- Execute Paginate Status
- Execute Batch Cancel Status
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Route Status Result had no outgoing connections after status
sub-workflow extraction. Added connections:
- list output → Send Container List
- status_direct output → Edit Container List
- error output → Send Docker Error
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replaced TODO placeholders with actual n8n workflow IDs:
- Batch UI: ZJhnGzJT26UUmW45
- Container Status: lqpg2CqesnKE2RJQ
- Confirmation Dialogs: fZ1hu8eiovkCk08G
- Updated instructions.md with new workflow IDs and renamed files
- All workflows deployed and activated in n8n
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>