Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

mikronova/funnel-core

.nornir/for-idiots.md

funnel-core — for beginners

No jargon. What this little library is and why it exists.

The one-sentence version

funnel-core turns a list of things that happened ("someone submitted an idea", "a plan was made", "a task finished") into an answer to a question ("what should I work on next?", "show me the kanban board", "which bugs are still open?").

The mental picture

Think of a diary. Each line is one small fact, written once and never erased:

- rickard had an idea: "add a dark theme"
- we made a plan for it
- the plan has 3 tasks: A, then B, then C
- task A is finished

funnel-core reads the whole diary from the top and rebuilds the current picture in memory. That picture is called a Funnel. You never edit the picture directly — you add a new diary line (an Event) and re-read.

It also refuses lines that don't make sense — a task that depends on itself, the same dependency written twice, or a loop ("A waits for B, B waits for A"). A loop is the nasty one: nothing in it can ever start, so the whole plan would freeze. funnel-core spots the loop the moment you try to add the line that would close it and says no, keeping every plan finish-able.

What you get out of it

Once the diary is read, you can ask for different views of the same facts:

Joining the plan to the actual code

Here's a thing the diary alone can't tell you: which files/crates does this plan actually touch?

Picture two diagrams side by side. On the left, the plan: boxes like "write the importer", "fix the crash". On the right, the code: boxes like funnel-core, nornir, nornir-viz, with arrows showing which one needs which. Now imagine drawing a string from a plan box across to a code box: "this task touches that crate." That string is a wire, and the pile of them is the wiring.

Once the strings are there you get two useful answers:

The part that matters most: admitting what isn't wired

It would be very easy — and very dishonest — for the library to look at a plan box with no string attached and cheerfully report "affects nothing". Empty because there's genuinely nothing downstream, and empty because nobody wired it up, are completely different answers that look identical.

So the library refuses to conflate them. Every plan box is listed as either mapped (has a string) or unmapped (doesn't), with a reason for the second:

And there's one row the library shouts about: a task marked finished that was never wired to anything. That means work landed in code the plan can't point at.

Strings are never deleted, by the way — the diary never erases. Rejecting a connection is just a new line saying "no, not that one", which is how the computer remembers not to suggest it again.

Why it's built this way

Because the answer is always computed fresh from the facts, the same diary always gives the same answer — no surprises, nothing hidden, and it's trivial to test. And because it holds none of the heavy machinery (no database, no graphics), both the big nornir app and the ordning app can use the exact same rules for free.