Query Contract Corpus — developer contract
tests/query-corpus/ is an end-to-end correctness suite for the query
engine of a stock netdata daemon. Fixtures enter through the real
streaming protocol and queries use the normal HTTP API. Structured responses
are strictly decoded before semantic checks; expectations are
fixture-derived, source-derived, or explicitly labeled stability/parity pins
under the classes below. tests/query-corpus/README.md describes L0-L11
plus cross-cutting API, options, and weights surfaces.
The suite is a self-contained Go module
(github.com/netdata/netdata/tests/query-corpus). Always run go commands
from inside tests/query-corpus/.
Choose the task
| Task |
Read |
| Review a corpus change |
Correctness model, affected architecture/manifest/fixture/oracle sections and existing validation evidence |
| Run or interpret results |
Running and The manifest; README for suite coverage |
| Add or change a fixture/case |
Correctness model, Authoring fixtures, Adding a case and manifest registration |
| Reproduce a query-engine bug |
Adding a case for a bug and the relevant independent oracle contract |
| Change an oracle, byte pin or harness |
Correctness model and Changing oracles, pins, and the harness; verify affected parser/source contracts |
For review, assess the complete assigned change without creating authoring artifacts or starting a daemon merely
because the running workflow appears below. Execution and Git steps apply only within existing task authorization;
recording a merged fix does not itself authorize a rebase or push. Preserve the full-suite gate when corpus delivery
and its push are authorized.
Correctness model — why this suite means something
The founding rule: semantic correctness expectations MUST be derived
independently of engine output. Capturing engine output is allowed only for
an explicitly labeled Class C stability pin; such a pin is not a correctness
oracle. Every check in the corpus belongs to one of three classes, with
different rules:
- Class A — first-principles oracles (the default). Fixtures are literal
Go definitions: charts, dimensions, and explicit
(timestamp, collected value, SN flags) points. Most deterministic
fixtures anchor at fixture.T0; wall-clock-only cases use bounded
envelopes. Expected values come from fixture arithmetic, conservation,
additivity, metadata laws, group-by folds, weights math, and anomaly-bit
counts. New checks MUST be Class A unless the transform genuinely cannot
be derived from first principles.
- Class B — ports of engine algorithms. Some transforms are engine
design decisions, not derivable math.
fixture/sn.go, fixture/tier.go,
fixture/timegroup.go, and fixture/viewpoints.go contain source-derived
ports; they also contain explicitly labeled Class A or contract helpers.
Class B code is written from the C source, never captured from engine
output. Rules:
- A port MUST cite
owner/repo @ commit plus the exact
repository-relative source path and line range it mirrors.
- Every divergence found between a port and the engine MUST be resolved
explicitly: either it is an engine bug (author a case for it) or an engine
quirk adopted into the oracle with a recorded pending ruling in the
manifest/SOW. Silently adjusting a port until the engine passes is the
cardinal sin of this suite ("fit-to-engine") and is prohibited.
- Where a port could hide drift, bound it independently (e.g. L2 pins the
SN quantization error envelope against the ORIGINAL values).
- A port MUST NOT be the oracle for a quantity that obeys an independent
law. Where one exists — conservation, monotonicity, additivity — that
law is derivable, so the check is Class A and the port has nothing to
contribute but the engine's own opinion.
ViewBuckets is a
source-derived model of the default tier-0 point-selection/interpolation
subset exercised by L9, not a port of the complete query executor. It is
appropriate only for those covered level-at-an-instant shapes.
ViewSumVolume is a Class A conservation oracle for volume and is
deliberately independent of that selection model. For every Class B
use, prefer an independent law when one exists.
- Fixtures MUST make the answer exact where the contract is exact. A
conservation check reads a difference, so anything else that moves the total
is noise the check will report as a defect. Above tier 0 the loudest such
source is resolution: when a window edge or a plan seam cuts a stored
record, the part inside can only be estimated from the record's width, and
with varying data that estimate is wrong by a share of the record — which
is what tiers cost, not a defect (see "Tiered rollups are not bugs").
- Grid-align the window so no edge falls inside a record, and where a
boundary is discovered rather than chosen (a rotated tier head), carry a
flat dimension alongside the varying ones: a constant survives rollup
exactly, so its share of a cut record is its exact truth and any
difference left is arithmetic.
- Worked example: CASE-026's seam contract first read 0.49s of data
"missing" across a plan switch, entirely from the seam cutting one
random-valued tier1 record. On the flat dimension the same three windows
answer 7,200,000 to the digit at every zoom. Had the noisy version been
committed, the corpus would have reported accepted rollup as an engine
bug — the mirror image of fit-to-engine, and just as damaging.
- Class C — stability pins and parity checks. Formatter byte pins
(primarily L7 and selected option tests) detect output-contract changes;
parity checks prove internal coherence only. Neither establishes
first-principles correctness. Rules:
- A Class C pin MUST be paired with independent validity checks where
they exist (e.g. "the payload parses as JSON", "values equal the
fixture-derived numbers inside the pinned envelope").
- Updating a pinned byte string requires a justified contract change
(a PR that deliberately changes the output format), never "the test
started failing".
Falsifiability discipline: first rule out an independently demonstrated fixture, harness or oracle defect.
Correct such a defect from fixture math or the cited source contract, with evidence explaining the error; observing
the engine result alone is never justification. Once the expectation is established and the engine disagrees,
there are exactly two exits — the engine is wrong (the case stays as written
and joins the broken list until it is fixed) or a recorded ruling says the
behavior is intended (the case is rewritten to assert the ruled behavior,
with the quirk documented). There is no third option where the oracle is
quietly bent to match, and none where the disagreement is filed away as
acceptable.
Architecture map
stream/stream.go — the fixture child. Speaks plugins.d over the
streaming socket: CHART/DIMENSION/CLABEL, live samples
(BEGIN2/SET2/END2), v1 paced samples (BEGIN/SET/END), and replication
(RBEGIN/RSET/REND). Protocol words quote-switch per word (qw()):
plugins.d accepts both ' and " delimiters, so ids carrying an
apostrophe ship double-quoted. SET2 sends the value explicitly because
the # shorthand truncates fractional values on the parser side. Exact
parser citations are listed under "Changing oracles, pins, and the
harness."
daemon/daemon.go — the harness. Resolves the binary and source tree as a
pair, boots the stock binary with a scratch run dir, assigns a unique
daemon identity, waits for that identity through the HTTP API, exposes
query helpers and WaitRetention, and uses bounded shutdown.
fixture/ — the fixture model plus source-derived Class B ports and
explicitly labeled Class A or contract helpers.
canon/ — the strict typed json2 decoder and point-column helpers. It
rejects invalid schema indices, widths, labels, field types/ranges, and
non-finite numeric metadata while decoding nullable value/hidden cells.
Query-specific assertion helpers enforce whether those nulls are semantically
valid and carry the required annotations.
*_test.go — layer*.go ladder tests, cross-cutting surface tests, and
per-bug caseNNN_test.go files.
manifest.json + MANIFEST.md — the ledger data and its human-readable
mirror (below). manifest.go embeds and validates the data. Keep all three
in sync in the same commit.
reference-python/ — local-only cross-check implementation. It is NOT
tracked and MUST NOT be committed.
The manifest
Every contract case has an entry in manifest.json; its proves, cloud, and
optional fixed_by fields are mirrored as a row in MANIFEST.md.
- One contract key MUST represent one independently actionable semantic
invariant. Multiple fixtures or inputs MAY share a key when they all prove
that same invariant. Independent claims, such as numeric value correctness
and unit rendering, MUST use separate keys and separately registered test or
subtest scopes. A shared green/red verdict is prohibited because an existing
failure in one claim can hide a new regression in another while the broken
contract roster remains unchanged.
- Register ordinary Go assertions with
trackContract(t, name) before any
operation that may fail or skip. Its cleanup records Error, Fatal, and
Skip.
- Use
assertContract(t, name, held) when the test computes an explicit
contract verdict. Call registerContract(t, name) before shared work, so
an earlier Fatal or Skip leaves the verdict visibly incomplete instead
of letting a default-true accumulator report it green.
- When independent test scopes jointly prove one contract, declare their
names in
ManifestCase.Components and register each with
trackContractComponent. One component passing never substitutes for
another component that did not run.
A broken contract fails. Always. On master, on a feature branch,
whether or not the break is already known.
- The manifest records NO expected outcome. There is no "known broken, and
therefore fine" state, and adding one is prohibited: it makes a broken
query engine report success, and this suite exists to name what is
broken, not to keep a list of exceptions.
- An unfiltered root-package run ends with the deduplicated list of broken
contracts and fails if any manifest contract or required component did
not run. That complete list is the corpus's answer — the open-defect
list produced by measurement rather than by hand.
- A filtered daemon-backed run reports how many contracts were fully evaluated
and never claims the complete corpus holds. The deliberately named
daemon-free harness/unit fast path prints only its Go test result and no
query-contract verdict.
-list also prints no contract verdict.
go test ./... therefore exits non-zero while any contract is broken or
the ledger is incomplete. That is the intended signal, not a problem to
suppress. The corpus is not wired into CI.
A case name is <layer-or-CASE-id>/<slug>; Proves is one sentence a
maintainer can read as the contract claim. A case whose bug is fixed keeps
its test as the regression guard and records FixedBy: "#PR".
Running
- Build the daemon first:
ninja -C build netdata from the repo root. By
default the suite pairs ../../build/netdata with ../../src.
- For another checkout, set both paths:
QUERY_CORPUS_NETDATA=/absolute/path/to/build/netdata QUERY_CORPUS_SRC=/absolute/path/to/src go test .... One-sided overrides
are rejected. The pair is operator-declared provenance; the harness does
not inspect binary build metadata.
- Full suite:
cd tests/query-corpus && go test ./... -count=1. Expect
several minutes; duration is hardware and case-selection dependent.
- One test:
go test -count=1 -run 'TestName' .. Some tests consume a
shared palette authored by an earlier layer; include that fixture-producing
test in the filter or run the full suite when a test reports that its
palette is unavailable. A prerequisite skip is not correctness evidence.
- Keep the daemon run dir for inspection:
QUERY_CORPUS_KEEP=1 (it is
always kept on failure; the path is printed as daemon run dir kept:).
- Capture the verdict honestly:
go test ... ; echo "exit=$?" — piping
through tail masks the exit code.
- Before every push of the corpus branch, run the full suite and compare
the broken list to the previous run. It must not grow, and no case may
break that was holding before. The list being non-empty is expected while
the query engine still has open defects.
Authoring fixtures
- Epoch: deterministic fixtures anchor at
fixture.T0; necessary wall-clock cases use the bounded envelopes
required below. For update_every > 1,
pre-align the series: base := fixture.T0 - fixture.T0%int64(ue) —
storage keeps pushed timestamps exactly, but views re-grid onto absolute
update_every multiples, so unaligned fixtures make expectations
needlessly hard.
- Host GUIDs:
guid(n) builds a deterministic machine GUID. n MUST
be unique across the whole suite — hosts persist in the shared daemon for
the entire run, so a collision silently cross-contaminates two tests.
Before taking a number, grep -n 'guid(' *_test.go and pick an unused
range; ranges used by loops (e.g. soak attempts) reserve their whole
span.
- Settle discipline: after pushing, block on
td.WaitRetention(...)
before querying. Ordinary helpers keep the connection open through
assertions to isolate storage/query checks from teardown timing. CASE-015
deliberately closes immediately and guards the #23118 delivered-data
drain guarantee; immediate close is no longer documented as data loss.
- Weights fixtures: rrdcontexts stamps retention ~1–2s after chart
creation; weights queries return empty until then. Settle on the
contexts
first_time_t (see weightsSettle), not only on retention.
- Tolerances: exact comparison is the default.
Chart.ValueTolerance
is ONLY for quantization-probing fixtures, with the reason in a comment.
- Tier window alignment:
TierWindows(gran) keys on ABSOLUTE multiples
of the granularity, not on offsets from T0. fixture.T0 % 60 == 20, so
the first tier-1 window ends at T0+40 and a fixture whose shape is
keyed on the sample index straddles two regimes per stored window. Anchor
tier queries at T0+40, and let the oracle — never the fixture's index
arithmetic — say what each window contains.
- Forcing wide-point re-delivery: ask for a view grid FINER than the
stored data (
DataParamsTier(ctx, 1, after, before, buckets, ...) with
buckets a multiple of the stored window count). Each stored point is
then delivered to several buckets, carrying its original start and an
INTERPOLATED value — so any grouping that reads value instead of the
window's own statistics answers differently per bucket. That is the only
way to reach the repeat path from a query, and it is how
CASE-023/tier-wide-point caught a constant window being judged on an
interpolated blend of two windows.
Adding a case
- Author the fixture (Class A first; reach for a Class B oracle only when
the transform requires it).
- Push it (
pushLiveBurst for live bursts; paced v1 or replication where
the ingestion path is the thing under test), settle, query.
- Compute expectations in Go from the fixture definition. Never paste a
number you got from the engine.
- Add one manifest entry and
MANIFEST.md row per independently actionable
semantic invariant, then register each contract at the narrowest
test/subtest scope that proves it. Do not put independent value, units,
metadata, or formatting claims behind one green/red verdict.
- Run the full suite; a new case MUST NOT destabilize existing cases
(watch for GUID collisions and shared-host mutations).
Adding a case for a bug (bug workflow)
A case for a known bug is written exactly like any other case: it states
the CORRECT behavior and fails while the engine gets it wrong. It is not
marked, excused, or inverted — it joins the broken list until the fix
lands, and the broken list is what the corpus is for.
- Reproduce the divergence deterministically in its own
caseNNN_test.go
with a minimal fixture. The check asserts the CORRECT behavior and feeds
the result into assertContract.
- Add the manifest entry with a
Proves sentence stating the contract
precisely (what correct is), not the bug's symptoms.
- Confirm it fails on today's daemon, and that the failure names the real
defect — a case that fails for the wrong reason is worse than none.
- The fix goes in its OWN branch/PR — never mixed into the corpus branch.
- Validate the fix branch against the corpus before opening the PR:
- build the fix branch, save the binary aside;
- from the corpus checkout:
QUERY_CORPUS_NETDATA=<fix-checkout>/build/netdata QUERY_CORPUS_SRC=<fix-checkout>/src go test -count=1 -run '<the case plus neighboring pins>' .
Both paths MUST describe the same operator-declared checkout.
- the case MUST now hold, and every other case that was holding MUST
still hold (zero collateral).
- When the fix merges: rebase the corpus branch onto the merge, record
FixedBy: "#PR", reword the case comment and Proves to describe the
contract in force, run the full suite, push. The case lives on as the
regression guard.
- If the divergence is ruled intended behavior instead: change the case to
assert the ruled behavior, document the quirk in the oracle comment and
the
Proves text, and record the ruling.
Changing oracles, pins, and the harness
- An oracle change MUST cite its justification: the fixture math (Class A)
or the C source being ported (Class B). "It makes the suite pass" is not
a justification — that is fit-to-engine.
- A Class B port correction that changes expected values MUST state which
divergence prompted it and why it is not an engine bug.
- Byte-pins change only with a deliberate output-contract change.
- Determinism: expectations MUST NOT depend on wall-clock time. Tests that
must touch "now" (live edge, relative windows) assert ENVELOPES (bounded
ranges, row-count bounds), not exact values.
- Protocol emitters (
stream/) mirror the parser's actual grammar. At
netdata/netdata @ 043f50ec075441010c1495250871d37a8ac69f8d, the
authoritative surfaces are:
- quote/token splitting:
src/libnetdata/line_splitter/line_splitter.h:34-119;
BEGIN2: src/plugins.d/pluginsd_parser.c:815-960;
SET2: src/plugins.d/pluginsd_parser.c:963-1125;
END2: src/plugins.d/pluginsd_parser.c:1128-1163;
- A/R/E flags:
src/plugins.d/pluginsd_internals.h:461-485;
RBEGIN/RSET/REND:
src/plugins.d/pluginsd_replication.c:112-215,217-280,367-441.
Extend emitters only from the relevant parser path and update the checked
revision/ranges when the port changes.
Known boundaries (extension points, not history)
Deliberately out of scope so far; extending into them is welcome and each
states what it takes:
- KS2 exact tail values: the ks2 weights oracle pins the engine's
special cases; a full KSfbar port would make every ks2 weight exact.
- Natural-points full oracle: natural mode pins count/values and a
two-candidate boundary check; a full oracle needs the natural-mode point
walk ported.
- 64-bit counter wrap: unreachable through the signed text protocol;
needs a different ingestion vector.
- Float collected values on the reset path: the v1 SET path parses
integers; the reset/overflow pins use integer counters only.
points > 86400: the API caps points; oversized-grid behavior is
unpinned.
- Cloud tier: replaying the raw halves of L5/L6 through the real cloud
aggregator is designed but lives outside this repo.
Gotchas
- Run
go commands from tests/query-corpus/ (own module); running from
the repo root fails with "go.mod not found".
- Values print through the engine's number formatter: a stored
22.000000000000004 prints as 22. Compare parsed numbers, not
strings, unless the check IS a byte-pin.
- The default shared daemon serves most tests. Tests that need isolation,
rotation, or restarts boot dedicated daemons; never restart or reconfigure
the default shared daemon from an unrelated test.
- After system library upgrades, rebuild
build/netdata before blaming a
test failure on the suite.
- IDE diagnostics on the Go files can be stale;
go vet ./... is the
authority.
1---2name: tests-query-corpus-23description: Run, extend or review the Netdata query contract corpus (tests/query-corpus), its fixtures, independent oracles, byte pins and harness. Use for query-engine regression cases, fix-branch validation and recording merged fixes.4---56# Query Contract Corpus — developer contract78`tests/query-corpus/` is an end-to-end correctness suite for the query9engine of a stock `netdata` daemon. Fixtures enter through the real10streaming protocol and queries use the normal HTTP API. Structured responses11are strictly decoded before semantic checks; expectations are12fixture-derived, source-derived, or explicitly labeled stability/parity pins13under the classes below. `tests/query-corpus/README.md` describes L0-L1114plus cross-cutting API, options, and weights surfaces.1516The suite is a self-contained Go module17(`github.com/netdata/netdata/tests/query-corpus`). Always run `go` commands18from inside `tests/query-corpus/`.1920## Choose the task2122| Task | Read |23|---|---|24| Review a corpus change | Correctness model, affected architecture/manifest/fixture/oracle sections and existing validation evidence |25| Run or interpret results | Running and The manifest; README for suite coverage |26| Add or change a fixture/case | Correctness model, Authoring fixtures, Adding a case and manifest registration |27| Reproduce a query-engine bug | Adding a case for a bug and the relevant independent oracle contract |28| Change an oracle, byte pin or harness | Correctness model and Changing oracles, pins, and the harness; verify affected parser/source contracts |2930For review, assess the complete assigned change without creating authoring artifacts or starting a daemon merely31because the running workflow appears below. Execution and Git steps apply only within existing task authorization;32recording a merged fix does not itself authorize a rebase or push. Preserve the full-suite gate when corpus delivery33and its push are authorized.3435## Correctness model — why this suite means something3637The founding rule: **semantic correctness expectations MUST be derived38independently of engine output.** Capturing engine output is allowed only for39an explicitly labeled Class C stability pin; such a pin is not a correctness40oracle. Every check in the corpus belongs to one of three classes, with41different rules:4243- **Class A — first-principles oracles (the default).** Fixtures are literal44 Go definitions: charts, dimensions, and explicit45 `(timestamp, collected value, SN flags)` points. Most deterministic46 fixtures anchor at `fixture.T0`; wall-clock-only cases use bounded47 envelopes. Expected values come from fixture arithmetic, conservation,48 additivity, metadata laws, group-by folds, weights math, and anomaly-bit49 counts. New checks MUST be Class A unless the transform genuinely cannot50 be derived from first principles.51- **Class B — ports of engine algorithms.** Some transforms are engine52 design decisions, not derivable math. `fixture/sn.go`, `fixture/tier.go`,53 `fixture/timegroup.go`, and `fixture/viewpoints.go` contain source-derived54 ports; they also contain explicitly labeled Class A or contract helpers.55 Class B code is written from the C source, never captured from engine56 output. Rules:57 - A port MUST cite `owner/repo @ commit` plus the exact58 repository-relative source path and line range it mirrors.59 - Every divergence found between a port and the engine MUST be resolved60 explicitly: either it is an engine bug (author a case for it) or an engine61 quirk adopted into the oracle **with a recorded pending ruling** in the62 manifest/SOW. Silently adjusting a port until the engine passes is the63 cardinal sin of this suite ("fit-to-engine") and is prohibited.64 - Where a port could hide drift, bound it independently (e.g. L2 pins the65 SN quantization error envelope against the ORIGINAL values).66 - A port MUST NOT be the oracle for a quantity that obeys an independent67 law. Where one exists — conservation, monotonicity, additivity — that68 law is derivable, so the check is Class A and the port has nothing to69 contribute but the engine's own opinion. `ViewBuckets` is a70 source-derived model of the default tier-0 point-selection/interpolation71 subset exercised by L9, not a port of the complete query executor. It is72 appropriate only for those covered level-at-an-instant shapes.73 `ViewSumVolume` is a Class A conservation oracle for volume and is74 deliberately independent of that selection model. For every Class B75 use, prefer an independent law when one exists.76- **Fixtures MUST make the answer exact where the contract is exact.** A77 conservation check reads a difference, so anything else that moves the total78 is noise the check will report as a defect. Above tier 0 the loudest such79 source is resolution: when a window edge or a plan seam cuts a stored80 record, the part inside can only be estimated from the record's width, and81 with varying data that estimate is wrong by a share of the record — which82 is what tiers cost, not a defect (see "Tiered rollups are not bugs").83 - Grid-align the window so no edge falls inside a record, and where a84 boundary is discovered rather than chosen (a rotated tier head), carry a85 **flat dimension** alongside the varying ones: a constant survives rollup86 exactly, so its share of a cut record is its exact truth and any87 difference left is arithmetic.88 - Worked example: CASE-026's seam contract first read 0.49s of data89 "missing" across a plan switch, entirely from the seam cutting one90 random-valued tier1 record. On the flat dimension the same three windows91 answer 7,200,000 to the digit at every zoom. Had the noisy version been92 committed, the corpus would have reported accepted rollup as an engine93 bug — the mirror image of fit-to-engine, and just as damaging.94- **Class C — stability pins and parity checks.** Formatter byte pins95 (primarily L7 and selected option tests) detect output-contract changes;96 parity checks prove internal coherence only. Neither establishes97 first-principles correctness. Rules:98 - A Class C pin MUST be paired with independent validity checks where99 they exist (e.g. "the payload parses as JSON", "values equal the100 fixture-derived numbers inside the pinned envelope").101 - Updating a pinned byte string requires a justified contract change102 (a PR that deliberately changes the output format), never "the test103 started failing".104105**Falsifiability discipline:** first rule out an independently demonstrated fixture, harness or oracle defect.106Correct such a defect from fixture math or the cited source contract, with evidence explaining the error; observing107the engine result alone is never justification. Once the expectation is established and the engine disagrees,108there are exactly two exits — the engine is wrong (the case stays as written109and joins the broken list until it is fixed) or a recorded ruling says the110behavior is intended (the case is rewritten to assert the ruled behavior,111with the quirk documented). There is no third option where the oracle is112quietly bent to match, and none where the disagreement is filed away as113acceptable.114115## Architecture map116117- `stream/stream.go` — the fixture child. Speaks plugins.d over the118 streaming socket: `CHART`/`DIMENSION`/`CLABEL`, live samples119 (`BEGIN2/SET2/END2`), v1 paced samples (`BEGIN/SET/END`), and replication120 (`RBEGIN/RSET/REND`). Protocol words quote-switch per word (`qw()`):121 plugins.d accepts both `'` and `"` delimiters, so ids carrying an122 apostrophe ship double-quoted. `SET2` sends the value explicitly because123 the `#` shorthand truncates fractional values on the parser side. Exact124 parser citations are listed under "Changing oracles, pins, and the125 harness."126- `daemon/daemon.go` — the harness. Resolves the binary and source tree as a127 pair, boots the stock binary with a scratch run dir, assigns a unique128 daemon identity, waits for that identity through the HTTP API, exposes129 query helpers and `WaitRetention`, and uses bounded shutdown.130- `fixture/` — the fixture model plus source-derived Class B ports and131 explicitly labeled Class A or contract helpers.132- `canon/` — the strict typed json2 decoder and point-column helpers. It133 rejects invalid schema indices, widths, labels, field types/ranges, and134 non-finite numeric metadata while decoding nullable value/hidden cells.135 Query-specific assertion helpers enforce whether those nulls are semantically136 valid and carry the required annotations.137- `*_test.go` — `layer*.go` ladder tests, cross-cutting surface tests, and138 per-bug `caseNNN_test.go` files.139- `manifest.json` + `MANIFEST.md` — the ledger data and its human-readable140 mirror (below). `manifest.go` embeds and validates the data. Keep all three141 in sync in the same commit.142- `reference-python/` — local-only cross-check implementation. It is NOT143 tracked and MUST NOT be committed.144145## The manifest146147Every contract case has an entry in `manifest.json`; its `proves`, `cloud`, and148optional `fixed_by` fields are mirrored as a row in `MANIFEST.md`.149150- **One contract key MUST represent one independently actionable semantic151 invariant.** Multiple fixtures or inputs MAY share a key when they all prove152 that same invariant. Independent claims, such as numeric value correctness153 and unit rendering, MUST use separate keys and separately registered test or154 subtest scopes. A shared green/red verdict is prohibited because an existing155 failure in one claim can hide a new regression in another while the broken156 contract roster remains unchanged.157- Register ordinary Go assertions with `trackContract(t, name)` before any158 operation that may fail or skip. Its cleanup records `Error`, `Fatal`, and159 `Skip`.160- Use `assertContract(t, name, held)` when the test computes an explicit161 contract verdict. Call `registerContract(t, name)` before shared work, so162 an earlier `Fatal` or `Skip` leaves the verdict visibly incomplete instead163 of letting a default-true accumulator report it green.164- When independent test scopes jointly prove one contract, declare their165 names in `ManifestCase.Components` and register each with166 `trackContractComponent`. One component passing never substitutes for167 another component that did not run.168169**A broken contract fails. Always.** On master, on a feature branch,170whether or not the break is already known.171172- The manifest records NO expected outcome. There is no "known broken, and173 therefore fine" state, and adding one is prohibited: it makes a broken174 query engine report success, and this suite exists to name what is175 broken, not to keep a list of exceptions.176- An unfiltered root-package run ends with the deduplicated list of broken177 contracts and fails if any manifest contract or required component did178 not run. **That complete list is the corpus's answer** — the open-defect179 list produced by measurement rather than by hand.180- A filtered daemon-backed run reports how many contracts were fully evaluated181 and never claims the complete corpus holds. The deliberately named182 daemon-free harness/unit fast path prints only its Go test result and no183 query-contract verdict. `-list` also prints no contract verdict.184- `go test ./...` therefore exits non-zero while any contract is broken or185 the ledger is incomplete. That is the intended signal, not a problem to186 suppress. The corpus is not wired into CI.187188A case name is `<layer-or-CASE-id>/<slug>`; `Proves` is one sentence a189maintainer can read as the contract claim. A case whose bug is fixed keeps190its test as the regression guard and records `FixedBy: "#PR"`.191192## Running193194- Build the daemon first: `ninja -C build netdata` from the repo root. By195 default the suite pairs `../../build/netdata` with `../../src`.196- For another checkout, set both paths:197 `QUERY_CORPUS_NETDATA=/absolute/path/to/build/netdata198 QUERY_CORPUS_SRC=/absolute/path/to/src go test ...`. One-sided overrides199 are rejected. The pair is operator-declared provenance; the harness does200 not inspect binary build metadata.201- Full suite: `cd tests/query-corpus && go test ./... -count=1`. Expect202 several minutes; duration is hardware and case-selection dependent.203- One test: `go test -count=1 -run 'TestName' .`. Some tests consume a204 shared palette authored by an earlier layer; include that fixture-producing205 test in the filter or run the full suite when a test reports that its206 palette is unavailable. A prerequisite skip is not correctness evidence.207- Keep the daemon run dir for inspection: `QUERY_CORPUS_KEEP=1` (it is208 always kept on failure; the path is printed as `daemon run dir kept:`).209- Capture the verdict honestly: `go test ... ; echo "exit=$?"` — piping210 through `tail` masks the exit code.211- **Before every push of the corpus branch, run the full suite and compare212 the broken list to the previous run.** It must not grow, and no case may213 break that was holding before. The list being non-empty is expected while214 the query engine still has open defects.215216## Authoring fixtures217218- **Epoch**: deterministic fixtures anchor at `fixture.T0`; necessary wall-clock cases use the bounded envelopes219 required below. For `update_every > 1`,220 pre-align the series: `base := fixture.T0 - fixture.T0%int64(ue)` —221 storage keeps pushed timestamps exactly, but views re-grid onto absolute222 `update_every` multiples, so unaligned fixtures make expectations223 needlessly hard.224- **Host GUIDs**: `guid(n)` builds a deterministic machine GUID. `n` MUST225 be unique across the whole suite — hosts persist in the shared daemon for226 the entire run, so a collision silently cross-contaminates two tests.227 Before taking a number, `grep -n 'guid(' *_test.go` and pick an unused228 range; ranges used by loops (e.g. soak attempts) reserve their whole229 span.230- **Settle discipline**: after pushing, block on `td.WaitRetention(...)`231 before querying. Ordinary helpers keep the connection open through232 assertions to isolate storage/query checks from teardown timing. CASE-015233 deliberately closes immediately and guards the #23118 delivered-data234 drain guarantee; immediate close is no longer documented as data loss.235- **Weights fixtures**: rrdcontexts stamps retention ~1–2s after chart236 creation; weights queries return empty until then. Settle on the237 contexts `first_time_t` (see `weightsSettle`), not only on retention.238- **Tolerances**: exact comparison is the default. `Chart.ValueTolerance`239 is ONLY for quantization-probing fixtures, with the reason in a comment.240- **Tier window alignment**: `TierWindows(gran)` keys on ABSOLUTE multiples241 of the granularity, not on offsets from `T0`. `fixture.T0 % 60 == 20`, so242 the first tier-1 window ends at `T0+40` and a fixture whose shape is243 keyed on the sample index straddles two regimes per stored window. Anchor244 tier queries at `T0+40`, and let the oracle — never the fixture's index245 arithmetic — say what each window contains.246- **Forcing wide-point re-delivery**: ask for a view grid FINER than the247 stored data (`DataParamsTier(ctx, 1, after, before, buckets, ...)` with248 `buckets` a multiple of the stored window count). Each stored point is249 then delivered to several buckets, carrying its original start and an250 INTERPOLATED value — so any grouping that reads `value` instead of the251 window's own statistics answers differently per bucket. That is the only252 way to reach the repeat path from a query, and it is how253 CASE-023/tier-wide-point caught a constant window being judged on an254 interpolated blend of two windows.255256## Adding a case2572581. Author the fixture (Class A first; reach for a Class B oracle only when259 the transform requires it).2602. Push it (`pushLiveBurst` for live bursts; paced v1 or replication where261 the ingestion path is the thing under test), settle, query.2623. Compute expectations in Go from the fixture definition. Never paste a263 number you got from the engine.2644. Add one manifest entry and `MANIFEST.md` row per independently actionable265 semantic invariant, then register each contract at the narrowest266 test/subtest scope that proves it. Do not put independent value, units,267 metadata, or formatting claims behind one green/red verdict.2685. Run the full suite; a new case MUST NOT destabilize existing cases269 (watch for GUID collisions and shared-host mutations).270271## Adding a case for a bug (bug workflow)272273A case for a known bug is written exactly like any other case: it states274the CORRECT behavior and fails while the engine gets it wrong. It is not275marked, excused, or inverted — it joins the broken list until the fix276lands, and the broken list is what the corpus is for.2772781. Reproduce the divergence deterministically in its own `caseNNN_test.go`279 with a minimal fixture. The check asserts the CORRECT behavior and feeds280 the result into `assertContract`.2812. Add the manifest entry with a `Proves` sentence stating the contract282 precisely (what correct is), not the bug's symptoms.2833. Confirm it fails on today's daemon, and that the failure names the real284 defect — a case that fails for the wrong reason is worse than none.2854. The fix goes in its OWN branch/PR — never mixed into the corpus branch.2865. Validate the fix branch against the corpus before opening the PR:287 - build the fix branch, save the binary aside;288 - from the corpus checkout:289 `QUERY_CORPUS_NETDATA=<fix-checkout>/build/netdata290 QUERY_CORPUS_SRC=<fix-checkout>/src go test -count=1 -run '<the case291 plus neighboring pins>' .`292 Both paths MUST describe the same operator-declared checkout.293 - the case MUST now hold, and every other case that was holding MUST294 still hold (zero collateral).2956. When the fix merges: rebase the corpus branch onto the merge, record296 `FixedBy: "#PR"`, reword the case comment and `Proves` to describe the297 contract in force, run the full suite, push. The case lives on as the298 regression guard.2997. If the divergence is ruled intended behavior instead: change the case to300 assert the ruled behavior, document the quirk in the oracle comment and301 the `Proves` text, and record the ruling.302303## Changing oracles, pins, and the harness304305- An oracle change MUST cite its justification: the fixture math (Class A)306 or the C source being ported (Class B). "It makes the suite pass" is not307 a justification — that is fit-to-engine.308- A Class B port correction that changes expected values MUST state which309 divergence prompted it and why it is not an engine bug.310- Byte-pins change only with a deliberate output-contract change.311- Determinism: expectations MUST NOT depend on wall-clock time. Tests that312 must touch "now" (live edge, relative windows) assert ENVELOPES (bounded313 ranges, row-count bounds), not exact values.314- Protocol emitters (`stream/`) mirror the parser's actual grammar. At315 `netdata/netdata @ 043f50ec075441010c1495250871d37a8ac69f8d`, the316 authoritative surfaces are:317 - quote/token splitting:318 `src/libnetdata/line_splitter/line_splitter.h:34-119`;319 - `BEGIN2`: `src/plugins.d/pluginsd_parser.c:815-960`;320 - `SET2`: `src/plugins.d/pluginsd_parser.c:963-1125`;321 - `END2`: `src/plugins.d/pluginsd_parser.c:1128-1163`;322 - A/R/E flags: `src/plugins.d/pluginsd_internals.h:461-485`;323 - `RBEGIN`/`RSET`/`REND`:324 `src/plugins.d/pluginsd_replication.c:112-215,217-280,367-441`.325 Extend emitters only from the relevant parser path and update the checked326 revision/ranges when the port changes.327328## Known boundaries (extension points, not history)329330Deliberately out of scope so far; extending into them is welcome and each331states what it takes:332333- **KS2 exact tail values**: the ks2 weights oracle pins the engine's334 special cases; a full KSfbar port would make every ks2 weight exact.335- **Natural-points full oracle**: natural mode pins count/values and a336 two-candidate boundary check; a full oracle needs the natural-mode point337 walk ported.338- **64-bit counter wrap**: unreachable through the signed text protocol;339 needs a different ingestion vector.340- **Float collected values on the reset path**: the v1 SET path parses341 integers; the reset/overflow pins use integer counters only.342- **`points` > 86400**: the API caps points; oversized-grid behavior is343 unpinned.344- **Cloud tier**: replaying the raw halves of L5/L6 through the real cloud345 aggregator is designed but lives outside this repo.346347## Gotchas348349- Run `go` commands from `tests/query-corpus/` (own module); running from350 the repo root fails with "go.mod not found".351- Values print through the engine's number formatter: a stored352 `22.000000000000004` prints as `22`. Compare parsed numbers, not353 strings, unless the check IS a byte-pin.354- The default shared daemon serves most tests. Tests that need isolation,355 rotation, or restarts boot dedicated daemons; never restart or reconfigure356 the default shared daemon from an unrelated test.357- After system library upgrades, rebuild `build/netdata` before blaming a358 test failure on the suite.359- IDE diagnostics on the Go files can be stale; `go vet ./...` is the360 authority.