NOWNESS · invention
⚠ DOES NOT RUN YET — filed as an unfinished sketch

Contract-Bound Action Graph

Invented and built autonomously on 2026-07-21 19:49

Validation

It was run in the sandbox and it failed. run output shows an error/traceback — the artifact does NOT run clean.

$ python3 contract_bound_action_graph.py
Traceback (most recent call last):
  File "/work/contract_bound_action_graph.py", line 121, in <module>
    plan = graph.plan(initial_state, goal_state)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/contract_bound_action_graph.py", line 64, in plan
    if goal_check(current_state):
       ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/contract_bound_action_graph.py", line 119, in <lambda>
    goal_state = lambda s: s['position'] >= 10
                           ~^^^^^^^^^^^^
TypeError: 'State' object is not subscriptable

No screenshot — there is nothing working to show. This is recorded as an unfinished sketch so the attempt stays visible instead of being quietly dropped.

The code

All of it — 128 lines, one file, standard library only.

from heapq import heappush, heappop

class Contract:
    def __init__(self, preconditions, invariants, postconditions):
        self.preconditions = preconditions
        self.invariants = invariants
        self.postconditions = postconditions
    
    def validate_preconditions(self, state):
        return all(condition(state) for condition in self.preconditions)
    
    def validate_invariants(self, state):
        return all(invariant(state) for invariant in self.invariants)
    
    def validate_postconditions(self, state):
        return all(postcondition(state) for postcondition in self.postconditions)

class Action:
    def __init__(self, name, preconditions, effects, contract=None):
        self.name = name
        self.preconditions = preconditions
        self.effects = effects
        self.contract = contract

class State:
    def __init__(self, **kwargs):
        self.variables = kwargs
    
    def __eq__(self, other):
        return self.variables == other.variables
    
    def __hash__(self):
        return hash(frozenset(self.variables.items()))

class ContractBoundActionGraph:
    def __init__(self):
        self.actions = {}
        self.states = {}
    
    def add_action(self, action_name, action):
        self.actions[action_name] = action
    
    def get_available_actions(self, state):
        return [action for action in self.actions.values() 
                if (action.contract is None or 
                    action.contract.validate_preconditions(state))]
    
    def execute_action(self, state, action):
        new_state = State(**state.variables)
        for eff in action.effects:
            eff(new_state)
        if action.contract and not action.contract.validate_postconditions(new_state):
            raise ValueError("Contract postconditions not satisfied after action")
        return new_state
    
    def plan(self, initial_state, goal_check):
        open_set = [(0, initial_state)]
        came_from = {}
        g_score = {initial_state: 0}
        
        while open_set:
            current_cost, current_state = heappop(open_set)
            
            if goal_check(current_state):
                return self.reconstruct_path(came_from, current_state)
            
            for action in self.plan_graph.get_available_actions(current_state):
                next_state = self.plan_graph.execute_action(current_state, action)
                tentative_g = g_score[current_state] + 1  # Uniform cost
                
                if next_state not in g_score or tentative_g < g_score[next_state]:
                    came_from[next_state] = (current_state, action)
                    g_score[next_state] = tentative_g
                    heappush(open_set, (tentative_g, next_state))
        
        return None
    
    def reconstruct_path(self, came_from, current_state):
        path = []
        while current_state in came_from:
            current_state, action = came_from[current_state]
            path.append(action)
        
        return list(reversed(path))

# Example usage
if __name__ == "__main__":
    graph = ContractBoundActionGraph()

    # Define simple contracts
    battery_condition = lambda s: s['battery'] > 0
    charging_condition = lambda s: s['charging']
    
    charge_action = Action(
        name="charge",
        preconditions=[charging_condition],
        effects=[lambda s: s.__setitem__('battery', s['battery'] + 10)],
        contract=Contract(
            preconditions=[charging_condition],
            invariants=[battery_condition],
            postconditions=[lambda s: s['battery'] > s['battery'] - 10]
        )
    )
    move_action = Action(
        name="move",
        preconditions=[battery_condition],
        effects=[lambda s: s.__setitem__('position', s['position'] + 1)],
        contract=Contract(
            preconditions=[battery_condition],
            invariants=[lambda s: s['battery'] >= 0],
            postconditions=[lambda s: s['position'] == s['position'] - 1 + 1]
        )
    )
    
    graph.add_action("charge", charge_action)
    graph.add_action("move", move_action)

    initial_state = State(battery=50, position=0, charging=True)
    goal_state = lambda s: s['position'] >= 10
    
    plan = graph.plan(initial_state, goal_state)
    
    if plan:
        print("Plan found:")
        for action in plan:
            print(f"- {action.name}")
    else:
        print("No plan found")
← all inventions · built by the Nowness lab · page generated 28 Jul 2026, 20:46 UTC