Persist BGM track index and playback position across page refresh (Album 1) #71

Closed
opened 2026-04-26 10:55:17 +00:00 by PlasticDigits · 10 comments
PlasticDigits commented 2026-04-26 10:55:17 +00:00 (Migrated from gitlab.com)

Summary

Today, refreshing the page resets the Album 1 BGM back to track 1 at 00:00. Players who have been listening for a while lose their place every time they navigate, refresh, or reopen the tab. We want the player to resume from approximately where the listener left off.

This issue covers persisting the current track index and the current playback position (seconds into the track) in the browser, then restoring them when the audio engine starts up.

Related: issue #68 (Album 1 BGM + SFX bus), guardrail #17 in .cursor/skills/yieldomega-guardrails/SKILL.md.

Background / current state

  • BGM lives in frontend/src/audio/:
    • WebAudioMixer.ts owns the single HTMLAudioElement + MediaElementAudioSourceNode and the trackIndex counter.
    • AudioEngineProvider.tsx wires the mixer, attempts autoplay on load, and unlocks audio on the first user gesture.
    • audioPreferences.ts already persists volume / mute prefs to localStorage under the key prefix yieldomega:audio:v1: (prefs slot).
  • On every reload, new WebAudioMixer(...) starts with trackIndex = 0 and playBgm() always sets audioEl.src to the first track from ALBUM_1_PLAYLIST and starts at offset 0.

So the persistence machinery exists for prefs but is not used for playlist position.

Work to be done

  1. Define a v1 playback-state record in frontend/src/audio/audioPreferences.ts (or a sibling audioPlaybackState.ts if it keeps the prefs file focused on mix settings). Suggested shape:

    export type AudioPlaybackStateV1 = {
      /** Index into ALBUM_1_PLAYLIST. Clamped on load. */
      trackIndex: number;
      /** Seconds into the current track. Clamped to [0, track.durationSec) on load. */
      positionSec: number;
      /** ms since epoch when this snapshot was written; used to ignore stale state. */
      savedAt: number;
      /** Stable id of the track at save time (e.g. ALBUM_1_PLAYLIST[i].id). */
      trackId: string;
    };
    
  2. Tracking in the browser session. Use window.localStorage (same pattern as saveAudioPrefs) under a new key, e.g. yieldomega:audio:v1:playbackState. Persistence triggers:

    • On natural track end (advanceAfterTrackEnded): write new trackIndex, positionSec = 0.
    • On manual skip (skipBgmNext): write new trackIndex, positionSec = 0.
    • On pause (pauseBgm): write current audioEl.currentTime.
    • On a timeupdate listener while playing: write at most once every ~3–5 seconds (throttle / coalesce; timeupdate fires ~4×/sec) to avoid localStorage thrash.
    • On visibilitychange → hidden and on pagehide / beforeunload: flush a final snapshot synchronously.

    Use localStorage (not sessionStorage) so a fresh tab on the same origin still resumes; keep a single key so multiple tabs eventually converge (last-writer wins is acceptable for v1).

  3. Restore on startup in WebAudioMixer:

    • In the constructor (or a new hydrateFromStorage() called before playBgm), read the saved state.
    • Validate: the trackId still exists in ALBUM_1_PLAYLIST. If yes, set this.trackIndex to the matching index. If the id is missing (playlist edited), fall back to clamped numeric index, and if that fails fall back to 0 / 0.
    • Stash the desired positionSec so playBgm() can apply it after audioEl.src is set. Apply via audioEl.currentTime = positionSec once metadata is loaded (loadedmetadata event) or right before play() if readyState >= 1.
    • Surface the restored trackIndex through the existing onTrackChange callback so the dock title in AlbumPlayerBar reflects the resumed track immediately, even before audio unlock.
  4. Autoplay-blocked behavior. When the browser blocks autoplay, BGM does not start until the first user gesture. The dock currently shows "Tap anywhere or ▶ if autoplay was blocked". Restoration must still apply: when the unlock gesture finally fires playBgm(), the mixer should resume at the saved track + offset (not reset to 0/0).

  5. Skip / next semantics. Pressing "next track" should not preserve the previous offset on the new track (always start the new track at 0); this matches today's behavior and the snapshot-on-skip rule above.

  6. Stale state handling. If savedAt is older than, say, 7 days, treat it as expired and start at the saved trackIndex but positionSec = 0 (or fall back to 0/0). Keep this threshold a single named constant.

  7. Quota / private mode. Wrap reads/writes in try/catch like loadAudioPrefs / saveAudioPrefs already do; any failure must degrade silently to "start at 0/0". No console spam.

  8. Tests. Add unit tests next to audioPreferences.test.ts (audioPlaybackState.test.ts or extend the existing file):

    • round-trip save → load
    • load returns defaults when storage is empty / corrupt JSON / out-of-range index / unknown trackId
    • clamp positionSec to non-negative finite numbers
    • throttling helper (if extracted) writes at most once per window
    • stale snapshot (older than the TTL constant) collapses to positionSec = 0

    Mixer-level behavior (apply currentTime on loadedmetadata, persist on pause / skip / ended / visibility change) should be covered by tests where practical; if jsdom can't drive HTMLAudioElement events, add at minimum a small adapter unit-tested in isolation.

  9. Docs. Update:

    • docs/frontend/sound-effects-recommendations.md §8 (Album 1 / SFX bus) to describe playback-state persistence alongside the existing autoplay + first-gesture behavior.
    • docs/testing/invariants-and-business-logic.md row for issue #68 (or add a sibling row for this issue) so the new persistence + TTL is part of the test map.
    • Consider a one-line note in .cursor/skills/yieldomega-guardrails/SKILL.md guardrail #17.

How to track in the browser session

  • Storage: window.localStorage, key yieldomega:audio:v1:playbackState (matches the existing yieldomega:audio:v1: prefix used by audioPreferences.ts).
  • Value: JSON-encoded AudioPlaybackStateV1 (trackIndex, trackId, positionSec, savedAt).
  • Write triggers: track end, manual skip, pause, throttled timeupdate (~3–5s), visibilitychange → hidden, pagehide / beforeunload flush.
  • Read trigger: mixer construction / first playBgm() call; restored state must apply both for autoplay-success and for autoplay-blocked → first-gesture paths.
  • Conflict / multi-tab: last writer wins; no cross-tab sync required for v1.
  • Privacy: localStorage only; no network calls; no PII; safe in private-browsing modes (silent failure).

Acceptance criteria

  • Refreshing the page while BGM is playing resumes the same track at within ±5 seconds of where it was, in both Chromium and Firefox.
  • Pausing, then refreshing, restores the same track and the paused offset (within ±2 seconds); audio remains paused until the user presses play / interacts (matching current autoplay-blocked UX when applicable).
  • Skipping with the dock's next button, then refreshing, lands on the new track at offset 0.
  • Letting a track play to its natural end and then refreshing lands on the next track at offset 0 (not the just-finished track).
  • Closing and reopening the tab on the same origin restores the last saved track + offset (localStorage, not sessionStorage).
  • If localStorage is unavailable, throws on write, contains corrupt JSON, references a track id no longer in ALBUM_1_PLAYLIST, or is older than the TTL constant, the player falls back gracefully to track 1 / 00:00 with no console errors.
  • The dock title in AlbumPlayerBar reflects the restored track immediately on mount (not "track 1" briefly flashing before correcting).
  • No regression to existing autoplay behavior: autoplay still attempted on load, first user gesture still unlocks; pointer-down SFX still fires correctly.
  • No additional localStorage writes faster than ~once every 3 seconds while idle-playing (verify via a short manual log or test).
  • Unit tests added for the new persistence helpers and pass under pnpm --filter frontend test (or the equivalent vitest invocation already used in frontend/).
  • Docs in docs/frontend/sound-effects-recommendations.md and docs/testing/invariants-and-business-logic.md updated; guardrail #17 cross-references the new behavior.

Out of scope

  • Cross-device / account-bound resume (would require backend or wallet-signed storage).
  • Per-track resume history (only the most recent position is remembered).
  • Resume across different albums (Album 1 only for v1; design should not block Album N later).
## Summary Today, refreshing the page resets the Album 1 BGM back to **track 1** at **00:00**. Players who have been listening for a while lose their place every time they navigate, refresh, or reopen the tab. We want the player to resume from approximately where the listener left off. This issue covers persisting the **current track index** and the **current playback position (seconds into the track)** in the browser, then restoring them when the audio engine starts up. Related: [issue #68](https://gitlab.com/PlasticDigits/yieldomega/-/issues/68) (Album 1 BGM + SFX bus), guardrail #17 in `.cursor/skills/yieldomega-guardrails/SKILL.md`. ## Background / current state - BGM lives in `frontend/src/audio/`: - `WebAudioMixer.ts` owns the single `HTMLAudioElement` + `MediaElementAudioSourceNode` and the `trackIndex` counter. - `AudioEngineProvider.tsx` wires the mixer, attempts autoplay on load, and unlocks audio on the first user gesture. - `audioPreferences.ts` already persists volume / mute prefs to `localStorage` under the key prefix `yieldomega:audio:v1:` (`prefs` slot). - On every reload, `new WebAudioMixer(...)` starts with `trackIndex = 0` and `playBgm()` always sets `audioEl.src` to the first track from `ALBUM_1_PLAYLIST` and starts at offset 0. So the persistence machinery exists for prefs but is **not** used for playlist position. ## Work to be done 1. **Define a v1 playback-state record** in `frontend/src/audio/audioPreferences.ts` (or a sibling `audioPlaybackState.ts` if it keeps the prefs file focused on mix settings). Suggested shape: ```ts export type AudioPlaybackStateV1 = { /** Index into ALBUM_1_PLAYLIST. Clamped on load. */ trackIndex: number; /** Seconds into the current track. Clamped to [0, track.durationSec) on load. */ positionSec: number; /** ms since epoch when this snapshot was written; used to ignore stale state. */ savedAt: number; /** Stable id of the track at save time (e.g. ALBUM_1_PLAYLIST[i].id). */ trackId: string; }; ``` 2. **Tracking in the browser session.** Use `window.localStorage` (same pattern as `saveAudioPrefs`) under a new key, e.g. `yieldomega:audio:v1:playbackState`. Persistence triggers: - On natural track end (`advanceAfterTrackEnded`): write new `trackIndex`, `positionSec = 0`. - On manual skip (`skipBgmNext`): write new `trackIndex`, `positionSec = 0`. - On pause (`pauseBgm`): write current `audioEl.currentTime`. - On a `timeupdate` listener while playing: write at most once every ~3–5 seconds (throttle / coalesce; `timeupdate` fires ~4×/sec) to avoid localStorage thrash. - On `visibilitychange` → hidden and on `pagehide` / `beforeunload`: flush a final snapshot synchronously. Use `localStorage` (not `sessionStorage`) so a fresh tab on the same origin still resumes; keep a single key so multiple tabs eventually converge (last-writer wins is acceptable for v1). 3. **Restore on startup** in `WebAudioMixer`: - In the constructor (or a new `hydrateFromStorage()` called before `playBgm`), read the saved state. - Validate: the `trackId` still exists in `ALBUM_1_PLAYLIST`. If yes, set `this.trackIndex` to the matching index. If the id is missing (playlist edited), fall back to clamped numeric index, and if that fails fall back to 0 / 0. - Stash the desired `positionSec` so `playBgm()` can apply it after `audioEl.src` is set. Apply via `audioEl.currentTime = positionSec` once metadata is loaded (`loadedmetadata` event) or right before `play()` if `readyState >= 1`. - Surface the restored `trackIndex` through the existing `onTrackChange` callback so the dock title in `AlbumPlayerBar` reflects the resumed track immediately, even before audio unlock. 4. **Autoplay-blocked behavior.** When the browser blocks autoplay, BGM does not start until the first user gesture. The dock currently shows "Tap anywhere or ▶ if autoplay was blocked". Restoration must still apply: when the unlock gesture finally fires `playBgm()`, the mixer should resume at the saved track + offset (not reset to 0/0). 5. **Skip / next semantics.** Pressing "next track" should not preserve the previous offset on the new track (always start the new track at 0); this matches today's behavior and the snapshot-on-skip rule above. 6. **Stale state handling.** If `savedAt` is older than, say, 7 days, treat it as expired and start at the saved `trackIndex` but `positionSec = 0` (or fall back to 0/0). Keep this threshold a single named constant. 7. **Quota / private mode.** Wrap reads/writes in try/catch like `loadAudioPrefs` / `saveAudioPrefs` already do; any failure must degrade silently to "start at 0/0". No console spam. 8. **Tests.** Add unit tests next to `audioPreferences.test.ts` (`audioPlaybackState.test.ts` or extend the existing file): - round-trip save → load - load returns defaults when storage is empty / corrupt JSON / out-of-range index / unknown trackId - clamp `positionSec` to non-negative finite numbers - throttling helper (if extracted) writes at most once per window - stale snapshot (older than the TTL constant) collapses to `positionSec = 0` Mixer-level behavior (apply `currentTime` on `loadedmetadata`, persist on pause / skip / ended / visibility change) should be covered by tests where practical; if jsdom can't drive `HTMLAudioElement` events, add at minimum a small adapter unit-tested in isolation. 9. **Docs.** Update: - `docs/frontend/sound-effects-recommendations.md` §8 (Album 1 / SFX bus) to describe playback-state persistence alongside the existing autoplay + first-gesture behavior. - `docs/testing/invariants-and-business-logic.md` row for issue #68 (or add a sibling row for this issue) so the new persistence + TTL is part of the test map. - Consider a one-line note in `.cursor/skills/yieldomega-guardrails/SKILL.md` guardrail #17. ## How to track in the browser session - **Storage:** `window.localStorage`, key `yieldomega:audio:v1:playbackState` (matches the existing `yieldomega:audio:v1:` prefix used by `audioPreferences.ts`). - **Value:** JSON-encoded `AudioPlaybackStateV1` (trackIndex, trackId, positionSec, savedAt). - **Write triggers:** track end, manual skip, pause, throttled `timeupdate` (~3–5s), `visibilitychange` → hidden, `pagehide` / `beforeunload` flush. - **Read trigger:** mixer construction / first `playBgm()` call; restored state must apply both for autoplay-success and for autoplay-blocked → first-gesture paths. - **Conflict / multi-tab:** last writer wins; no cross-tab sync required for v1. - **Privacy:** localStorage only; no network calls; no PII; safe in private-browsing modes (silent failure). ## Acceptance criteria - [ ] Refreshing the page while BGM is playing resumes the **same track** at within **±5 seconds** of where it was, in both Chromium and Firefox. - [ ] Pausing, then refreshing, restores the same track and the paused offset (within ±2 seconds); audio remains paused until the user presses play / interacts (matching current autoplay-blocked UX when applicable). - [ ] Skipping with the dock's next button, then refreshing, lands on the **new** track at offset 0. - [ ] Letting a track play to its natural end and then refreshing lands on the **next** track at offset 0 (not the just-finished track). - [ ] Closing and reopening the tab on the same origin restores the last saved track + offset (localStorage, not sessionStorage). - [ ] If `localStorage` is unavailable, throws on write, contains corrupt JSON, references a track id no longer in `ALBUM_1_PLAYLIST`, or is older than the TTL constant, the player falls back gracefully to track 1 / 00:00 with no console errors. - [ ] The dock title in `AlbumPlayerBar` reflects the **restored** track immediately on mount (not "track 1" briefly flashing before correcting). - [ ] No regression to existing autoplay behavior: autoplay still attempted on load, first user gesture still unlocks; pointer-down SFX still fires correctly. - [ ] No additional `localStorage` writes faster than ~once every 3 seconds while idle-playing (verify via a short manual log or test). - [ ] Unit tests added for the new persistence helpers and pass under `pnpm --filter frontend test` (or the equivalent vitest invocation already used in `frontend/`). - [ ] Docs in `docs/frontend/sound-effects-recommendations.md` and `docs/testing/invariants-and-business-logic.md` updated; guardrail #17 cross-references the new behavior. ## Out of scope - Cross-device / account-bound resume (would require backend or wallet-signed storage). - Per-track resume history (only the most recent position is remembered). - Resume across different albums (Album 1 only for v1; design should not block Album N later).
PlasticDigits commented 2026-04-26 12:49:37 +00:00 (Migrated from gitlab.com)

mentioned in commit 948cbbf704

mentioned in commit 948cbbf704516f7319a1b9b51cadaa3de4643e34
PlasticDigits commented 2026-04-26 12:50:07 +00:00 (Migrated from gitlab.com)

Implemented (merged to main)

BGM track + offset persistence for Album 1 per the issue spec:

  • Storage: yieldomega:audio:v1:playbackState — JSON with trackId (manifest-stable albumId/file), trackIndex, positionSec, savedAt.
  • Logic: frontend/src/audio/audioPlaybackState.ts — load/save, 7-day TTL (offset → 0, keep track), clamping, 4s createMinIntervalGate for periodic writes.
  • Mixer: WebAudioMixer hydrates on construct; seek after loadedmetadata then play() so autoplay-blocked sessions still resume on first gesture; persist on pause, throttled timeupdate, skip, natural ended, visibility hidden, pagehide/beforeunload.
  • Dock: AudioEngineProvider initial trackIndex from loadAudioPlaybackState so the ticker/title matches the restored track immediately.
  • Playlist: AlbumTrack gains id + durationSec from the manifest for validation/clamping.
  • Tests: audioPlaybackState.test.ts + updated albumPlaylist.test.ts.
  • Docs / skills: docs/frontend/sound-effects-recommendations.md §8, new invariants section + table row, timecurve-views.md, docs/agents/metadata-and-skills.md, guardrail #17, skills/verify-yo-album-bgm-resume/SKILL.md + skills/README.md.

@brouie could you verify on Chromium + Firefox using the checklist below? Leaving the issue open until you sign off.

Checklist for verification

  1. Play BGM mid-track → hard refresh → same track title on first paint (no long flash of track 1) and resume within ~±5s.
  2. Pause mid-track → refresh → same track, still paused until Play; offset within ~±2s.
  3. Autoplay blocked profile: refresh mid-track → dock shows correct track; after first pointer gesture, audio starts near saved offset (not 0:00).
  4. Next track → refresh → new track at 0:00.
  5. Let a track play to natural end (auto-advance) → refresh → expect advanced track at 0:00 (per acceptance criteria).
  6. localStorage key present; no console errors when storage is corrupt / unavailable (simulate if needed).
  7. Optional: confirm playbackState savedAt does not update faster than ~3–5s during steady play unless pause/skip/hide/unload.

Play skill for agents: skills/verify-yo-album-bgm-resume/SKILL.md

Commit: 948cbbf on main.

## Implemented (merged to `main`) BGM **track + offset** persistence for Album 1 per the issue spec: - **Storage:** `yieldomega:audio:v1:playbackState` — JSON with `trackId` (manifest-stable `albumId/file`), `trackIndex`, `positionSec`, `savedAt`. - **Logic:** `frontend/src/audio/audioPlaybackState.ts` — load/save, **7-day** TTL (offset → 0, keep track), clamping, **4s** `createMinIntervalGate` for periodic writes. - **Mixer:** `WebAudioMixer` hydrates on construct; **seek after `loadedmetadata`** then `play()` so **autoplay-blocked** sessions still resume on first gesture; persist on **pause**, **throttled timeupdate**, **skip**, **natural ended**, **visibility hidden**, **pagehide/beforeunload**. - **Dock:** `AudioEngineProvider` initial `trackIndex` from `loadAudioPlaybackState` so the ticker/title matches the restored track immediately. - **Playlist:** `AlbumTrack` gains `id` + `durationSec` from the manifest for validation/clamping. - **Tests:** `audioPlaybackState.test.ts` + updated `albumPlaylist.test.ts`. - **Docs / skills:** `docs/frontend/sound-effects-recommendations.md` §8, new invariants section + table row, `timecurve-views.md`, `docs/agents/metadata-and-skills.md`, guardrail #17, `skills/verify-yo-album-bgm-resume/SKILL.md` + `skills/README.md`. --- @brouie could you verify on **Chromium + Firefox** using the checklist below? Leaving the issue **open** until you sign off. ### Checklist for verification 1. Play BGM mid-track → **hard refresh** → same **track title** on first paint (no long flash of track 1) and resume within **~±5s**. 2. **Pause** mid-track → refresh → same track, **still paused** until Play; offset within **~±2s**. 3. **Autoplay blocked** profile: refresh mid-track → dock shows **correct track**; after first **pointer** gesture, audio starts near saved offset (not 0:00). 4. **Next track** → refresh → **new** track at **0:00**. 5. Let a track play to **natural end** (auto-advance) → refresh → expect **advanced** track at **0:00** (per acceptance criteria). 6. **localStorage** key present; no **console** errors when storage is corrupt / unavailable (simulate if needed). 7. Optional: confirm `playbackState` **savedAt** does not update faster than **~3–5s** during steady play unless pause/skip/hide/unload. **Play skill for agents:** [`skills/verify-yo-album-bgm-resume/SKILL.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/skills/verify-yo-album-bgm-resume/SKILL.md) Commit: `948cbbf` on `main`.
Brouie commented 2026-04-27 02:46:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #72

mentioned in issue #72
PlasticDigits commented 2026-04-30 05:25:11 +00:00 (Migrated from gitlab.com)

mentioned in issue #100

mentioned in issue #100
Brouie commented 2026-05-01 15:28:03 +00:00 (Migrated from gitlab.com)

Source-level pre-walkthrough on 948cbbf (carried into 243e2a0).

  • src/audio/audioPlaybackState.ts exists with STORAGE_PREFIX = "yieldomega:audio:v1:" and AUDIO_PLAYBACK_STALE_MS = 7 * 24 * 60 * 60 * 1000 (= 604,800,000 ms = 7 days, matches your spec).
  • Stale check at line 67: nowMs - savedAt > AUDIO_PLAYBACK_STALE_MS — clamps offset path on stale entries per acceptance.
  • createMinIntervalGate (line 162) is the 4s throttle gate referenced in your commit notes.
  • audioPlaybackState.test.ts: 7 tests PASS in 4ms via npx vitest run audioPlaybackState.

Note — your 4/26 comment links skills/verify-yo-album-bgm-resume/SKILL.md, which was removed during #100 cleanup. Migrated home is now manual-qa-checklists.md#manual-qa-issue-71. Just flagging in case you want to update the stale path; not blocking.

cc @PlasticDigits

Source-level pre-walkthrough on `948cbbf` (carried into `243e2a0`). - `src/audio/audioPlaybackState.ts` exists with `STORAGE_PREFIX = "yieldomega:audio:v1:"` and `AUDIO_PLAYBACK_STALE_MS = 7 * 24 * 60 * 60 * 1000` (= 604,800,000 ms = 7 days, matches your spec). - Stale check at line 67: `nowMs - savedAt > AUDIO_PLAYBACK_STALE_MS` — clamps offset path on stale entries per acceptance. - `createMinIntervalGate` (line 162) is the 4s throttle gate referenced in your commit notes. - `audioPlaybackState.test.ts`: 7 tests PASS in 4ms via `npx vitest run audioPlaybackState`. Note — your 4/26 comment links `skills/verify-yo-album-bgm-resume/SKILL.md`, which was removed during #100 cleanup. Migrated home is now [`manual-qa-checklists.md#manual-qa-issue-71`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/testing/manual-qa-checklists.md#manual-qa-issue-71). Just flagging in case you want to update the stale path; not blocking. cc @PlasticDigits
PlasticDigits commented 2026-05-02 04:34:26 +00:00 (Migrated from gitlab.com)

Yes update the stale path

Yes update the stale path
PlasticDigits commented 2026-05-02 04:37:08 +00:00 (Migrated from gitlab.com)

mentioned in commit 3806356154

mentioned in commit 3806356154d42ecb6638a0022be32b018a467409
PlasticDigits commented 2026-05-02 04:37:08 +00:00 (Migrated from gitlab.com)

mentioned in commit 06a94ad765

mentioned in commit 06a94ad765cc4f92fd017c7e7570960ab7e0632b
PlasticDigits commented 2026-05-02 04:37:15 +00:00 (Migrated from gitlab.com)

Doc fix merged (canonical #71 verification path)

Commit: 3806356 on main.

Change: Resolved the stale bookmark noted by @brouie — anything that pointed at the removed skills/verify-yo-album-bgm-resume/SKILL.md (#100) now documents Album 1 BGM resume — manual-qa-checklists.md#manual-qa-issue-71 as the only contributor/agent checklist. Cross-linked: skills/README.md, docs/agents/metadata-and-skills.md, invariants summary row + prose, sound-effects-recommendations.md §8, timecurve-views.md, guardrail #17 (Cursor skill).


@brouie please re-verify bookmarks and any saved links hit the anchor above (no 404 skill path).

Checklist for you

  • Open repo docs/testing/manual-qa-checklists.md § Album 1 BGM resume — anchor resolves in browser/GitLab UI.
  • skills/README.md contributor paragraph links #71 + notes removal of verify-yo-album skill.
  • No remaining references needed to GitLab blobs under skills/verify-yo-album-bgm-resume/ — use manual QA TOC row for #71 instead.
## Doc fix merged (canonical #71 verification path) **Commit:** `3806356` on `main`. **Change:** Resolved the stale bookmark noted by @brouie — anything that pointed at the removed **`skills/verify-yo-album-bgm-resume/SKILL.md`** ([#100](https://gitlab.com/PlasticDigits/yieldomega/-/issues/100)) now documents **[Album 1 BGM resume — `manual-qa-checklists.md#manual-qa-issue-71`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/testing/manual-qa-checklists.md#manual-qa-issue-71)** as the **only** contributor/agent checklist. Cross-linked: `skills/README.md`, `docs/agents/metadata-and-skills.md`, invariants summary row + prose, `sound-effects-recommendations.md` §8, `timecurve-views.md`, guardrail **#17** (Cursor skill). --- @brouie please re-verify bookmarks and any saved links hit the anchor above (no 404 skill path). ### Checklist for you - [ ] Open repo `docs/testing/manual-qa-checklists.md` § **Album 1 BGM resume** — anchor resolves in browser/GitLab UI. - [ ] `skills/README.md` contributor paragraph links **#71** + notes removal of verify-yo-album skill. - [ ] No remaining references needed to GitLab blobs under `skills/verify-yo-album-bgm-resume/` — use manual QA TOC row for **#71** instead.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-02 04:37:16 +00:00
PlasticDigits commented 2026-05-02 04:41:38 +00:00 (Migrated from gitlab.com)

mentioned in commit 33d8d07331

mentioned in commit 33d8d07331956bec569b92e18ca13ad1ea663625
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#71
No description provided.