phase: 190_app_name_settings_fix
All gates re-verified green. Report: - **Verified (all 4 tasks already complete; this was the final pass):** `effective_settings` resolves the 3 brand strings panel-row → tab-row → env (`applied_override_keys`, presence-not-value); `PUT /api/ui-settings` ignores string body fields; Theme-tab form is colors-only (17 pickers, no `#theme-app-name`/`#theme-placeholder`/`#theme-footer`); the ONE shared `applyBrandFromConfig` re-applies title/`.brand-text`/footer/placeholder after a panel save-reset and a tab save-reset; boot path byte-identical (single `/api/config`). - **Completion criteria:** - strings order panel→tab→env, both branches — ✅ `tests/unit/test_theming.py::test_effective_app_name_prefers_settings_panel_row_over_ui_settings_row`, `..._fall_back_to_ui_settings_row_without_panel_row`, `..._per_field_panel_then_tab_then_env`, `..._ignore_panel_rows_when_the_overlay_is_off` - PUT ignores string fields + no 3 inputs in the tab — ✅ `tests/integration/test_ui_settings_api.py::test_put_ignores_string_fields_in_body` (+2) and the E2E `test_theme_tab_dom_is_colors_only` - live apply without reload + incident regression — ✅ `tests/e2e/test_app_name_settings_fix.py` tests 1–4 - byte-identical boot, no double-apply — ✅ `tests/unit/test_brand_live.py` markers + E2E "exactly one /api/config" - suite green, coverage >90%, ruff+pyright clean — ✅ - no behavior change in prior phases — ✅ (palette, phase-168 panel, env fallback suites all green) - atomic commit — **left to the harness** (pipeline rule overrides per-phase committing; no git write run) - **Gates:** `uv run pytest --cov=app --cov-report=term-missing` → **4630 passed, TOTAL 6941 16 99%**, exit 0 · `uv run pytest tests/e2e/test_app_name_settings_fix.py -v --no-cov` → **6 passed** in isolation · regression E2E (isolated, one process each, all exit 0): `test_smoke` `test_configurable_brand` `test_admin_theme_tab` `test_theme_save_and_coverage` `test_theme_semantic_completion` `test_themed_favicon` `test_dark_tech_theme` `test_admin_settings_panel` `test_admin_settings_layout` `test_settings_mobile_value_width` · `uv run ruff check .` → All checks passed · `uv run pyright` → 0 errors. - **Documentation:** README — fixed "saving one repaints *every* open page" (only the open document repaints; other pages on next load) and a broken paragraph wrap in *Customizing the look*; AGENTS.md rule 16 — `test_chunks_hnsw_recall.py` now described accurately (index paths forced with `enable_seqscan`/`indexonlyscan`/`bitmapscan` off, unforced plan asserted only on a pristine relation); `tests/unit/test_theme_frontend.py` — two stale section headers ("20 form fields"/"20 inputs" → 17 color). No AGENTS.md settings-overlay/resolution-order clause exists, so per the phase none was added. Full env-var cross-check (`BOR_*` in `app/config.py` vs README) → 0 gaps; 0 missing file references. - **Notable:** the working tree also carries this phase's flake hardening of the phase-188 `tests/integration/test_chunks_hnsw_recall.py` (verified legit and green). Live infra untouched; shared DB left clean (0 `app_settings`, 0 `ui_settings`). **Flagged, not changed:** `settings_overlay.applied_override_keys` lets a `ProgrammingError` (missing `app_settings`) propagate from public `GET /api/config`, where `load_overrides` deliberately fails soft — only reachable on an un-migrated (0027) DB, outside this phase's pinned A1 semantics, so left for the owner to rule on rather than silently deviating. - **Next pending phase:** `191_source_name_labels_tags`.
This commit is contained in:
+17
-48
@@ -1275,8 +1275,9 @@
|
||||
|
||||
<!-- Phase 91 (task 04): the Theme view — the shell's seventh
|
||||
folded view (the phase-76 fold pattern, the phase-79 Tokens
|
||||
view as the most recent precedent): the admin-only palette +
|
||||
branding editor. /theme.html serves THIS document (the shell
|
||||
view as the most recent precedent): the admin-only palette
|
||||
editor (the brand strings are the Settings panel's since phase
|
||||
190). /theme.html serves THIS document (the shell
|
||||
route in app/main.py); the router shows this section for that
|
||||
pathname. The CSS-file theming (BOR_THEME, phase 62) is
|
||||
retired (task 03): the effective theme is injected into every
|
||||
@@ -1297,7 +1298,7 @@
|
||||
<div class="container theme-shell">
|
||||
<!-- Phase 91 (task 04): anonymous sign-in gate — the EXACT
|
||||
#sources-gate pattern (phase 16) and the same .sources-gate
|
||||
visual language: the palette + branding is what the login
|
||||
visual language: the palette is what the login
|
||||
locks (B5, owner-locked 2026-09-09). Visible for
|
||||
anonymous, hidden for the admin (theme.js). The gate's
|
||||
Sign in returns to the Theme view (the header's ?next=
|
||||
@@ -1308,7 +1309,7 @@
|
||||
</div>
|
||||
<h2 id="theme-gate-title">Sign in to change the theme</h2>
|
||||
<p class="sources-gate-sub">
|
||||
The palette and branding are admin-only. Chat — and any
|
||||
The palette is admin-only. Chat — and any
|
||||
document an answer cites — stays open to everyone.
|
||||
</p>
|
||||
<a class="sources-gate-link" href="/login.html?next=/theme.html">Sign in</a>
|
||||
@@ -1325,7 +1326,9 @@
|
||||
Changes preview live as you pick;
|
||||
<strong>Save theme</strong> bakes the palette into every
|
||||
page it is served on — it applies on the first paint, no
|
||||
pop-in.
|
||||
pop-in. The app name, the chat placeholder and the footer
|
||||
line are the Settings panel's: it owns the brand strings
|
||||
and applies them the moment they are saved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1333,50 +1336,16 @@
|
||||
the bindings — effective-value populate, the live preview,
|
||||
the §7.4 Save/Reset lifecycle, the WCAG contrast warnings
|
||||
in #theme-contrast). No real submit: both buttons are
|
||||
type="button"; maxlength=300 mirrors the server's 300-char
|
||||
limit (the server re-validates — 422 naming the field).
|
||||
The color inputs ship the BUILT-IN values (app/core/
|
||||
theming.py BUILTIN_COLORS) — task 05 re-populates them
|
||||
with the EFFECTIVE values on mount. -->
|
||||
type="button". The 17 color inputs ship the BUILT-IN
|
||||
values (app/core/theming.py BUILTIN_COLORS) — task 05
|
||||
re-populates them with the EFFECTIVE values on mount.
|
||||
Phase 190 (task 02, A1): the old "Branding" fieldset and
|
||||
its three string inputs (#theme-app-name /
|
||||
#theme-placeholder / #theme-footer) are GONE — the admin
|
||||
Settings panel is the single writable owner of the brand
|
||||
strings, so the tab neither shows nor sends them (a save
|
||||
here can no longer shadow a panel value). -->
|
||||
<form id="theme-form" novalidate>
|
||||
<fieldset class="theme-group">
|
||||
<legend class="theme-group-title">Branding</legend>
|
||||
<!-- B4 (owner-locked): the strings keep the brand.js
|
||||
runtime application — they apply via the /api/config
|
||||
boot fetch on the NEXT page load; the live preview
|
||||
covers the palette only. An empty field restores the
|
||||
default (the env value). -->
|
||||
<p class="theme-note">
|
||||
These strings apply on the next page load — the live
|
||||
preview covers the palette only. Leaving a field empty
|
||||
restores its default.
|
||||
</p>
|
||||
<label for="theme-app-name">App name</label>
|
||||
<input
|
||||
id="theme-app-name"
|
||||
name="app_name"
|
||||
type="text"
|
||||
maxlength="300"
|
||||
autocomplete="off"
|
||||
>
|
||||
<label for="theme-placeholder">Chat input placeholder</label>
|
||||
<input
|
||||
id="theme-placeholder"
|
||||
name="input_placeholder"
|
||||
type="text"
|
||||
maxlength="300"
|
||||
autocomplete="off"
|
||||
>
|
||||
<label for="theme-footer">Footer line</label>
|
||||
<input
|
||||
id="theme-footer"
|
||||
name="footer_text"
|
||||
type="text"
|
||||
maxlength="300"
|
||||
autocomplete="off"
|
||||
>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="theme-group">
|
||||
<!-- The eight text/background pairs (the five identity
|
||||
pairs + the three semantic ink-on-bg pairs from the
|
||||
|
||||
Reference in New Issue
Block a user