---
title: "Behavioral spec: op_picker"
---
import RepoFile from '../../../../components/RepoFile.astro'

**Status**: Open — Phase 1, no confirmation needed

## Problem

<RepoFile path="src/console/widgets/op_picker/mod.rs" /> is now **2331L** total (was ~1712L at original analysis — +36% growth). It has a `//!` doc but no INV-format invariant contract. The 4-level drill-down state machine has subtle invariants around the `op://` reference format and the absence of secret values in the picker path.

The render counterpart <RepoFile path="src/console/widgets/op_picker/render.rs" /> is **865L** (separate file).

## Key invariants

| INV | Description | Verify by |
|---|---|---|
| INV-1 | Field selection commits `OpField::reference` verbatim when present; only fixtures missing `reference` use the synthesized `op://<vault>/<item>/<label>` fallback | selection path returns `field.reference.clone()` first, then falls back to `format!("op://{}/{}/{}"...)` |
| INV-2 | No secret values in picker path — `RawOpField` struct has no `value` field; serde drops it silently | grep `value` in op_picker/mod.rs; exhaustive destructure test at `operator_env.rs:~2055` |
| INV-3 | Loading is async (background worker + channel); key handlers stay synchronous and only advance UI state / `poll_load()` | background loaders use `std::thread::spawn`; key handlers do not call the CLI directly |

## State machine

4 stages: `Accounts` → `Vaults` → `Items` → `Fields`. Each stage has a background loader and a key handler. Loaders post results via channel; `poll_load()` drains them before each render.

## Steps

1. Create `docs/src/content/docs/internal/specs/op-picker.mdx` (once Developer Reference setup exists).
2. Use INV-N template for the three invariants above.
3. Add sidebar entry under Developer Reference → Specs.
4. Link from the `op_picker/mod.rs` `//!` doc to the spec URL once the internal docs section exists.

## Related files

- <RepoFile path="src/console/widgets/op_picker/mod.rs" /> — 2331L total (state machine + loader + key handler)
- <RepoFile path="src/console/widgets/op_picker/render.rs" /> — 865L (render logic)
- <RepoFile path="src/operator_env.rs" /> — uses `RawOpField`; exhaustive destructure test
