Skip to content

A rule cannot read what another rule concluded #477

Description

@WaylandYang

Related to #476, but a different axis: that one is about the shape of one rule (and / or), this one is about rules feeding each other — A → B → C.

Today they do not. Three separate reasons, each in a different place:

  • Inputs are asserted only. attribute_facts() reads facts; a rule's conclusion lands in derived_facts. A concluded attribute value is never an input to anything.
  • Subject scope is the asserted type. The runner filters an entity into a rule by entities.type_id. A rule that concludes class B does not make its subjects members of B for a rule scoped to B.
  • One pass. run evaluates each rule once, in whatever order they load. Nothing re-reads what the round produced.

The contrast is worth naming: the axiom reasoner already chains. derive() runs a semi-naive fixed point precisely so ceo_of → works_at → employs connects, with a per-predicate cap and cycles handled as contradictions. So chaining is not foreign to this system; it is just not wired for business rules.

What it would take

Feed conclusions back in. Derived typings join the subject scope; derived attribute values join the fact pool. Then rules and axioms are two producers into one round.

A fixed point, not an ordering. Round after round until nothing new, with the cap and the cycle guard the axiom path already has. Without it, whether A → B → C fires depends on the order rules happen to load, which is the worst possible answer — it works on one machine and not another.

Premises become a tree — but the cascade is already free. A chained conclusion's premises are derived rows, so a leaf reading changing has to retire everything downstream of it. That sounds like the expensive part and is not: retirement here is not an incremental walk, it is a full recompute. Every run builds wanted — everything that should hold now — and invalidates every live derived_facts row that is not in it. If the leaf changes, the chain simply is not rebuilt, so the whole tail falls out of wanted and retires in the same pass. What the tree does cost is display: a premise that is itself derived means the entity's proof goes one level deeper than the UI draws today.

One decision to settle: may a rule see its own conclusions, or only other rules'? Self-feeding is where the cheap cycles come from.

Cuts

  1. Decision record: what a chained conclusion's proof is, and how retirement cascades.
  2. Runner: conclusions back into the round, fixed point with cap and cycle guard, real-DB tests for A → B → C, for a cycle, and for a leaf reading changing and taking the chain with it.
  3. UI: the rule table says which rules feed which — a chain is worth seeing before you delete the rule in the middle of it. On the schema diagram the edges already compose visually: Well → GasBearingWell → Producer is two rule edges in a row.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions