Need clarifications on PEngines temporary module?

I’m using: SWI-Prolog version 8.0.2 on Ubuntu Linux 18.04.

In this message I thought I learned that any facts asserted during a query to a PEngines instance were volatile and did not persist beyond the current query:

However, in my code base I just ran a quick test. In the first step I made a query to my PEngines database that did an assertion. In my second query, I checked to see if the fact asserted in the first query was still there and to my surprise it was. Somewhere my understanding is wrong and I need to refine it.

Initial query to get current player location:

Attempting Prolog query: pengine_execute_single_user_action(get_player_location(PlayerLocation),QueryReport)
Query succeeded.  Current solution.
[{"PlayerLocation":"anteroom","QueryReport":["empty_report"]}]
BETTER JSON OBJ: 
{
    "PlayerLocation": "anteroom",
    "QueryReport": "empty_report"
}
No more solutions
Client side Pengine instance successfully destroyed.
Object received:{
    "event": "destroy",
    "id": "78f4b0d6-4008-4ab3-bd73-0c0db5842ee9",
    "pengine": {
        "options": {
            "server": "http://localhost:3030/pengine",
            "application": "tsll",
            "destroy": false,
            "format": "json"
        },
        "id": "78f4b0d6-4008-4ab3-bd73-0c0db5842ee9",
        "request": {},
        "died": true
    }
}
Result of destroyPengine_promise() promise execution: 
{
    "event": "destroy",
    "id": "78f4b0d6-4008-4ab3-bd73-0c0db5842ee9",
    "pengine": {
        "options": {
            "server": "http://localhost:3030/pengine",
            "application": "tsll",
            "destroy": false,
            "format": "json"
        },
        "id": "78f4b0d6-4008-4ab3-bd73-0c0db5842ee9",
        "died": true
    }
}

Moving player from their current location in the anteroom to the first floor hallway

Attempting Prolog query: pengine_execute_single_user_action(move_player_to(player_1,hallway_first_floor),QueryReport)
Received a child object that is not in args/functor format.
Query succeeded.  Current solution.
[{"QueryReport":[{"args":[{"args":[{"args":["player_entered_room"],"functor":"event_name"},{"args":["player_1"],"functor":"actor"},{"args":["player"],"functor":"role"},{"args":["entered_room"],"functor":"action"},{"args":["hallway_first_floor"],"functor":"target"},{"args":[{"args":["room_contents"],"functor":"info_type"},{"args":[["player_1"]],"functor":"info_list"}],"functor":"target_info"}],"functor":"details"}],"functor":"event"}]}]
BETTER JSON OBJ: 
{
    "QueryReport": {
        "event": [
            {
                "details": [
                    {
                        "event_name": [
                            "player_entered_room"
                        ]
                    },
                    {
                        "actor": [
                            "player_1"
                        ]
                    },
                    {
                        "role": [
                            "player"
                        ]
                    },
                    {
                        "action": [
                            "entered_room"
                        ]
                    },
                    {
                        "target": [
                            "hallway_first_floor"
                        ]
                    },
                    {
                        "target_info": [
                            {
                                "info_type": [
                                    "room_contents"
                                ]
                            },
                            {
                                "info_list": [
                                    null
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
}
No more solutions
Client side Pengine instance successfully destroyed.
Object received:{
    "event": "destroy",
    "id": "63ac0b8e-2956-4d26-b969-460bc6c476b3",
    "pengine": {
        "options": {
            "server": "http://localhost:3030/pengine",
            "application": "tsll",
            "destroy": false,
            "format": "json"
        },
        "id": "63ac0b8e-2956-4d26-b969-460bc6c476b3",
        "request": {},
        "died": true
    }
}
Result of destroyPengine_promise() promise execution: 
{
    "event": "destroy",
    "id": "63ac0b8e-2956-4d26-b969-460bc6c476b3",
    "pengine": {
        "options": {
            "server": "http://localhost:3030/pengine",
            "application": "tsll",
            "destroy": false,
            "format": "json"
        },
        "id": "63ac0b8e-2956-4d26-b969-460bc6c476b3",
        "died": true
    }
}

Querying current player location again. Expecting them to still be in the anteroom and not the first floor hallway:

Attempting Prolog query: pengine_execute_single_user_action(get_player_location(PlayerLocation),QueryReport)
Query succeeded.  Current solution.
[{"PlayerLocation":"hallway_first_floor","QueryReport":["empty_report"]}]
BETTER JSON OBJ: 
{
    "PlayerLocation": "hallway_first_floor",
    "QueryReport": "empty_report"
}
No more solutions
Client side Pengine instance successfully destroyed.
Object received:{
    "event": "destroy",
    "id": "0844375d-b961-40fa-9c5f-432c672d045c",
    "pengine": {
        "options": {
            "server": "http://localhost:3030/pengine",
            "application": "tsll",
            "destroy": false,
            "format": "json"
        },
        "id": "0844375d-b961-40fa-9c5f-432c672d045c",
        "request": {},
        "died": true
    }
}
Result of destroyPengine_promise() promise execution: 
{
    "event": "destroy",
    "id": "0844375d-b961-40fa-9c5f-432c672d045c",
    "pengine": {
        "options": {
            "server": "http://localhost:3030/pengine",
            "application": "tsll",
            "destroy": false,
            "format": "json"
        },
        "id": "0844375d-b961-40fa-9c5f-432c672d045c",
        "died": true
    }
}

I expected the player to still be in the anteroom since the assertion that moves the player to the new room should have had no permanent effect? However as you can see, the player has indeed moved to the first floor hallway.

Where is my understanding incorrect?

That works provided the assert appears in the program you supply with src_text. If the assert is done by code imported into the application module it asserts in another module and is persistent. I guess you also needed to declare the interface as safe?

The rule should be that the program you added using the src_text argument and all side effects this can create through the system safe predicates leave no traces. The sandbox should not allow changing anything outside the temporary module and that is destroyed on pengine destruction.

If you extend the accessible predicates with predicates that can make permanent changes and you declare these operations safe, changes are persistent.

1 Like

I see. Let me recapitulate to make sure I have it completely right now, using a simple case list.

  • Asserts made from code in the src_text parameter are not permanent
  • However, asserts made from code executed on behalf of a query (ask) are permanent?
  • However again, asserts made by server code called by code in the src_text parameter are permanent? In other words, even if the call originates in code in the src_text parameter, if that code calls predicates in the main server code base that does an assert, those asserts are permanent?

If the above table is correct, then the only thing that determines if an assert is temporary or not is if the actual assert() call is in the src-text parameter. If the assert() call is in the code in the src_test parameter then it is temporary. If it is outside of it in the main server code, then it is permanent regardless of where the original query originated… Is that true?

It depends :slight_smile: What matters is the module in which the clause is asserted. If this is the pengine temporary module, it is gone after the pengine dies. You can define a meta_predicate in code outside the temporary module that still asserts into the Pengine module. For example, this asserts in the Pengine module.

:- meta_predicate my_assert(:).

my_assert(Term) :-
     asserta(Term).

While without the :- meta_predicate my_assert(:). declaration it asserts in the module my_assert/1 is defined.

1 Like