Phase 1 added impl Drop for SessionHandle on the Rust side so .free()
now actually removes the SESSIONS registry entry. The JS-side
try { current.free() } catch { /* already freed */ } swallow was
hiding the fact that .free() wasn't doing the cleanup at all;
post-Phase-1 it has to go so failures surface instead of being lost.
.free() callsite audit: exactly one match under extension/src/ — the
SW session.ts line this commit edits. Lifecycle audit: clearCurrent()
is reached via (a) popup lock → router popup-only.ts and (b)
session-timer expiry → service-worker/index.ts.
Refs: docs/superpowers/specs/2026-05-04-security-polish-design.md (Phase 2)
Refs: docs/superpowers/reviews/2026-05-04-architecture-review.md (P1.1, DEV-C P2 service-worker)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Non-functional tightening flagged in the slice-3 code review:
- session.ts: document future multi-vault refactor (β+) so the module-
scope singleton is explicitly "deliberately simple," not an oversight.
- vault.ts: move findByHostname doc comment above the function; note
α's intentionally-coarse hostname match (no www-stripping, no
public-suffix matching) and that tighter matching is a β/γ concern.
- index.ts: expand the passphrase scope-clearing comment to make
the theatre explicit rather than leaving it looking like real defense.
- index.ts: TODO(slice-4) marker on delete_item's non-atomic two-write
path — consider manifest-first ordering or retry/rollback at router-
split time.
- index.ts: cross-reference comment on itemToManifestEntry pointing at
the Rust-side ManifestEntry::from_item derivation it must mirror.
No behavior change; build still compiles with 2 bundle-size warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>