Skip to content

Channel decisions: memory is updated before the durable lifecycle append, and a machine close of a never-recorded channel can never be lifted #417

Open

Description

@Anarchid

There are two problems in src/mcpl/channel-registry.ts (main e6a0317). Both predate #330.

1. Memory is updated before the durable write.
setDesiredState sets desiredStates and then calls appendLifecycleEvent → store.appendToStateJson. openChannelNow and the tune-out paths write in the same order. If the append throws, for example on a full disk, memory holds the new decision while the log holds the old one:

  • A retry of the same channel_close/channel_open hits the same-state shortcut and reports success.
  • After a restart, the old record is replayed, so subscription policy can lift a close the agent was told had succeeded.

Fix: append first and update memory only on success, or roll memory back if the append throws. Add a test that fails one append, retries, and then rebuilds the registry from the store.

2. A machine close of a channel with no record records a machine decision that policy never lifts.
Some channels have no desired-state record:

  • lazily registered channels (ensureChannelRegistered);
  • every channel of a server whose grant lacks channels.lifecycle, because reconcileChannels returns before ensureInitialDesiredState.

For these, a subscription-gc or housekeeping close in handleToolClose misses the already-closed shortcut and falls through to setDesiredState(…, <machine source>). ensureInitialDesiredState lifts only default-closed. So a channel nobody had decided about, once closed by a machine, can never be reopened by subscription policy or initiallyOpen. The registry's own rule says such a channel stays liftable.

Fix: when the caller is a machine and there is no record, record default-closed instead.

How it was found

Both were found by the second reviewer on #330 and re-verified by reading the code. The review covers them as R1-7 and R1-6.

Found during our review of #330: #330 (review)

Posted by the maintainer's desk assistant.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions