diff --git a/docs/00_overview/DASHBOARD.md b/docs/00_overview/DASHBOARD.md index 97289665..0fdd2182 100644 --- a/docs/00_overview/DASHBOARD.md +++ b/docs/00_overview/DASHBOARD.md @@ -6,7 +6,7 @@ _Top-level index across MVP1 → GA v1+ as of **2026-05-19**. Click a release na | Release | Theme | Progress | Status | |---|---|---|---| -| [MVP1 / v0.1](MVP1_DASHBOARD.md) | The Loop | 42 / 42 scoped done · 4 remaining | **In progress** | +| [MVP1 / v0.1](MVP1_DASHBOARD.md) | The Loop | 46 / 46 scoped done | **Complete** | | [MVP2 / v0.2](MVP2_DASHBOARD.md) | Observable | 1 / 1 scoped done · 1 remaining | **In progress** | | MVP3 / v0.3 | Production Stacks | — | **Not yet scoped** | | MVP4 / v0.4 | Multi-tenant, Multi-LLM | — | **Not yet scoped** | diff --git a/docs/00_overview/MVP1_DASHBOARD.md b/docs/00_overview/MVP1_DASHBOARD.md index 87632200..830472e2 100644 --- a/docs/00_overview/MVP1_DASHBOARD.md +++ b/docs/00_overview/MVP1_DASHBOARD.md @@ -14,16 +14,16 @@ Pull from the Idea backlog or capture a new feature spec. | Metric | Value | |---|---| -| Scoped items done | **42 / 42** (100%) — feat_/infra_/chore_/epic_ past idea stage | -| Path to MVP1 | **4** items remaining (features + bugs + chores) | +| Scoped items done | **46 / 46** (100%) — feat_/infra_/chore_/epic_ past idea stage | +| Path to MVP1 | **0** items remaining (features + bugs + chores) | | Open bugs | 0 | -| Open chores | 4 (idea-stage debt) | +| Open chores | 0 (idea-stage debt) | | Backlog ideas | 0 idea-only feat/infra (not yet scoped into MVP1) | | In flight | 0 feature(s) actively shipping | ## Pipeline -### Done (51) +### Done (55) | Feature | Type | One-liner | Depends on | Status | |---|---|---|---|---| @@ -54,10 +54,14 @@ Pull from the Idea backlog or capture a new feature spec. | [chore_chat_last_message_preview](implemented_features/2026_05_14_chore_chat_last_message_preview/idea.md) | Chore | Complete | — | Complete | | [chore_ci_gitignore_paths_ignore_gap](implemented_features/2026_05_13_chore_ci_gitignore_paths_ignore_gap/idea.md) | Chore | Complete | — | Complete | | [chore_ci_gitleaks_workflow_step](implemented_features/2026_05_13_chore_ci_gitleaks_workflow_step/idea.md) | Chore | Complete | — | Complete | +| [chore_ci_prettier_check](implemented_features/2026_05_19_chore_ci_prettier_check/idea.md) | Chore | Complete | — | Complete | | [chore_cluster_delete_ui](implemented_features/2026_05_13_chore_cluster_delete_ui/idea.md) | Chore | Complete | — | Complete | | [chore_data_table_columnvisibility_tanstack](implemented_features/2026_05_19_chore_data_table_columnvisibility_tanstack/idea.md) | Chore | Complete | — | Complete | +| [chore_detail_page_shell_primitive](implemented_features/2026_05_19_chore_detail_page_shell_primitive/idea.md) | Chore | Complete | — | Complete | | [chore_digest_worker_narrow_except](implemented_features/2026_05_14_chore_digest_worker_narrow_except/idea.md) | Chore | Complete | — | Complete | | [chore_env_guard_extend_deny_pattern](implemented_features/2026_05_13_chore_env_guard_extend_deny_pattern/idea.md) | Chore | Complete | — | Complete | +| [chore_extract_shadcn_select_test_mock](implemented_features/2026_05_19_chore_extract_shadcn_select_test_mock/idea.md) | Chore | Complete | — | Complete | +| [chore_form_dropdown_guide_screenshot_refresh](implemented_features/2026_05_19_chore_form_dropdown_guide_screenshot_refresh/idea.md) | Chore | Complete | — | Complete | | [chore_form_dropdown_primitive](implemented_features/2026_05_18_chore_form_dropdown_primitive/feature_spec.md) | Chore | Ready for Execution | — | [PR #126](https://github.com/SoundMindsAI/relyloop/pull/126) merged 2026-05-16 | | [chore_infra_foundation_github_token_file_retirement](implemented_features/2026_05_13_chore_infra_foundation_github_token_file_retirement/idea.md) | Chore | Complete | — | Complete | | [chore_openapi_contract_validation](implemented_features/2026_05_13_chore_openapi_contract_validation/idea.md) | Chore | Complete | — | Complete | @@ -91,14 +95,9 @@ _None._ _None._ -### Idea (4) +### Idea (0) -| Feature | Type | One-liner | Depends on | Status | -|---|---|---|---|---| -| [chore_ci_prettier_check](../02_product/planned_features/chore_ci_prettier_check/idea.md) | Chore | `.github/workflows/pr.yml`'s `frontend` job runs: | — | Idea — surfaced during `/impl-execute --ad-hoc` of `infra_e2e_wire_seed_helper_into_studies_spec`. | -| [chore_detail_page_shell_primitive](../02_product/planned_features/chore_detail_page_shell_primitive/idea.md) | Chore | Six of the seven `/{entity}/[id]` detail routes hand-roll the same three-state scaffold around their data query. The structure is **identical** down to the className strings, with two minor copy varia | — | Idea — surfaced during a UI-refactor audit run after [`chore_form_dropdown_primitive`](../../../00_overview/implemented_features/2026_05_18_chore_form_dropdown_primitive/feature_spec.md) (PR #136) and [`feat_data_table_primitive`](../../../00_overview/implemented_features/2026_05_16_feat_data_table_primitive/feature_spec.md) (PR #126) merged. | -| [chore_extract_shadcn_select_test_mock](../02_product/planned_features/chore_extract_shadcn_select_test_mock/idea.md) | Chore | A factor-and-share refactor was attempted during `chore_form_dropdown_primitive` post-implementation. I extracted the mock to `ui/src/__tests__/helpers/shadcn-select-mock.tsx` exporting `mockShadcnSel | — | Idea — captured during `chore_form_dropdown_primitive` execution (PR pending). | -| [chore_form_dropdown_guide_screenshot_refresh](../02_product/planned_features/chore_form_dropdown_guide_screenshot_refresh/idea.md) | Chore | Each affected guide has a Playwright spec at `ui/tests/e2e/guides/*.spec.ts` that captures screenshots when run against the real backend. The PR's UI changes produce different screenshots: | — | Idea — captured during `chore_form_dropdown_primitive` post-implementation guide-impact assessment. | +_None._ ## Dependency graph @@ -191,8 +190,16 @@ graph LR class infra_e2e_seed_completed_study done; chore_form_dropdown_primitive["form dropdown primitive"] class chore_form_dropdown_primitive done; + chore_ci_prettier_check["ci prettier check"] + class chore_ci_prettier_check done; chore_data_table_columnvisibility_tanstack["data table columnvisibility tanstack"] class chore_data_table_columnvisibility_tanstack done; + chore_detail_page_shell_primitive["detail page shell primitive"] + class chore_detail_page_shell_primitive done; + chore_extract_shadcn_select_test_mock["extract shadcn select test mock"] + class chore_extract_shadcn_select_test_mock done; + chore_form_dropdown_guide_screenshot_refresh["form dropdown guide screenshot refresh"] + class chore_form_dropdown_guide_screenshot_refresh done; infra_e2e_wire_seed_helper_into_studies_spec["e2e wire seed helper into studies spec"] class infra_e2e_wire_seed_helper_into_studies_spec done; feat_study_lifecycle --> feat_digest_proposal diff --git a/docs/00_overview/dashboard.html b/docs/00_overview/dashboard.html index 0e065fc1..173e33bd 100644 --- a/docs/00_overview/dashboard.html +++ b/docs/00_overview/dashboard.html @@ -371,8 +371,8 @@

Releases

MVP1 / v0.1
The Loop
-
42 / 42 scoped done · 4 remaining
- In progress +
46 / 46 scoped done
+ Complete
diff --git a/docs/02_product/planned_features/chore_ci_prettier_check/idea.md b/docs/00_overview/implemented_features/2026_05_19_chore_ci_prettier_check/idea.md similarity index 100% rename from docs/02_product/planned_features/chore_ci_prettier_check/idea.md rename to docs/00_overview/implemented_features/2026_05_19_chore_ci_prettier_check/idea.md diff --git a/docs/02_product/planned_features/chore_detail_page_shell_primitive/idea.md b/docs/00_overview/implemented_features/2026_05_19_chore_detail_page_shell_primitive/idea.md similarity index 100% rename from docs/02_product/planned_features/chore_detail_page_shell_primitive/idea.md rename to docs/00_overview/implemented_features/2026_05_19_chore_detail_page_shell_primitive/idea.md diff --git a/docs/02_product/planned_features/chore_extract_shadcn_select_test_mock/idea.md b/docs/00_overview/implemented_features/2026_05_19_chore_extract_shadcn_select_test_mock/idea.md similarity index 100% rename from docs/02_product/planned_features/chore_extract_shadcn_select_test_mock/idea.md rename to docs/00_overview/implemented_features/2026_05_19_chore_extract_shadcn_select_test_mock/idea.md diff --git a/docs/02_product/planned_features/chore_form_dropdown_guide_screenshot_refresh/idea.md b/docs/00_overview/implemented_features/2026_05_19_chore_form_dropdown_guide_screenshot_refresh/idea.md similarity index 100% rename from docs/02_product/planned_features/chore_form_dropdown_guide_screenshot_refresh/idea.md rename to docs/00_overview/implemented_features/2026_05_19_chore_form_dropdown_guide_screenshot_refresh/idea.md diff --git a/docs/00_overview/mvp1_dashboard.html b/docs/00_overview/mvp1_dashboard.html index 6ef7710a..ca23d177 100644 --- a/docs/00_overview/mvp1_dashboard.html +++ b/docs/00_overview/mvp1_dashboard.html @@ -384,13 +384,13 @@

MVP1 Progress

Scoped items done
-
42 / 42
+
46 / 46
100% of feat_/infra_/chore_/epic_ items past idea stage
-
+
Path to MVP1
-
4
+
0
items left = features + bugs + chores
@@ -398,9 +398,9 @@

MVP1 Progress

0
tracked bug_* idea files
-
+
Open chores
-
4
+
0
idea-stage chore_* (debt)
@@ -428,54 +428,7 @@

Pipeline

-

Idea 4

- -
- -
- Chore - -
-
`.github/workflows/pr.yml`'s `frontend` job runs:
- - -
- - -
- -
- Chore - -
-
Six of the seven `/{entity}/[id]` detail routes hand-roll the same three-state scaffold around their data query. The structure is **identical** down to the className strings, with two minor copy varia
- - -
- - -
- -
- Chore - -
-
A factor-and-share refactor was attempted during `chore_form_dropdown_primitive` post-implementation. I extracted the mock to `ui/src/__tests__/helpers/shadcn-select-mock.tsx` exporting `mockShadcnSel
- - -
- - -
- -
- Chore - -
-
Each affected guide has a Playwright spec at `ui/tests/e2e/guides/*.spec.ts` that captures screenshots when run against the real backend. The PR's UI changes produce different screenshots:
- - -
+

Idea 0

@@ -495,7 +448,7 @@

Implementing 0

-

Done 51

+

Done 55

@@ -821,6 +774,18 @@

Done 51

+
+ +
+ Chore + merged 2026-05-19 +
+
Complete
+ + +
+ +
@@ -845,6 +810,18 @@

Done 51

+
+ +
+ Chore + merged 2026-05-19 +
+
Complete
+ + +
+ +
@@ -869,6 +846,30 @@

Done 51

+
+ +
+ Chore + merged 2026-05-19 +
+
Complete
+ + +
+ + +
+ +
+ Chore + merged 2026-05-19 +
+
Complete
+ + +
+ +
@@ -1201,8 +1202,16 @@

Dependency graph (feat_ + infra_)

class infra_e2e_seed_completed_study done; chore_form_dropdown_primitive["form dropdown primitive"] class chore_form_dropdown_primitive done; + chore_ci_prettier_check["ci prettier check"] + class chore_ci_prettier_check done; chore_data_table_columnvisibility_tanstack["data table columnvisibility tanstack"] class chore_data_table_columnvisibility_tanstack done; + chore_detail_page_shell_primitive["detail page shell primitive"] + class chore_detail_page_shell_primitive done; + chore_extract_shadcn_select_test_mock["extract shadcn select test mock"] + class chore_extract_shadcn_select_test_mock done; + chore_form_dropdown_guide_screenshot_refresh["form dropdown guide screenshot refresh"] + class chore_form_dropdown_guide_screenshot_refresh done; infra_e2e_wire_seed_helper_into_studies_spec["e2e wire seed helper into studies spec"] class infra_e2e_wire_seed_helper_into_studies_spec done; feat_study_lifecycle --> feat_digest_proposal @@ -1364,8 +1373,16 @@

Dependency graph (feat_ + infra_)

class infra_e2e_seed_completed_study done; chore_form_dropdown_primitive["form dropdown primitive"] class chore_form_dropdown_primitive done; + chore_ci_prettier_check["ci prettier check"] + class chore_ci_prettier_check done; chore_data_table_columnvisibility_tanstack["data table columnvisibility tanstack"] class chore_data_table_columnvisibility_tanstack done; + chore_detail_page_shell_primitive["detail page shell primitive"] + class chore_detail_page_shell_primitive done; + chore_extract_shadcn_select_test_mock["extract shadcn select test mock"] + class chore_extract_shadcn_select_test_mock done; + chore_form_dropdown_guide_screenshot_refresh["form dropdown guide screenshot refresh"] + class chore_form_dropdown_guide_screenshot_refresh done; infra_e2e_wire_seed_helper_into_studies_spec["e2e wire seed helper into studies spec"] class infra_e2e_wire_seed_helper_into_studies_spec done; feat_study_lifecycle --> feat_digest_proposal diff --git a/state.md b/state.md index f1b12dbc..27cde82b 100644 --- a/state.md +++ b/state.md @@ -2,13 +2,13 @@ > Read this first. Snapshots the active branch, what just shipped, what's in flight, what's queued, and where the project currently sits in the MVP1 → GA roadmap. Updated whenever a feature lands or a priority shifts. -**Last updated:** 2026-05-19 (after `chore_data_table_columnvisibility_tanstack` shipped via `/impl-execute --ad-hoc` as PR #150 squash commit `c1e4545` — closes the residual DataTable follow-ups: item 5 migrates the primitive from `columns.filter(...)` to TanStack's `state.columnVisibility` API (memoized per Gemini feedback), item 3 locked the flat-prop `DataTableProps` API as canonical with a "Shipped contract addendum" on the historical implementation plan's Story 2.6. Folder renamed `chore_data_table_primitive_followups` → `chore_data_table_columnvisibility_tanstack`. Earlier 2026-05-19 PR #148 (`infra_e2e_wire_seed_helper_into_studies_spec`, squash `65f4150`) — restored the 2 digest-panel E2E tests deferred from PR #130, diagnosed and fixed the real root cause of the original smoke-lane failure (`GET /api/v1/proposals` was silently ignoring the `?study_id=` filter, returning the most-recent global pending proposal), added 5-case integration regression coverage at `backend/tests/integration/test_proposals_study_filter.py`. Plus: (a) earlier 2026-05-18 PR #146 (`bug_install_skip_ui_rebuild`, squash `7299fca`) made `make up` rebuild every Compose service (`docker compose build` no-args), switched `make down` to `docker compose down`, and added a `verify_install_builds_all_services.sh` CI gate to lock the contract; (b) earlier 2026-05-18 PR #147 captured `chore_detail_page_shell_primitive` idea (squash `8854e47`). Two new follow-ups filed: `chore_ci_prettier_check` (CI's frontend job has no `prettier --check` step — surfaced when PR #136 drift in 2 unrelated files blocked an unrelated commit) and the in-flight `chore_detail_page_shell_primitive` (third primitive after DataTable + EntitySelect).) +**Last updated:** 2026-05-19 (after a 4-PR shipping run drained the actionable post-MVP1 chore backlog: PR #152 `chore_ci_prettier_check` (`476db78`) + PR #153 `chore_extract_shadcn_select_test_mock` (`199e225`) + PR #154 `chore_form_dropdown_guide_screenshot_refresh` (`ed4121f`) + PR #155 `chore_detail_page_shell_primitive` (`9a72514`). PR #155 is the third primitive after `` and `` — 6 detail-page migrations + new lint guard + flattens a latent UX bug where only `proposals/[id]` discriminated 404 from network error. Earlier the same session: PR #150 (`chore_data_table_columnvisibility_tanstack`, `c1e4545`) — closes the residual DataTable follow-ups: item 5 migrates the primitive from `columns.filter(...)` to TanStack's `state.columnVisibility` API (memoized per Gemini feedback), item 3 locked the flat-prop `DataTableProps` API as canonical with a "Shipped contract addendum" on the historical implementation plan's Story 2.6. Folder renamed `chore_data_table_primitive_followups` → `chore_data_table_columnvisibility_tanstack`. Earlier 2026-05-19 PR #148 (`infra_e2e_wire_seed_helper_into_studies_spec`, squash `65f4150`) — restored the 2 digest-panel E2E tests deferred from PR #130, diagnosed and fixed the real root cause of the original smoke-lane failure (`GET /api/v1/proposals` was silently ignoring the `?study_id=` filter, returning the most-recent global pending proposal), added 5-case integration regression coverage at `backend/tests/integration/test_proposals_study_filter.py`. Plus: (a) earlier 2026-05-18 PR #146 (`bug_install_skip_ui_rebuild`, squash `7299fca`) made `make up` rebuild every Compose service (`docker compose build` no-args), switched `make down` to `docker compose down`, and added a `verify_install_builds_all_services.sh` CI gate to lock the contract; (b) earlier 2026-05-18 PR #147 captured `chore_detail_page_shell_primitive` idea (squash `8854e47`). Two new follow-ups filed: `chore_ci_prettier_check` (CI's frontend job has no `prettier --check` step — surfaced when PR #136 drift in 2 unrelated files blocked an unrelated commit) and the in-flight `chore_detail_page_shell_primitive` (third primitive after DataTable + EntitySelect).) --- ## Current branch / execution context -- **Branch:** `main` (post-merge of PR #150 squash commit `c1e4545` 2026-05-19). Finalization docs PR off `docs/finalize-data-table-columnvisibility-tanstack`. Prior squashes: PR #148 `65f4150` 2026-05-19 (`infra_e2e_wire_seed_helper_into_studies_spec` — `?study_id=` filter bug + E2E test restore), PR #147 `8854e47` 2026-05-18 (capture chore_detail_page_shell_primitive idea), PR #146 `7299fca` 2026-05-18 (bug_install_skip_ui_rebuild — `make up`/`make down` lifecycle fix), PR #136 `cb7d9ee` 2026-05-18 (chore_form_dropdown_primitive), PR #132 `ee4c8d4` 2026-05-17 (chore_data_table_primitive_followups items 1+2+4+6), PR #130 `13b3383` 2026-05-17 (infra_e2e_seed_completed_study), PR #128 `73459d2` 2026-05-17 (bug_cursor_decode_value_validation), PR #126 `d6115b3` 2026-05-16 (feat_data_table_primitive). `v0.1.0` annotated tag still on `main` commit `d099536` 2026-05-13; GitHub Release at https://github.com/SoundMindsAI/relyloop/releases/tag/v0.1.0. +- **Branch:** `main` (post-merge of PR #155 squash commit `9a72514` 2026-05-19). Finalization docs PR off `docs/finalize-may19-chore-batch`. Prior squashes: PR #154 `ed4121f` 2026-05-19 (`chore_form_dropdown_guide_screenshot_refresh`), PR #153 `199e225` 2026-05-19 (`chore_extract_shadcn_select_test_mock`), PR #152 `476db78` 2026-05-19 (`chore_ci_prettier_check`), PR #151 `110dc5a` 2026-05-19 (finalize chore_data_table_columnvisibility_tanstack), PR #150 `c1e4545` 2026-05-19 (`chore_data_table_columnvisibility_tanstack`), PR #149 `da9506b` 2026-05-19 (finalize infra_e2e_wire_seed_helper_into_studies_spec), PR #148 `65f4150` 2026-05-19 (`infra_e2e_wire_seed_helper_into_studies_spec` — `?study_id=` filter bug + E2E test restore), PR #147 `8854e47` 2026-05-18 (capture chore_detail_page_shell_primitive idea), PR #146 `7299fca` 2026-05-18 (bug_install_skip_ui_rebuild — `make up`/`make down` lifecycle fix), PR #136 `cb7d9ee` 2026-05-18 (chore_form_dropdown_primitive), PR #132 `ee4c8d4` 2026-05-17 (chore_data_table_primitive_followups items 1+2+4+6), PR #130 `13b3383` 2026-05-17 (infra_e2e_seed_completed_study), PR #128 `73459d2` 2026-05-17 (bug_cursor_decode_value_validation), PR #126 `d6115b3` 2026-05-16 (feat_data_table_primitive). `v0.1.0` annotated tag still on `main` commit `d099536` 2026-05-13; GitHub Release at https://github.com/SoundMindsAI/relyloop/releases/tag/v0.1.0. - **Active feature:** none in flight. **Three PRs shipped 2026-05-15:** PR #122 (Phase 1, 16th MVP1 feature — Tooltip primitive + 26 placements on create-study modal + study detail), PR #123 (Phase 1 finalization docs), PR #124 (Phases 2 + 3 — 17th MVP1 feature; 21 additional tooltips on judgments + proposals + cluster registration + 2 new first-run components: chat ExamplePrompts strip + Stripe-style StartHereChecklist on home page). The original "MVP1 Phase 1 only" scope-lock was reversed mid-day: operator decided to ship Phases 2 + 3 together with a Stripe-style design call rather than wait for MVP2. PR #124 took 2 hours from idea-folder reuse to merge. 47 total tooltip placements + 2 new first-run components live in `main`. **PR #122 shipped 2026-05-15 morning** — `feat_contextual_help` Phase 1 (16th MVP1 feature). Adds the first Tooltip primitive (`@radix-ui/react-tooltip@~1.2.8` + shadcn-style wrapper at `ui/src/components/ui/tooltip.tsx`), two glossary-backed wrappers (`InfoTooltip` standalone + asChild modes; `HelpPopover` click-to-open with `react-markdown` safety filter), and a 49-key glossary source-of-truth at `ui/src/lib/glossary.ts` (8 enum groups parity-tested against `enums.ts`). 26 tooltip placements across the create-study modal (Step 1 target + Step 3 template + 9 Step 5 inputs), study-header (status badge dynamic key + Best metric + Trials), trials-table (5 column headers + Sort label), and digest panel (5 section labels + Open PR enabled + Open PR disabled). The disabled Open PR button refactored from native `disabled` to `aria-disabled="true"` so it stays focusable and the tooltip reveals on focus (AC-11). Gemini Code Assist: 2 findings (1 accepted + fixed, 1 rejected with cited counter-evidence). Final GPT-5.5 review: 1 Medium accepted-framing-but-deferred. Spec converged at GPT-5.5 cycle 3 (24 findings, 23 accepted + 1 rejected); plan converged at cycle 2 (12 findings, 10 accepted + 1 rejected + 1 spec patch). UI vitest now **279 passing across 48 files** (was 249 across 45 — +3 new test files, +30 cases). Playwright E2E **8 passing** (was 5 — +3 new contextual-help tests). One follow-up filed: `infra_e2e_seed_completed_study/idea.md` tracks the E2E gap for digest-panel triggers + AC-11 (cross-subsystem helper for seeding a completed study with digest + proposal; component-level coverage is in place). Phases 2 + 3 deferred to MVP2 via `feat_contextual_help_mvp2/` (judgments + proposals tooltips; chat + cluster + home onboarding; the home-page "Start here" panel is the only product-design-shaped item). **Earlier — seven PRs shipped 2026-05-14:** `feat_judgments_periodic_resume_sweep` (PR #104, 14th MVP1 feature), `bug_query_inline_crud_since_filter_uuidv7_ms_collision` (PR #106 — UUIDv7 ms-collision test flake), `infra_dashboard_regen_pre_commit_conflict §2+§4` (PR #108 — dashboard regen idempotency + relative-link rewriting), `infra_make_targets_split_backend_only` (PR #110 — `make backend-fmt/lint/typecheck` + symmetric `ui-fmt` so Node-18 contributors aren't blocked), `chore_digest_worker_narrow_except` (PR #112 — narrowed `except Exception` allowlist to `(ValueError,)` + ERROR-level `digest_importance_failed_unexpected` event), `infra_structlog_test_helpers` (PR #114 — factored the two structlog test-assertion patterns into `backend/tests/_log_helpers.py`), and `chore_chat_last_message_preview` (PR #117 — `last_message_preview` + `last_message_at` on `ConversationSummary` via LATERAL JOIN; frontend shows preview under title + swaps displayed timestamp from `created_at` to `last_message_at`). Plus PR #116 dropped `chore_studies_ui_shadcn_polish` as won't-do (forward-compat audit on NavigationMenu primitive + ClusterFilterSelect precedent on native `` family crashes inside jsdom + Dialog focus traps (testing-library's `patchedFocus` shim recurses through Radix's internal focus-trap). Three modal test files (`clusters/register-cluster-modal.test.tsx`, `query-sets/create-query-set-modal.test.tsx`, `studies/create-study-modal.test.tsx`) duplicated the same ~50-LOC native-`