mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
* fix(diagnostics): keep pre-restart daemon log and line-aligned event tails Two gaps made incident support bundles useless after a relaunch: 1. Every packaged launch opened each sidecar's latest.log with mode "w", destroying the previous session's log — the bundle held only the ~70 lines written since the restart while the incident-time daemon log was gone. openLog now rotates the prior file aside as previous.log (exactly one prior session, rename overwrites), and the diagnostics export bundles logs/<app>/previous.log whenever it exists, under the same per-file tail cap. The source entry is existence-conditional so non-rotating launchers (tools-dev appends) do not gain missing-file placeholder noise. 2. The 2MB tail cap on runs/*/events.jsonl cut bytes from mid-file, so the first kept line was half a JSON object and jsonl consumers fell over on line 1. readMaybeTail now advances the cut to the next line boundary (with a guard byte so an already-aligned cut loses nothing); a window with no newline keeps the raw cut. * fix(packaged): keep the prior log when rotation fails instead of truncating it A non-ENOENT rename failure (Windows share-lock on previous.log, read-only or exotic filesystem) still fell through to open(path, "w"), destroying the only copy of the pre-restart log while previous.log stayed unavailable — the exact data loss this rotation exists to prevent. Truncate only when the prior bytes are provably elsewhere: moved aside, or never written (first-launch ENOENT). Otherwise open in append mode, since a merged two-session log is recoverable and an erased one is not. * fix(diagnostics): never export a partial record, and never hide an unreadable log Two holes in the truncation/collection contract: - A single event larger than the whole tail budget left no complete line to align to, and the fallback kept the raw cut — so the export shipped the interior of one JSON record and any consumer streaming the bundle through a jsonl parser died on line 1, exactly what alignment exists to prevent. Signal "no complete line" instead and let the collector record it, so the bundle carries a self-describing placeholder rather than half an object. - The optional-source gate treated EVERY access failure as absence, so a previous.log that exists but is unreachable (EACCES on the log directory, EIO) vanished with no manifest entry and no warning. Only ENOENT may drop the entry now; anything else stays listed and reports the real error.