Conversation
flamboh
added this pull request to stack #113
September 25, 2026 10:02
Scope accumulation keeps summed packets and bytes per unique address instead of a bare address set. Rollups merge children by summing, so per-address totals stay additive. Counters are stored unaligned, so each entry grows by exactly 16 bytes. Every MAAD computation now runs three measures for IPv4 and IPv6 at every granularity: addresses (structure, spectrum, dimensions, unchanged), packets and bytes (structure and dimensions only). A weighted measure excludes addresses whose counter sums to 0, records the count as zeroWeightAddrs in the row metadata and logs it. address_structure_stats gains a measure key column with a CHECK that limits spectrum rows to addresses. The table, product schema, pipeline contract, result config and MAAD contract versions bump, and the measure set joins the product identity, so a fresh product database is required. Compare, export, verify and the web-verify queries key on or filter by measure, and verify --require-maad-data checks that every measure is present.
Structure, spectrum and file-detail MAAD queries now bind a measure from a shared parser (parseMaadParams / parseMaadStatsParams, default addresses), so the MAX(CASE) pivots never mix measures. Spectrum routes reject packets and bytes with a 400 because no weighted spectrum exists. The file detail page gets a shared MaadMeasureFilter next to the address family control. Packets and bytes hide the spectrum section. A Drizzle migration adds the measure key and CHECKs and keeps existing rows as addresses.
…allel Each scoped address set now runs one shared prefix walk for addresses, packets and bytes, falling back to separate walks only when a weighted measure has zero-weight addresses. The MAAD pool grows from 2 workers to the available parallelism, capped at 8. Rollup merges no longer reserve capacity for every child entry. On one uoregon day the stored tables are identical to the previous build.
…urrent one A scoped decode thread works on batch N+1 while the writer publishes batch N, so decode workers no longer wait for MAAD and SQLite writes. At most two decoded batches are held. Revision checks still bracket every decode.
…tch publishes Planning, revision checks and decoding for nfcapd batch N+1 still overlap publishing batch N, but their errors are reported only after batch N is published, restoring publish-then-plan error order. The overlap loop is a small helper with tests for a corrupt capture in the second of several 13-request batches and for a planning failure. The inline comment is removed.
flamboh
force-pushed
the
maad/06-weighted-pipeline
branch
from
September 27, 2026 05:17
79cb220 to
da1fe86
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
🤖 Claude Opus 5.5 on behalf of Oliver
What changes
The pipeline stores packet- and byte-weighted MAAD next to the existing address-count MAAD for every bucket, scope, and address side. Flows that report 0 packets are dropped before aggregation. For now you switch measures on the file detail page. A dashboard view of the weighted measures will follow in a PR on top of #119.
Flows to exercise
Setup. Build a small CSV fixture in an empty directory
$FIX(all addresses are documentation ranges):RUST_LOG=info ./scripts/netflow-db.sh pipeline --config $FIX/pipeline.json --maad-workers 2.3 complete, 0 partial, 10 unknowncoverage. The logs showdropped zero-packet flows before aggregationwithdropped_zero_packet_flows=1for buckets0and300.SELECT bucket_start, flows, packets FROM traffic_stats WHERE granularity='5m' AND ip_version=4 AND src_locality='all' AND dst_locality='all' AND bucket_start <= 300returns0|2|5and300|0|0. Bucket 300 stays observed (complete coverage, zero traffic) even though its only flow was dropped.SELECT measure, COUNT(*) FROM address_structure_stats WHERE structure_kind='structure' GROUP BY measurereturns equal counts foraddresses,packets, andbytes.datasets.json, perdocs/user/setup-pipeline.md), run./scripts/netflow-db.sh verify <db> --dataset-id <id> --require-data --require-maad-data --require-processed --require-rollup-parity --require-no-raw-ip. ExpectOK. To see the per-key check fail, delete a singlebytesstructure row for one bucket and side. Expect a nonzero exit andaddress_structure_stats is missing bytes structure rows for source … bucket … <side>.--maad-workers.--maad-workers 0(or-1ormany) is rejected by argument parsing. Omit the option to keep the default of available parallelism capped at 8. The worker count is not part of the product identity, so changing it on an existing database does not force a rebuild.bun run devagainst the database. Open a file detail page and switch the measure between addresses, packets, and bytes. Spectrum is hidden for packets and bytes./api/netflow/structure-stats?measure=packetsreturns rows./api/netflow/spectrum-stats?measure=packetsreturns 400.Edge cases and decisions
nfcapdand CSV input (sorted and unsorted CSV) and to daily-active-source qualification. A dropped flow adds nothing to traffic, protocols, ports, or address sets. It also adds nothing to theaddressesmeasure, so an address seen only in zero-packet flows disappears from every product. Bucket coverage is unchanged. The pipeline logs the dropped flow count for each bucket, counted asflow_countrather than records.packetsand are counted inzeroWeightAddrs. Without this rule, a CSV dataset with no packets column would publish as empty.bytes, as are packets-unknown CSV addresses frompackets. Their count is inmetadata_json.zeroWeightAddrs. Prefix validity still uses distinct-address counts. Weighted measures have no spectrum. The owner judged it degenerate, and a DB CHECK enforces its absence.0005marks existing D1 rows asaddresses.Verification
cargo fmt --all --check,cargo clippy --workspace --all-targets --all-features --locked -- -D warnings,bun run format,bun run lint,bun run typecheck,bun run test:db.bun run test:webcovers the web layer from the original PR; the review fixes don't touch web code.pipelineCLI run that asserts the drop logs and the observed zero bucket--maad-workersparsing and pool-resize rejectionpipeline+verify --require-maad-dataon a fresh database, checking the zero-packet drop log volume