A `profiles/<name>` directory that carries none of config.yaml / .env /
SOUL.md / profile.yaml / auth.json / state.db was still enumerated by
`_iter_named_profile_dirs`, so a marker-less shell (a cron-ticker ghost
left behind before tombstones existed, or a stray infrastructure dir)
was listed by `hermes profile list` and the Desktop Bots roster, served
and ticked by the multiplex cron scheduler, and — worst — handed the
default install's `.env` by `backfill_profile_envs` on the next
`hermes update`, which turned the ghost into a real profile with live
credentials (#95188 path D, #94823, #99392). `resolve_profile_env`
(`-p`/`--profile`) and `profile_exists` also accepted such a dir, so a
stale Desktop boot target could still spawn `serve --profile <ghost>`
whose ensure_hermes_home() rebuilt the whole tree.
Add `named_profile_has_identity` / `named_profile_is_live` beside the
tombstone helpers in hermes_constants and gate the one producer
(`_iter_named_profile_dirs`), `profile_exists`, `resolve_profile_env`
and the hosted-room local roster on it. `create_profile` may now replace
any identity-less shell (not only tombstoned ones) so users can take the
name back; dirs with identity files still fail closed.
Test fixtures that mkdir'd bare profile dirs now write a config.yaml
marker; two invariant tests pin the listing/serve/backfill/resolve
contract and the hosted-room sibling.
Based on the marker-gate idea in #99495.
Co-authored-by: Nathan Shan <nathanielcrush51@gmail.com>