Chain of causality

The engine goes to great lengths to make sure your knowledge base is internally consistent. This involves linking generated rules to their preconditions; if you invalidate the preconditions of a rule (like retracting one of the facts), its actions will be undone, so all the generated facts will be retracted as well. If the same fact was generated by multiple rules, it will be retracted when all of them are invalidated. If you manually asserted the same fact as well, that will prevent it from being retracted automatically.

Since there are matchers that fire on absense of facts (neg and none; see matchers), you can cause infinite cascades if you're not careful.

Simple actions have an extended form that allows you to react to the invalidation of a rule:

rule {
  forall {
    # ...
  }
  make {
    action activate: ->(token) { ... }, deactivate: ->(token) { ... }
  }
}

# or

class MyAction
  def initialize(*args, &block)

  end

  def execute(token)
    # ...
  end

  def deexecute(token)
    # ...
  end
end

rule {
  forall {
    # ...
  }
  make {
    action MyAction, *args, &block
  }
}