Repository navigation
Queen actors loop: weak points of actors.t27 and the plan to close them #9598
Description
Re-filed from #6971. An attempt claimed that issue on 2026-10-07 and left an empty branch, and a dispatch row that has spent its retry ceiling keeps its issue for good - so no bee could take it again, however much the brief improved. The work below is carried over unchanged.
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
The instruments
Every one of these reads and prints; none of them writes. Run them from the repository root, with <spec> replaced by the file in ## Boundary:
.t27 is not Rust and not Zig, and a bee fluent in either writes one by
accident. Measured 2026-09-20: a bee filled eight bodies in
specs/file/watcher.t27 with return Ok(());, Err(FileError::WatcherNotFound)
and for i in 0..watchers.length. The parse ratchet refused the whole file --
Unexpected token in expression: RParen, line 123 -- and a spec that does not
parse generates nothing, so every test it already carried stopped running.
At the top level the parser accepts exactly these eight forms, with an optional
pub, and no others:
const var fn enum struct test invariant bench
There is no trait, no impl, no type X = ..., no generics, no macro. What
a bee reaches for from another language, and what happens:
- Rust's result sugar (
Ok(()),Err(E::V),?) is not a construct here. - Rust macros (
println!,format!,vec!) are not constructs here. - A range loop (
for i in 0..n) is Rust and Zig, not this language. - Zig builtins (
catch unreachable,@intCast,@constCast) are not constructs here. - Cross-module reuse (
use other::fn;) parses and then generates a comment and an unqualified call, so the Zig fails withuse of undeclared identifier(use a::b; generates no import, so no spec can reuse a function from another spec #4298). It does not work yet.
t27c parse <spec> answers in one line whether what you wrote is the language.
Run it before you report, every time.
t27c spec-status <spec>- the compiler's one-word verdict: IMPLEMENTED, PARTIAL, UNWRITTEN, NOPARSE, NOFN. Exit code is 0 whatever it says, so read the word.t27c symbols <spec>- every name the file declares, with its kind. Answers "does this already exist here?" before you add it.t27c outline <spec>- per function: its locals, what it calls, what it returns. The contract you are implementing against.t27c coverage <spec>- which functions have a test and which do not. The issue asks for tests; this is how you check you wrote them.t27c lint <spec>- style and shape warnings. It OVER-REPORTShas no test or invariant: measured 2026-09-20 over 60 specs it printed 677 of those wherecoveragefound 190 untested functions, disagreeing on 59 of the 60 - it warns aboutbit_to_trit_pairinspecs/base/ternary_encoding.t27, whichtest bit_to_trit_pair_zerocalls on line 249. Read it as a hint;coverageis the answer.t27c typecheck <spec>- types, before generation. PrintsTypecheck OK (0 errors, 0 warnings)or the errors.t27c test-report <spec>- builds this spec and runs its own tests, which is what the oracle does.BLOCKEDmeans the generated Zig does not compile, with the error beside it.python3 tools/dupe_scan.py --name <function>- where that function already lives, if it does. 576 of 4021 bodies here are byte-identical copies.
The rest of the toolbelt is in docs/BEE_TOOLBELT.md.
Activity