docs: resolve Phase 18 OQ7 seek-index granularity to 0.5s buckets
This commit is contained in:
@@ -473,8 +473,8 @@ Settings menu** (not a bare app-bar control); OQ2 default → **Opus by default,
|
|||||||
network-awareness); OQ3 remembered → **persisted via the dark-mode seam** (cookie → prerender-read →
|
network-awareness); OQ3 remembered → **persisted via the dark-mode seam** (cookie → prerender-read →
|
||||||
`PersistentComponentState` → client cookie service); OQ4 → **always-on Opus + Backfill-Opus**; OQ5 →
|
`PersistentComponentState` → client cookie service); OQ4 → **always-on Opus + Backfill-Opus**; OQ5 →
|
||||||
**Ogg Opus**; OQ6 transcode model → **background job after the file is available, with a visible
|
**Ogg Opus**; OQ6 transcode model → **background job after the file is available, with a visible
|
||||||
Post-Processing phase on the CMS upload meter.** One new tuning OQ (OQ7: seek-index granularity — recommend
|
Post-Processing phase on the CMS upload meter.** OQ7 (seek-index granularity) → **0.5 s (half-second)
|
||||||
~1–2 s buckets) is non-blocking.
|
buckets** (~115 KB index for a 1-hour mix).
|
||||||
|
|
||||||
**Architectural spine — a derived artifact set + a delivery param + one new decoder + a precomputed
|
**Architectural spine — a derived artifact set + a delivery param + one new decoder + a precomputed
|
||||||
accurate seek index; leaf implementations only, zero changes to existing format code (the strong OCP
|
accurate seek index; leaf implementations only, zero changes to existing format code (the strong OCP
|
||||||
@@ -496,8 +496,8 @@ path on browsers that can't decode it.
|
|||||||
byte-offset seek and rough page interpolation are inadequate for VBR Opus — there is no linear time↔byte
|
byte-offset seek and rough page interpolation are inadequate for VBR Opus — there is no linear time↔byte
|
||||||
relationship. The fix is an **accurate transfer function built at transcode time** (the one moment the
|
relationship. The fix is an **accurate transfer function built at transcode time** (the one moment the
|
||||||
whole encoded stream is walked): a precomputed **seek index** mapping Ogg-page `granulepos` (48 kHz sample
|
whole encoded stream is walked): a precomputed **seek index** mapping Ogg-page `granulepos` (48 kHz sample
|
||||||
counts → time) → exact byte offset (recommend ~1–2 s buckets snapped to page starts; ~58 KB for a 1-hour
|
counts → time) → exact byte offset (**0.5 s buckets** snapped to page starts — OQ7; ~7,200 entries ×
|
||||||
mix). The decode **setup header** (`OpusHead`/`OpusTags`, needed to decode any mid-stream slice) is made
|
16 bytes ≈ ~115 KB for a 1-hour mix). The decode **setup header** (`OpusHead`/`OpusTags`, needed to decode any mid-stream slice) is made
|
||||||
available too. Recommended concrete design: **one sidecar artifact per track = `[setup header][seek
|
available too. Recommended concrete design: **one sidecar artifact per track = `[setup header][seek
|
||||||
index]`, built at transcode, stored beside the Opus bytes, fetched once on track load**, parsed into
|
index]`, built at transcode, stored beside the Opus bytes, fetched once on track load**, parsed into
|
||||||
`OpusSeekData`. Client seek flow: `calculateByteOffset(t)` binary-searches the index for the exact page
|
`OpusSeekData`. Client seek flow: `calculateByteOffset(t)` binary-searches the index for the exact page
|
||||||
@@ -554,8 +554,8 @@ bytes to serve, decode, or seek against until those artifacts exist.
|
|||||||
|
|
||||||
**Dependency shape:** `18.1 → 18.2 → {18.3 ∥ 18.4} → 18.5`; `18.6 ∥` (needs 18.3 for the live toggle);
|
**Dependency shape:** `18.1 → 18.2 → {18.3 ∥ 18.4} → 18.5`; `18.6 ∥` (needs 18.3 for the live toggle);
|
||||||
18.1 is the only cold-start wave. **Phase-level: 18 precedes Phase 21** (windowed refill consumes the Phase
|
18.1 is the only cold-start wave. **Phase-level: 18 precedes Phase 21** (windowed refill consumes the Phase
|
||||||
18 seek-index resolver). **OQ1–OQ6 RESOLVED (above); OQ7 (seek-index granularity, recommend ~1–2 s buckets)
|
18 seek-index resolver). **OQ1–OQ7 RESOLVED (above); OQ7 (seek-index granularity) = 0.5 s buckets.** None
|
||||||
is a non-blocking tuning steer.** None block 18.1.
|
block 18.1.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
Product spec. Status: **design / framing — open questions RESOLVED (Daniel, 2026-06-23); implementation-ready.**
|
Product spec. Status: **design / framing — open questions RESOLVED (Daniel, 2026-06-23); implementation-ready.**
|
||||||
Author: product-designer. Date: 2026-06-23. **No code has been written by this doc.**
|
Author: product-designer. Date: 2026-06-23. **No code has been written by this doc.**
|
||||||
|
|
||||||
> **Resolution pass (Daniel, 2026-06-23).** OQ1–OQ6 are resolved (see §6 — each marked RESOLVED, kept
|
> **Resolution pass (Daniel, 2026-06-23).** OQ1–OQ7 are resolved (see §6 — each marked RESOLVED, kept
|
||||||
> visible per file convention). Two resolutions reshaped the spec materially: (a) the listener quality
|
> visible per file convention; OQ7 — seek-index granularity — set to **0.5 s buckets**). Two resolutions
|
||||||
|
> reshaped the spec materially: (a) the listener quality
|
||||||
> selection lives inside a **new public-site Settings menu surface** (not a bare app-bar control) — §4 +
|
> selection lives inside a **new public-site Settings menu surface** (not a bare app-bar control) — §4 +
|
||||||
> §4a; and (b) Daniel rejected the "approximate page-interpolation" seek hand-wave outright — **VBR-safe
|
> §4a; and (b) Daniel rejected the "approximate page-interpolation" seek hand-wave outright — **VBR-safe
|
||||||
> *accurate* seeking is now a first-class part of the architecture** (a precomputed seek-index artifact +
|
> *accurate* seeking is now a first-class part of the architecture** (a precomputed seek-index artifact +
|
||||||
@@ -329,15 +330,17 @@ estimated.
|
|||||||
fixed-width records is the natural shape (e.g. a `uint64 granulepos` + `uint64 byteOffset` per entry);
|
fixed-width records is the natural shape (e.g. a `uint64 granulepos` + `uint64 byteOffset` per entry);
|
||||||
the exact encoding is staff-engineer's, but it should be a **compact binary blob**, fetched once and
|
the exact encoding is staff-engineer's, but it should be a **compact binary blob**, fetched once and
|
||||||
parsed into a typed array client-side.
|
parsed into a typed array client-side.
|
||||||
- **Granularity vs. size (the one real tuning knob).** One entry per Ogg page is the most precise but
|
- **Granularity vs. size — RESOLVED: 0.5 s (half-second) buckets (Daniel, 2026-06-23).** One entry per
|
||||||
largest; an Ogg page is typically a few KB of audio (~tens of ms to a few hundred ms), so a 1-hour mix
|
Ogg page is the most precise but largest; an Ogg page is typically a few KB of audio (~tens of ms to a
|
||||||
could be tens of thousands of pages. Recommend a **coarser bucket: one index entry per ~1–2 seconds of
|
few hundred ms), so a 1-hour mix could be tens of thousands of pages. The chosen bucket is **one index
|
||||||
audio** (snap each bucket boundary to the *nearest enclosing page start*, so every indexed offset is
|
entry per 0.5 seconds of audio** (snap each bucket boundary to the *nearest enclosing page start*, so
|
||||||
still an exact page boundary). At ~1 s granularity a 1-hour mix is ~3,600 entries × 16 bytes ≈ **~58 KB**
|
every indexed offset is still an exact page boundary). At 0.5 s granularity a 1-hour mix is
|
||||||
— a trivial one-time fetch, and 1 s seek resolution is more than fine (the decoder re-syncs to the exact
|
~7,200 entries × 16 bytes ≈ **~115 KB** — still a trivial one-time fetch, and 0.5 s seek resolution is
|
||||||
page within the bucket anyway — see the client flow). **Per-page precision is the fallback if 1 s buckets
|
finer than required (the decoder re-syncs to the exact page within the bucket anyway — see the client
|
||||||
ever prove too coarse**, at a larger index. The number is staff-engineer's call; the *shape* (precomputed
|
flow — so the in-bucket trim is *sub-half-second*, tighter than the earlier ~1–2 s recommendation).
|
||||||
exact granule→byte, bucketed, snapped to page starts) is fixed.
|
**Per-page precision remains the fallback if 0.5 s buckets ever prove too coarse**, at a larger index.
|
||||||
|
The bucket size is now fixed; the *shape* (precomputed exact granule→byte, bucketed, snapped to page
|
||||||
|
starts) is unchanged.
|
||||||
- **Sidecar, not embedded (recommended).** Store the index as a **third derived artifact** alongside the
|
- **Sidecar, not embedded (recommended).** Store the index as a **third derived artifact** alongside the
|
||||||
Opus bytes and the waveform datum — the same "derived artifacts get their own vault" pattern this phase
|
Opus bytes and the waveform datum — the same "derived artifacts get their own vault" pattern this phase
|
||||||
already uses (S2 / `track-opus`; the `track-waveforms` precedent). Keep it a separate vault resource
|
already uses (S2 / `track-opus`; the `track-waveforms` precedent). Keep it a separate vault resource
|
||||||
@@ -395,8 +398,8 @@ With the sidecar (`OpusSeekData` = setup header + granule→byte index) fetched
|
|||||||
page start, the stream is immediately Ogg-sync-aligned.
|
page start, the stream is immediately Ogg-sync-aligned.
|
||||||
4. **Fine re-sync within the bucket.** The granule of the first decoded page tells the decoder the *exact*
|
4. **Fine re-sync within the bucket.** The granule of the first decoded page tells the decoder the *exact*
|
||||||
time it landed at (≤ the bucket granularity ahead of `t`); the scheduler trims/positions to land
|
time it landed at (≤ the bucket granularity ahead of `t`); the scheduler trims/positions to land
|
||||||
playback at `t` precisely. With ~1 s buckets the trim is sub-second; with per-page granularity it is
|
playback at `t` precisely. With 0.5 s buckets the trim is sub-half-second; with per-page granularity it
|
||||||
near-zero. **Either way the listener lands at the correct time, not approximately** (AC9).
|
is near-zero. **Either way the listener lands at the correct time, not approximately** (AC9).
|
||||||
|
|
||||||
#### D. Composition with Phase 21 windowed refill
|
#### D. Composition with Phase 21 windowed refill
|
||||||
|
|
||||||
@@ -581,9 +584,9 @@ the "one source, multiple views" / design-for-adaptability discipline applied to
|
|||||||
|
|
||||||
## 6. Open questions — RESOLVED (Daniel, 2026-06-23)
|
## 6. Open questions — RESOLVED (Daniel, 2026-06-23)
|
||||||
|
|
||||||
All six original open questions are resolved. Kept visible per file convention, each with the decision and
|
All seven open questions are resolved. Kept visible per file convention, each with the decision and
|
||||||
the section that now carries it. One new open question (OQ7) is raised by the seek-model design; it is a
|
the section that now carries it. OQ7 (raised by the seek-model design) is a narrow tuning call, now set to
|
||||||
narrow tuning/scoping call, not a blocker.
|
0.5 s buckets.
|
||||||
|
|
||||||
- **OQ1 — Selection UX — RESOLVED: global, via a Settings *menu* (not a bare app-bar control).** Daniel:
|
- **OQ1 — Selection UX — RESOLVED: global, via a Settings *menu* (not a bare app-bar control).** Daniel:
|
||||||
*"Global is perfect, but we need a menu system for settings, don't just slap the quality control directly
|
*"Global is perfect, but we need a menu system for settings, don't just slap the quality control directly
|
||||||
@@ -612,15 +615,15 @@ narrow tuning/scoping call, not a blocker.
|
|||||||
track is lossless-only until its Opus finishes — accepted, and now made visible rather than implicit.
|
track is lossless-only until its Opus finishes — accepted, and now made visible rather than implicit.
|
||||||
`[RESOLVED — §3.1a]`
|
`[RESOLVED — §3.1a]`
|
||||||
|
|
||||||
**New open question raised by the seek-model design (§3.4a) — narrow, non-blocking:**
|
**New open question raised by the seek-model design (§3.4a) — RESOLVED:**
|
||||||
|
|
||||||
- **OQ7 — Seek-index granularity (tuning, leans implementation).** The seek index trades precision against
|
- **OQ7 — Seek-index granularity — RESOLVED: 0.5 s (half-second) buckets (Daniel, 2026-06-23).** The seek
|
||||||
size: per-Ogg-page (most precise, largest) vs. coarser time buckets snapped to page starts. Recommend
|
index trades precision against size: per-Ogg-page (most precise, largest) vs. coarser time buckets snapped
|
||||||
**~1–2 s buckets** (~58 KB for a 1-hour mix at 1 s; the decoder fine-re-syncs within the bucket so seek
|
to page starts. Daniel set the bucket at **0.5 s** (finer than the ~1–2 s the spec had recommended):
|
||||||
*accuracy* is unaffected — only the in-bucket trim distance changes). This is largely staff-engineer's
|
~7,200 entries × 16 bytes ≈ **~115 KB** for a 1-hour mix — still a trivial one-time fetch. The decoder
|
||||||
call at implementation; flagged because the *number* is a deliberate choice and Daniel may have a feel
|
fine-re-syncs within the bucket so seek *accuracy* is unaffected; at 0.5 s the in-bucket trim is
|
||||||
for acceptable index size vs. in-bucket trim. Does **not** block — the shape (precomputed exact
|
sub-half-second, tighter than before. The shape (precomputed exact granule→byte, page-snapped) is
|
||||||
granule→byte, page-snapped) is fixed regardless of the bucket size. `[Daniel steer — not a blocker]`
|
unchanged. `[RESOLVED — §3.4a A]`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -652,7 +655,7 @@ narrow tuning/scoping call, not a blocker.
|
|||||||
the client fetches and parses it once on track load (into `OpusSeekData`) before issuing any seek.
|
the client fetches and parses it once on track load (into `OpusSeekData`) before issuing any seek.
|
||||||
- **AC9 (the seek-accuracy criterion) — an Opus seek lands at the *correct* time, not approximately.**
|
- **AC9 (the seek-accuracy criterion) — an Opus seek lands at the *correct* time, not approximately.**
|
||||||
Seeking to time `t` in an Opus stream resolves via the precomputed index and lands playback at `t`
|
Seeking to time `t` in an Opus stream resolves via the precomputed index and lands playback at `t`
|
||||||
(within the fine-resync tolerance — sub-second at the recommended bucket granularity), **measurably
|
(within the fine-resync tolerance — sub-half-second at the chosen 0.5 s bucket granularity), **measurably
|
||||||
accurate**, not a `byteRate`/interpolation estimate. Verifiable: seek to a known marker (e.g. a downbeat
|
accurate**, not a `byteRate`/interpolation estimate. Verifiable: seek to a known marker (e.g. a downbeat
|
||||||
at a known timestamp) and confirm playback resumes there, not seconds off. This holds **without** the
|
at a known timestamp) and confirm playback resumes there, not seconds off. This holds **without** the
|
||||||
full PCM decoded in memory (composes with Phase 21).
|
full PCM decoded in memory (composes with Phase 21).
|
||||||
|
|||||||
Reference in New Issue
Block a user