Consider a simple condition like Door contact is open. If you run a piston containing that condition using the Test button it will look at the current value of the Door contact attribute to see if it is open. If, however, the piston has fired because of a Door contact event, the piston will look at the event value instead. The values can be different.
The stays condition is an unusual one. It is classed as a trigger and that means the piston subscribes to the device attribute it uses. The actual comparisons are like conditions though. A trigger condition can normally only evaluate to true if the piston is currently processing the trigger event, but stays doesn’t work like that.
Considering stays away from locked for 30 seconds, the piston starts by looking to see if the lock status is locked. If it is (bearing in mind the value may come from the event) the comparison returns false, job done.
If the lock status is not locked, the piston sets a timer for 30 seconds time but also immediately returns false and continues.
After 30 seconds the piston wakes up, and unless it has been cancelled, continues where it left off, returning true. This is why it sometimes gets called a timed trigger.
In order to stop the piston returning true, an event has to occur in those thirty seconds to make it run again, which in your case is the locked event. The first ‘if’ group will now return false and cancel any scheduled events set up last time around when it was true. However it would appear that the stays timer doesn’t count as a scheduled task and that the stays trigger actually needs to be evaluated again for it to see the lock status has changed.
That’s how I see things but there are bits where I am really fuzzy about the details. For instance a long wait, implemented by an exit and a wake up, doesn’t seem to turn the piston’s idea of the current event into a timer, it seems to leave it alone.