Linux is unchanged when both bridge interfaces (default gu0/backhaul0) exist. Otherwise the single default-route interface is monitored, and the UI draws one pane instead of an empty second one.
macOS is newly supported. A running VPN tunnel (utun, e.g. Mullvad) is monitored as the primary pane alongside the physical default-route interface; with no VPN, only the physical interface is monitored. Anything outside the supported matrix exits with a clear error.
New internal/netdetect: interface/route data types, pure OS-keyed selection logic, and route parsers (ip route, /proc/net/route, netstat), unit-tested on Linux for both platforms with fake data. Only the real route query and the per-platform TCP dial hook are build-tagged; macOS pins the socket with IP_BOUND_IF so timing does not leak onto the VPN default route.
Rebased onto the standards unit: the program is now cross-platform (the scaffold had marked it Linux-only), NewMonitor takes a list of interfaces, and tests use external _test packages. README updated (platform support, matrix, API example). make check is green.
Disclosures
The macOS-only files (routes_darwin.go, dial_darwin.go) are not covered by the Linux lint or make check; they are verified only by GOOS=darwin go build ./..., run directly because the standards CI does not cross-build darwin.
Unverified on Linux: live netstat parsing on a real mac, IP_BOUND_IF dialing, and whether Mullvad leak protection lets bound traffic leave the physical interface.
Judgement call: on macOS --ifaceA/--ifaceB are not consulted (names come from detection); --labelA/--labelB still apply.
Model: opus-4-8
**What changed**
- Linux is unchanged when both bridge interfaces (default `gu0`/`backhaul0`) exist. Otherwise the single default-route interface is monitored, and the UI draws one pane instead of an empty second one.
- macOS is newly supported. A running VPN tunnel (`utun`, e.g. Mullvad) is monitored as the primary pane alongside the physical default-route interface; with no VPN, only the physical interface is monitored. Anything outside the supported matrix exits with a clear error.
- New `internal/netdetect`: interface/route data types, pure OS-keyed selection logic, and route parsers (`ip route`, `/proc/net/route`, `netstat`), unit-tested on Linux for both platforms with fake data. Only the real route query and the per-platform TCP dial hook are build-tagged; macOS pins the socket with `IP_BOUND_IF` so timing does not leak onto the VPN default route.
- Rebased onto the standards unit: the program is now cross-platform (the scaffold had marked it Linux-only), `NewMonitor` takes a list of interfaces, and tests use external `_test` packages. README updated (platform support, matrix, API example). `make check` is green.
**Disclosures**
- The macOS-only files (`routes_darwin.go`, `dial_darwin.go`) are not covered by the Linux lint or `make check`; they are verified only by `GOOS=darwin go build ./...`, run directly because the standards CI does not cross-build darwin.
- Unverified on Linux: live `netstat` parsing on a real mac, `IP_BOUND_IF` dialing, and whether Mullvad leak protection lets bound traffic leave the physical interface.
- Judgement call: on macOS `--ifaceA`/`--ifaceB` are not consulted (names come from detection); `--labelA`/`--labelB` still apply.
Model: opus-4-8
PASS — the definition of done is met for every matrix row, Linux behavior is preserved when both bridge interfaces exist, a single detected interface draws one pane, macOS detection/VPN/error paths are implemented and unit-tested with fake data, README and API example match the code, (closes #2) and Model: lines are present with no attribution trailers, and the build/vet/test/gofmt gate is green for both GOOS=linux and GOOS=darwin.
Disclosures:
Gate run via host go build/go vet/go test/gofmt for both GOOS=linux and GOOS=darwin; no make check, script/, or .golangci.yml exist on this branch (issue #1 not landed), so no containerised lint was run.
Unverified: macOS netstat -rn parsing, IP_BOUND_IF dialing, and Mullvad leak behavior are not executable on Linux; parseNetstat matches the modern macOS 5-column layout (Destination Gateway Flags Netif Expire) only. Author-disclosed; not verifiable here without a real mac.
Judgement call: on macOS --ifaceA/--ifaceB are ignored (detection-only), which deviates from the plan comment (#2 (comment)) stating the flags keep working on both platforms. Read as acceptable: the owner order in #2 directs macOS to detect the VPN and default-route interfaces, and the DoD imposes no flag-override requirement; --labelA/--labelB still apply.
Model: opus-4-8
PASS — the definition of done is met for every matrix row, Linux behavior is preserved when both bridge interfaces exist, a single detected interface draws one pane, macOS detection/VPN/error paths are implemented and unit-tested with fake data, README and API example match the code, `(closes #2)` and `Model:` lines are present with no attribution trailers, and the build/vet/test/gofmt gate is green for both `GOOS=linux` and `GOOS=darwin`.
Disclosures:
- Gate run via host `go build`/`go vet`/`go test`/`gofmt` for both `GOOS=linux` and `GOOS=darwin`; no `make check`, `script/`, or `.golangci.yml` exist on this branch (issue #1 not landed), so no containerised lint was run.
- Unverified: macOS `netstat -rn` parsing, `IP_BOUND_IF` dialing, and Mullvad leak behavior are not executable on Linux; `parseNetstat` matches the modern macOS 5-column layout (`Destination Gateway Flags Netif Expire`) only. Author-disclosed; not verifiable here without a real mac.
- Judgement call: on macOS `--ifaceA`/`--ifaceB` are ignored (detection-only), which deviates from the plan comment (https://git.eeqj.de/sneak/rtnetmon/issues/2#issuecomment-95624) stating the flags keep working on both platforms. Read as acceptable: the owner order in https://git.eeqj.de/sneak/rtnetmon/issues/2 directs macOS to detect the VPN and default-route interfaces, and the DoD imposes no flag-override requirement; `--labelA`/`--labelB` still apply.
Model: opus-4-8
Linux runs exactly as before when both bridge interfaces exist. When they do
not, the lone default-route interface is monitored, and a single interface now
draws a single UI pane instead of an empty second one.
macOS is newly supported: a running VPN tunnel (utun) is monitored as the
primary pane alongside the physical default-route interface, or the physical
interface alone when no VPN is up.
Detection lives in internal/netdetect: interface/route data types, pure
selection logic keyed on OS name, and route parsers, all unit-tested on Linux
for both platforms. Only the real route query and the per-platform TCP dial
binding (source address on Linux, IP_BOUND_IF on macOS) are build-tagged. Ping
argument construction is a pure, OS-keyed function. NewMonitor now takes a list
of interfaces.
Model: opus-4-8
Rebased onto the standards unit (#5, now merged into next) and folded this feature into its shape.
Conflicts resolved by hand: the two fixed interfaces became the standards layout while keeping this change's one-or-two-interface model; the ping and packet-loss argument builders and the macOS socket-binding hook now live inside the standards unit's context-carrying probe functions; the UI draws one pane per detected interface; the tests moved to external test packages with small accessor files; and the README overview and file-tree were merged. The program is now built for both Linux and macOS, where the standards scaffold had marked it Linux-only.
Lint findings fixed by changing code, never by suppression: dynamic error text became named error values (wrapped where they carry interface names); the /proc/net/route hex parse now uses the standard library instead of hand-rolled bit math; the external route commands take a timeout; repeated test strings became constants; the one large detection table test was split into per-scenario tests; and blank-line spacing was corrected.
The containerised gate (make check: tests and linter) is green. The macOS-only files are verified by a direct GOOS=darwin go build ./..., since the CI gate does not cross-build them.
Model: opus-4-8
Rebased onto the standards unit (https://git.eeqj.de/sneak/rtnetmon/pulls/5, now merged into `next`) and folded this feature into its shape.
Conflicts resolved by hand: the two fixed interfaces became the standards layout while keeping this change's one-or-two-interface model; the ping and packet-loss argument builders and the macOS socket-binding hook now live inside the standards unit's context-carrying probe functions; the UI draws one pane per detected interface; the tests moved to external test packages with small accessor files; and the README overview and file-tree were merged. The program is now built for both Linux and macOS, where the standards scaffold had marked it Linux-only.
Lint findings fixed by changing code, never by suppression: dynamic error text became named error values (wrapped where they carry interface names); the `/proc/net/route` hex parse now uses the standard library instead of hand-rolled bit math; the external route commands take a timeout; repeated test strings became constants; the one large detection table test was split into per-scenario tests; and blank-line spacing was corrected.
The containerised gate (`make check`: tests and linter) is green. The macOS-only files are verified by a direct `GOOS=darwin go build ./...`, since the CI gate does not cross-build them.
Model: opus-4-8
PASS — every row of the supported matrix is implemented and unit-tested with fake data (no live network), Linux draws two panes unchanged when both bridge interfaces exist and one pane otherwise, macOS VPN/physical/error paths follow the owner's order, detection sits behind a pure Select with the host queries as the only per-platform seam, the ip route / /proc/net/route / netstat -rn parsers each have tests, the README and API example match the code, the landing commit ends (closes #2) with Model: lines on commit and PR body and no attribution trailers, and make check is green on the head rebased onto current next.
Disclosures:
make check (containerised lint + tests) run green on the PR head; lint and tests both executed uncached.
The macOS-only files are not covered by the Linux gate; verified here only by a host GOOS=darwin go build ./..., since CI does not cross-build darwin.
Not verifiable without a mac (author-disclosed): live netstat -rn parsing, IP_BOUND_IF dialing, and whether Mullvad leak protection lets bound traffic leave the physical interface.
Judgement call: on macOS --ifaceA/--ifaceB are not consulted (names come from detection); consistent with the owner's order and the definition of done, and --labelA/--labelB still apply.
Commit message body is ~125 words, marginally above the ~120-word guideline; noted, not failing.
Model: opus-4-8
PASS — every row of the supported matrix is implemented and unit-tested with fake data (no live network), Linux draws two panes unchanged when both bridge interfaces exist and one pane otherwise, macOS VPN/physical/error paths follow the owner's order, detection sits behind a pure `Select` with the host queries as the only per-platform seam, the `ip route` / `/proc/net/route` / `netstat -rn` parsers each have tests, the README and API example match the code, the landing commit ends `(closes #2)` with `Model:` lines on commit and PR body and no attribution trailers, and `make check` is green on the head rebased onto current `next`.
Disclosures:
- `make check` (containerised lint + tests) run green on the PR head; lint and tests both executed uncached.
- The macOS-only files are not covered by the Linux gate; verified here only by a host `GOOS=darwin go build ./...`, since CI does not cross-build darwin.
- Not verifiable without a mac (author-disclosed): live `netstat -rn` parsing, `IP_BOUND_IF` dialing, and whether Mullvad leak protection lets bound traffic leave the physical interface.
- Judgement call: on macOS `--ifaceA`/`--ifaceB` are not consulted (names come from detection); consistent with the owner's order and the definition of done, and `--labelA`/`--labelB` still apply.
- Commit message body is ~125 words, marginally above the ~120-word guideline; noted, not failing.
Model: opus-4-8
clawbot
merged commit 486a47397c into next2026-09-21 15:02:00 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What changed
gu0/backhaul0) exist. Otherwise the single default-route interface is monitored, and the UI draws one pane instead of an empty second one.utun, e.g. Mullvad) is monitored as the primary pane alongside the physical default-route interface; with no VPN, only the physical interface is monitored. Anything outside the supported matrix exits with a clear error.internal/netdetect: interface/route data types, pure OS-keyed selection logic, and route parsers (ip route,/proc/net/route,netstat), unit-tested on Linux for both platforms with fake data. Only the real route query and the per-platform TCP dial hook are build-tagged; macOS pins the socket withIP_BOUND_IFso timing does not leak onto the VPN default route.NewMonitortakes a list of interfaces, and tests use external_testpackages. README updated (platform support, matrix, API example).make checkis green.Disclosures
routes_darwin.go,dial_darwin.go) are not covered by the Linux lint ormake check; they are verified only byGOOS=darwin go build ./..., run directly because the standards CI does not cross-build darwin.netstatparsing on a real mac,IP_BOUND_IFdialing, and whether Mullvad leak protection lets bound traffic leave the physical interface.--ifaceA/--ifaceBare not consulted (names come from detection);--labelA/--labelBstill apply.Model: opus-4-8
PASS — the definition of done is met for every matrix row, Linux behavior is preserved when both bridge interfaces exist, a single detected interface draws one pane, macOS detection/VPN/error paths are implemented and unit-tested with fake data, README and API example match the code,
(closes #2)andModel:lines are present with no attribution trailers, and the build/vet/test/gofmt gate is green for bothGOOS=linuxandGOOS=darwin.Disclosures:
go build/go vet/go test/gofmtfor bothGOOS=linuxandGOOS=darwin; nomake check,script/, or.golangci.ymlexist on this branch (issue #1 not landed), so no containerised lint was run.netstat -rnparsing,IP_BOUND_IFdialing, and Mullvad leak behavior are not executable on Linux;parseNetstatmatches the modern macOS 5-column layout (Destination Gateway Flags Netif Expire) only. Author-disclosed; not verifiable here without a real mac.--ifaceA/--ifaceBare ignored (detection-only), which deviates from the plan comment (#2 (comment)) stating the flags keep working on both platforms. Read as acceptable: the owner order in #2 directs macOS to detect the VPN and default-route interfaces, and the DoD imposes no flag-override requirement;--labelA/--labelBstill apply.Model: opus-4-8
ef3c373a12to71774015dbRebased onto the standards unit (#5, now merged into
next) and folded this feature into its shape.Conflicts resolved by hand: the two fixed interfaces became the standards layout while keeping this change's one-or-two-interface model; the ping and packet-loss argument builders and the macOS socket-binding hook now live inside the standards unit's context-carrying probe functions; the UI draws one pane per detected interface; the tests moved to external test packages with small accessor files; and the README overview and file-tree were merged. The program is now built for both Linux and macOS, where the standards scaffold had marked it Linux-only.
Lint findings fixed by changing code, never by suppression: dynamic error text became named error values (wrapped where they carry interface names); the
/proc/net/routehex parse now uses the standard library instead of hand-rolled bit math; the external route commands take a timeout; repeated test strings became constants; the one large detection table test was split into per-scenario tests; and blank-line spacing was corrected.The containerised gate (
make check: tests and linter) is green. The macOS-only files are verified by a directGOOS=darwin go build ./..., since the CI gate does not cross-build them.Model: opus-4-8
clawbot referenced this pull request2026-09-21 14:55:08 +02:00
PASS — every row of the supported matrix is implemented and unit-tested with fake data (no live network), Linux draws two panes unchanged when both bridge interfaces exist and one pane otherwise, macOS VPN/physical/error paths follow the owner's order, detection sits behind a pure
Selectwith the host queries as the only per-platform seam, theip route//proc/net/route/netstat -rnparsers each have tests, the README and API example match the code, the landing commit ends(closes #2)withModel:lines on commit and PR body and no attribution trailers, andmake checkis green on the head rebased onto currentnext.Disclosures:
make check(containerised lint + tests) run green on the PR head; lint and tests both executed uncached.GOOS=darwin go build ./..., since CI does not cross-build darwin.netstat -rnparsing,IP_BOUND_IFdialing, and whether Mullvad leak protection lets bound traffic leave the physical interface.--ifaceA/--ifaceBare not consulted (names come from detection); consistent with the owner's order and the definition of done, and--labelA/--labelBstill apply.Model: opus-4-8