# Bounded Observation Limits and State Eviction Policies in pi-computer-use

> Explore bounded observation limits and state eviction policies in pi-computer-use. Learn how the StateStore manages UI observations with FIFO eviction for optimal performance.

- Repository: [injaneity/pi-computer-use](https://github.com/injaneity/pi-computer-use)
- Tags: deep-dive
- Published: 2026-07-16

---

**The pi-computer-use framework stores UI observations in an immutable, insertion-ordered `StateStore` bounded to 128 entries, evicting the oldest observations via FIFO policy when capacity is exceeded and throwing deterministic errors for evicted state references.**

The `pi-computer-use` repository implements a deterministic observation management system that balances memory efficiency with reliable UI automation. Understanding the **bounded observation limits and state eviction policies** is essential for building resilient client code that handles resource epochs gracefully. The architecture guarantees that old observations either resolve exactly or fail clearly, preventing silent data corruption.

## The 128-Entry Bounded Store Architecture

In [`src/state.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/state.ts), the framework defines `SavedStates` using a bounded capacity store:

```typescript
new StateStore<UiObservation>(128)   // bounded to 128 entries

```

This **immutable, insertion-ordered store** maintains UI observations in a strict FIFO queue. Each observation persists for the duration of its **resource epoch**, ensuring that references remain valid only while the observation occupies a slot within the bounded buffer.

The generic `StateStore` implementation in [`src/runtime.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/runtime.ts) provides the underlying mechanics for this bounded storage, enforcing capacity limits without compromising performance.

## FIFO Eviction Mechanics

When the store reaches its 128-entry capacity, the **oldest entries are evicted** using FIFO (First-In-First-Out) ordering. This eviction policy ensures predictable memory usage while maintaining a recent window of observable UI states.

Evicted observations trigger deterministic failures. The system in [`src/bridge.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/bridge.ts) throws explicit errors such as "No observation state is available" or "Observation has been evicted" when client code attempts to reference a `stateId` that has been removed from the buffer. This design prevents silent fallbacks to stale data that could corrupt automation sequences.

## State Scoping and Resource Epochs

Observations are **state-scoped**, meaning they can only be accessed via the specific `stateId` returned with the observation. This scoping mechanism creates distinct resource epochs where:

- Valid `stateId` references resolve to their exact observation data
- Invalid or evicted `stateId` values immediately produce errors  
- Client code must re-observe to obtain fresh state after eviction

According to the architecture documentation in [`docs/architecture.md`](https://github.com/injaneity/pi-computer-use/blob/main/docs/architecture.md), this bounded store model ensures that "old refs either resolve to their exact observation **or fail clearly after eviction**."

## Handling Eviction in Client Code

Client implementations should treat `stateId` values as valid **only while they remain in the bounded store**. When `act_ui()` receives an evicted state reference, it throws an error requiring the client to re-observe.

**Obtaining and using observations:**

```typescript
// Obtain a fresh observation
const {stateId, ...} = await observe_ui({ ... });

// Use refs from that observation in a later call
await act_ui({
  steps: [{ click: "@e12" }],   // "@e12" comes from the previous observation
  stateId,                     // Must match the observation that produced the ref
});

```

**Graceful eviction handling:**

```typescript
// Handling eviction gracefully
try {
  await act_ui({ steps, stateId });
} catch (e) {
  if (e.message.includes("evicted")) {
    const fresh = await observe_ui({ ... });
    // retry with the new stateId
    await act_ui({ steps, stateId: fresh.stateId });
  } else {
    throw e;
  }
}

```

If the store has evicted the observation, `act_ui` throws: `"Observation has been evicted – re‑observe before proceeding."`

## Key Implementation Files

The bounded observation system spans several critical source files:

- **[`src/state.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/state.ts)**: Defines `SavedStates` with `StateStore<UiObservation>(128)` and eviction logic
- **[`src/runtime.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/runtime.ts)**: Implements the generic `StateStore` used for bounded observation storage  
- **[`src/bridge.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/bridge.ts)**: Throws errors when observations are missing or evicted
- **[`docs/architecture.md`](https://github.com/injaneity/pi-computer-use/blob/main/docs/architecture.md)**: Documents the immutable bounded-store model and FIFO eviction behavior

## Summary

- The observation store is **bounded to 128 entries** via `StateStore<UiObservation>(128)` in [`src/state.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/state.ts)
- **FIFO eviction** removes the oldest observations when capacity is exceeded, ensuring predictable memory usage
- Access requires valid **state-scoped** `stateId` values that fail deterministically after eviction
- Client code must **re-observe** to obtain fresh state IDs when encountering eviction errors
- The architecture prevents silent stale data usage by throwing explicit errors in [`src/bridge.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/bridge.ts)

## Frequently Asked Questions

### What happens when the observation store reaches 128 entries?

When the `StateStore` capacity is exceeded, the **oldest entries are evicted** using FIFO ordering. New observations continue to be inserted while the oldest resource epochs are removed, ensuring the store never grows beyond its fixed 128-entry limit.

### How do I handle "observation has been evicted" errors?

Wrap `act_ui` calls in try-catch blocks to detect eviction messages. When caught, call `observe_ui()` to generate a fresh observation with a new `stateId`, then retry the action using the updated state reference.

### Why are observations scoped to specific state IDs?

**State scoping** ensures that UI element references (like `"@e12"`) are only valid within the specific observation that created them. This prevents automation scripts from accidentally interacting with outdated UI elements after the interface has changed, as invalid references throw clear errors rather than performing dangerous stale operations.

### Where is the bounded store limit configured?

The 128-entry limit is hardcoded in [`src/state.ts`](https://github.com/injaneity/pi-computer-use/blob/main/src/state.ts) where `SavedStates` is instantiated as `new StateStore<UiObservation>(128)`. This fixed capacity balances memory constraints against the need for recent observation history in UI automation workflows.