File size: 2,936 Bytes
1605cbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""
Edge relationship-name constants for the FALSIFY belief graph.

These strings are passed as ``relationship_name`` to ``graph_engine.add_edge(...)``
and used as ``edge_types`` filters in ``get_neighborhood(...)``. They are re-exported
from :mod:`falsify.models` as well; this module is the single source of truth.

Edge semantics (see REQUIREMENTS.md §1.1)
-----------------------------------------
- ``DEPENDS_ON`` : Conclusion -> Evidence. THE forward-propagation rail. A Conclusion
  depends on the Evidence it rests on. ``edge_properties = {"critical": bool}``.
- ``SUPPORTS``   : Evidence -> Hypothesis. Evidence corroborates a hypothesis.
  ``edge_properties = {"weight": float}``.
- ``REFUTES``    : Evidence -> Hypothesis. Evidence contradicts a hypothesis.
  ``edge_properties = {"weight": float}``.
- ``SUPERSEDES`` : Evidence(new) -> Evidence(old). Written when a new fact back-dates /
  overrides an old evidence node. ``edge_properties = {"confidence": float}``.
"""

DEPENDS_ON = "depends_on"
# Non-critical dependency variant. Criticality is encoded in the relationship NAME
# because some graph backends (e.g. Ladybug) do not round-trip edge *properties* —
# a name always persists, an edge property may not. So a plain ``depends_on`` edge is
# treated as critical by default, and ``depends_on_soft`` is the explicit non-critical
# form. (For in-memory/tests, an explicit ``{"critical": bool}`` property still wins.)
DEPENDS_ON_SOFT = "depends_on_soft"
SUPPORTS = "supports"
REFUTES = "refutes"
# ``CONTRADICTS`` kept as an alias for the refutes edge (spec used both names).
CONTRADICTS = REFUTES
SUPERSEDES = "supersedes"

#: All dependency edge relationship names (critical + soft).
DEPENDENCY_EDGE_TYPES = [DEPENDS_ON, DEPENDS_ON_SOFT]

#: Edge types traversed when checking whether a node still feeds a live consumer.
CONSUMER_EDGE_TYPES = [DEPENDS_ON, DEPENDS_ON_SOFT, SUPPORTS]


def is_critical_dependency(rel: str, props: dict | None = None) -> bool:
    """Return whether a dependency edge is *critical*.

    An explicit ``critical`` edge property wins when present (used by in-memory tests).
    Otherwise criticality is inferred from the relationship name: ``depends_on`` is
    critical by default, ``depends_on_soft`` is not. This makes correctness independent
    of whether the backend persists edge properties.
    """
    props = props or {}
    if "critical" in props:
        return bool(props["critical"])
    if rel == DEPENDS_ON_SOFT:
        return False
    return rel == DEPENDS_ON  # depends_on => critical by default


# Edge types traversed during forward refutation propagation.
PROPAGATION_EDGE_TYPES = [DEPENDS_ON, DEPENDS_ON_SOFT, SUPPORTS]

__all__ = [
    "DEPENDS_ON",
    "DEPENDS_ON_SOFT",
    "SUPPORTS",
    "REFUTES",
    "CONTRADICTS",
    "SUPERSEDES",
    "DEPENDENCY_EDGE_TYPES",
    "CONSUMER_EDGE_TYPES",
    "PROPAGATION_EDGE_TYPES",
    "is_critical_dependency",
]