aboutsummaryrefslogtreecommitdiff
path: root/scripts/newos4-triage.py
Commit message (Collapse)AuthorAgeFilesLines
* feat(feedback): chat plane on the dashboard + honest triage rankingAgando4 days1-1/+17
| | | | | | | | | | | | | | | | | | Tasks 3-8 of the chat-plane plan: - cron newos4-chat-ingest (0cc4bb4d2f82, */10, script-only, silent when idle) - collect.py: plan_key() normalises the two ledger spellings on read (5 rows carried a plan name without .md and were silently unmatched); per-item bulk_pass for the 2026-10-26 pass; counts.chat_total - feedback.html: 5th tile "from chat"; card shows who closed an item and when, with a bulk marker - triage: UNFILEABLE class -> top_real now ranks actionable errors only (first row went from an 18 203 fetch failure to the 989 toLowerCase runtime error); network/abort signatures move to policy_noise - AGENTS.md: the chat plane documented as an intake Verified: autoreview --dry-run over the 5 chat reports -> "nothing provable (5 left for the operator)" (R6 refuses auto:false); maintain 16 PASS 0 FAIL; feedback.html inline JS node --check OK; collect -> awaiting 5, chat_total 5.
* feat(newos4): fix ledger + norm clustering — the loop now knows what a fix ↵Agando2026-10-231-0/+46
| | | | | | | | | | | | | | | | | | | | | | | | | | was worth Lifetime counts ranked an 8-day-old outage above today's live crash, and nothing asserted that a shipped fix actually held: a regression of a fixed bug looked exactly like a new bug. - api/debug/ingest.php: norm_key() stores `norm` (host/port/scheme/`?v=`/`//` stripped) — the client hash covers the raw URL, so one outage became two signatures (`/ollama//api/tags` 18 203x and `/ollama/api/tags` 16 540x). PHP + Python implementations verified byte-identical on 5 real messages. - scripts/newos4-ledger.py: data/maintenance/fixes.json maps norm -> {commit, fixed_at, note}, and verify() returns REGRESSED / WATCHING / CLOSED / UNSEEN. "Seen after the fix" alone is not a regression (a fix shipped 10d ago with one sighting 9d ago has been silent since) — regressed means seen after the fix AND recent; otherwise the silence wins. - scripts/newos4-triage.py: clusters (grouped by norm, recency-ordered), active<24h / stale>7d counts, FIX| verdict lines; digest gains clusters + fixes and active/stale/cluster/regressed counters. - api/debug/dashboard.php: Clusters / Active<24h / Stale>7d / Regressed columns and a red REGRESSED detail line, so a regression is visible without reading JSON. Seeded with the two fixes whose signatures exist: 2855c63 (pipe crash, WATCHING 69.3h silent) and 563a9be (emptyTrash, UNSEEN). Verdict logic proven on fixtures: recurrence 5m after fix -> REGRESSED, silent 9d -> CLOSED, last seen 2d -> REGRESSED, fixed 5m ago/last seen 3d ago -> WATCHING. Loop verified end to end: triage via newos4-maintenance.sh prints ACTIVE/CLUSTER/FIX lines, maintain OK, skill audit 7/7, dashboard ALL VIEWPORTS OK.
* fix(newos4): empty-pipeline crash, stacks in reports, frame in digest + ↵Agando2026-10-231-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | dashboard (v4.6.55) Root cause: splitPipe() splits on every '|', so `help |`, `| wc -l`, `a || b` produced a stage with no argv and executePipeChain() called parts[0].toLowerCase() on undefined — 989 occurrences, first filed 2026-10-20, unfixable from the report because bug reports dropped the stack that named executePipeChain:3955. Same unguarded read existed in _classify(). - terminal.js: _classify() returns an inert classification for empty argv; executePipeChain() parses each stage once, filters stages with no argv (so the last real stage stays final), warns only when the whole pipeline is empty. Last-stage test now compares against the filtered length. - module-system.js: `bug` diagnostics include the stack (10 frames, 1200 chars); auto-filed reports carry it too — they are the majority of the inbox and were previously message-only. - report.php: per-stack 2 KB cap; fingerprint pinned to message/source/count so adding `stack` cannot break dedupe against reports filed before today. - ingest.php: first_frame() parsed once on ingest, stored as `frame` on each signature. - newos4-triage.py: FRAME| line with the first application frame. - dashboard.php: frame under each Top Errors row. - modules/test/test-pipe-guard.js: ordering tripwire (guard must precede the parts[0] read). Verified: test RED exit=1 -> GREEN exit=0; browser matrix on v4.6.55 (help |, | wc -l, echo hi || echo bye, ls | | wc -l, |) -> 0 new error signatures, "|" warns; auto-filed report now carries stack (RPT-...f3e31124, archived after the probe); frame = modules/core/core-bundle.js:3955:42; maintain OK; skill audit 7/7.
* feat(newos4): maintenance agent channel — triage engine, two-way replies, cronAgando2026-10-231-0/+166
- scripts/newos4-triage.py: deterministic collector (records vs occurrences, real vs noise vs self-referential, new reports since last run, checker WARN/FAIL). Untrusted strings are sanitised and prefixed DATA| before they can reach an agent prompt; state + output written under flock with mode 644. - scripts/newos4-reply.py: appends one reply to data/maintenance/replies.json under flock. Hermes writes here instead of POSTing with an admin cookie, so an expired session can never look like a delivered reply. - api/debug/agent-replies.php: GET/POST (admin-gated by nginx) half of the thread. - api/debug/report.php: accepts thread + kind=maintenance so in-app feedback is distinguishable from operator bug reports. - terminal: `feedback <message>` and `feedback-inbox` commands; help.html rows added (help coverage 357/357, modules-index regenerated). Live proof: `feedback "…"` filed RPT-20261023-123825-781fba86 with thread thr-glmfwae2 and kind=maintenance; agent-replies GET returned the posted reply, POST returned 201; triage first run reported 9 new reports, second run 0. Cron: newos4-maintenance (7e3b326daa4c) daily 07:15, newos4-skills-weekly (cb6bc2a16216) Mondays 06:30.