Interaction terms: recovering product/bilinear relationships
Every relationship causal inference has fit so far has been a function of one variable at a time — a source's own polynomial expansion, or a target's own self-lag. That's exactly right for a relationship that decomposes additively, but it can't represent a non-separable coupling — one that isn't a sum of single-variable terms — and the canonical case is bilinear/product coupling: mass-action kinetics, Lotka-Volterra predator-prey, SIR-style epidemiological compartments.
- New checkbox in the review UI: "Also test for interaction effects between related variables" (off by default — most systems don't need it, and it costs a little extra fitting time to try). When on, causal inference additionally tries a product term (
rate × source × target) for each candidate relationship, on top of everything it already tries. - Selection and acceptance reuse the existing machinery end to end — no separate mechanism: it's one more axis in the same lag/degree/penalty search, gated by the same held-out score and the same aggregate-magnitude acceptance test.
- No schema or execution-engine change was needed — an interaction term renders as an ordinary edge equation referencing both endpoints' own symbols, the same pattern the component library's relative-position templates already use.
- Verified end-to-end against a synthetic bilinear system: recovered linear coefficient 1.99 (true 2.0), interaction coefficient 0.79 (true 0.8), self-rate −0.59 (true −0.6).
Causal inference: replay a column's real recorded values instead of guessing its dynamics
Found and fixed while reviewing what actually happens when a causal-inference model is run forward: a column nothing in the CSV predicts (a "root" variable) got no dynamics at all — not even a frozen value at its last known point, but a hardcoded zero, regardless of what the data actually showed.
- Every newly created state's initial value is now seeded from that column's own first recorded row, not zero.
- Any mapped column — not just a root one — can be marked "input" in the review UI: this replays that column's exact recorded trajectory during the run, computed from a generated local-slope provider rather than a fitted equation. It's exact at any solver resolution, not just the CSV's own sampling interval, since a constant-rate segment integrates exactly under Euler regardless of substep count.
- Marking a column as input correctly supersedes any self-term or edge that would otherwise also target it, so nothing gets double-counted.
- Measured on our own 8-node validation system: forward-simulated downstream error is 0.90 with root columns replayed this way, versus 10.15 — over 11× worse — left to their own fitted self-decay alone.
Both features are documented in Causal inference, with the full design history (including approaches considered and rejected) in Interaction terms and Input replay. Both are covered by permanent regression tests, including one that commits and runs a real project through the actual engine rather than a hand-rolled simulation.
Installation notes: Konjugate isn't code-signed yet (an active choice while the project is in alpha), so your OS may show a security warning on first launch. This doesn't mean the download is corrupted.
- macOS — if you see "is damaged and can't be opened": move Konjugate.app to Applications, then in Terminal run
xattr -cr /Applications/Konjugate.app. Or: System Settings → Privacy & Security → Open Anyway.- Windows — if you see a blue "Windows protected your PC" warning from SmartScreen, click More info, then click the Run anyway button that appears.
Full Changelog: v0.7.1...v0.7.2