Commit Graph
10 Commits
Author SHA1 Message Date
ducoterra bef24e05e2 phase: 123_chat_image_questions
Build and Push Containers / build-and-push-app (push) Successful in 1m54s
Build and Push Containers / build-and-push-db (push) Failing after 13s
All gates green. Verification complete.

**Phase 123 — final verification pass (all 4 tasks already in `complete/`)**

- Verified the full implementation is in the working tree: `app/api/chat_images.py` (upload/serve pair), `ChatRequest.image`/`ChatMessage.image` (path-validated, omitted-when-None), toggle-off + stale-file hinted error frames, `build_user_content` multimodal build at both sites (chat.py deflected branch + `run_agent`), config-gated composer attach/preview/upload-then-send, restore + shared rendering, CSP `img-src 'self' data:` carve-out, mock-LLM capture buffer.
- `uv run pytest` → **2796 passed**, exit 0 (unit + integration).
- `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99%** (29/4615 missed; phase-123 modules 99–100%).
- `uv run pytest tests/e2e/test_chat_image_questions.py -v --no-cov` → **5 passed** in isolation.
- `uv run ruff check . && uv run pyright` → clean (0 errors).

**Completion criteria:** (1) attach→send→multimodal text+image to the model, bubble/reload/shared all render it, saved chat stores the PATH with `"base64" not in json.dumps(stored)` — **verified** (E2E tests 1–4 + integration round-trip); (2) `BOR_IMAGES=false` — control hidden, exact hinted error frame, zero model calls / no query_log row — **verified** (E2E test 5 + integration); (3) text-only byte-identical (`content` stays a plain `str`) — **verified** (unit + integration); (4) all gates green — **verified**; (5) commit + phase move — left to the harness per pipeline rules (no `git add`/`commit` run).

No defects found; no live-infrastructure changes (repo + local dev DB only). **Next pending phase: none** — 123 is the last phase in `todo/`.
2026-09-25 05:19:18 -04:00
ducoterra df91c6316c phase: 92_theme_save_and_coverage
Build and Push Containers / build-and-push-app (push) Successful in 1m47s
Build and Push Containers / build-and-push-db (push) Successful in 11s
**Phase 92 final verification pass — all green.** This pass re-verified the completed tasks (all 5 task files already in `complete/`) against every completion criterion; no defects found, nothing to fix.

- Verified: 9th identity var `grid_line` end-to-end (migration `0015` at head, model/`theming.py`/schemas/API, 422 + built-in→NULL tests present); `styles.css` zero hardcoded literals outside `:root` + derived `--brand-*` vars; 9th picker in theme form; wordmark themed; `theme.js` save/reset/re-show/mount live-sync; dedicated E2E suite + phase-91 suite updated.
- `uv run pytest --cov=app --cov-report=term-missing` → **1845 passed, exit 0, TOTAL 99%** (>90%)
- `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings
- `uv run pytest tests/e2e/test_theme_save_and_coverage.py -v --no-cov` → **3 passed** (save-live, reset-live, whole-site)
- `uv run pytest tests/e2e/test_admin_theme_tab.py -v --no-cov` → **5 passed**
- Criteria: (1) Save/Reset repaint open page, no nav, SPA-nav survives, pre-paint intact ✅; (2) both `rg` gates green (only `:root` + documented `#fff` Stop label; zero SVG hex attrs), grid/selection/hovers/wash/wordmark E2E-proven ✅; (3) no-op contract live-checked: row-less `/` = no tag + exact A1 CSP, grid-only row = 9-var tag in `COLOR_FIELDS` order + sha256 CSP, with-row ≡ row-less bytes ✅; (4) full suite/coverage/lint/both E2E ✅; (5) commit left to the harness per instructions.
- Deviations (previously made, probe-verified, kept): live repaint uses CSSOM `<html>` overrides because Chromium blocks `<style>` textContent mutations under the locked sha256-only CSP (tag text still mirrors the next load; `<html>` style exact-saved after Save, empty after Reset); wordmark themed via 3 `.brand-mark` CSS rules instead of inline styles (task 03's inline attrs were CSP-blocked — fixed during task 04).
- Next pending phase: none — `todo/` contains only `92_theme_save_and_coverage`.
2026-09-10 00:23:08 -04:00
ducoterra 5abe8871e3 fix(chat): raise pre-token guard from 120 s to 300 s
Build and Push Containers / build-and-push-app (push) Successful in 1m48s
Build and Push Containers / build-and-push-db (push) Successful in 15s
The client-side TURN_TIMEOUT_MS was the binding constraint: turns with
slow prompt processing (no first SSE frame within 120 s of visible time)
errored with the 'stuck' copy even though nginx (300 s) and
BOR_LLM_TIMEOUT (300 s) would have let them run. Raise the guard to
300 s so the upstream timeouts are reachable, and re-pin the tests:
the unit constant pins and the fake-clock E2E timeline (295 s hidden
+ 290 s after the re-arm = 585 s: past the original 300 s deadline,
short of the re-armed 595 s deadline).

Verified: tests/unit (full, 100% pass), tests/e2e/test_hidden_tab_stream.py
and tests/e2e/test_loading_feedback.py in isolation.
2026-09-08 09:37:33 -04:00
ducoterra 88293ed02f feat(rag): retry a failed LLM request before the first token lands — BOR_LLM_RETRIES/BOR_LLM_RETRY_DELAY with a live 'retrying' status 2026-09-02 10:52:38 -04:00
ducoterra 6832957ab0 feat(chat): retry the last answer — redo-in-place Retry button on the latest brain bubble 2026-08-29 18:32:15 -04:00
ducoterra 1a60ecbd8b feat(chat): stop an in-flight answer — Send becomes Stop, the partial is kept and persisted, the model stream is torn down 2026-08-29 17:27:04 -04:00
ducoterra fe55be0c35 feat(brand): configurable app name — BOR_APP_NAME drives /api/config + the frontend brand layer
Build and Push Containers / build-and-push (push) Successful in 1m50s
One env var (BOR_APP_NAME, default "Brain of Reese") now drives the app's
display name everywhere (TODO.md L12 — owner ask: "a way to customize the
name for 'Brain of'. Should be an env var."). The existing app_name setting
is the source of truth (phase locked decision — no new variable, no rename);
with the variable unset the app is byte-identical to before.

Endpoint (A10 public/stateless, no secrets):
  GET /api/config → exactly {app_name, version} (app/api/config.py, the
  health.py pattern; registered before the static mount). Integration tests:
  anonymous 200, default values, a Settings override follows, key set is
  exactly two keys — no other setting may leak in later.

Frontend brand layer (A11 — runtime fetch, static templates stay static):
  assets/brand.js — a CLASSIC script, first on all six pages, so its top
  level runs at parse time: window.BOR_BRAND = "Brain of Reese"
  synchronously (the default renders immediately, no blank flash), then a
  no-store fetch of /api/config applies the name — document.title (global
  replace), every .brand-text (a name starting "Brain of " keeps the bold
  split Brain of <strong>rest</strong>, any other name renders plain; the
  operator-controlled name is HTML-escaped before innerHTML), a TreeWalker
  over text nodes (script/style rejected — page source never rewritten),
  and the aria-label/placeholder/meta-content attributes. Fetch failure
  keeps the default + console.warn (the loadHealth house style).
  app.js (status labels, typing label, elapsed-hint aria, tool labels) and
  document.js (viewer titles) read window.BOR_BRAND at CALL time via
  brand() — a label set after the fetch lands carries the configured name.
  Containerfile: esbuild minify line for brand.js (classic, like markdown.js);
  the phase-33 ?v= cache-busting picks the new asset ref up automatically.

E2E (A16 — one story, one file, isolated): test_configurable_brand.py boots
a SECOND app instance (same DB/mock-LLM/admin-auth env block, port APP_PORT+1,
BOR_APP_NAME="Brain of Testy") — the shared conftest server keeps the
default name so every other suite's title/label assertions stay untouched —
and asserts /api/config on both instances, the index title/brand/greeting/
#messages aria-label, the sources + login page titles, and one pre-token
chat turn (think out loud marker) whose #send-status reads "Brain of Testy
is thinking"; the no-op regression pins the shared server's default bytes.

Docs: .env.example App section + README configuration reference — what it
affects (titles, header brand, status labels, aria text), the default, the
bold-split rendering rule.

Gates: 695 unit+integration passed, app/ coverage 99% (>90%), story E2E
green in isolation (two consecutive runs), brand-string suites (smoke,
shared header, header consistency, chat persistence) green, ruff + pyright
clean.
2026-08-27 02:24:16 -04:00
ducoterra b16deb2b1d feat(chat): stream model thinking over SSE and show it in a collapsible block 2026-08-24 09:52:27 -04:00
ducoterra 2f738a7f19 feat(ui): dark tech theme — emoji-free chrome, subtle animated CSS background, WCAG AA dark palette 2026-08-21 23:34:36 -04:00
ducoterra e5810b0bcf feat(ui): explicit chat state machine — typing indicator, streaming progress, timeout and error recovery 2026-08-21 18:45:27 -04:00