337 lines
8.6 KiB
Markdown
337 lines
8.6 KiB
Markdown
# Surgical Fix Report: Work Order Start Tracking Error
|
|
## Date: November 27, 2025
|
|
## Strategy: Diagnosis → Plan → Implementation
|
|
|
|
---
|
|
|
|
## STEP 1: DIAGNOSIS
|
|
|
|
### Error Received
|
|
```
|
|
TypeError: Cannot set properties of undefined (setting 'trackingEnabled')
|
|
at Function [Work Order buttons]:143:37
|
|
```
|
|
|
|
### Root Cause Analysis
|
|
|
|
**Node:** Work Order buttons
|
|
**Line:** 143
|
|
**Problem:** `msg.payload` was **undefined**
|
|
|
|
**Code that failed:**
|
|
```javascript
|
|
msg._mode = "production-state";
|
|
msg.productionStarted = true;
|
|
msg.machineOnline = true;
|
|
|
|
// ❌ ERROR HERE - msg.payload doesn't exist!
|
|
msg.payload.trackingEnabled = true;
|
|
msg.payload.productionStarted = true;
|
|
msg.payload.machineOnline = true;
|
|
```
|
|
|
|
**Why it failed:** The `msg` object in Node-RED doesn't automatically have a `payload` property. We were trying to set properties on an object that didn't exist, causing `Cannot set properties of undefined`.
|
|
|
|
### Secondary Issue: Mold Presets Handler Noise
|
|
|
|
**Node:** Mold Presets Handler
|
|
**Problem:** Logging warnings for every message it receives, including non-mold topics like `machineStatus`, `kpis`, `chartsData`, etc.
|
|
|
|
**Debug output:**
|
|
```
|
|
"Unknown topic: selectMoldPreset"
|
|
"Received: "
|
|
"Unknown topic: "
|
|
```
|
|
|
|
**Why:** No filter to silently ignore messages not meant for this handler.
|
|
|
|
---
|
|
|
|
## STEP 2: THE FIX PLAN
|
|
|
|
### Fix 1: Initialize msg.payload Before Use
|
|
|
|
**Architectural Decision:**
|
|
- Initialize `msg.payload = {}` before setting properties
|
|
- Set state flags at BOTH `msg` level AND `msg.payload` level for maximum compatibility
|
|
- Preserve all existing global.set() calls (especially `kpiBuffer` clearing)
|
|
|
|
**Compatibility Reasoning:**
|
|
The "Back to UI" node reads: `msg.payload?.trackingEnabled ?? msg.trackingEnabled`
|
|
|
|
This means it checks BOTH locations. By setting flags in both places, we ensure compatibility regardless of which path the message takes.
|
|
|
|
### Fix 2: Silent Ignore for Mold Presets Handler
|
|
|
|
**Architectural Decision:**
|
|
- Add early return for non-mold topics
|
|
- Define explicit list of ignored topics
|
|
- Only log messages for mold-related operations
|
|
|
|
**Topics to silently ignore:**
|
|
- `machineStatus` - Dashboard state updates
|
|
- `kpis` - KPI calculations
|
|
- `chartsData` - Graph data
|
|
- `activeWorkOrder` - Work order updates
|
|
- `workOrderCycle` - Cycle updates
|
|
- `workOrdersList` - Work order list
|
|
- `scrapPrompt` - Scrap entry prompts
|
|
- `uploadStatus` - Upload confirmations
|
|
- Empty string (`""`)
|
|
|
|
---
|
|
|
|
## STEP 3: IMPLEMENTATION
|
|
|
|
### Fix 1: Work Order buttons - "start" action
|
|
|
|
**Before (Lines 136-146):**
|
|
```javascript
|
|
msg._mode = "production-state";
|
|
msg.productionStarted = true;
|
|
msg.machineOnline = true;
|
|
|
|
// Send through output 2 to trigger KPI calculation
|
|
// Add state info to the msg itself (will be sent to Calculate KPIs)
|
|
msg.payload.trackingEnabled = true; // ❌ ERROR
|
|
msg.productionStarted = true;
|
|
msg.payload.productionStarted = true;
|
|
msg.machineOnline = true;
|
|
msg.payload.machineOnline = true;
|
|
|
|
return [null, msg, null, null];
|
|
```
|
|
|
|
**After (Lines 136-148):**
|
|
```javascript
|
|
msg._mode = "production-state";
|
|
|
|
// Initialize payload object BEFORE setting properties
|
|
msg.payload = msg.payload || {};
|
|
|
|
// Set state flags at both msg and msg.payload levels for compatibility
|
|
msg.trackingEnabled = true;
|
|
msg.productionStarted = true;
|
|
msg.machineOnline = true;
|
|
|
|
msg.payload.trackingEnabled = true;
|
|
msg.payload.productionStarted = true;
|
|
msg.payload.machineOnline = true;
|
|
|
|
return [null, msg, null, null];
|
|
```
|
|
|
|
**What was preserved:**
|
|
✅ `global.set("trackingEnabled", true)`
|
|
✅ `global.set("kpiBuffer", [])`
|
|
✅ `node.warn('[START] Cleared kpiBuffer for fresh production run')`
|
|
✅ All other global.set() calls
|
|
✅ Return statement structure
|
|
✅ Output routing
|
|
|
|
---
|
|
|
|
### Fix 2: Mold Presets Handler - Silent ignore
|
|
|
|
**Before (Lines 1-4):**
|
|
```javascript
|
|
const topic = msg.topic || '';
|
|
const payload = msg.payload || {};
|
|
|
|
// Log every incoming request
|
|
node.warn(`Received: ${topic}`);
|
|
```
|
|
|
|
**After (Lines 1-19):**
|
|
```javascript
|
|
const topic = msg.topic || '';
|
|
const payload = msg.payload || {};
|
|
|
|
// ===== IGNORE NON-MOLD TOPICS SILENTLY =====
|
|
// These are KPI/dashboard messages not meant for this handler
|
|
const ignoredTopics = [
|
|
'machineStatus',
|
|
'kpis',
|
|
'chartsData',
|
|
'activeWorkOrder',
|
|
'workOrderCycle',
|
|
'workOrdersList',
|
|
'scrapPrompt',
|
|
'uploadStatus'
|
|
];
|
|
|
|
if (ignoredTopics.includes(topic) || topic === '') {
|
|
return null; // Silent ignore
|
|
}
|
|
|
|
// Log only mold-related requests
|
|
node.warn(`Received: ${topic}`);
|
|
```
|
|
|
|
**What was preserved:**
|
|
✅ All mold preset handling logic
|
|
✅ Lock/dedupe mechanisms
|
|
✅ Database operations
|
|
✅ Error handling
|
|
✅ Existing functionality unchanged
|
|
|
|
---
|
|
|
|
## STEP 4: VERIFICATION
|
|
|
|
### Verification Checklist
|
|
|
|
**Fix 1: Work Order buttons**
|
|
- ✅ `msg.payload = msg.payload || {};` - Initialization added
|
|
- ✅ `msg.trackingEnabled = true;` - Top-level flag set
|
|
- ✅ `msg.payload.trackingEnabled = true;` - Nested flag set
|
|
- ✅ `global.set("kpiBuffer", [])` - Buffer clearing preserved
|
|
- ✅ `[START] Cleared kpiBuffer` - Warning message preserved
|
|
- ✅ No duplicate flag settings
|
|
- ✅ Clean code structure
|
|
|
|
**Fix 2: Mold Presets Handler**
|
|
- ✅ `ignoredTopics` array defined
|
|
- ✅ `machineStatus` in ignore list
|
|
- ✅ `kpis` in ignore list
|
|
- ✅ `chartsData` in ignore list
|
|
- ✅ Early return for ignored topics
|
|
- ✅ Silent operation (no warnings for ignored topics)
|
|
- ✅ Original logging preserved for mold topics
|
|
|
|
---
|
|
|
|
## EXPECTED BEHAVIOR AFTER DEPLOYMENT
|
|
|
|
### Before Fix
|
|
```
|
|
User clicks START
|
|
↓
|
|
❌ Error: Cannot set properties of undefined (setting 'trackingEnabled')
|
|
❌ Production does not start
|
|
❌ Debug panel full of "Unknown topic" warnings
|
|
```
|
|
|
|
### After Fix
|
|
```
|
|
User clicks START
|
|
↓
|
|
✅ [START] Cleared kpiBuffer for fresh production run
|
|
✅ Production starts successfully
|
|
✅ trackingEnabled = true at global, msg, and msg.payload levels
|
|
✅ Button changes from START to STOP
|
|
✅ KPIs update continuously
|
|
✅ No "Unknown topic" warnings in debug panel
|
|
✅ Clean, noise-free debug output
|
|
```
|
|
|
|
---
|
|
|
|
## TESTING INSTRUCTIONS
|
|
|
|
1. **Deploy the updated flows.json in Node-RED**
|
|
|
|
2. **Test Fix 1 - START button:**
|
|
```
|
|
- Load Home dashboard
|
|
- Verify active work order exists
|
|
- Click START button
|
|
- Expected: No errors in debug panel
|
|
- Expected: Message "[START] Cleared kpiBuffer for fresh production run"
|
|
- Expected: Button changes to STOP
|
|
- Expected: Production tracking begins
|
|
```
|
|
|
|
3. **Test Fix 2 - Silent ignore:**
|
|
```
|
|
- Monitor debug panel
|
|
- Navigate between dashboard tabs
|
|
- Expected: No "Unknown topic" warnings for machineStatus, kpis, etc.
|
|
- Expected: Only mold-related messages logged
|
|
```
|
|
|
|
4. **Integration test:**
|
|
```
|
|
- Complete a full production cycle
|
|
- Submit scrap
|
|
- Verify KPIs update
|
|
- Check graphs display data
|
|
- Verify no errors throughout
|
|
```
|
|
|
|
---
|
|
|
|
## ARCHITECTURAL NOTES
|
|
|
|
### Message Flow (Corrected)
|
|
|
|
```
|
|
START button click
|
|
↓
|
|
Work Order buttons (case "start")
|
|
├─ Sets: global.set("trackingEnabled", true)
|
|
├─ Clears: global.set("kpiBuffer", [])
|
|
├─ Initializes: msg.payload = {}
|
|
├─ Sets: msg.trackingEnabled = true
|
|
├─ Sets: msg.payload.trackingEnabled = true
|
|
└─ Sends: [null, msg, null, null] → Output 2
|
|
↓
|
|
Calculate KPIs (receives msg with _mode="production-state")
|
|
├─ Reads: global.get("trackingEnabled") ✅
|
|
├─ Performs: KPI calculations
|
|
└─ Sends: Output 1 → Refresh Trigger
|
|
↓
|
|
Refresh Trigger (sees _mode="production-state")
|
|
└─ Routes: [null, msg] → Output 2
|
|
↓
|
|
Back to UI (sees mode="production-state")
|
|
├─ Reads: msg.payload?.trackingEnabled ?? msg.trackingEnabled ✅
|
|
├─ Creates: homeMsg with topic="machineStatus"
|
|
└─ Sends: [null, homeMsg, null, null]
|
|
↓
|
|
link out → Home Template
|
|
└─ Updates: scope.isProductionRunning = msg.payload.trackingEnabled ✅
|
|
↓
|
|
Button displays: STOP ✅
|
|
```
|
|
|
|
### Why Both msg and msg.payload?
|
|
|
|
The "Back to UI" node uses optional chaining:
|
|
```javascript
|
|
trackingEnabled: msg.payload?.trackingEnabled ?? msg.trackingEnabled ?? false
|
|
```
|
|
|
|
This checks:
|
|
1. `msg.payload?.trackingEnabled` first (nested)
|
|
2. Falls back to `msg.trackingEnabled` (top-level)
|
|
3. Defaults to `false`
|
|
|
|
By setting both, we ensure compatibility regardless of how the message is processed or which properties survive through the flow.
|
|
|
|
---
|
|
|
|
## FILES MODIFIED
|
|
|
|
- `/home/mdares/.node-red/projects/Plastico/flows.json`
|
|
- Work Order buttons node (ID: `9bbd4fade968036d`)
|
|
- Mold Presets Handler node
|
|
|
|
---
|
|
|
|
## ROLLBACK INSTRUCTIONS
|
|
|
|
If issues occur:
|
|
```bash
|
|
cd /home/mdares/.node-red/projects/Plastico/
|
|
cp flows.json.backup_20251127_124628 flows.json
|
|
# Restart Node-RED
|
|
```
|
|
|
|
---
|
|
|
|
**Status: SURGICAL FIX COMPLETE ✅**
|
|
**Deployment: READY**
|
|
**Risk Level: LOW** (Isolated changes, preservation verified)
|