# Updating a local action gateway without breaking agent work

An action gateway update is a control-plane change, not routine desktop housekeeping. If an agent is midway through a repository edit, an HTTP write, or an SSH operation, the update can split one piece of work into two uncertain halves. The safe approach is to choose a work boundary, drain or stop active actions deliberately, and prove the new version can authorize, act, and account for work before you let automation continue.

The usual mistake is treating every active agent as disposable. Some are disposable. Others hold a carefully built plan, an open remote shell, or a request whose result the caller has not received. You need to know which kind you have before you touch the application.

## Schedule updates around a work boundary

A good maintenance window begins when the agent has reached a state a human can understand and resume. The boundary does not need to mean that every task is complete. It means the next person, process, or agent can tell what happened, what remains, and what must not be repeated.

Ask the agent to stop taking new external actions first. Then have it write a short handoff in the repository, ticket, or operator notes. The handoff should name the current branch and commit, files changed but not committed, tests already run, remote systems contacted, and the next intended action. This is more useful than a transcript that forces someone to reconstruct intent from hundreds of tool calls.

A sensible update window has four phases:

1. Announce a freeze on new agent runs and new credentialed calls.
2. Drain bounded work, or stop it at a recorded boundary.
3. Update and perform a small set of checks with a new agent process.
4. Release the freeze only after you reconcile the activity during the window.

Do not wait for a calendar slot if the gateway has a security defect that affects credentials or authorization. In that case, stop or revoke exposed work first, record the interruption, and update under incident discipline. But do not invent urgency because a new version exists. Frequent casual updates teach teams to skip the checks that catch bad assumptions.

For routine maintenance, prefer a point after the agent has committed its code and before it starts deployment, data migration, account changes, or remote cleanup. A local code edit can usually resume. A half-finished permission change often cannot.

You also need an owner for the window. That person decides when to freeze work, judges ambiguous outcomes, and declares the gateway ready. A chat channel full of people who assume someone else watched the update is not an operating model.

## Treat process authorization and action completion as separate facts

An approved agent process and a completed external action answer different questions. People blur them because both show up near the same time, but the distinction controls how you recover from interruption.

Process authorization asks: "May this specific running program ask the gateway to act?" Action completion asks: "Did the remote system accept and finish this particular request?" Restarting an application can change the first answer. A network failure can hide the second answer. Neither answer implies the other.

For HTTP calls, write down whether an operation is safe to retry. A read request usually is. Creating a user, sending a payment, publishing a release, or rotating a credential may not be. If the agent times out after submitting such a request, it must query the target system for the resulting object or event before retrying. Retrying because the tool call has no visible result is how duplicate work appears.

SSH has its own failure modes. A terminal may carry a foreground command, a background job, an editor buffer, a database transaction, or a deployment tool that keeps running after the client disconnects. Before maintenance, ask the agent to report the remote host, working directory, current command, and any job identifiers. If it started a long operation, decide whether to wait for it, terminate it through an explicit remote command, or hand it to a supervised process that survives the shell.

Do not use a gateway restart as a vague way to "clear things out." That creates uncertainty while giving you no record of the intended stop. Revoke or end the specific agent run when you mean to stop it, and make the agent state what it last observed.

A practical handoff note can be as plain as this:

```text
Agent run: release-fix
Repository state: commit 4f2c... created, working tree clean
Remote work: SSH command started on build host, job ID 8127
HTTP writes: staging deployment request accepted, status still pending
Safe next action: query deployment status; do not submit another deployment
```

That artifact gives the operator a way to check the world after the update. Without it, the team often restarts the agent and mistakes a fresh explanation for continuity.

## Freeze new work before draining old work

A maintenance freeze works only when it closes the entry point for new work. Telling developers not to start another agent is polite but unreliable, especially when editor integrations, terminals, and scheduled scripts can launch processes independently.

Record every active agent process before the freeze. Capture enough detail to distinguish them: who started it, what repository or task it owns, its intended external access, and whether it has live work. If the gateway exposes a session view, use it as the primary record. Supplement it with the human task owner, because a process record cannot tell you whether an unfinished change is still wanted.

Then separate active work into three groups:

- Work that has no external side effect can stop immediately.
- Short, observable actions can finish under supervision.
- Long-running or irreversible operations need an explicit decision from the task owner.

Do not drain forever. Set a deadline that fits the operation. A request that should finish in seconds but has run for far longer has already become an investigation, not a reason to delay maintenance indefinitely. Capture its identifiers and determine its state at the remote service.

An agent that continues to produce local edits during the freeze can still create confusion, even if it cannot call external tools. Ask it to stop cleanly once it has written its handoff. If you need it to retain context, preserve the task notes and repository state rather than relying on an uninterrupted process lifetime.

Sallyport records agent runs in its Sessions journal and individual calls in its Activity journal. Use those records to identify the work you intentionally allowed to finish, rather than inferring it later from a terminal scrollback.

## Handle ambiguous network outcomes like an incident

A request that loses its response during an update has an unknown outcome until the remote system tells you otherwise. Calling it failed because the local client saw an error is a costly shortcut.

Suppose an agent sends an API request to create a deployment and the local gateway closes or restarts before the response arrives. Four outcomes remain possible: the request never left the machine, the service rejected it, the service accepted it but has not finished, or the service completed it. The local error message does not reliably distinguish those outcomes.

Resolve the ambiguity in this order:

1. Find the request identifier, deployment name, commit reference, or other correlation value that the agent used.
2. Query the remote service for that value using a fresh, supervised action.
3. Compare the remote result with the intended change and the audit record.
4. Retry only when the remote system shows that no equivalent operation occurred.

This is why idempotency matters. When an API supports an idempotency token or client-supplied request identifier, have the agent use one for write operations. The same token turns an uncertain retry into a queryable operation. If an API does not support it, use an object name or change reference that lets a human determine whether the first attempt took effect.

The HTTP Semantics specification, RFC 9110, defines idempotent methods in terms of the intended effect of repeated requests, not whether the server returns the same response each time. That is useful, but it does not make every `PUT` or `DELETE` harmless in your environment. A repeated request can still trigger notifications, race with another writer, or delete a resource that a different actor recreated. Treat the RFC classification as a starting point, then account for the target service's behavior.

For SSH, gather evidence from the remote host. Check process tables, service logs, deployment status, transaction state, and files created by the command. Do not ask the agent to rerun a shell command simply because its local session disappeared. Shell commands rarely carry the replay protections that mature APIs provide.

## Verify the release before you put it in the action path

A signed application package tells you who signed the code and whether the package changed after signing. It does not tell you whether the release preserves your vault format, session behavior, helper compatibility, or operator workflow.

Apple Platform Security explains that code signing lets macOS identify signed code and detect modification. That is a necessary property for an application that handles credentials. It is not a substitute for release notes, a test run, or a recovery plan. Teams often grant signing too much magic because the cryptographic check is clear and visible while operational compatibility is not.

Before the window, read the release notes for changes to these areas:

- vault storage or migration behavior
- authorization and session handling
- bundled command helpers and agent connection details
- audit storage, export, or verification
- macOS version requirements and permissions

Keep a record of the running version and the target version in the maintenance note. Also decide what would cause you to stop: failure to unlock the vault, failure to establish a new approved agent session, unexpected action denial, or audit verification failure are all valid stop conditions.

A rollback plan needs more than an old copy of an app. It needs a rule for when to use it and a plan for the state the new version may have changed. If a release migrates local data, rolling back without vendor instructions can turn a recoverable issue into data loss. Test the exact upgrade path on a spare Mac or noncritical setup when the release changes storage or authorization. A clean install tells you almost nothing about the state you actually operate.

Avoid testing with the credential that can cause the largest blast radius. Start with an account scoped to a harmless read or a disposable endpoint. You are checking the path through the app, authorization, credential injection, and result handling. You do not need a production deployment to prove that a menu-bar application launched.

## Run post-update checks with a fresh agent process

A post-update test should prove the paths that active agents will use, not merely prove that the interface opens. Use a newly started agent process so you test the authorization boundary you expect after maintenance.

Check the vault gate first. Lock and unlock it through the normal local flow. While it is locked, attempt the safe test action and confirm that the gateway denies it. Then unlock it and confirm that a new process receives the expected authorization prompt or approval path. This catches a bad assumption that an old approval survived, or that the new version accidentally cannot identify the calling process.

Next, run one safe HTTP request and one safe SSH request if your team uses both channels. A useful HTTP test asks for a read-only endpoint that returns a recognizable result. A useful SSH test runs a harmless command against a noncritical host, such as printing the current directory or a fixed marker. Record the time, destination, and result so you can find those calls in the activity history.

Sallyport keeps credentials in its encrypted vault and performs HTTP and SSH actions itself, so the agent receives the result rather than the secret. That design reduces what the update test needs to expose, but it does not remove the need to test each channel you depend on.

Finally, test the audit trail. Run the documented offline verification command:

```sh
sp audit verify
```

The expected output shape should report a successful verification of the audit chain. Do not rely on a remembered sentence or scrape it in a brittle script unless the command documentation promises a stable machine-readable format. The useful result is simple: the command exits successfully, reports verification success, and you can locate the deliberate test calls in the journals.

If verification fails, stop. Do not wave it through because the app can still make a request. An audit chain that cannot verify after maintenance removes evidence exactly when you need to understand the change.

## Reconcile every action that crossed the maintenance window

The update ends only after you account for actions that started before the freeze, continued during it, or appeared after the new version started. This reconciliation is where careful operators find the retry that duplicated an API call or the SSH job that kept running unseen.

Make a short table in the maintenance record. For each active agent at the start, note the intended last action, the observed result, the source that confirmed it, and whether a human allowed any retry. The source might be an activity record, a remote service status page, a host log, or a repository commit. If two sources disagree, treat the remote system as the authority on external state and investigate the difference.

Pay special attention to actions that return slowly. A gateway may log that it sent a request while the target system remains pending. That is not a contradiction. It tells you where the action reached, not whether a remote asynchronous job has finished. Keep monitoring through the target's normal status mechanism until it reaches a terminal state or the task owner takes over.

Session records help you answer who had authorization during the window. Activity records help you answer what calls occurred. Do not substitute one for the other. An approved process may make no calls; a completed call may have begun before the maintenance record was opened.

This reconciliation should also expose unexpected callers. A new process that appeared during the freeze means your freeze was incomplete, even if its request caused no harm. Find the launch path before the next window. It may be a developer terminal, an editor extension, or an unattended local script that nobody considered part of the agent workflow.

## Keep approval boundaries after the update

Updates are a tempting moment to weaken controls because operators want tests to pass quickly. Avoid turning broad approval into the permanent answer to a noisy workflow.

Per-session authorization fits normal agent work when one known process needs several related calls. It lets the operator identify and approve that run, then review its activity as a unit. Per-call confirmation fits credentials where every use deserves an intentional human decision, such as actions that alter production access, delete data, or initiate an irreversible external event.

The mistake is configuring the stricter setting as punishment after a bad incident, then leaving it on for routine low-risk reads until people approve prompts without looking. Repeated approvals train people to click past the very screen that should make them pause. Put per-call confirmation on the credentials where the cost of one wrong action is high. Keep the rest under session-level review and narrow credential scope where possible.

The vault lock should remain an absolute stop. During planned maintenance, lock it when you need a hard boundary that denies all actions. When you unlock it for verification, do so with the deliberate test process already chosen. This turns a broad maintenance event into a small number of observed actions.

Do not confuse an action gateway with a general policy engine. A gateway can keep credentials away from an agent and put a human at authorization boundaries. It cannot infer the business meaning of every API call, repair a bad deployment plan, or know that a harmless-looking endpoint triggers a costly downstream workflow. The task owner still owns those decisions.

## Write the runbook for the interruption you will actually have

A useful runbook does not say "update gateway and test." It names the evidence you capture, the decisions you make under uncertainty, and the exact point where autonomous work may resume.

Keep the runbook short enough that someone uses it under pressure. Mine has a freeze owner, a list of active runs, an explicit rule for live SSH and ambiguous HTTP writes, the target version, a rollback decision, fresh-process tests, audit verification, and reconciliation. It also has a place to record the one uncomfortable question that always arrives: "Did that action finish before we interrupted it?"

If you cannot answer that question from the agent handoff, the activity record, and the target system, do not restart the agent with permission to repeat the action. Pause the task and resolve the external state first. That discipline is slower for a few minutes and much faster than untangling two deployments, two access changes, or a remote command that both the agent and operator believed had stopped.

The first improvement to make is simple: require every agent that can reach external systems to leave a resumable handoff before maintenance. Once that becomes routine, release timing, authorization, update testing, and recovery stop depending on somebody's memory of a terminal window.
