Repository navigation
Queen actors loop: weak points of actors.t27 and the plan to close them #6971
Description
Why
specs/queen/actors.t27 (#6963, PR #6966) takes the BEAM/OTP actor rules for the Queen's agent runtimes. A self-review of that spec found places where the contract is weaker than the systems it borrows from, or where its own tests do not reach. This epic records each one as a sub-issue and the loop that closes them.
Weak points found (self-review, 2026-10-06)
- A cancel can be dropped by a full mailbox. Section 6 says a cancel is taken ahead of queued offers by selective receive, but
deliverdrops ANY message when the bounded mailbox is full -- the cancel included. The BEAM keeps exit signals out of the mailbox and Akka keeps system messages in their own queue; this spec had one lane. - No request/reply. A call (send, wait for the answer) is the most common actor exchange and the spec had none: nothing said what ends a call, or what happens to a reply that arrives after the caller gave up. Without OTP 24's process alias a late reply sits in the bounded mailbox for good.
- A slow crash loop restarts forever. Restart intensity counts restarts in a window: a child crashing every 101 s against 3 in 300 s never trips it, and each restart is a fresh paid agent turn. Akka's BackoffSupervisor and Kubernetes' CrashLoopBackOff back off instead.
affectedhad no direct test, and the section 7 departures (bounded mailbox, no hot swap, ...) were asserted nowhere.- Mutation runs are a throwaway script.
tri mutate runperturbs numeric literals only; guard and operator mutants of a.t27spec need a hand-written pairs list each time.
Plan
- control lane for cancel and heartbeat -- actors.t27: a control lane so a cancel survives a full mailbox #6972
- call outcome and alias -- actors.t27: call outcome and a process alias for late replies #6974
- restart backoff and the unstable-streak give-up -- actors.t27: restart backoff so a slow crash loop reaches the parent #6975
- direct coverage:
affected, section 7 as an invariant -- actors.t27: direct coverage for affected and the section 7 departures #6976 - a hung turn is killed and reclaimed (Temporal start-to-close) -- actors.t27: a hung turn is killed and its task reclaimed #6990
- dead letters make a dropped message visible -- actors.t27: dead letters make a dropped message visible #6991
- the two Erlang corners ruled out in text, lane order stated -- actors.t27: state the two places it differs from Erlang on purpose #6992
- a
trihelper for guard/operator mutation of a.t27spec -- tri mutate spec: guard and operator mutants of a .t27 spec, run through t27c gen + zig test #6993 - competitor comparison recorded in a comment here with sources
Each item lands with: all backends (gen, gen-rust, gen-c, gen-verilog) exit 0, zig test green, t27c test-report with 0 vacuous passes, and a mutation run over the new lines whose survivors are either killed or explained as equivalent.
Work is stacked on branch claude/queen-actors-next and opened as one PR after #6966 merges, because the Actions queue is the bottleneck (100+ queued runs on 2026-10-06).
Boundary
specs/queen/actors.t27
User Scenarios
- Given the actors.t27 spec has five identified weak points (cancel dropping, no call semantics, unbounded restart loop, missing
affectedcoverage, throwaway mutation), When the planned sub-issues are implemented and merged, Then all backends compile, the test suite passes with zero vacuous passes, and mutation runs over new lines yield no unexplained survivors.
Requirements
FR-001: The spec MUST add a dedicated control lane for cancel and heartbeat signals that bypasses the bounded mailbox
FR-002: The spec MUST define request/reply (call) semantics including outcome handling and alias-based late-reply protection
FR-003: The spec MUST implement restart backoff with an unstable-streak give-up threshold
FR-004: The spec MUST add direct invariant tests for affected and all section 7 departures (bounded mailbox, no hot swap, etc.)
FR-005: The spec MUST ensure hung turns are killed and reclaimed per Temporal start-to-close semantics
FR-006: The spec MUST route dropped messages to a dead-letter mechanism for visibility
FR-007: The spec MUST explicitly document the two Erlang corners ruled out and state the lane ordering guarantee
FR-008: The tri tool MUST provide a helper for guard/operator mutation of .t27 specs without hand-written pairs lists
Success Criteria
t27c build specs/queen/actors.t27exits 0 for all backends (gen,gen-rust,gen-c,gen-verilog)zig testexits 0t27c test-report specs/queen/actors.t27shows 0 vacuous passes- Mutation run over new lines in
specs/queen/actors.t27yields 0 unexplained survivors (all killed or documented equivalent) - Sub-issues actors.t27: a control lane so a cancel survives a full mailbox #6972, actors.t27: call outcome and a process alias for late replies #6974, actors.t27: restart backoff so a slow crash loop reaches the parent #6975, actors.t27: direct coverage for affected and the section 7 departures #6976, actors.t27: a hung turn is killed and its task reclaimed #6990, actors.t27: dead letters make a dropped message visible #6991, actors.t27: state the two places it differs from Erlang on purpose #6992, tri mutate spec: guard and operator mutants of a .t27 spec, run through t27c gen + zig test #6993 all closed
Activity
gHashTag commentedon Oct 6, 2026
Competitor comparison (read from official docs, 2026-10-06)
calluses one so late replies are not received; call timeout 5000 ms defaultcall_outcome,live_alias)significantchildren +auto_shutdown(OTP 24)killreaches links as a trappablekill;exit(self(), normal)kills a non-trapping processhung_turn_signal):max_children; Registry drops a crashed process's keys;Task.Supervisor.async_nolinkturns a crash into a DOWNUnverified (not stated on the pages read): why spawn_link must be atomic; Akka typed backoff reset default; where Dapr stores reminders (two pages disagree); whether Restate
ctx.runcan run twice before its result is journaled.Next candidates, in order: journal/replay hand-off to control.t27's event log; restart jitter; significant children; call-cycle (reentrancy) rule; max_children per domain.
gHashTag commentedon Oct 6, 2026
Loop tick 2 (2026-10-06T17:55Z):
specs/numeric/formats.t27DRIFTED (fix(spec-guards): ring-096 and specs/numeric/formats.t27 agree on f32, as the gf16 SSOT says #6894), which predates it.tri mutate spec) is committed onclaude/tri-mutate-specand waits for spec(queen): actors control lane, call, backoff, hung turn, dead letters (Closes #6972 #6974 #6975 #6976 #6990 #6991 #6992) #7001, so the Actions queue (321 queued) does not get two PRs at once. Its first whole-file run on actors.t27: 149 of 157 killed. The 2 test gaps are closed in spec(queen): actors control lane, call, backoff, hung turn, dead letters (Closes #6972 #6974 #6975 #6976 #6990 #6991 #6992) #7001; the 6 equivalents are named there.spec(queen): actors control lane, call, backoff, hung turn, dead lett…
feat(tri): tri mutate spec -- guard, operator and arithmetic mutants …
spec(queen): actors jitter, significant children, call cycle, max chi…
feat(t27b): std.mem.eql/indexOf on byte slices and byte-array pointers (
fix(codegen): gen-rust enum order and gen-zig float-call cast (#6941) (…
gHashTag commentedon Oct 7, 2026
Queen mutation census on master
05e633d03, 2026-10-07 (Railway lab, master release build,tri mutate spec --file F --jobs 8 --timeout 60 --zig-threads 6, one run per spec). Every spec inspecs/queen/:<-><=on a min assignment), 223 (running >= cap->>: both return 0 at equality), 230 (eligible < slots-><=: same value at equality)effective_levelnamed in #7077then): #6519All 7 hung mutants are
drop-stepon a loop counter (n = n + 1->n = nand the like: actors 116, 134, 226; review_log 44; task_analysis 68, 81; views 287), so the loop the mutant made never ends; none is a hang of the spec.Against #7077's pass nothing regressed: it printed 35 of 35 for task_analysis and 76 of 76 for views; this run prints 33 killed + 2 hung and 75 killed + 1 hung, and 0 survivors in both.
Killed (by a failing test or an invariant at compile time), of everything that ran: 783 of 844 (92.8 %), with 54 survived and 7 hung. Without dispatch.t27: 688 of 710 (96.9 %); the other 22 are 7 hung and 15 survivors, each a named equivalent or closed by an open PR.
gHashTag commentedon Oct 7, 2026
Reopened 2026-10-07: the bulk close of issues without a
## Boundarysection was reverted by the owner. Nothing to do here; this comment replaces the earlier close notice.spec(queen): a file owner actor admits disjoint edits (Closes #8037) (#…
spec(queen): reviewer concurrency follows the backlog, not a fixed 4 (C…
github-actions commentedon Oct 15, 2026
Re-filed as #9598.
An attempt claimed this issue on 2026-10-07 and left an empty branch. A dispatch row that has spent its retry ceiling is released once and then keeps its issue for good, which is the right rule for a third identical failure and the wrong outcome for an issue nobody ever attempted twice. The new issue carries the same work, the same boundary, and today's brief.
Closing this one so the swarm can take the work again.