Skip to content

Queen actors loop: weak points of actors.t27 and the plan to close them #9598

Open

Description

@github-actions

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)

  1. A cancel can be dropped by a full mailbox. Section 6 says a cancel is taken ahead of queued offers by selective receive, but deliver drops 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.
  2. 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.
  3. 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.
  4. affected had no direct test, and the section 7 departures (bounded mailbox, no hot swap, ...) were asserted nowhere.
  5. Mutation runs are a throwaway script. tri mutate run perturbs numeric literals only; guard and operator mutants of a .t27 spec need a hand-written pairs list each time.

Plan

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).

Refs #6963, #6657

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 affected coverage, 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

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 with use 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-REPORTS has no test or invariant: measured 2026-09-20 over 60 specs it printed 677 of those where coverage found 190 untested functions, disagreeing on 59 of the 60 - it warns about bit_to_trit_pair in specs/base/ternary_encoding.t27, which test bit_to_trit_pair_zero calls on line 249. Read it as a hint; coverage is the answer.
  • t27c typecheck <spec> - types, before generation. Prints Typecheck 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. BLOCKED means 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions