Why won't "wait until a'active" return when the signal a is assigned the same value as before?
Because the OP's question contains a std.env.stop call we know the VHDL design specification is compliant with the 2008 LRM:

IEEE Std 1076-2008
14.7.3 Propagation of signal values
14.7.3.1 General  


  As simulation time advances, the transactions in the projected output waveform of a given driver (see 14.7.2) will each, in succession, become the value of the driver. When a driver acquires a new value in this way or as a result of a force or deposit scheduled for the driver, regardless of whether the new value is different from the previous value, that driver is said to be active during that simulation cycle. ...


16.2.4 Predefined attributes of signals


The implication is a'active is true for any simulation cycle where a's driver is updated regardless of whether the evaluated new value is different from the previous value.

There's also the matter of signals in the sensitivity list for the wait statement:

        wait until a'active;


10.2 Wait statement
(paragraph 3 in part):


  The sensitivity clause defines the sensitivity set of the wait statement, which is the set of signals to which the wait statement is sensitive. Each signal name in the sensitivity list identifies a given signal as a member of the sensitivity set. Each signal name in the sensitivity list shall be a static signal name, and each name shall denote a signal for which reading is permitted. If no sensitivity clause appears, the sensitivity set is constructed according to the following (recursive) rule:  
  
  The sensitivity set is initially empty. For each primary in the condition of the condition clause, if the primary is  
  
  
    ...
    — An attribute name, if the designator denotes a signal attribute, add the longest static prefix of the name of the implicit signal denoted by the attribute name to the sensitivity set; otherwise, apply this rule to the prefix of the attribute name.
    ...  
  


Yet when we simulate the report statement doesn't get executed (p1 never resumes from the wait statement).

Why?

10.2 paragraph 9:


  The suspended process also resumes as a result of an event occurring on any signal in the sensitivity set of the wait statement. If such an event occurs, the condition in the condition clause is evaluated. If the value of the condition is FALSE, the process suspends again. Such repeated suspension does not involve the recalculation of the timeout interval.


Which leads us to the definition of event:

14.7.3.4 Signal update
paragraph 3:


  The current value of a signal of type T is said to change if and only if application of the predefined “=” operator for type T to the current value of the signal and the value of the signal prior to the update evaluates to FALSE. If updating a signal causes the current value of that signal to change, then an event is said to have occurred on the signal, unless the update occurs by application of the vhpi_put_value function with an update mode of vhpiDeposit or vhpiForce to an object that represents the signal. This definition applies to any updating of a signal, whether such updating occurs according to the preceding rules or according to the rules for updating implicit signals given in 14.7.4. The occurrence of an event will cause the resumption and subsequent execution of certain processes during the simulation cycle in which the event occurs, if and only if those processes are currently sensitive to the signal on which the event has occurred.


There is no event causing process p1 to resume while the predefined attribute 'ACTIVE would return TRUE. The current value does not change by executing the assignment to a in the stimulus process.

If you were to assign a value different than the initial value provided in the signal a declaration in the stimulus process p1:

    stimulus: process
    begin
        wait for 100 ns;
        a &lt;= '1'; -- WAS '0';
        wait for 100 ns;
        std.env.stop;
    end process;


process p1 would resume and the report statement would execute:

ghdl -a --std=08 vhdl_active_minimal_testbench.vhdl
ghdl -e --std=08 vhdl_active_minimal_testbench
ghdl -r vhdl_active_minimal_testbench
vhdl_active_minimal_testbench.vhdl:21:9:@100ns:(report note): p2: a'active AND a'transaction'event
vhdl_active_minimal_testbench.vhdl:15:9:@100ns:(report note): p1: a'active
simulation stopped @200ns


Note there is no guarantee the order wait statements of suspended processes are evaluated (process statements are concurrent statements).

14.7 Execution of a model
14.7.1 General
paragraph 3:  


  For any given signal that is explicitly declared within a model, the kernel process contains variables representing the driving value and current value of that signal. Any evaluation of a name denoting a given signal retrieves the current value of the corresponding variable in the kernel process. During simulation, the kernel process updates these variables from time to time, based upon the current values of sources of the corresponding signal.


We don't get to peer into the kernel process, part of the simulator itself.

The underlying idea is events are caused by changes to the current value of a signal while active relates to update regardless of causing an event. A wait statement condition clause (until condition) isn't evaluated unless there is an event. VHDL simulation is event driven.

The Doulos VHDL Golden Reference Guide description of S'ACTIVE referenced in Don Fusili's answer is not causal. 

Determining a change in the current value of a signal does not rely here on a'transaction'event which would entail a delta delay during simulation. S'TRANSACTION is a signal and it's updated current value is not observable in the same simulation cycle as S'ACTIVE without another update in value of S (here a,  which isn't updated in successive cycles with the same simulation time in this design model).