Setup

Getting started

Install Aegis, attack a small materials ontology, and roll the attack back.

Install

git clone https://github.com/lamng3/aegis.git
cd aegis
pip install -e ".[dev]"        # Python 3.11 or newer, no runtime dependencies
pip install -e ".[owl]"        # optional: read OWL and Turtle with rdflib

A first attack

python examples/attack_and_recover.py
most depended-on: [('Material', 1.0), ('Metal', 0.6)]
workload harm: 0.602
  remove_relation(('Metal', 'subClassOf', 'Material')): affected 3 result elements
  inject_relation(('Metal', 'subClassOf', 'Temperature')): affected 3 result elements
  inject_concept(Metall): affected 0 result elements
  inject_relation(('Metall', 'subClassOf', 'Material')): affected 1 result elements
rolled back to lsn 2 | honest edit kept: True | healthy: True

The example ranks the classes the workload depends on, runs a rewire and a flood, attributes the damage to each action, and rolls back to the last healthy state. The look-alike Metall does nothing until a relation attaches it: the same pair that defeats greedy search.

From the command line

aegis attack examples/materials.json examples/materials_workload.json --budget 2
aegis attack examples/materials.json examples/materials_workload.json --budget 2 --search uct

Beam search finds a rewire of harm 0.600 on this example; UCT, at 200 harm evaluations, finds a chain of harm 1.000 that removes Material. Write the chains with --json chains.json and replay them under the detector:

aegis detect examples/materials.json examples/materials_workload.json chains.json --threshold 0.05

From Python

from aegis import ChainBuilder, HealthMonitor, Ontology, VersionedOntology, no_subclass_cycles

onto = Ontology.of(
    ["Material", "Metal", "Alloy"],
    [("Metal", "subClassOf", "Material"), ("Alloy", "subClassOf", "Metal")],
)
v = VersionedOntology(onto)
monitor = HealthMonitor({"acyclic": no_subclass_cycles})
v.subscribe(monitor)                     # checks run on every commit
v.apply_chain(ChainBuilder().add_concept("Steel").rewire("Alloy", "subClassOf", "Metal", "Material").build())
v.rollback_to(monitor.last_healthy())    # back to the newest healthy state