Skip to content

v0.30.0

Latest

Choose a tag to compare

@github-actions github-actions released this 05 Sep 07:35
· 4 commits to main since this release

NetWatch gains a diagnostic engine: a Diagnose tab that names what is wrong,
ranks the explanations by the checks that separated them, offers a fix, and
closes the issue when its own success condition holds. The chrome is rebuilt to
one panel definition across every tab, and AI Insights becomes a commentary
block inside Diagnose rather than a tab of its own.

Added

  • Diagnose (tab 9) — issue → probable cause → remediation → verified
    close.
    Deterministic; no model involved. Per-metric EWMA baselines with
    standard deviation, learned over a minimum of 30 minutes and scoped to a
    fingerprint of the network that taught them, so carrying a laptop from a
    1.2 ms office resolver to a hotel hotspot doesn't fire every rule at once. A
    25-rule catalogue with an explicit suppression graph, so a dead gateway is
    one finding with its consequences underneath rather than six. Causes are
    ranked by weighted check-pass fraction and shown as a word — strong,
    likely, possible — because the number underneath is not a calibrated
    probability and 92% invites reading it as one; checks that couldn't run
    report as not run and count neither way.

    Remediations are key-bound and reversible, and journal their intent before
    they write, so a SIGKILL can't leave /etc/resolv.conf pointing where
    NetWatch put it — the next start reverts what a dead process left behind, and
    declines if something else has edited the file since. report.md and
    report.json come from the same Vec<Issue> the screen renders; a test
    fails if any line quotes a number no evidence field can justify.

    Four of the 25 rules are declared Planned and can never open an issue,
    because their inputs don't exist yet (a DNSSEC reference query, per-reply DNS
    flags, wireless statistics, a STUN probe), and two more detectors report
    their strongest check as not run for the same reason. The header states the
    split: a tool that lists 25 rules and evaluates 19 is misreporting its own
    coverage.

  • A verdict line under the tab bar on every tab, from that same issue list:
    what is wrong, since when, what to press. When the baselines aren't learned
    yet it says so rather than claiming health it hasn't earned — the dashboard,
    Lite and Dense readouts now defer to the engine for the word "nominal".

  • --demo replays a recorded incident through the real engine, rules and
    UI. Diagnose has nothing to say on a healthy machine and wants 30 minutes of
    baseline first, which makes it impossible to demonstrate honestly otherwise.
    Every frame is labelled, remediations touch nothing, and the issue still
    closes through the normal verify path.

Changed

  • btop-style chrome across the whole tool. Every box now comes from one
    widgets::Panel — rounded corners, title inline in the brand accent,
    metadata right-aligned in the same border row. There were 48 hand-built
    blocks across 15 files agreeing by convention rather than construction, two
    already drifted to a different border style on the same screen. Tab bar,
    table headers and panel titles move to the tool's lowercase voice; dropping
    the tab brackets returns twenty columns and stops the status chips clipping
    at 150 columns.
  • AI Insights is no longer a tab. It renders inside Diagnose as labelled
    commentary on findings the engine has already established. insights_enabled
    and the other config keys are unchanged; tab 9 is Diagnose, and a config
    naming insights as its start tab resolves there.
  • screenshots/ is excluded from the published crate, as docs/media/ already
    was.

Fixed

  • pid:0 owned megabytes of traffic on Connections, Processes and Egress.
    PID 0 is the kernel swapper; this was what the label printed when attribution
    returned None, so "644 MB owned by pid:0" meant 644 MB unattributed — and
    the invented process sent an investigation hunting the sandbox for a bug that
    was in a format string. Unattributed traffic now says so; a known PID whose
    comm couldn't be read still reads pid:<n>.
  • E export silently did nothing under the default sandbox. Exports went
    to $HOME, which the Landlock policy makes read-only, so every one failed
    with Permission denied — indistinguishable, with no confirmation on screen,
    from one that worked. They now land in the working directory the sandbox
    grants, and the path is shown.
  • The five KPI sparklines covered different spans at identical width.
    Gateway, DNS and loss are sampled once per health probe; throughput once per
    refresh tick. All drew "the last N samples", so at five ticks per probe the
    latency tiles showed five minutes beside a throughput tile showing one, in a
    row meant to be read across. Every tile is resampled onto one window first.
  • Latency sparklines rendered flat, in both directions. RTT was rounded to
    whole milliseconds, so a 0.5 ms resolver collapsed to 0 or 1 and any non-zero
    sample drew full height; and the ceiling was a raw max(), so one 200 ms
    excursion against a 2 ms baseline scaled everything else to the floor. RTT
    now plots in microseconds against a 95th-percentile ceiling with headroom
    above the median.
  • The Connections state column truncated ESTABLISHED to ESTABLI…, which
    is not a state anyone can look up. States now have short names that fit whole
    estab, time-wait, close-wait — and a mixed group drops the
    denominator rather than clipping the word.
  • The Timeline's "now" cursor overwrote the newest sample it pointed at,
    painting a one column in from the panel border so it read as doubled
    chrome. It tints the cells already there, which is what the "cyan = now"
    legend always claimed.
  • The footer advertised 1-8:Tab and --help said 1-7 Switch tabs while the
    bar drew ten tabs.

Install: cargo install netwatch-tui, brew install netwatch, or a binary below.

Full Changelog: v0.29.2...v0.30.0