Skip to content

Wake a seat again after a lease that came to nothing, and prove a handover under load - #56

Merged
andreisavu merged 3 commits into
mainfrom
claude/two-hosts
Sep 10, 2026
Merged

Wake a seat again after a lease that came to nothing, and prove a handover under load#56
andreisavu merged 3 commits into
mainfrom
claude/two-hosts

Conversation

@andreisavu

Copy link
Copy Markdown
Contributor

Branches from main after #54. Three commits: the wake retry, the handover harness with the rule it forced, and the fixes from an independent review pass. It takes the core of PR 7 in SPLIT_PLAN.md on #48, from the log's own order rather than a heard field on the wire.

The one idea

A message is answered by a lease that heard it, and a lease that came to nothing answers nothing.

  • A failed or expired activation is retried. A wake was answered by any lease of its id, so a seat whose model threw, or whose lease the dead run held, was never woken again. The chaos sweep pinned the loss. Now a lease that expired or failed counts as one attempt, the wake is pending again after the backoff under the next attempt's id, and at the cap the room stops. runtime.retry holds the policy for wakes and summaries alike. Backlog item 34 closes.
  • The log says who heard a message. A steer is the room's word to a running activation, and the log did not record it: a run that died while a seat worked lost the steer, and so did a failure in a pass the activation rebuilt after the record moved. The fold now reads who was at work when a message landed: a lease that holds a row before it and ends, if it ends, after it. A lease heard a message when it was at work as the message landed, or when it was claimed after it. The message is answered while such a lease runs and once it stood down. A lease that expired or failed answers nothing it heard, whatever it said: its words stay on the record, and the seat reads them at the next attempt. Backlog item 31 closes.
  • A lease that stood down answers through the seq its last renewal confirmed. An activation renews, sees the record has not moved, and releases; a question that lands while the release is on the wire reaches no activation. The released lease answers through its renewal, and the question is pending for the seat as a first attempt.
  • The assistant composing hears no steer, so a message reaches it by name alone.

What the harness proves, and what it found

test/hosts.test.ts, run by pnpm test at every third write and by pnpm chaos at every write:

  • A handover under load. A cast under trouble runs the crash sweep: the product's model is down the first time it takes a person's question, the colleague's answers are questions to the product, and the room crashes at every write. The second host wakes the failed seat again after the backoff, and a peer's say the product heard as a steer before the crash is answered on the next run. Every answer lands once.
  • The split the design forbids. Host B resumes a name while host A is alive. Both assign the same seqs, and a later reader folds a record with a seq twice. The test pins that fact and turns when a fence lands. No fence is built here.

The harness found the steer loss twice before the rule above closed it: once as a crash mid-activation after a say, once as a failure at the start of a rebuilt pass. The heard field the split plan gives PR 7 would not have caught either, because it counted "spoke" per lease.

What the review pass changed

An independent adversarial pass over the branch found one blocker, reproduced and fixed with two regression tests: a message that landed between the last renewal and the release was marked answered by the released lease that never heard it. Also taken: the composing assistant excluded from steers in the fold; the split test pins the divergence positively; the world bounds a run's errors by that run's failures alone.

Behaviour that changes, stated in the docs

  • A room whose only activation failed is working until the backoff passes; settled() waits for the retry. agent.md §5. The session test and the live refused-call test abort the room before they wait.
  • A seat woken again after its lease expired reads its own words on the record and stands down. agent.md §5.
  • agent.md rule 2 and §5, toolchain.md §8, backlog items 29, 31 and 34.

The tests that pin it

  • test/reconcile.test.ts: a wake pending again after a lease that came to nothing, the cap, the window between the last renewal and the release, the composing assistant.
  • test/lease.test.ts: the seat woken again after its release was lost and after its renewals were lost, and a question answered from the release window, through a hold fault on the transport.
  • test/restart.test.ts: the seat woken again on the next run.
  • test/hosts.test.ts, test/support/cast.ts (Cast, steady, troubled), test/support/scripted.ts (unanswered, answersEveryQuestion), test/support/chaos.ts (the world takes a cast).

Checks

pnpm format && pnpm check is green, 338 tests. pnpm chaos is green, 489 tests. The build's three TS4023 lines from test/live/support.ts are on main too.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SJjjR3S6iwqEbDXsRDJgiq


Generated by Claude Code

… the summaries use

A wake was answered by any lease of its id, so a seat whose activation
failed or expired without a word was never woken again. The chaos sweep
pinned the loss: a seat whose lease the dead run held answered nothing.

A lease answers the wake it took while it runs, once it ended released,
refused or revoked, and once the activation spoke. A lease that expired
or failed without a word counts as one attempt. The wake is pending again
after the backoff, under the next attempt's id, and at the cap the room
stops. runtime.retry holds the policy for wakes and summaries alike.

The chaos outcome holds every answer to exactly once again. The lease,
reconcile and restart tests pin the seat woken again, on the same run and
on the next. A room whose only activation failed is working until the
backoff passes, so the tests that waited for it to settle abort it first.

Backlog item 34 closes; item 29 covers the cap for wakes too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJjjR3S6iwqEbDXsRDJgiq
…er load

A steer is the room's word to a running activation, and the log did not
say who heard it. A run that died while a seat worked lost the steer:
the message stayed on the record and nobody woke the seat for it. The
same loss followed a failure in a pass the activation rebuilt after the
record moved, because a lease that spoke counted as having answered
everything it heard.

The log says who was at work when a message landed: a lease that holds
a row before it and ends, if it ends, after it. A lease heard a message
when it was at work as the message landed, or when it was claimed after
the message. The message is answered while such a lease runs and once it
stood down. A lease that expired or failed answers nothing it heard,
whatever it said: its words stay on the record, the seat reads them at
the next attempt, and the failure counts as one attempt.

hosts.test.ts runs a cast under trouble through the crash sweep: the
product's model is down the first time it takes a question, the
colleague's answers are questions to the product, and the second host
wakes the failed seat again and the peer answers on the next run. The
same file pins the split the design forbids, two live hosts over one
log, as a test that fails until a fence exists: both hosts assign the
same seqs.

Backlog item 31 closes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJjjR3S6iwqEbDXsRDJgiq
…as it stands

An independent review found that a message that landed between an
activation's last renewal and its release counted as answered by the
released lease. The activation had renewed, seen the record had not
moved, and dropped the steer that came after. The release row landed
after the message, so the fold read the lease as at work for it.

A lease that stood down now answers through the seq its last renewal
confirmed, and a message past that is pending for the seat as a first
attempt. The assistant composing hears no steer, so a message reaches
it by name alone. The reconcile and lease tests pin both, with a hold
fault on the transport that lands a question while the release is on
the wire.

The split test pins what the storage ends up with, both hosts writing
the same seqs, and turns when a fence lands. The world bounds a run's
errors by the failures of that run alone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJjjR3S6iwqEbDXsRDJgiq
@andreisavu
andreisavu merged commit d031840 into main Sep 10, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants