Commit Graph
11 Commits
Author SHA1 Message Date
KeelrLeek 5e877c0b0a chore: ignore dev-note artifacts, start alpha versioning at 0.1.0-alpha.1
.gitignore now excludes everything that is not part of the app itself:
memory/, research/, TODO-Feature-Docs/, HANDOFF*/GAMEPLAN notes, .codex/,
.claude/ and logs. Version begins the alpha line at 0.1.0-alpha.1 across
the cargo workspace, package.json and tauri.conf.json.
2026-07-23 16:04:54 -05:00
KeelrLeek df75433795 Handoff: mark Phase 2C verification done, log Kyle's TBD open issues
Centering fix confirmed working in the native Tauri app. Wheel, a11y,
dev-handle removal, and real-app checks all closed out. Added a section
for the bugs/glitches/changes Kyle reported but did not yet specify —
placeholders to fill in, plus non-confirmed places to look.
2026-07-22 19:46:56 -05:00
KeelrLeek 56036216f8 Phase 2C: fix reel centering via window-relative card positioning
The transitioned track translateY collapsed to 0 in Chromium (percent-
translated zero-height track), leaving the active cover one stride low
per step. The track is now a fixed anchor at the reel centre; each card
positions itself at (index - activeIndex) * stride and animates its own
small `top`, so no coordinate ever exceeds +/-RENDER_RADIUS * stride.

Verified with the transition ON: centre offset 0 at every index in the
12- and 500-item fixtures, 5 cards in the DOM at scale, wheel gates,
dialog semantics, Tab containment, focus restore, and polite announce
all pass. Dev window.__preview*/__ui handles removed from App.svelte.
2026-07-22 19:38:10 -05:00
KeelrLeek e6252b9bb3 Handoff doc for Phase 2C reel-centering bug 2026-07-22 19:27:37 -05:00
KeelrLeek d051f0db28 Phase 2C WIP: PreviewOverlay modal + root integration (reel centering bug)
Working:
- PreviewOverlay.svelte mounted at app root; opens over a fixture manifest
  (window.__previewFixture(n) in dev), inert background, player bar hidden,
  focus trap, keyboard nav, F3 rail, T3 swaps, R1b capsule, accent extraction.
- previewSession.svelte.js: store + service wiring (production + fixture).
- Root integration in App.svelte; revision-gateway bumps + notePlaybackGeneration
  threaded through state.svelte.js player entry points; api.win guarded so plain
  vite browser mounts.
- Launcher on the artist page builds a real artist manifest and opens the modal
  with a play-full starter.
- 70 JS tests still green.

Two bugs found and fixed during bring-up:
- effect_update_depth_exceeded: bleed-crossfade and bump effects read AND wrote
  the same $state; wrapped writes in untrack(). This loop was breaking Svelte's
  scheduler globally (even ui.* stopped reacting).
- accentFromImage now sets crossOrigin for remote covers.

KNOWN BROKEN (handoff): reel vertical centering. The active card stays centred
at index 0 but drifts by one stride per step. Root cause isolated — see
TODO-Feature-Docs/scrollable-track-previews/HANDOFF-PHASE2C.md.
2026-07-22 19:26:41 -05:00
KeelrLeek 8cb3cd593b Phase 2A+2B: native preview backend and renderer glue
Rust (2A):
- metadata: deezer_track_uncached (fresh mint, cache-updating, paced) and
  fetch_preview_media — dedicated client whose custom redirect policy
  re-validates every hop against the media allowlist; bounded body read
  (cap enforced on received bytes, not Content-Length's promise); Date
  header captured for provider-clock lease math. httpdate dep added.
- src-tauri/preview.rs: second Player instance + soulstream:preview event
  channel; preview_resolve (fresh mint → host gate → MIME gate → ID3v2
  shell strip → MPEG sync check → clip file + opaque lease id → safe_for_ms
  mirroring lease.js); preview_load with start_paused via the
  desired-paused latch; preview_control/dispose; player_pause_acked
  exposing the Phase 0.4 ack on the MAIN player. 9 unit tests.

JS (2B):
- api.js: preview command surface (opaque lease ids only).
- nativeTransport.js: stamps {sessionId, generation, sessionKey} onto
  backend events; cleared context makes stragglers dispatch nothing.
- productionResolver.js: DTO → MediaLease, failure classes preserved.
- focusBridge.js: production coordinator binding with the documented
  renderer-side generation invariant (buffering counter + gateway).
- service.js: the orchestrator — settle window, resolve→load→play under
  focus, single capped retry, one forward lease prefetch with safe-window
  expiry, stale re-checks before every transport command, close/handoff.
  The service constructs its transport around its own dispatch — the
  factory signature exists because a pre-built transport silently loses
  the event wiring (caught by test).

70 JS tests passing (npm test); metadata 46 + app preview 9 in cargo.
2026-07-22 18:45:29 -05:00
KeelrLeek 8ede6a8adf Phase 1: preview contracts and pure session core, 61 tests
src/lib/preview/ — framework-free ESM modules, per design §12–14:
- contracts.js: versioned manifest/item/source-ref factories; signed
  URLs structurally excluded from manifests; Apple identity first-class.
- lease.js: discriminated MediaLease union; computeSafeForMs derives
  lifetimes provider-clock-first with fallback/contradiction handling
  (margins are ADRs backed by Phase 0 soak evidence).
- redact.js: URL redaction (host+hash+exp only) and the HTTPS + exact
  host allowlist gate applied to initial URLs and every redirect.
- manifest.js: artist (rank order, exact-id dedupe), album (disc/track
  sort, context inheritance) and fixture builders — pure, no fetching.
- session.js: reducer with session/generation guards on every async
  action; keyed active item with derived playable indices/cursor;
  auto-advance under fresh generations; close is terminal.
- resolver.js: PreviewResolver contract + scripted fixture resolver
  with classified failures (stale_lease/not_found/network/…).
- transport.js: transport seam + deterministic fake (manual ticks).
- focus.js: revision gateway (all main-player entry points; focus-
  internal tag) and the coordinator — acquisition only via a
  generation-bound silence ack, restore only with revisions unchanged.

tests/preview/*.test.mjs run via `npm test` (node --test): 61 passing,
covering the full Phase 1 list in IMPLEMENTATION-PLAN §6 including the
exit gate: stale lease/play events are inert, no restoration after any
simulated main command, and no component renders anywhere.
2026-07-22 18:29:03 -05:00
KeelrLeek 6dcc62a2fd Phase 0.4: silence-ack primitive — pause_acked + desired-paused latch
Player::pause_acked() returns a generation-bound PauseAck applied on the
audio thread; a desired-paused latch makes an in-flight decoder come up
paused instead of auto-starting, closing the window where a pause lands
during decode setup. Proven live by examples/focus_ack_probe.rs:
ack-while-playing freezes position; ack-while-buffering never becomes
audible; resume clears the latch; plain pause() during buffering is
demonstrated to auto-start (pre-existing hazard, filed separately).

Transport ADR recorded (native), Phase 0 marked complete in the plan.
2026-07-22 18:17:37 -05:00
KeelrLeek 58918cf79d Phase 0.2 complete: lease soak results, ID3-shell universality, long tracks
Soak: signed URLs serve 206 through their parsed exp (+14.96 min batch)
and return 403 with an Akamai HTML error page by +17.5 min. Resolver
must refresh ahead of exp, treat 403 as stale-lease (re-mint by track
id), and validate audio/mpeg before decoding. ID3v2.4 empty shell
verified byte-identical on 7/7 extra samples; 18- and 26-minute tracks
carry the same uniform 30 s / 480 KB / 128 kbps preview artifact.
2026-07-22 18:07:35 -05:00
KeelrLeek abe9bc33db Phase 0: corpus probe results, transport bakeoff probes, first findings
- research/PHASE0-VALIDATION-2026-07-22.md: 71-track Deezer corpus
  (uniform 128k CBR MP3, per-fetch signed URLs, exp 13-15 min, HTTP-200
  error bodies), WebView transport suite pass, native transport pass
  after isolating the empty-ID3v2.4-shell decode failure in
  rodio/symphonia; bakeoff scorecard leaning native.
- crates/player/examples/preview_probe.rs: isolated native probe (two
  coexisting Player instances, real preview bytes).
- mockups/phase0-webview-transport-probe.html: single-root-audio
  lifecycle probe with injected resolver-style URLs.
- IMPLEMENTATION-PLAN.md: Phase 0 status row updated.
2026-07-22 18:00:09 -05:00
KeelrLeek a667b4b28e Baseline: full tree snapshot after git repository loss
The previous .git directory was found gutted (only info/ remained), so
history is unrecoverable locally. This commit restores version control
with the tree exactly as it stands: the working app, the preview-tracks
launcher on the artist hero, the scrollable-track-previews design bundle
(docs + approved mockups), and the Phase 0 validation artifacts.
2026-07-22 17:57:00 -05:00