`plan.defaultOnStartup` records a `mode_change` before the composer restores its draft; without this the draft-cleanup arm check treats the file as durable and the metadata-only JSONL leak reappears for default-plan sessions.
Added a regression case that drives a model_change + mode_change + draft-clear cycle and asserts the session file is dropped on close().
Fixes#4571
Limit empty-session close cleanup to files whose draft sidecar lifecycle
materialized an otherwise startup-metadata-only session. Direct
ensureOnDisk() callers now remain discoverable even when they have no
user/assistant messages yet, and handoff custom_message entries survive
close before the next user turn.
Added regression coverage for resumed draft cleanup, ACP-style explicit
ensureOnDisk() records, and handoff custom messages.
Fixes#4571
`SessionManager.saveDraft(text)` calls `ensureOnDisk()` so the draft
sidecar has a parent JSONL. A follow-up `saveDraft("")` only unlinks
the sidecar — the session file was left behind, and `#shouldHaveSessionFile()`
could not prune it once the load path latched `#fileIsCurrent` and
`#forceFileCreation` to true. Each draft-then-clear-then-exit cycle
leaked a ~500–750 B zombie into `~/.omp/agent/sessions/<cwd>/`
containing only the title slot, session header, and a handful of
`model_change`/`mode_change`/`thinking_level_change` entries.
`close()` now calls `#dropIfEmptyAndNoDraft()` after draining the
writer: when the file exists, holds no user/assistant messages, and
no draft sidecar is present, it removes the session file and its
artifacts directory via `deleteSessionWithArtifacts`. Real conversations,
sessions with a saved draft still on disk (needed for `--resume`), and
never-materialized sessions are untouched.
Fixes#4571