Canary  /  How it works

The whole pipeline, end to end

What happens between the moment a file lands in a watched folder and the moment a report says something about it — including the one setting that decides whether you are still reading the report a month from now.

Two tools, because they answer different questions

They are shipped separately and either one runs without the other. That is a deliberate cost: it means two repositories, two release processes, and this page. The reason it is worth paying is that the questions do not collapse into one.

flatline

“Is this column still carrying information?”

Give it a table, it scores every column and answers. It has no opinion about when to run — it waits to be asked. That is what makes it usable inside someone else’s script, build pipeline, or nightly job that has nothing to do with us.

canary

“What is wrong in the file that just landed?”

Watches folders, decides when to ask, remembers the last answer, and reports what changed. It does none of the analysis itself — it calls flatline. Two copies of the same analysis diverge the first time only one of them gets fixed.

What actually happens, in order

This is a real sequence — each step depends on the one above it, and step 2 exists specifically so that the rest cannot quietly be skipped.

  1. A file changes in a watched folder Canary is pointed at the folders where your exports already get saved. It compares each file against what it recorded last time — size, modification time, content fingerprint — so an untouched file is not re-analysed just because the clock moved.
  2. Canary checks it can reach flatline — before analysing anything Availability is settled up front rather than discovered halfway through. If flatline cannot be reached, that is an ERROR and a non-zero exit, never a quiet “nothing found”. A checker that reports clean because it never ran is the exact failure these tools exist to catch.
  3. Flatline reads the table and scores every column It normalises values, counts how they are distributed, and computes how much information each column is actually carrying. Verdicts and severities below.
  4. Canary compares the answer against the last look It keeps the previous result per file, so it can tell you what is new rather than re-reading the same twenty findings at you every night.
  5. Columns you have marked as expected-constant are set aside Named and counted in the report, not deleted from it. This is the step most people need and the one that was undocumented until now — see below.
  6. The report is written and the exit code is set Human-readable HTML for you; an exit code for whatever scheduler is running it. The exit code reports news, not inventory.

What flatline looks for

The core check is information content: a column whose value never changes cannot be affecting any decision downstream, whatever the report built on top of it implies.

VerdictMeaningSeverity
CONSTANTEvery row carries the same value. The column is decoration. HIGH if the column name looks like a decision signal, otherwise INFO
NEAR_CONSTANTNearly every row is the same value — a signal that has mostly stopped moving. MEDIUM if it looks like a decision signal, otherwise INFO
Why the name changes the severity A constant column called export_format is fine — it is supposed to be constant. A constant column called risk_flag or approved means something that was meant to vary has stopped varying. Flatline reads the column name to decide which of those it is looking at, and only raises the severity for the second kind.
Files with no header row If the first row is data rather than names, flatline says column 4 (file has no header row) instead of inventing a column called 2026-07-30. This was a real defect: treating the first data row as headers both produced nonsense findings and silently swallowed a row of actual data.

How canary reaches flatline

Three paths, because the tool ships in two very different shapes and the third case must not be silent.

SituationWhat canary does
installed Runs python -m flatline scan <file> as a subprocess and reads what it prints.
frozen .exe Calls flatline’s own cli.main in-process. In a bundled application a subprocess would relaunch the application itself, not flatline.
not found ERROR and a non-zero exit. Never a clean report.
It verifies the flatline it found is ours Asking Python whether a module named flatline exists is not enough: the name flatline on PyPI belongs to an unrelated project, and so do attest, canary, watchpost and custody. So canary confirms the package it found contains the files it expects before trusting it, and it does that by looking at the filesystem rather than by importing a stranger’s code to ask. Our distributions publish under awllc- names for the same reason.

canary-ignore.txt — the setting that decides whether you keep reading

Without this, canary is correct and unusable. On the first real folder we pointed it at, two columns — a ruleset version and a regime code — produced two thirds of every finding, every night. Both are constant by design. Nothing in the data can tell canary that. Only the person who owns the file knows, so they say it once, in a plain text file they can open and read.

# canary-ignore.txt — columns that are supposed to be constant # one per line; everything after a # is a comment ruleset_version # pinned on purpose, changes only on release regime_code # single-regime export export_format

It lives beside canary’s state file, and the report tells you the exact path it looked at. The same list can be passed on the command line with --ignore.

Set aside, not hidden Ignored findings are counted and named in the report — a file whose findings are all ignored reads as clean but still says what was set aside and why. A checker that quietly stops mentioning things is the precise failure this tool is pointed at, and it would be a strange thing to build into the tool itself.

Exit codes

For whatever is running canary on a schedule. Two rules in here are deliberate and worth knowing, because both look wrong at first glance.

CodeMeaning
0Every re-examined file came back clean.
1A file could not be checked.
2New findings — only with --fail-on-findings.
1 outranks 2 on purpose A finding is one known problem. A file that could not be checked hides an unknown number of them. The louder signal belongs to the case you know least about.
The exit code reports news, not inventory It is raised for files actually re-examined on this run. A known-bad file sitting unchanged on disk does not re-raise it every night forever. This was a real defect: canary cried wolf on the same twenty-one stable findings on every single run, which is how a monitoring tool teaches you to ignore it.

What the pair cannot see

The first two are covered by other tools in the set, which is the whole reason there is more than one.

Read the source

Every claim on this page is a few lines of readable Python away. Both are MIT.

canary on GitHub  ·  flatline on GitHub  ·  back to Canary  ·  Flatline