← back to AbramsEgo
build-queue/done/17-localfleet-lastgood-cache.md
31 lines
# AbramsEgo task 17 — Fleet · Local panel is dead live: last-good cache + visible error
Read SPEC.md. SPEC panel 2 (Fleet health, Mac2 pm2) is broken on the RUNNING instance right now:
`/api/data` → `localFleet = {"procs":[],"error":"Command failed: …pm2 jlist"}` — no `up`/`total`
at all — because the Mac2 pm2 daemon crawls under swap pressure and the 8s `sh()` timeout kills
`pm2 jlist`. The front end then silently shows `—/— up` + "no local pm2 procs" and drops the
`error` field on the floor. Even the AI chat reads "Local fleet: undefined/undefined online."
The Kamatera collector already solved this exact problem with a last-good disk cache
(`KAM_CACHE`, `server.js:129–149`); the local collector never got one.
1. `server.js` `collectLocalFleet()` (lines 108–125):
- Add `const LOCAL_CACHE = path.join(DATA_DIR, 'local-fleet.json');` next to `KAM_CACHE` (~line 129).
- Bump the `sh(pm2Bin, ['jlist'], 8000)` timeout to `20000` (daemon is slow, not dead).
- On success: `fs.writeFileSync(LOCAL_CACHE, JSON.stringify({fetchedAt:new Date().toISOString(), procs}))`
before returning (keep the current return shape).
- On failure (`!r.ok` or JSON parse fail): read `LOCAL_CACHE`; if present return
`{procs:c.procs, up:c.procs.filter(p=>p.status==='online').length, total:c.procs.length,
fetchedAt:c.fetchedAt, note:'pm2 slow — cached snapshot', error:r.err}`; if no cache yet,
return the current `{procs:[], error}` **plus** `up:null, total:null, note:'pm2 unreachable — no cached snapshot yet'`.
2. `public/index.html` (~lines 342–343): surface degradation instead of silence — after the
`loc-up` counts, when `l.note` is set append
`<span class="warn" style="font-size:11px" title="${esc(l.error||'')}">⚠ ${esc(l.note)}</span>`,
and pass `l.note` as the empty-text for `#loc-list` (same pattern as `k.note` in `renderKamFleet`).
3. Seed the cache: run `~/.npm-global/bin/pm2 jlist` once in a shell (let it take its time) to
confirm the daemon answers; the next snapshot after restart writes the cache on first success.
Verify: `pm2 restart abramsego && sleep 35 && curl -s -u admin:'DW2024!' http://127.0.0.1:9773/api/data | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const f=JSON.parse(s).localFleet;console.log(f.up,'/',f.total,f.note||'live')})"`
— expect real numbers (live or cached+note), never silent `undefined/undefined`.
Commit: `git add -A && git commit -m "fix: local fleet panel — last-good cache + visible degradation note (was silently dead)" --author="Steve <steve@designerwallcoverings.com>"`
Local only, no deploy. Do not restyle other panels.