INSTANCE-AXES grill — Round 1
Retrieved from doyle session 0fe9417f, messages at 04:15Z, 05:17Z and 05:19Z on 2026-09-25. Your answers save in this browser as you type. "Copy answers" puts them on the clipboard as Markdown to paste back.
What you've settled so far
- Two separate state machines. The controlled axis tracks whether a controller is attached; only attach and detach change it, and viewers never count. The instance axis is active / dormant / suspended / offline.
- Active ordering: a per-id activation counter carried in the registry. Activating takes the highest counter seen plus one; ties break on node id.
- What makes an instance active: an adapter-reported user-input event (never
rckeystrokes); any incoming message, except a normal message from the active sibling; a--handoffmessage; waking or coming up, under the boot rule. - What makes an instance dormant: a sibling becoming active. Nothing else.
- Auto-suspend: three modes,
disable,dormant-enable,enable. Condition: uncontrolled AND agent idle (plus dormant indormant-enable), all held without interruption for the timeout; the timer resets when any part breaks. - Resolver order: node-qualified → the unique active instance → local → sole → refuse. Offline excluded; suspended ranks below dormant.
- Messaging handoff: a dormant instance may message only its active sibling. Active → dormant sibling: a normal message causes no transition (a suspended sibling wakes into dormant);
--handoffswaps the two. A deliberate message from any other endpoint to a non-active instance makes it active. - Wake on attach stays: attaching to a suspended endpoint has to wake it. Which state it lands in is Q1.
- Milestone: a new one.
Code facts from the lookup (05:19Z)
- Q7 dropped: registry
Instancealready carriescontrolled: bool, replicated (registry.rs:215), pluscontroller_node. - No dedicated user-input event.
api state busywith aUSER_INPUTpayload already reaches the daemon (broker.rs:6398).api presenceonly writes a local file the daemon never reads. doyle's lean: the busy report carryingUSER_INPUTbecomes the trigger (Round 2 question). - Activation counter confirmed missing; every existing epoch is per-node and not comparable across nodes. New replicated field.
- Where
Wakefires today: controller attach, a shell waking its owner, a remote wake,spt endpoint wake,spt go, the picker's remote wake.
Round 1 questions
Q1Which state does a wake land in, by cause?
You said attaching alone never makes an instance active, but waking from suspended does. That conflicts when the wake is caused by an attach. Each cause needs its own landing state:
- (a) a controller attaches to a suspended instance;
- (b) an explicit
spt wakefrom the user; - (c) a normal message from the active sibling (you ruled: dormant);
- (d) a message from any other endpoint (you ruled: active, it steals);
- (e) an owned shell's wake-watcher reviving its suspended owner.
Recommended: (a) dormant — attach is a controlled-axis event, and the first user input then makes it active. (b) active — the user asked for it. (e) dormant — device contact is not agent activity; the device's own
user-msg, if one follows, makes it active.Q2Which inbound traffic counts as "a message" that steals active?
msganduser-msgfrom another endpoint;- spt-core system frames (away/return notices, update notices, notifs);
- shell-channel traffic from shells it owns (stdout, sensory);
- pacer and alchemy shell replies;
- psyche and commune echoes;
- its own self-sends (the recharge wake).
Recommended: only
msg and user-msg sent by another endpoint steal active. System frames, owned-shell traffic, psyche and self-sends never do — otherwise a pacer nudge or an update notice would move active onto a seat nobody is using.Q3What does "agent idle" read for auto-suspend?
Recommended: the activity sentinel (
busy|idle, adapter-reported) — the same axis W10 made the only input to the delivery window. One activity signal, used in two places.Q4Boot rule wording
You said it comes up active only if a trigger fires "shortly after bringup", or it has no siblings and its previous state was active.
- (a) Is there a real time window, or does "shortly" collapse to "come up dormant, and any trigger makes it active whenever it fires"?
- (b) Should "no siblings" be "no active sibling"? As written, a node that was active before a reboot, with a dormant sibling elsewhere, comes back dormant — then no instance of the id is active at all.
Recommended: (a) No window. Come up dormant; any trigger at any later time makes it active. (b) "No active sibling", so the id is never left with no active instance just because a dormant one exists.
Q5What does a dormant instance get refused, and how?
- Does the rule also cover its own shells,
user-msgfrom a Gateway it hosts, notif acks, psyche/commune, and replies? - What does the refusal say?
Recommended: covers only peer
msg to endpoints other than its own active sibling. Own shells, psyche and spt-core API calls untouched. Refusal is loud and names the way out: SEND_REFUSED_DORMANT: <id@node> is dormant; message your active sibling <id@node2>, or send --handoff through it. A dormant instance can still take active through its own user input.Q6Handoff edge cases
- (a) Can only the active instance send
--handoff? - (b) A handoff to a suspended sibling: it wakes and becomes active, while the sender goes dormant?
- (c) A handoff to a sibling that turns out to be offline: refuse, or queue?
- (d) Does a handoff also carry a message body?
Recommended: (a) Yes, only active. (b) Yes. (c) Refuse, sender stays active, so active never lands on a seat that can't take it. (d) Yes, a normal body; the swap is a flag on the send, not a separate verb.
Q7Is controlled replicated? — DROPPED
Already answered by the code: Instance.controlled exists and replicates (registry.rs:215). No answer needed.
Q8Auto-suspend configuration
- Keep the existing knob chain (node default, then endpoint override)?
- Change the value from milliseconds-or-off to
{mode, after_ms}? - Keep the default as
disable? - Migrate old values:
ms > 0→dormant-enable, 0 or absent →disable?
Recommended: yes to all four. Keep the chain, keep
disable default, migrate old values to dormant-enable (closest to today's behaviour).Q9How are the requests cut in the new milestone?
- #345: the resolver order.
- New A: the axis split, the activation counter, the boot rule and the auto-suspend modes.
- New B: handoff messaging and the dormant send restriction.
B depends on A, and #345's active-preference rung only means anything once A exists.
Recommended: three requests, build order A → #345 → B, B allowed to slip without blocking the release. Milestone name: INSTANCE-AXES.