Selkie.git | t/ | 106-subscribe-prime-reentry.rakutest
use Test;
use lib 'lib';
use Selkie::Store;
# subscribe-path-callback primes by invoking the callback synchronously.
# A callback that re-subscribes its own id on some condition (the
# App::Cantina AvatarList cache-miss re-arm, 2026-08-11) used to recurse
# without bound inside the hosting tick — a silent app-wide freeze. The
# store now latches ids whose prime is on the call stack: the nested
# subscription still registers, but its prime is skipped.
plan 3;
subtest 'self-re-subscribing prime terminates and stays armed' => {
plan 4;
my $store = Selkie::Store.new;
my $calls = 0;
sub arm() {
$store.subscribe-path-callback(
'reentrant', ['ui', 'ready'],
-> $v {
$calls++;
# Unconditional worst case: every prime re-arms.
arm() unless $v.defined;
},
Selkie::Widget,
);
}
lives-ok { arm() }, 'the re-arming prime returns instead of recursing';
is $calls, 1, 'callback ran exactly once (nested prime skipped)';
is $store.subscription-count, 1, 'subscription is registered once';
$store.assoc-in('ui', 'ready', value => 'pixels');
$store.tick;
is $calls, 2, 'the armed subscription still fires on a real change';
};
subtest 'mutual-cycle primes terminate' => {
plan 2;
my $store = Selkie::Store.new;
my @order;
sub arm-a() {
$store.subscribe-path-callback('cycle-a', ['a'], -> $ {
@order.push('a');
arm-b();
}, Selkie::Widget);
}
sub arm-b() {
$store.subscribe-path-callback('cycle-b', ['b'], -> $ {
@order.push('b');
arm-a();
}, Selkie::Widget);
}
lives-ok { arm-a() }, 'a→b→a subscription cycle terminates';
# a primes, arms b; b primes, tries to re-arm a — a is still priming,
# so its nested prime is skipped and the cycle ends.
is-deeply @order, ['a', 'b'], 'each id primed exactly once';
};
subtest 'independent nested subscription still primes' => {
plan 2;
my $store = Selkie::Store.new;
my Bool $inner-primed = False;
$store.subscribe-path-callback('outer', ['x'], -> $ {
$store.subscribe-path-callback('inner', ['y'], -> $ {
$inner-primed = True;
}, Selkie::Widget);
}, Selkie::Widget);
ok $inner-primed,
'a different id subscribed from a prime still gets its prime';
is $store.subscription-count, 2, 'both subscriptions registered';
};
done-testing;