Skip to content
Back to Blog

Upgrading an Agent That Is Still Running

Published Updated Editorial policy & corrections

Share:XBSMRedditHNEmail

At 09:00 UTC, a photo-archive cleanup agent proposes moving twelve old image exports to the trash. Its read-only selection tool receives this rule:

{
  "collection_id": "collection_exports",
  "older_than_days": 30,
  "as_of": "2026-10-30T09:00:00Z"
}

Under the admitted v1 contract, “older” means time since the file was last modified. The selector returns twelve files. The agent prepares an immutable manifest containing their exact IDs and object versions. The user sees those twelve thumbnails and the proposed action: “Move these twelve files to trash.” The approval request binds the manifest, complete action, capability revision, policy, and release references. It expires at 09:15. The run enters waiting_approval.

The selection rule is not dispatch authority. The eventual mutation must address the exact approved files and versions. If the provider can only execute a fresh age-based query and cannot enforce that target set, the gateway cannot safely use it for this approval.

At 09:05, a new worker and selector are deployed. In v2, “older” means time since the file was originally uploaded. The property remains an integer, and every required field still validates. Four files uploaded sixty days ago were edited three days ago. V1 excluded them; v2 includes them. Re-evaluating the unchanged rule now selects sixteen files.

At 09:10, the user approves the original twelve-file proposal. That click authorizes the stored manifest under its bound interpretation. It does not authorize the latest selector’s results. A conversation transcript containing “approved” cannot enlarge the target set, and a model’s opinion that all sixteen files look disposable cannot establish permission.

The resumed worker verifies the checkpoint, current ownership, and saved artifacts. It compares the v2 candidate with the original manifest, detects four extra targets, and blocks dispatch. The approval receipt and original proposal remain intact. No files move and no provider mutation begins. Repeating the selection successfully is not successful continuation of the approved action.

Two useful paths remain. An admitted old execution path can finish against the frozen twelve-file manifest if current authority, object versions, approval, controls, and deadline remain valid. Alternatively, an explicitly reviewed migration can use a supported v2 mutation that addresses those twelve files directly. If that path changes capability, arguments, or bound release references, it creates a new action binding and needs fresh approval wherever approval is required. Preserving the visible selection does not transfer a receipt to different bound bytes.

The migration retains the predecessor operation, accounting, and recovery information. A changed action uses a newly governed, linked replacement rather than overwriting its digest. If an earlier batch attempt might already have moved some files, reconcile it first. Never infer non-dispatch from a missing success message.

Three conditions require fresh approval:

  1. The effect changes: selected file IDs, object versions, destination, action, or another material term differs. Moving sixteen files is not the approved twelve-file cleanup; permanent deletion is not moving them to trash.
  2. The exact binding changes: capability, arguments, evidence, policy, profile, authority, or release references differ, even if the selected files look unchanged.
  3. The approval is no longer valid: its interval expired, it was revoked or consumed in a way that disallows a new effect, or current entitlement or quorum requirements are unsatisfied. Fresh approval cannot override revoked execution authority or a prohibited action.

A deployment needs a continuation contract

Long-running agents cross release boundaries while waiting for a person, a timer, a remote job, or an external event. The next worker inherits unfinished obligations. A successful process restart says little about whether those obligations retain their meaning.

The migration contract must answer three questions independently:

  • Interpretation: which historical semantics define the saved proposal and prior observations?
  • Permission: which checks must be satisfied against current authoritative state before the next protected action?
  • Continuation: which execution path can preserve the operation, or safely replace it with explicitly linked new work?

This article proposes an application-level procedure for answering them. Sources were checked on October 30, 2026; the documentation below is not presented as a release from this week. The photo-archive service, its v1/v2 selection change, and the migration records are fictional. No live files were changed, and no platform upgrade experiment or production migration was performed for this article.

The earlier managed-harness article, published September 15 and updated October 16, covers drift, rollback, and application responsibility broadly. Here the unit of analysis is one paused, unfinished operation. This is design guidance, not an addition to the normative ContextOS schema or a claim that any cited platform implements the complete procedure.

Compatibility has several layers

Two current primary sources make the distinction concrete.

The MCP C# SDK versioning documentation says SDK 2.0.0 implements protocol revision 2026-07-28 while retaining compatibility with older peers, including the legacy initialization handshake. It explicitly excludes the experimental Tasks implementation from v1.3.0 and v1.4.x: v2 Tasks has neither API nor wire compatibility with it and requires negotiation of 2026-07-28 or later. An older peer can therefore remain connectable while its unfinished task lifecycle cannot simply continue through the new Tasks interface.

That documentation establishes a compatibility exception. It does not supply a migration bridge for old task IDs, pending input requests, cancellation, or result retrieval. A team with outstanding experimental tasks must establish that bridge, drain them through a supported old path, or stop for intervention. Successful negotiation alone is insufficient evidence.

Temporal Worker Versioning describes a different boundary. Pinned workflows stay on one Worker Deployment Version unless explicitly moved. Auto-Upgrade workflows move with the current version and must be kept replay-safe by the application, for example through patching. Activities generally start on their workflow’s version, but Independent Activities use their own task queue’s Current or Ramping Version. Child inheritance also depends on versioning behavior and task-queue membership; it is not an unconditional property of the parent.

These are orchestration choices, not evidence that a particular cleanup action remains authorized. Temporal’s workflow determinism documentation concerns reproducing the required command sequence against history. It places external interactions, including LLM calls, in Activities. A workflow history can replay correctly while a newly executed tool interprets an unchanged integer differently. Business compatibility needs its own tests.

Compatibility claimEvidence it needsWhat it leaves unresolved
Source/API compatibilityConsumer builds and API contractsPersisted work and remote behavior
Wire compatibilityNegotiation and request/response fixturesMeaning of a selector, cancellation, or terminal status
State compatibilityVersioned decoding and invariant checksWhether the next effect matches the proposal
Replay compatibilityHistorical command replayCurrent authority and external preconditions
Semantic compatibilityDomain postconditions and failure behaviorWhether a stored approval covers new bindings
Authorization compatibilityExact binding plus current entitlement and policy checksWhether the provider already applied an earlier attempt

The useful question is: compatible for which artifact, transition, and effect?

Inventory the versions that actually matter

One deployment label is too coarse. Build a manifest of the artifacts used to interpret and execute the run, with immutable references where available.

ArtifactRecordMigration question
Worker implementationBuild/image digest, runtime and state decoderCan this worker read the checkpoint and preserve control flow?
Model and prompt configurationExposed model revision, prompt, tools, decoding settings, prior outputsDoes continuation reuse a decision or generate a new proposal?
Tool contractCapability revision, schema, semantic definition, defaults, errors, retry/cancellation contractDoes the same request still mean the same effect?
Persisted stateCheckpoint format, operation ledger, pending remote IDs and inputsAre all unfinished obligations represented after transformation?
GovernanceContract, policy and profile revisions, authority referencesDoes a required policy change force migration and reauthorization?
ApprovalExact action digest, stored request, validity interval, approvers and redemption stateDoes the receipt authorize this exact dispatch?
External recoveryProvider/account/API scope, request payload, deduplication key and mapping revision, retentionCan an uncertain attempt be reconciled or safely retried?
Accounting and ownershipShared ledger revisions, spent/reserved capacity, absolute deadline, executor generationCan takeover preserve limits and exclude stale dispatchers?

A schema digest detects changed schema bytes. It cannot detect an undocumented change in a remote service. Bind the admitted semantic contract as an artifact too, and require evidence that the selected endpoint implements it. A version string supplied by the server remains a claim until verified through the deployment’s admission process.

Model pins deserve similar precision. Record what the provider exposes; an alias may not identify immutable weights or an immutable hosted harness. Preserve original model outputs and proposal artifacts. Re-running a prompt with the same temperature is not a state migration, and it does not reproduce an approval-bound decision by definition.

The existing ContextOS orchestration contract already requires verified historical pins and current resume checks. The execution contract includes ExecutionCheckpoint, operation and budget ledgers, ownership, and pending work. The procedure below organizes those obligations around an explicit migration boundary; it does not imply these primitives are absent.

Preserve meaning; refresh permission

Historical interpretation and present permission have different lifetimes.

Keep the original proposal, its complete structured action, its user-facing presentation, and the artifacts needed to interpret both. In the example, the stored presentation identifies twelve files and the move-to-trash action. A replacement presentation showing sixteen files or permanent deletion changes the proposal even if the selection-rule JSON happens to match.

Before new protected reads as well as writes, obtain current verified observations for identity, revocation, delegation restrictions, approval validity, required active boundaries, data policy, external preconditions, and budget. A valid old checkpoint cannot resurrect a revoked principal. Reconciliation itself may read protected archive data and needs an authorized path.

Pinned policies preserve the original decision’s interpretation. They are not an exemption from a required policy update. If current admission requires different policy artifacts, stop ordinary resume and perform explicit migration and reauthorization. Never overwrite the old policy reference and treat the checkpoint as unchanged.

For a simplified dispatch predicate:

dispatch_allowed =
    verified_artifacts_and_interpretation
    AND current_exclusive_ownership
    AND exact_approval_requirements_satisfied
    AND current_authority_and_required_policy_satisfied
    AND current_boundary_data_and_external_preconditions_satisfied
    AND shared_budget_and_deadline_satisfied
    AND provider_recovery_contract_allows_this_attempt

Each term needs scoped, fresh evidence. Unknown is blocking. Checks performed at initial planning or migration time cannot stand in for checks required at dispatch.

ContextOS’s exact action binding includes complete arguments and capability, evidence, policy, profile, authority, and release references. Its digest uses canonical JSON with a versioned domain. Compare the complete binding, not just the displayed selection or tool name. An unchanged digest is useful only if the bound artifacts retain their verified meaning.

Two consequences follow. A new worker that still executes the intact admitted v1 action under the original bound release path may be able to use the original approval. Replacing a release reference inside that action changes the binding and cannot reuse the receipt. Likewise, a semantic adapter can justify constructing a new proposal, but cannot make the old approval authorize different bytes.

Approval, authority, and preconditions remain separate gates. A user can approve a cleanup after one of its files has been edited; the gateway must still reject the stale object version. Fresh approval cannot restore a file that another actor already removed.

Choose among three migration paths

The path is selected per unfinished operation and dependency, rather than once for the entire deployment.

PathEvidence requiredStop condition
Finish through the old pathVerified old artifacts and decoder; supported provider semantics; current permission and controls; sufficient lifetime and capacityOld endpoint retired, artifact unavailable, required control unsupported, or execution prohibited
Transform at an explicit boundaryVersioned deterministic transform; source-to-target invariant checks; replay/domain tests; complete obligation mapping; fresh approvals for changed bindingsMeaning cannot be preserved or approved; pending work cannot be mapped; uncertainty could be lost
Suspend for interventionDurable reason, frozen dispatch, preserved evidence and ledgers, named recovery ownerNo automatic dispatch until an authorized recovery plan satisfies the gates

Keeping old workers is useful only while their dependencies remain usable. A pinned image cannot pin a mutable remote API. A vulnerable or prohibited old execution path should not be revived merely because it would avoid reapproval.

For the archive example, changing the age threshold cannot generally repair the semantics. Files have different upload and modification histories; no single v2 threshold is guaranteed to reproduce the twelve-file v1 set. Preserve the exact manifest and use an admitted explicit-target mutation, or stop. If v2 can only mutate whatever its query selects, it is not a compatible execution path for the frozen proposal.

The transform should reject unsupported inputs explicitly. It should not ask a model to infer whether an extra file is “probably” disposable or silently change a selection basis. If the recorded v1 interpretation is incomplete, preserve that uncertainty and escalate.

A worked migration procedure

1. Establish a dispatch barrier and current ownership

Stop admitting new dispatches for the affected run or capability path. Claim the run against its current revision and executor generation in a protected store. An approval arriving during migration can be appended against its original request, but it cannot bypass the barrier or retarget itself to the new proposal.

Quiescence must cover children, queued work, callbacks, and the gateway. Killing the visible worker process is insufficient. Fence stale ownership where dispatch occurs and, when the workflow requires it, at the external target. A provider request already accepted before the barrier remains an outstanding obligation.

2. Read authoritative state and classify every operation

Verify checkpoint bytes and all pinned artifacts. Compare the checkpoint’s ledger references with current owned store state; do not restore an older budget or operation snapshot over newer progress.

Classify operations using the existing effect states:

  • not_dispatched: inspect the exact-attempt records before concluding that nothing was sent; an outcome label alone is insufficient.
  • confirmed: retain verified outcome evidence; do not dispatch the effect again.
  • not_applied: a new attempt still needs the declared recovery contract and current gates.
  • partial: retain confirmed sub-effects and reconcile the remainder.
  • unknown: retain the attempt and reconcile; migration does not turn it into absence.

Inspect durable exact-attempt start decisions and queued or outstanding sends under current generation fencing. A claimed attempt with no observation may still have a local not_dispatched outcome label. If the dispatch protocol cannot exclude an accepted request or later application, treat the effect as uncertain and reconcile it. Absence of an observation is not evidence of non-dispatch.

Inventory pending approvals, remote tasks, child obligations, reservations, and cancellation requests alongside these operations. Every item needs a target representation or an explicit unresolved disposition. Equal operation counts alone cannot prove that no obligation was dropped.

3. Construct the target state without external effects

Run a versioned transform against the immutable source plus verified current ledger state. Produce a candidate checkpoint and a separate migration record. The record should identify source and target artifacts, transform revision, each operation mapping, changed approval bindings, retained provider identifiers, and the checks supporting the decision.

This is an application record, not a new field inserted into the closed ExecutionCheckpoint or ActionBinding schemas. Bind it through an explicitly supported versioned attachment mechanism or the application’s protected migration store.

Required invariants include:

same logical operation => retain operation identity and provider-key mapping
confirmed effect      => retain outcome evidence; no new dispatch
unresolved effect     => retain uncertainty and reconciliation obligation
same shared budget    => retain current spent/reserved capacity and deadline
changed action binding => old approval cannot authorize the new action

For this case, a migrated v2 mutation addresses the frozen twelve-file manifest through an admitted explicit-target capability. If its bound capability, arguments, or release differs, it has a new proposal identity and action digest. The reference operation ledger binds an immutable action digest; an ordinary retry cannot replace it. Preserve the original operation record and use a newly governed replacement operation, linked through the application’s migration record to the same business request. This distinction applies even when the selected file IDs are preserved.

Authorize that replacement only after authoritative exact-attempt records, the queued/outstanding send inventory, and enforced fencing establish that the predecessor neither applied nor can still apply. Durably prohibit its later dispatch. In this case, that evidence establishes actual non-dispatch; the not_dispatched label alone would not. If the outcome is uncertain or partial, reconcile first; if it is already confirmed, retain that result and decide whether the business request is already satisfied. A changed operation ID is never permission to bypass this check. An unchanged operation migrated without changing its bound action retains its original identity and provider-key mapping.

For a partially applied batch, this is not permission to replace the whole batch. Retain confirmed per-file outcomes and their evidence. A newly governed remainder action may include only file versions proven untouched, after excluding any later application by the predecessor; its changed binding needs fresh approval as required. Keep unknown members blocked. If the provider reports only a partial count without identifying the affected files, reconcile membership before constructing a remainder. Do not retry the original partial operation or rotate its keys to evade the restriction.

4. Verify interpretation and pending lifecycle mappings

Test the transform without dispatching tools. Check the canonical postcondition: exactly the twelve approved file versions move to the approved trash destination, with no additional files affected, under the declared preconditions. Validate the resulting bindings and explain exactly why any new approval is required.

A saved remote task needs more than a new status enum. Verify how the target implementation will address the same task, deliver pending input responses, retrieve results, interpret failures, and cancel or reconcile it. When that evidence is unavailable, keep the old task unresolved and block automatic continuation. This is the operational question exposed by the MCP Tasks exception.

Lifecycle names can also conceal domain failures. The C# SDK’s v2 Tasks documentation says Completed includes tool results with IsError = true; task cancellation is cooperative and eventually consistent. Therefore retain and interpret the underlying result and provider outcome. A migrated terminal label or cancellation acknowledgment alone cannot establish a successful or absent file mutation.

5. Commit the cutover and its recovery decision

Use compare-and-swap against the source revision and current ownership to make exactly one target checkpoint authoritative. Publish the checkpoint pointer and migration outcome through an atomic transaction or a tested recovery protocol. Multiple independently successful writes do not establish a complete cutover.

The protocol must specify what a restart does if the record was written but the pointer was not, if the pointer changed before acknowledgment, or if an approval arrived concurrently. Recovery reads the authoritative revision and the stored migration receipt. It must not rerun the transformation as a new operation or reactivate both source and target.

Keep the dispatch barrier until the authoritative target state and its outstanding approval obligations are known. In the example, the run remains waiting for the new v2 approval. The original receipt remains evidence about the v1 proposal.

6. Revalidate immediately before the next attempt

Once fresh approval arrives, recheck current authority, exact binding, required controls, file versions, destination, budget, deadline, cancellation, and ownership. Bind external preconditions to the provider’s supported conditional mutation and object-version checks; otherwise a check-then-write race remains. If required atomic precondition enforcement is unavailable, block or use an explicitly supported alternative.

Persist the exact-attempt start decision through the protected dispatch protocol before invoking the provider. Approval redemption, operation claiming, and budget reservation must compose correctly across crashes and takeover. Separately passing each validator does not grant an independent right to send another request.

If the provider commits and the response is lost, retain unknown and reconcile under the saved recovery contract. The migration is complete only in the sense that continuation ownership changed; the business operation may still be unfinished.

Preserve the operation across uncertain outcomes

The most dangerous migration bug is assigning a fresh provider key to an old uncertain operation.

Suppose v1 submitted the cleanup batch, the archive service moved some files, and the response disappeared. V2 imports the conversation, finds no success message, and creates another batch with a new key. It may repeat already applied mutations or include changed targets. The new worker’s clean state has destroyed the relationship needed to deduplicate or reconcile them.

Preserve the original provider key, its mapping revision, provider account/API scope, exact payload, and deduplication window. The AWS Builders’ Library discussion of idempotent APIs explains why caller request identity and parameter validation matter: the same request identifier with different parameters can represent changed intent and should be rejected. Its examples also make retention and late-arriving requests explicit design concerns.

An equivalent business action may require different wire parameters after migration. That does not imply the provider accepts those parameters with the original key. If its idempotency contract compares the original payload, use a compatible recovery path or reconcile first. Never evade a mismatch by rotating the key and calling the result a retry.

A lookup returning “not found” is sufficient only when provider guarantees rule out the original attempt committing later. Eventual visibility, delayed processing, and an elapsed local timeout do not establish that fact. Without sufficient evidence, retain uncertainty and require an authorized reconciliation path.

Resource accounting follows its own evidence. Known terminal usage can settle a reservation according to the ledger contract even while an effect remains uncertain; unknown usage cannot be released merely because a migration or cancellation completed. A new run must not mint another allowance for unresolved work.

Test the upgrade at the waits and crash gaps

Treat the old checkpoint, proposal presentation, action binding, ledger state, provider contract, and target release as one frozen test fixture. Replay tests and domain tests answer different questions; run both where applicable.

Injected conditionRequired observation
Same rule shape, age basis changesSixteen-file candidate cannot execute under twelve-file approval
V2 supports explicit targetsFrozen twelve-file manifest is preserved; changed binding requires new approval
V2 supports only query-based mutationNo guessed threshold; unsupported exact-target enforcement blocks
Approval arrives during cutoverReceipt stays attached to original request; barrier holds
Approval expires or principal is revokedNo new protected action under stale approval or authority
Required policy/profile revision changesExplicit migration and reauthorization; no silent reference replacement
Crash before or after pointer cutoverOne authoritative continuation; migration receipt is recoverable
Worker crashes after a claimed attempt, before recording its send/outcomeOutcome label cannot authorize a replacement; inspect exact-attempt records and reconcile any possible send
Stale worker wakes after takeoverIts generation cannot start a new attempt
Provider commits before response lossSame operation and saved key survive; no blind second effect
Batch partially appliesConfirmed files stay settled; only a definitively untouched remainder may enter a newly governed action; unknown members block
Task protocol or result semantics cannot be mappedPending work remains unresolved; automatic continuation blocks
Shared budget consumed while pausedCurrent spending and reservations survive; old checkpoint cannot replenish capacity
Provider precondition changes after local checkConditional mutation rejects or required unsupported control blocks

Add a positive case: a verified old path, intact exact approval, current authority, valid preconditions, and sufficient budget should complete useful work. A migration gate that blocks every run has demonstrated denial, not correct continuation.

Measure unauthorized and duplicate effects, lost obligations, unresolved-outcome age, time to safe continuation, operator effort, and total migration cost. Define acceptance thresholds for the actual workflow before testing. A low average failure rate cannot excuse a fixture that dispatches an unapproved sixteen-file cleanup.

For ContextOS adoption, production claims require the exact workflow, implementation, release, environment, and selected profiles to have current useful, denial, and fault conformance evidence. The table is a proposed test plan; these fault cases were not executed against MCP, Temporal, or a deployed ContextOS runtime for this article.

Rollback is another continuation decision

Rolling back a worker does not reverse a provider transaction, restore a retired protocol, unconsume an approval, or convert v2 state into v1 state. A reverse migration needs its own decoder, obligation mapping, and evidence. When those are unavailable, a safer recovery may preserve the new state, stop further effects, and finish reconciliation manually.

Keep the source checkpoint as historical evidence under current access and retention rules. Do not reactivate it over later effects or accounting. Avoid copying raw credentials into migration records, and keep sensitive archive metadata accessible only to entitled recovery actors. Historical reproducibility remains bounded by lawful retention and available artifacts.

The operational release question is precise: Can the next protected action preserve the unfinished operation’s meaning, satisfy current permission, and retain everything needed to establish what happened? The deployment pipeline can deliver the code. The continuation contract decides whether that code may act.

Sources and evidence notes

  • MCP C# SDK versioning: protocol negotiation, stable API scope, and the explicit experimental Tasks exception. The v2 documentation describes compatibility policy; it does not establish a tested legacy-task migration bridge.
  • MCP C# SDK Tasks: result-status and cooperative cancellation semantics. Protocol task status and business effect state need separate interpretation.
  • Temporal Worker Versioning: pinned and Auto-Upgrade workflows, Independent Activities, and conditional child version inheritance.
  • Temporal Workflow Definition: deterministic command replay and placement of external interactions in Activities. Replay safety does not establish action approval.
  • AWS Builders’ Library: Making retries safe with idempotent APIs: caller request identifiers, changed parameters, retention, and late arrivals. Provider-specific guarantees must be checked separately.
  • ContextOS Orchestration, Execution Contract, Control Profiles, and Conformance: current normative obligations underlying this proposed procedure. The repository’s deterministic reference checks supplied records; implementing runtimes supply protected stores, enforcement, and provider evidence.

Found this useful? Share it.

Share:XBSMRedditHNEmail

Continue through the same topic without returning to the index.

View the series