# state/ — must-do follow-ups

- `work_state.py`: on the next work `__status.json` format change, start writing
  the `v` field that readers already accept (absent means v1). Keep the supported
  version set explicit and update the upgrade note before changing the writer.
- `ops/legacy_native_import.py`: stop writing the legacy import report's unused
  `schema_version` after the released reader that requires it is outside the
  compatibility window. The current reader already defaults an absent field to 1.

- Versioned ZIP membership/digest recipe and immutable capture descriptor for
  native-transcript.jsonl (native-transcript-capture.md stage 4). Inventory now
  accepts a sealed snapshot as the transcript member; old publisher ZIPs keep
  implicit history.jsonl. Do not invent descriptors for restored old records.

- process_scope_projection.py callers in spawn_service.py and process_cleanup.py:
  move synchronous projection reads off the async event-loop thread with
  `asyncio.to_thread()`. Reads now have a bounded lock wait, but can still block
  the loop for up to that bound when a projection writer is wedged.
- [#454] state↔ops import cycle for identity migration: user_paths.py
  dynamically imports ops/migration.py, which imports back into state identity;
  legacy-id reading is duplicated in both. #388's B2 already removed the
  lock_held cross-cycle flag and the unlocked writer; the residual is
  structural — move the identity-transition mechanism into a state-owned
  project_identity module and leave ops with only active-spawn policy + CLI
  rendering. (B3)
