diff --git a/docs/00_overview/DASHBOARD.md b/docs/00_overview/DASHBOARD.md index 9cdc0741..3f215565 100644 --- a/docs/00_overview/DASHBOARD.md +++ b/docs/00_overview/DASHBOARD.md @@ -6,8 +6,8 @@ _Top-level index across MVP1 → GA v1+ as of **2026-06-04**. Click a release na | Release | Theme | Progress | Status | |---|---|---|---| -| [MVP1 / v0.1](MVP1_DASHBOARD.md) | The Loop | 94 / 94 scoped done | **Complete** | -| [MVP2 / v0.2](MVP2_DASHBOARD.md) | Three-Engine + Real Signals | 18 / 28 scoped done · 26 remaining | **In progress** | +| [MVP1 / v0.1](MVP1_DASHBOARD.md) | The Loop | 95 / 95 scoped done | **Complete** | +| [MVP2 / v0.2](MVP2_DASHBOARD.md) | Three-Engine + Real Signals | 18 / 27 scoped done · 25 remaining | **In progress** | | MVP3 / v0.3 | Observable | — | **Not yet scoped** | | GA v1 / v1.0 | Production-ready | — | **Not yet scoped** | diff --git a/docs/00_overview/MVP1_DASHBOARD.md b/docs/00_overview/MVP1_DASHBOARD.md index 80e3affe..2efb3c32 100644 --- a/docs/00_overview/MVP1_DASHBOARD.md +++ b/docs/00_overview/MVP1_DASHBOARD.md @@ -14,8 +14,8 @@ Pull from the Idea backlog or capture a new feature spec. | Metric | Value | |---|---| -| Filed under MVP1 | **130** folders total (done + specced not-done + idea backlog + bugs) | -| Specced features done | **94 / 94** (100%) — of features *past the idea stage* (those with a spec); the idea backlog below is NOT in this denominator, so 100% ≠ release complete | +| Filed under MVP1 | **131** folders total (done + specced not-done + idea backlog + bugs) | +| Specced features done | **95 / 95** (100%) — of features *past the idea stage* (those with a spec); the idea backlog below is NOT in this denominator, so 100% ≠ release complete | | Pending work | **0** items (every not-done feat/infra/chore/bug across all priorities) | | → P0 — do next | **0** unblocking / paying daily cost | | → P1 | **0** high-value, ready when P0 clears | @@ -28,7 +28,7 @@ Pull from the Idea backlog or capture a new feature spec. ## Pipeline -### Done (130) +### Done (131) | Feature | Type | One-liner | Depends on | Status | |---|---|---|---|---| @@ -62,6 +62,7 @@ Pull from the Idea backlog or capture a new feature spec. | [feat_study_lifecycle](implemented_features/2026_05_10_feat_study_lifecycle/feature_spec.md) | Feature | A relevance engineer creates a study via API or chat, the orchestrator enqueues N parallel `run_trial` jobs, trials accumulate in real time on the study detail page, the orchestrator detects stop-cond | — | [PR #18](https://github.com/SoundMindsAI/relyloop/pull/18) merged 2026-05-10 | | [feat_study_preflight_overlap_probe](implemented_features/2026_05_22_feat_study_preflight_overlap_probe/feature_spec.md) | Feature | `POST /api/v1/studies` issues a single bounded `ids`-existence query against the study's target asking "for the *first* query in the query set that has any judgments (chosen deterministically by `id A | — | [PR #193](https://github.com/SoundMindsAI/relyloop/pull/193) merged 2026-05-21 | | [feat_study_target_judgment_mismatch_guard](implemented_features/2026_05_21_feat_study_target_judgment_mismatch_guard/feature_spec.md) | Feature | `POST /api/v1/studies` rejects the mismatch at create time with a specific machine-readable error code (`JUDGMENT_TARGET_MISMATCH`, 422). | — | [PR #184](https://github.com/SoundMindsAI/relyloop/pull/184) merged 2026-05-21 | +| [feat_walkthrough_video_cursor_captions](implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/feature_spec.md) | Feature | All 10 walkthrough videos are re-recorded with (1) a visible **synthetic arrow cursor** that glides to each target and pulses on click, (2) **smoother, human-paced** motion, and (3) **WebVTT step capt | — | [PR #451](https://github.com/SoundMindsAI/relyloop/pull/451) merged 2026-06-04 | | [infra_adapter_elastic](implemented_features/2026_05_10_infra_adapter_elastic/feature_spec.md) | Infra | A single `ElasticAdapter` implements the `SearchAdapter` Protocol and serves both Elasticsearch (8.11+ / 9.x) and OpenSearch (2.x / 3.x), distinguished by a `engine_type` column. | — | [PR #16](https://github.com/SoundMindsAI/relyloop/pull/16) merged 2026-05-10 | | [infra_ci_smoke_makeup](implemented_features/2026_05_13_infra_ci_smoke_makeup/idea.md) | Infra | CI runs `make test-unit && make test-integration && make test-contract` against a service-container Postgres on `localhost:5432` — a synthetic environment that masks every real-world `make up` failure | — | Complete | | [infra_dashboard_regen_pre_commit_conflict](implemented_features/2026_05_14_infra_dashboard_regen_pre_commit_conflict/idea.md) | Infra | The pre-commit pipeline does: | — | Complete | @@ -378,6 +379,8 @@ graph LR class chore_e2e_api_base_url_construction done; chore_state_md_size_compression["state md size compression"] class chore_state_md_size_compression done; + feat_walkthrough_video_cursor_captions["walkthrough video cursor captions"] + class feat_walkthrough_video_cursor_captions done; feat_study_lifecycle --> feat_digest_proposal feat_llm_judgments --> feat_digest_proposal infra_foundation --> feat_llm_judgments diff --git a/docs/00_overview/MVP2_DASHBOARD.md b/docs/00_overview/MVP2_DASHBOARD.md index 0296ca36..33fa1a4a 100644 --- a/docs/00_overview/MVP2_DASHBOARD.md +++ b/docs/00_overview/MVP2_DASHBOARD.md @@ -20,15 +20,15 @@ Plan approved; run /impl-execute to ship | Metric | Value | |---|---| -| Filed under MVP2 | **50** folders total (done + specced not-done + idea backlog + bugs) | -| Specced features done | **18 / 28** (64%) — of features *past the idea stage* (those with a spec); the idea backlog below is NOT in this denominator, so 100% ≠ release complete | -| Pending work | **30** items (every not-done feat/infra/chore/bug across all priorities) | +| Filed under MVP2 | **49** folders total (done + specced not-done + idea backlog + bugs) | +| Specced features done | **18 / 27** (67%) — of features *past the idea stage* (those with a spec); the idea backlog below is NOT in this denominator, so 100% ≠ release complete | +| Pending work | **29** items (every not-done feat/infra/chore/bug across all priorities) | | → P0 — do next | **0** unblocking / paying daily cost | | → P1 | **0** high-value, ready when P0 clears | -| → P2 (default) | 26 important to file, not blocking | +| → P2 (default) | 25 important to file, not blocking | | → Backlog | 4 captured for record, not planned | | Open bugs | 9 | -| Legacy "Path to MVP2" | 26 items — scoped-not-done + bugs + chore-ideas only (excludes feat/infra ideas) | +| Legacy "Path to MVP2" | 25 items — scoped-not-done + bugs + chore-ideas only (excludes feat/infra ideas) | | Backlog ideas | 4 idea-only feat/infra (not yet scoped into MVP2) | | In flight | 0 feature(s) actively shipping | @@ -63,7 +63,7 @@ Plan approved; run /impl-execute to ship _None._ -### Plan (12) +### Plan (11) | # | Priority | Feature | Type | One-liner | Depends on | Status | |---|---|---|---|---|---|---| @@ -71,14 +71,13 @@ _None._ | 2 | P2 | [feat_query_normalization_tuning](planned_features/02_mvp2/feat_query_normalization_tuning/feature_spec.md) | Feature | A template that opts in by declaring `query_normalizer` as a Categorical param gets the Optuna loop deciding empirically — on the operator's judgment set — whether lowercasing, trimming, or contractio | — | — | | 3 | P2 | [feat_query_normalizer_typed_pipeline](planned_features/02_mvp2/feat_query_normalizer_typed_pipeline/feature_spec.md) | Feature | A new typed search-space member `NormalizerPipelineParam` lets a template declare an **ordered list of normalization steps**; the Optuna loop samples over the powerset of declared steps and proposes t | — | — | | 4 | P2 | [feat_ubi_llm_study_comparison](planned_features/02_mvp2/feat_ubi_llm_study_comparison/feature_spec.md) | Feature | A single dedicated route `/studies/compare?a={id}&b={id}` renders the two studies side-by-side with a per-panel diff column: a sentence-level digest-narrative diff, a best-trial parameter table with s | — | [PR #320](https://github.com/SoundMindsAI/relyloop/pull/320) | -| 5 | P2 | [feat_walkthrough_video_cursor_captions](planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/feature_spec.md) | Feature | All 10 walkthrough videos are re-recorded with (1) a visible **synthetic arrow cursor** that glides to each target and pulses on click, (2) **smoother, human-paced** motion, and (3) **WebVTT step capt | — | [PR #448](https://github.com/SoundMindsAI/relyloop/pull/448) | -| 6 | P2 | [chore_arq_pool_aclose_deprecation](planned_features/02_mvp2/chore_arq_pool_aclose_deprecation/feature_spec.md) | Chore | Both call sites use `await arq_pool.aclose()`; no `DeprecationWarning` on shutdown; a regression guard asserts the async-correct form on both paths so a future edit cannot silently reintroduce `close( | — | — | -| 7 | P2 | [chore_cluster_detail_rung_badge](planned_features/02_mvp2/chore_cluster_detail_rung_badge/feature_spec.md) | Chore | The cluster-detail page surfaces a `` for the cluster, scoped by a user-selected (or auto-seeded) query set + target. | — | [PR #320](https://github.com/SoundMindsAI/relyloop/pull/320) | -| 8 | P2 | [chore_demo_seeding_integration_tests_rewrite](planned_features/02_mvp2/chore_demo_seeding_integration_tests_rewrite/feature_spec.md) | Chore | The 9 skipped cases are rewritten to the async "POST + poll-until-terminal" shape, the timeout case is re-homed to the worker layer, a new `AC-Async` case asserts the `running → complete` polling tran | — | [PR #286](https://github.com/SoundMindsAI/relyloop/pull/286) | -| 9 | P2 | [chore_studies_post_arq_spy_fixture](planned_features/02_mvp2/chore_studies_post_arq_spy_fixture/feature_spec.md) | Chore | A reusable `arq_pool_spy` integration fixture that records every `enqueue_job(name, *args)` call, letting studies-POST tests positively assert `spy.calls == []` on rejection and `spy.calls == [("start | — | — | -| 10 | P2 | [chore_ubi_reader_search_after_pagination](planned_features/02_mvp2/chore_ubi_reader_search_after_pagination/feature_spec.md) | Chore | A new engine-neutral `SearchAdapter.scan_all` cursor-scan lets `UbiReader` iterate the **entire** matching event/query stream for a window (subject to a caller ceiling), folding each page into the agg | — | [PR #413](https://github.com/SoundMindsAI/relyloop/pull/413) | -| 11 | P2 | [bug_baseline_phase_test_isolation](planned_features/02_mvp2/bug_baseline_phase_test_isolation/feature_spec.md) | Bug | The three `TestComputeBaselineWaitS` cases pass standalone — `.venv/bin/python -m pytest backend/tests/unit/workers/test_orchestrator_baseline_phase.py -p no:randomly` is all-green with no reliance on | — | — | -| 12 | P2 | [bug_judgment_header_omits_click_bucket](planned_features/02_mvp2/bug_judgment_header_omits_click_bucket/feature_spec.md) | Bug | The header renders all three buckets (`llm`, `human`, `click`) so the displayed terms sum to the displayed total count, making the doc-comment claim ("the UI's source-breakdown card now renders all th | — | — | +| 5 | P2 | [chore_arq_pool_aclose_deprecation](planned_features/02_mvp2/chore_arq_pool_aclose_deprecation/feature_spec.md) | Chore | Both call sites use `await arq_pool.aclose()`; no `DeprecationWarning` on shutdown; a regression guard asserts the async-correct form on both paths so a future edit cannot silently reintroduce `close( | — | — | +| 6 | P2 | [chore_cluster_detail_rung_badge](planned_features/02_mvp2/chore_cluster_detail_rung_badge/feature_spec.md) | Chore | The cluster-detail page surfaces a `` for the cluster, scoped by a user-selected (or auto-seeded) query set + target. | — | [PR #320](https://github.com/SoundMindsAI/relyloop/pull/320) | +| 7 | P2 | [chore_demo_seeding_integration_tests_rewrite](planned_features/02_mvp2/chore_demo_seeding_integration_tests_rewrite/feature_spec.md) | Chore | The 9 skipped cases are rewritten to the async "POST + poll-until-terminal" shape, the timeout case is re-homed to the worker layer, a new `AC-Async` case asserts the `running → complete` polling tran | — | [PR #286](https://github.com/SoundMindsAI/relyloop/pull/286) | +| 8 | P2 | [chore_studies_post_arq_spy_fixture](planned_features/02_mvp2/chore_studies_post_arq_spy_fixture/feature_spec.md) | Chore | A reusable `arq_pool_spy` integration fixture that records every `enqueue_job(name, *args)` call, letting studies-POST tests positively assert `spy.calls == []` on rejection and `spy.calls == [("start | — | — | +| 9 | P2 | [chore_ubi_reader_search_after_pagination](planned_features/02_mvp2/chore_ubi_reader_search_after_pagination/feature_spec.md) | Chore | A new engine-neutral `SearchAdapter.scan_all` cursor-scan lets `UbiReader` iterate the **entire** matching event/query stream for a window (subject to a caller ceiling), folding each page into the agg | — | [PR #413](https://github.com/SoundMindsAI/relyloop/pull/413) | +| 10 | P2 | [bug_baseline_phase_test_isolation](planned_features/02_mvp2/bug_baseline_phase_test_isolation/feature_spec.md) | Bug | The three `TestComputeBaselineWaitS` cases pass standalone — `.venv/bin/python -m pytest backend/tests/unit/workers/test_orchestrator_baseline_phase.py -p no:randomly` is all-green with no reliance on | — | — | +| 11 | P2 | [bug_judgment_header_omits_click_bucket](planned_features/02_mvp2/bug_judgment_header_omits_click_bucket/feature_spec.md) | Bug | The header renders all three buckets (`llm`, `human`, `click`) so the displayed terms sum to the displayed total count, making the doc-comment claim ("the UI's source-breakdown card now renders all th | — | — | ### Spec (0) @@ -136,8 +135,6 @@ graph LR class feat_query_normalizer_typed_pipeline plan; feat_ubi_llm_study_comparison["ubi llm study comparison"] class feat_ubi_llm_study_comparison plan; - feat_walkthrough_video_cursor_captions["walkthrough video cursor captions"] - class feat_walkthrough_video_cursor_captions plan; feat_contextual_help_mvp2["contextual help mvp2"] class feat_contextual_help_mvp2 done; feat_study_sub_warmup_guard["study sub warmup guard"] diff --git a/docs/00_overview/dashboard.html b/docs/00_overview/dashboard.html index 77934d3f..dc3ca60b 100644 --- a/docs/00_overview/dashboard.html +++ b/docs/00_overview/dashboard.html @@ -384,7 +384,7 @@

Releases

The Loop
-
94 / 94 scoped done
+
95 / 95 scoped done
Complete
@@ -392,7 +392,7 @@

Releases

Three-Engine + Real Signals
-
18 / 28 scoped done · 26 remaining
+
18 / 27 scoped done · 25 remaining
In progress
diff --git a/docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/feature_spec.md b/docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/feature_spec.md similarity index 100% rename from docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/feature_spec.md rename to docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/feature_spec.md diff --git a/docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/idea.md b/docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/idea.md similarity index 100% rename from docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/idea.md rename to docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/idea.md diff --git a/docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/implementation_plan.md b/docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/implementation_plan.md similarity index 100% rename from docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/implementation_plan.md rename to docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/implementation_plan.md diff --git a/docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/pipeline_status.md b/docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/pipeline_status.md similarity index 69% rename from docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/pipeline_status.md rename to docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/pipeline_status.md index ae0be559..66fecc8e 100644 --- a/docs/00_overview/planned_features/02_mvp2/feat_walkthrough_video_cursor_captions/pipeline_status.md +++ b/docs/00_overview/implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/pipeline_status.md @@ -28,4 +28,10 @@ - Phases covered: single phase (all of spec scope) ## Implementation -- Status: Not started +- Status: Complete — merged to main as PR #451 (squash `199a3ed5`), 2026-06-04 +- All 7 stories implemented; all 10 decks re-recorded operator-path (video-only). +- Post-PR review: Gemini + CodeQL 5 findings accepted; final GPT-5.5 1 finding rejected (golden corpus committed `f71d0e70`, partial-diff false positive). CodeQL clean ("No new alerts"). +- Gates: 1154 vitest · 61 build_guides pytest · 13 freshness self-test · asset-ref guard (30 refs) · mkdocs build --strict · reuse lint. All 18 pr.yml checks green. + +## Done +- Status: Complete. Folder moved to `implemented_features/2026_06_04_feat_walkthrough_video_cursor_captions/` (this finalization PR). diff --git a/docs/00_overview/mvp1_dashboard.html b/docs/00_overview/mvp1_dashboard.html index f616d0ec..f9fe13cb 100644 --- a/docs/00_overview/mvp1_dashboard.html +++ b/docs/00_overview/mvp1_dashboard.html @@ -397,8 +397,8 @@

MVP1 Progress

Specced features done
-
94 / 94
-
100% specced · 130 filed under MVP1
+
95 / 95
+
100% specced · 131 filed under MVP1
@@ -483,7 +483,7 @@

Implementing 0

-

Done 130

+

Done 131

@@ -875,6 +875,19 @@

Done 130

+
+ +
+ Feature + + PR #451 merged 2026-06-04 +
+
All 10 walkthrough videos are re-recorded with (1) a visible **synthetic arrow cursor** that glides to each target and pulses on click, (2) **smoother, human-paced** motion, and (3) **WebVTT step capt
+ + +
+ +
@@ -2375,6 +2388,8 @@

Dependency graph (feat_ + infra_)

class chore_e2e_api_base_url_construction done; chore_state_md_size_compression["state md size compression"] class chore_state_md_size_compression done; + feat_walkthrough_video_cursor_captions["walkthrough video cursor captions"] + class feat_walkthrough_video_cursor_captions done; feat_study_lifecycle --> feat_digest_proposal feat_llm_judgments --> feat_digest_proposal infra_foundation --> feat_llm_judgments @@ -2616,6 +2631,8 @@

Dependency graph (feat_ + infra_)

class chore_e2e_api_base_url_construction done; chore_state_md_size_compression["state md size compression"] class chore_state_md_size_compression done; + feat_walkthrough_video_cursor_captions["walkthrough video cursor captions"] + class feat_walkthrough_video_cursor_captions done; feat_study_lifecycle --> feat_digest_proposal feat_llm_judgments --> feat_digest_proposal infra_foundation --> feat_llm_judgments diff --git a/docs/00_overview/mvp2_dashboard.html b/docs/00_overview/mvp2_dashboard.html index b4d50641..5a6e5915 100644 --- a/docs/00_overview/mvp2_dashboard.html +++ b/docs/00_overview/mvp2_dashboard.html @@ -397,13 +397,13 @@

MVP2 Progress

Specced features done
-
18 / 28
-
64% specced · 50 filed under MVP2
-
+
18 / 27
+
67% specced · 49 filed under MVP2
+
Pending work
-
30
+
29
every not-done feat/infra/chore/bug across all priorities
@@ -425,7 +425,7 @@

MVP2 Progress

P2 (default)
-
26
+
25
important to file, not blocking
@@ -435,7 +435,7 @@

MVP2 Progress

Legacy "Path to MVP2"
-
26
+
25
scoped not-done + bugs + chore-ideas only (excludes feat/infra ideas)
@@ -706,7 +706,7 @@

Spec 0

-

Plan 12

+

Plan 11

@@ -760,19 +760,6 @@

Plan 12

-
- -
- Feature - P2 - PR #448 -
-
All 10 walkthrough videos are re-recorded with (1) a visible **synthetic arrow cursor** that glides to each target and pulses on click, (2) **smoother, human-paced** motion, and (3) **WebVTT step capt
- - -
- -
@@ -1163,8 +1150,6 @@

Dependency graph (feat_ + infra_)

class feat_query_normalizer_typed_pipeline plan; feat_ubi_llm_study_comparison["ubi llm study comparison"] class feat_ubi_llm_study_comparison plan; - feat_walkthrough_video_cursor_captions["walkthrough video cursor captions"] - class feat_walkthrough_video_cursor_captions plan; feat_contextual_help_mvp2["contextual help mvp2"] class feat_contextual_help_mvp2 done; feat_study_sub_warmup_guard["study sub warmup guard"] @@ -1226,8 +1211,6 @@

Dependency graph (feat_ + infra_)

class feat_query_normalizer_typed_pipeline plan; feat_ubi_llm_study_comparison["ubi llm study comparison"] class feat_ubi_llm_study_comparison plan; - feat_walkthrough_video_cursor_captions["walkthrough video cursor captions"] - class feat_walkthrough_video_cursor_captions plan; feat_contextual_help_mvp2["contextual help mvp2"] class feat_contextual_help_mvp2 done; feat_study_sub_warmup_guard["study sub warmup guard"] diff --git a/state.md b/state.md index 0c96dac7..335835dd 100644 --- a/state.md +++ b/state.md @@ -26,16 +26,16 @@ MVP1 (v0.1) **shipped** — all six differentiators live (Bayesian/TPE optimizer Detail + reasoning for each is in [`state_history.md`](state_history.md). +- **2026-06-04** — `feat_walkthrough_video_cursor_captions` (PR #451, squash-merged `199a3ed5`). **Synthetic cursor + smoother pacing + WebVTT step captions on the 10 walkthrough videos.** A polish pass on the videos shown on relyloop.com (and the in-app ``): a synthetic white-fill/dark-outline SVG **arrow cursor** that glides to each control + pulses on click (Playwright video records no OS cursor), **smoother stepped pacing** (`slowMo` 350→60 + explicit per-target glide-and-dwell), and on-screen **WebVTT step captions** sourced from each deck's `metadata.json` `screenshots[].caption` (same text under the page screenshots, so video + screenshot captions can't drift). **Website + test-tooling only — NO backend, NO DB, NO API, NO in-app frontend, NO migration** (head stays `0022`). 7 stories / 3 epics: Epic 1 = the recorder side — pure Node-safe `captions-vtt.ts` formatter (unit-tested by vitest; `normalizeCaption` strips the `-->` cue separator via literal `split/join`, `escapeVttCueText` escapes `&`/`<`/`>`, `buildCaptionsVtt` emits strictly-increasing cues w/ `end=next start`, last `+4000ms` tail) + `demo-cursor.ts` Playwright glue (`installCursor` via `addInitScript` w/ `window.__mh` guard + DOMContentLoaded-deferred attach; resilient `glide` try/catch; `StepTimer`; `shot()` no-ops under `DEMO_VIDEO_ONLY` + try/finally cursor-restore; `loadStepCaptions` all-or-nothing classifier; `writeCaptionsVtt` slug-validated; `finalizeCaptions` collapses the 10 specs' end-block boilerplate) adopted in all 10 guide specs. Epic 2 = the generator side — `build_video_block(+has_vtt)` emits ``, `copy_deck_assets` copies `captions.vtt`, `verify_captions_consistency` fails loud on cue text/count drift **and** on a captions-in-metadata-but-missing-vtt deck (mirrors the all-or-nothing record contract); TS↔Python transform parity locked by a shared `captions-vtt-golden.json` corpus asserted by BOTH vitest + pytest; runbook section. Epic 3 = operator-path re-record of all 10 decks (fresh `walkthrough.webm` + iOS-safe `walkthrough.mp4` + `captions.vtt`) + website regen. Also fixed a pre-existing footgun in `09_generate_judgments_llm.spec.ts` (UBI-readiness auto-select could hide `#gen-template`; spec now forces `method=LLM-as-judge` after a deterministic `waitForResponse` on the readiness probe) + added `**/*.vtt` to `REUSE.toml` (WebVTT can't carry an inline SPDX header). Cross-model: spec 14 findings + plan 6 findings GPT-5.5 converged; phase-gate GPT-5.5 4 accepted (zero-caption path, `mark()` signature, vtt WEBVTT-header requirement, `shot` try/finally); Gemini + CodeQL 5 accepted (2 high-sev `js/bad-tag-filter` cleared via literal split; fail-loud consistency gap; `finalizeCaptions` DRY ×10; `waitForResponse` over fixed sleep); final GPT-5.5 1 rejected (golden corpus exists, committed `f71d0e70` — partial-diff false positive). 1154 vitest + 61 build_guides pytest + 13 freshness self-test; CodeQL clean ("No new alerts"). All 18 `pr.yml` checks green; CodeQL/Scorecard posture reds are pre-existing (created 2026-05-31, unrelated files). - **2026-06-04** — `feat_website_walkthrough_guides` (PR #448, squash-merged `36932256`). **Walkthrough guides on the public website (relyloop.com).** Surfaces the in-repo walkthrough decks + long-form guides — previously visible only in the running app — on the public MkDocs site under a new top-level **Guides** nav tab (Walkthroughs: 10 screenshot/video decks; In-depth: 4 long-form guides). **Website + tooling only — NO backend, NO DB, NO API, NO in-app frontend, NO migration** (head stays `0022`). Core is a **stdlib-only** Python generator (`website/scripts/build_guides.py`) that mirrors `ui/public/guides//*` + `docs/08_guides/*.md` into `website/docs/guides/**` + `website/docs/assets/guides/**` + a managed `Guides:` nav fragment between BEGIN/END sentinels in `mkdocs.yml` (rest of nav stays hand-written) — same single-direction-mirror + prune discipline as `ui/scripts/copy-docs.mjs`. 11 stories / 2 epics: Epic 1 = the generator (`discover_decks` slug-sorted single sort point + locked `walkthrough.webm` + path-traversal-safe slug/screenshot validation; `emit_deck_page` + card-grid indexes w/ `{.glightbox-skip}` thumbnails; `build_video_block` MP4-source-first + sibling iOS download link; `rewrite_link` urlsplit-based passthrough/anchor/intra-list/off-site-blob-or-tree w/ path-existence check + full-text scan handling line-spanning + nested-`[id]` link text + fail-loud on unresolved/unmapped/unsupported-syntax; `run_transcode_pass` `--transcode` w/ `-y -pix_fmt yuv420p +faststart -f mp4` + temp/atomic-rename; `prune_all` 3 generator-owned dirs; YAML single-quote nav encoder + anchor/marker-order validation + byte-stable splice). Epic 2 = `.github/workflows/build-guides-freshness.yml` (own workflow, NO paths-ignore — escapes `pr.yml`'s `website/**` filter — runs generator unit tests + 4-case self-test + freshness gate + `mkdocs build --strict` PR-time); `scripts/ci/{verify,test_verify}_build_guides_fresh.sh` (gate + harness; MP4 excluded from the gate scope per D-2/D-18); `regen-generated-artifacts.sh` 4th step; `mkdocs-glightbox==0.5.2` + `extra.css`; `install.md`/`quickstart.md` outbound GitHub-blob links de-duped to in-site (AC-11); runbook + testing.md + CLAUDE.md docs. `mkdocs build --strict` caught two real link-rewriter bugs (line-wrapped `[smoke\ntest](url)` + `[id]` nested brackets) — fixed + regression-tested. Cross-model: spec 3-cycle (31 findings) + plan 3-cycle (10 findings) GPT-5.5 converged; phase-gate GPT-5.5 3 accepted (path-traversal guard, skip-missing-screenshot rows, anchor/marker-order validation); Gemini 6 accepted (`encoding="utf-8"` on all 8 text I/O — Windows `cp1252` would mangle em-dashes/emojis); final GPT-5.5 2 accepted (index thumbnail skips missing screenshot; single-quoted `` detection) / 2 rejected (testing.md + CLAUDE.md already committed). 50 generator unit tests + 9-case freshness self-test; 10 MP4s transcoded; generator idempotent. All 18 `pr.yml` checks green (smoke skipped — opt-in/off). - **2026-06-04** — `feat_proposal_full_param_space_view` (PR #446, squash-merged `3baea3f0`). **Full parameter-space panel on the proposal detail page.** A new `` mounts below `` on `/proposals/[id]` and lists every parameter the proposal's template declares, partitioned into three groups: **Tuned (changed by this proposal)** (keys in `config_diff`, with from→to delta), **Tuned (unchanged)** (in the study's `search_space.params` but not in `config_diff`), and **Not in search space** (declared on the template, absent from this study's tuning surface). Now that the overnight autopilot swaps templates + tunes different knobs automatically, the proposal page IS the morning artifact operators read; this panel makes "what did the optimizer leave on the table" answerable at a glance. **Frontend-only, no backend, no migration** (head stays `0022`) — everything derives client-side from data already on the page (`ProposalDetail.config_diff` + `.template.id`, `StudyDetail.search_space.params`, `QueryTemplateDetail.declared_params`). 4 stories: (1.1) promote `extractFromTo` + `renderValue` to a shared `ui/src/lib/config-diff.ts`; (1.2) pure `partitionTemplateParams` (`ui/src/lib/proposal-param-space.ts`) — partition universe `declaredParams ∪ configDiff` (D-9, search-space-only drift keys silently dropped), `config_diff` membership = "tuned" (D-10), drift keys render type `(unknown)` (AC-6); uses `Object.entries` to satisfy `noUncheckedIndexedAccess`; (1.3) `` + new `proposal.full_param_space` glossary key; (1.4) page integration — **lift BOTH `useTemplate` (now from `proposal.template.id`, null-safe) AND `useStudy` (drop `hasActionableFollowup`)** so the panel has its data for every proposal shape (D-13 — the cycle-3 correctness fix; without lifting `useStudy`, study proposals with text-only digests would mis-classify search-space params as `untuned`), with race-aware mount gating (FR-4 — waits for `parentStudy` settled so `tunedUnchanged` never flashes a transient mis-classification). Caps 2 (cross-panel param linking) + 3 (study-detail mount) explicitly deferred WITHOUT `phase*_idea.md` artifacts (D-14). 9 partition unit + 7 config-diff unit + 7 component + 6 new page (incl. dual-deferred race-gating + FR-3 regression guard + FR-7 study-error) + 1 new real-backend E2E; full UI suite 1143 green. Cross-model: spec 3-cycle + plan 3-cycle GPT-5.5 converged (19 + 19 findings); phase-gate GPT-5.5 4 accepted/1 rejected (Record-based exhaustiveness ≡ never-switch); Gemini 2 accepted (null-`search_space.params` guard + widened type → real TypeError fix; grid-aligned tuned rows); final GPT-5.5 1 accepted (race-gating test had a coverage hole — `untuned` group would render on premature mount but wasn't asserted absent) / 1 rejected (`ACTIONABLE_FOLLOWUP_KINDS` still consumed at `prefillValues`). Guide 02 screenshots regenerated against the running stack (proposal-detail now shows the panel). Tangential sweep: existing 12 page tests now fire the lifted secondary fetches (cancel on unmount before MSW errors; vitest doesn't fail on console.error) — noted in PR body, not a regression. All 17 `pr.yml` checks green. - **2026-06-04** — `feat_overnight_studies_summary_card` (PR #444, squash-merged `ba1e6d68`). **"Ran while you were away" card on /studies.** The index-page surface for the overnight autopilot — Cap 2 delegated out of `feat_overnight_final_solution_phase2` (which shipped the detail-page ``). A dismissible card above the `/studies` table surfaces overnight follow-up chains that completed since the operator's last visit. **Backend:** new read-only endpoint `GET /api/v1/studies/chains/recent` — repo helper `list_recent_completed_chains` reuses the Phase 1 `get_chain_for_study` traversal + `derive_chain_stop_reason` (no chain math re-derived); filters `parent_study_id IS NOT NULL` (length ≥ 2 implied) + terminal status + `completed_at IS NOT NULL` + optional `?since=` cutoff; scan-caps candidates at `limit * 5` then dedupes to one row per anchor; defensive in-flight + concurrent-delete skips; inert pagination (`next_cursor: null`, `has_more: false`, `X-Total-Count = len(data)`) per OQ-2; declared BEFORE `/studies/{study_id}` so the static `chains` segment isn't captured. `RecentChainSummary` + `RecentChainsResponse` schemas (10 + 3 fields). **Frontend:** `` self-contained — owns its data via `useRecentChains(since)` (TanStack, window-focus refetch only) + `useStudiesVisited()` (localStorage `relyloop.last_visited_studies_at`, `now − 7d` first-visit default, `dismiss(T)` writes `T + 1ms` exclusive nudge per FR-5). Early-returns `null` on pending/error/empty (best-effort discoverability). Per-row: anchor ``, chain length, "Best {metric}: {value}", "Lift: {±value}" via shared `formatSignedLift`, stop-reason via shared `CHAIN_STOP_REASON_PHRASE` (defensive `?? 'Chain stopped'` fallback). Null-metric branch (AC-11) drops the numeric line. TWO `` affordances (recent_chains_card + overnight_autopilot) per FR-6. New `recent_chains_card` glossary key. Mounted on `/studies/page.tsx` above the target-filter chip row. **No migration** (head stays `0022`). 33 new tests: 11 backend integration (repo dedup/since/in-flight/failed-tail/concurrent-delete + endpoint AC-1/5/11 + route-order regression) + 9 contract (response shape, enum literals, OpenAPI presence, X-Total-Count, 422 envelope) + 12 vitest (4 hook + 8 card) + 2 Playwright E2E (smoke-job opt-in). Cross-model: Epic 1 GPT-5.5 1 finding (rejected — `select_best_link` is signed `-> str | None`); Epic 2 GPT-5.5 2 (1 accepted — raw-enum fallback → `'Chain stopped'`; 1 rejected — plan gates null branch on `best_metric` only, matching the chain panel's `formatSignedLift` "—" convention); Gemini 4 (2 accepted — N+1 elimination via `seen_study_ids` set + corrupt-localStorage `Date.parse` guard; 2 rejected — SSR-hydration false positives, card renders null during pending + matches `use-local-storage-set.ts` convention); final GPT-5.5 0 findings. Tangential: OQ-2 (keyset pagination) + OQ-3 (Postgres indexes) deferrals filed in `99_backlog/`. CI tripped the OpenAPI-surface allowlist (`test_openapi_has_no_orphan_endpoints`) — fixed inline by registering the new route, exactly as plan §3.3 anticipated. All 17 `pr.yml` checks green. - **2026-06-04** — `feat_overnight_final_solution_phase2` (PR #442, squash-merged `0c4e0358`). **Morning summary card + read-only strategy line.** Phase 2 of the overnight autopilot, frontend-only. Adds `` above `` on `/studies/{id}` — mounts only when the chain has terminated (`stop_reason !== 'in_flight'`) AND has ≥ 2 links — compressing the rolled-up answer into one glance: headline lift (`formatSignedLift`, shared with the chain panel), winning-link convergence chip (`` reading `StudyDetail.convergence.verdict`), explored-path tokens (`narrow → swap to {name} → widen`, anchor dropped, legacy-narrow chains get a path-less card per D-7), best-config CTA (three-case render matrix per D-13), stop-reason phrase, and a `truncateNarrative`-clamped digest excerpt with a "View full digest →" link. Plus a read-only "Strategy: Refine same knobs / Try suggested follow-ups" line inside `` for any study whose `config.auto_followup_strategy` is set. 6 stories / 1 epic: (1) extract `CHAIN_STOP_REASON_PHRASE` + `formatSignedLift` into shared `ui/src/lib/` modules (FR-8) + 2 new glossary keys (`overnight_result`, `auto_followup_strategy_line` — landed early because `` is type-locked); (2) pure `pathTokenForLink` with `Record` exhaustiveness; (3) card shell + headline + path + best-config + stop-reason + narrative + `truncateNarrative` + `shouldShowOvernightResultCard` predicate, hook-order invariant per D-19, per-link `useTemplate` in `` child per D-11; (4) `` (parent-gates-mount per D-18) + `id="digest"` anchor on ``; (5) ``; (6) tutorial guide + ui-architecture doc + real-backend E2E spec. **No backend code, no migration** (consumes existing `/chain` + `/studies/{id}` + `/digest` + `/query-templates/{id}`; head stays `0022`). Cap 2 (index-page surface) delegated to sibling `feat_overnight_studies_summary_card` per D-4. Spec + plan each GPT-5.5 3-cycle converged (22 D-log entries). Cross-model: Gemini cycle-1 1 finding (accepted — StrategyLine `inline-flex` markup); GPT-5.5 final 2 findings (1 accepted+fixed — AC-11 tautology strengthened to assert the hook's `best_link_id` + `enabled` args; 1 deferred — FR-9 populated-stack screenshot, demo seed can't produce a `follow_suggestions` chain with winning digest+proposal, tracked as `chore_overnight_result_card_screenshot`). Tests: 15 vitest lib unit + 26 card component + 5 strategy-line + 3 glossary lock + 2 Playwright E2E; full suite 1102+ green. All 17 `pr.yml` checks green. -- **2026-06-04** — `feat_overnight_final_solution` (PR #440, squash-merged `1e9522a0`). **Autonomous cross-knob overnight tuning.** Teaches the overnight autopilot to consume the parent digest's *executable* follow-ups (narrow / widen / **swap_template**) on each chain link instead of always running the hardcoded ±50% narrow on the same template — so a chain can branch knobs AND templates while you sleep. Opt-in via a new wizard **Strategy** toggle (`"narrow"` default = byte-identical legacy behavior; `"follow_suggestions"` = the new mode); the existing `test_auto_followup.py` passes unmodified (that's the backward-compat gate). 7 stories / 4 epics: (1.1) `StudyConfigSpec.auto_followup_strategy: str | None` + `_validate_auto_followup_strategy` via the `AUTO_FOLLOWUP_STRATEGY_INVALID` 422 envelope (str-not-Literal per D-13 so the canonical error-code unwrap works) + a `mode="before"` validator rejecting operator-submitted worker-managed keys (single-writer rule, D-14); (1.2) wizard Strategy `