# v0.26-beta Migration Guide

> **Audience**: operators upgrading an existing agent-tempo deployment from v0.25.x
> to v0.26.0-beta.1 or later. If you're starting fresh, ignore this file — the
> `agent-tempo up` command registers the current search-attribute set automatically.
>
> **Epic reference**: #174 (parent). Four-PR ladder: #175, #176, #177, #178.

---

## TL;DR — Three things you need to know

1. **Breaking search-attribute change.** `ClaudeTempoStatus` is removed. Long-lived
   Temporal clusters must manually drop it — Temporal does not auto-unregister
   search attributes.
2. **Breaking SDK-type change.** `SessionStatus`, `SessionMetadata.status`,
   `EnsembleSessionInfo.status`, and `MaestroPlayerInfo.status` are removed or
   renamed. External consumers of `TempoClient` that read those fields need updates
   (see the consumer section below).
3. **End-to-end upgrade required.** An older CLI/TUI paired with a v0.26 daemon — or
   an older daemon with a v0.26 CLI/TUI — is **not supported**. Upgrade both sides
   together.

---

## What changed

The #174 shim-removal epic finished the v0.25 attachment-phase lifecycle migration.
The legacy lifecycle model — sessions tracked a `status` field (`pending` → `active`
→ `stale | blocked | terminated`) driven by a 3-min stale and 5-min blocked heuristic
— was held in place through v0.25.x as a compatibility shim. v0.26-beta removes it.

### Removed surface

| Removed | Replaced by |
|---|---|
| `ClaudeTempoStatus` search attribute | `ClaudeTempoAttachmentState` (seven-phase values) |
| `SessionStatus` TypeScript enum | `AttachmentPhase` type (`booting | attached | processing | awaiting | draining | detached | gone`) |
| `SessionMetadata.status` field | `attachmentInfo` query on the workflow |
| `EnsembleSessionInfo.status` field | `EnsembleSessionInfo.phase?: AttachmentPhase` |
| `MaestroPlayerInfo.status` (rename) | `MaestroPlayerInfo.phase?: AttachmentPhase` |
| `BLOCKED_WINDOW_MS` export | *no replacement — heuristic deleted* |
| `_heartbeat` / `_ping` internal probe messages | adapter `heartbeat` signal (v0.25) |
| 3-min stale / 5-min blocked heuristics | lease-expiry + `processingDeadline` (adapter-driven) |

### Ensemble tool output

`ensemble` and `agent-tempo status` now render **five** user-facing labels (collapsed
from the seven underlying phases per the Option-B mapping locked in #176 / #177):

| Label | Underlying phases | Color |
|---|---|---|
| `active` | `attached`, `processing` | green |
| `idle` | `awaiting` | neutral |
| `disconnected` | `draining`, `detached` | yellow |
| `pending` | `booting` | dim |
| `gone` | `gone` | dim |

Where you previously saw `(stale)` or `(blocked)` tags, you now see `(disconnected)`.
Where you previously saw `(pending)`, the tag is unchanged but the underlying phase
is `booting`. Where you previously saw `(terminated)`, the tag is now `(gone)`.

### TUI status chips

The TUI's `StatusBar` summary collapses to the same five labels. `gone` sessions are
excluded from the bar's breakdown (they're terminal, not part of the working
ensemble); the `PlayerDetailView` still shows `gone` if you drill in on a session.

---

## Upgrade steps

### 1. Upgrade the daemon and CLI together

```bash
npm install -g agent-tempo@0.26.0-beta.1
```

Stop any running daemon **before** upgrading — the workflow bundle changed, and a
mixed-version fleet will fail on replay:

```bash
agent-tempo daemon stop
# verify:
agent-tempo daemon status
# then upgrade, then:
agent-tempo up
```

### 2. Drop the legacy search attribute from your Temporal cluster

Temporal does **not** auto-unregister search attributes. You need to drop
`ClaudeTempoStatus` by hand once — new session workflows won't write to it, but old
workflow histories will still reference it, and the attribute itself will linger
unless you remove it.

**Temporal Cloud** — drop via the cloud admin UI or `tcld`:

```bash
tcld namespace search-attributes remove \
  --namespace <YOUR_NAMESPACE> \
  --sa ClaudeTempoStatus
```

**Self-hosted Temporal (OSS)** — use the `temporal operator` CLI:

```bash
temporal operator search-attribute remove \
  --namespace <YOUR_NAMESPACE> \
  --name ClaudeTempoStatus
```

**Dev server / fixtures** — rebuild. The `agent-tempo up` command no longer
registers `ClaudeTempoStatus`, and the `test/fixtures/multi-host/docker-compose.yml`
fixture has been updated. Bring the fixture down and up:

```bash
docker compose -f test/fixtures/multi-host/docker-compose.yml down
docker compose -f test/fixtures/multi-host/docker-compose.yml up -d
```

### 3. Verify

```bash
# Attribute is gone:
temporal operator search-attribute list --namespace <YOUR_NAMESPACE> | grep ClaudeTempo
# Expected: 9 rows (previously 10). No `ClaudeTempoStatus` line.

# Sessions expose phase via the new search attr:
temporal workflow list --namespace <YOUR_NAMESPACE> \
  --query 'WorkflowType = "claudeSessionWorkflow" AND ExecutionStatus = "Running"' \
  --fields long | grep ClaudeTempoAttachmentState

# CLI renders phase-based tags:
agent-tempo status
```

### 4. Update external TempoClient consumers (if any)

If you have code importing from `agent-tempo`, check for:

```ts
// Remove — types no longer exported:
import type { SessionStatus } from 'agent-tempo';
```

```ts
// Update reads:
session.status        // → session.phase (on MaestroPlayerInfo / EnsembleSessionInfo)
metadata.status       // → (removed — query `attachmentInfo` for phase)
```

```ts
// Field rename on MaestroPlayerInfo (v0.26):
player.status   // → player.phase
```

The `TempoClient.EnsembleInfo.conductorStatus` field name is **kept** for public API
compatibility, but its value is now an `AttachmentPhase` string instead of a legacy
`SessionStatus` string.

---

## Rollback plan

If v0.26-beta surfaces blockers, roll the CLI and daemon back together:

```bash
agent-tempo daemon stop
npm install -g agent-tempo@0.25.1  # last shim-era release
agent-tempo up
```

You do **not** need to re-register `ClaudeTempoStatus` on your Temporal cluster.
Older daemon versions will not write to it; new session workflows on the rolled-back
version will still omit it (the rollback daemon shares the same post-removal
workflow bundle). Only re-register if you need to inspect old workflow histories via
the Temporal UI's search-attribute filter.

---

## FAQ

**Do I need to destroy running sessions before upgrading?**
No. The workflow itself is forward-compatible — `patched()` markers are preserved
across the entire #174 epic, so running sessions replay cleanly on the new bundle.
What you **must** do is stop the daemon before upgrading so the old and new bundles
don't collide on the same task queue.

**My `ensemble` output shows `(disconnected)` for a session I expect to be
live — what changed?**
`(disconnected)` maps to the `draining` or `detached` phase. The session is alive
(its workflow is still running) but either no adapter has claimed it, or the
adapter is in the middle of detaching. In v0.25 this bucket was split across
`(stale)` (3-min undelivered messages) and `(blocked)` (5-min no-response). The
underlying behavior of the adapter hasn't changed; the label is more accurate now.

**A session is stuck in `booting` — is that a bug?**
`booting` means the workflow exists but no adapter has called `claimAttachment`
yet. On a successful `recruit`, you'd expect the adapter to claim within a few
seconds (the terminal or Copilot bridge has to launch and connect). If it stays
there for more than ~30 seconds, the spawn likely failed — check
`~/.agent-tempo/daemon.log` for the `spawnProcess` activity result.

**Why is `gone` counted separately from `disconnected`?**
`gone` is terminal — the workflow has completed after `destroy`. `disconnected`
(`draining` / `detached`) is alive — the workflow is still running and waiting for
a fresh `claimAttachment`. Restart / migrate on a `gone` session is an error; on a
`detached` session it's the happy path.

---

## Related

- Epic issue: [#174](https://github.com/vinceblank/agent-tempo/issues/174)
- Design: [`docs/design/archive/session-lifecycle-rebuild-v2.md`](../design/archive/session-lifecycle-rebuild-v2.md)
- Sequencing memo: [`docs/design/archive/session-lifecycle-rebuild-v2-sequencing.md`](../design/archive/session-lifecycle-rebuild-v2-sequencing.md) §11
- Concepts glossary: [`docs/concepts.md`](../concepts.md) § "Attachment phase"
- Wire protocol: [`docs/WIRE-PROTOCOL.md`](../WIRE-PROTOCOL.md) § "Search Attributes"
