Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lx9FNLG2CqeBbVGGd9bFsP
nmon build milestones
The build follows the six gated milestones in docs/spec/spec.md.
Each milestone has its own document here. It is written before any code for that milestone and
its Gate log is filled in when the gate passes. A milestone is done only when:
make lintis clean: maintainability is a hard rule (docs/MAINTAINABILITY.md), and every gate script runs lint first,- every acceptance line it closes (from
build-detail.md) has a test that passes, make test(go test -race ./...) andmake test-integrationpass,- its gate command (
make gate-mN) passes when run by the supervisor, and - the tree is committed and tagged
mN.
| # | Milestone | Gate | Doc | Status |
|---|---|---|---|---|
| M1 | Skeleton and fixtures | nmon serve polls the counters fixture and /api/v1/query returns rising ifHCInOctets |
M1 | passed, tagged m1 |
| M2 | Discovery and profiles | every fixture's expect.yaml passes, including v1 and v3, and the PDU budget holds | M2 | passed, tagged m2 |
| M3 | Graphs and UI | a port's in/out graph renders at 1 h, 24 h and 30 d from the counters fixture | M3 | in progress (web UI done on mock data) |
| M4 | Alerting | stopping a parent fixture sends one notification naming it and its children | M4 | in progress (WP2 rules and WP3 notify done) |
| M5 | Push ingest, rollup, checks | a replayed Proxmox sample shows under its node and a 2 y query hits the 1 h tier | M5 | planned |
| M6 | Auth and ops | a viewer gets 403 on PUT and the 2,000-device loadtest cycle finishes under 40 s | M6 | planned |
| M7 | gNMI streaming | after v1; not built in this run | — | out of scope |
How the work is run
- Supervisor (Claude Opus): writes these docs, splits each milestone into work packages (WPs), reviews every diff, runs every gate command itself, commits and tags.
- Implementers (Claude Sonnet sub-agents): one WP each. WPs in different
internal/packages run in parallel. Shared files (go.mod,cmd/nmon/*.gowiring,openapi.json,Makefile) are changed only by the supervisor or by the single WP that owns them in that milestone.
Departures from the spec are recorded in docs/DEVIATIONS.md.
Rules every WP follows (from "Decisions that don't move")
-
Maintainability is a hard rule. Follow
docs/MAINTAINABILITY.md: zero golangci-lint and ESLint findings in your packages, the function, complexity and file-size limits, and the layering rules. Every WP brief cites it. -
One static binary,
CGO_ENABLED=0. No raw SQL outsideinternal/store. -
The 60 s poll path talks only to devices (SNMP, ICMP) and the local hot store.
-
Metric labels on SNMP series:
device=<slug>, plusiface=<ULID>on interface series. Nothing else. -
Every port is polled, up or down. Only the profile's
exclude_ifnamepatterns drop a port. -
Rollups store rates, never raw counters.
-
IPv6 first: every network path works on v6 and v4; tests default to
::1. -
Time comes from
internal/clock. Notime.Now()/time.Sleepin logic that a test must control. -
Tests never need real hardware. Fixtures are
.snmprecfiles served byinternal/simagent.
Deferred (revisit after v1 milestones)
- Deployment playbook: install layout (binary,
/usr/share/nmon/mibssidecar, systemd unit granting port 162, key file location), TLS/ACME or proxy setup, IdP configuration, backups, and upgrades. Raised by the user on 2026-10-22; deliberately postponed.
Review artifacts
- From M3 on, each UI milestone's gate captures Playwright screenshots of every page into
docs/screenshots/<milestone>/for the user to review.