chore(agent): track .agent/ planning tree in git
Build and Push Containers / build-and-push-app (push) Successful in 12s
Build and Push Containers / build-and-push-db (push) Successful in 10s

Remove the blanket .agent/ gitignore so the phase roadmap, user
stories, reports, and PLAN.md are versioned with the code. Only
runtime artifacts (.agent/phase-sessions/, .agent/pipeline.log)
remain ignored. Update AGENTS.md git protocol rule to match.
This commit is contained in:
2026-09-01 10:18:22 -04:00
parent 5fa620fde5
commit 4971e2859d
818 changed files with 23964 additions and 4 deletions
+51
View File
@@ -0,0 +1,51 @@
# Story: Configurable app name
**Phase:** `39_configurable_brand` · **E2E:** `tests/e2e/test_configurable_brand.py`
## Narrative
As **the owner**, the app is "Brain of Reese" because that's what I named
it — but the name is hard-coded across every template and JS string. I want
to be able to **rename the app with one env var** (`BOR_APP_NAME`) so every
page title, the header brand, the status labels, and the aria text carry
the new name without touching code.
- **Given** the app is running with `BOR_APP_NAME="Brain of Testy"`
- **When** I open any page (chat, sources, tuning, login, document viewer)
- **Then** the title, the header brand, the status labels
("Brain of Testy is thinking"), the empty-state greeting, and the
document-viewer titles all say "Brain of Testy" — and with the variable
unset the app is byte-identical to today ("Brain of Reese").
## Acceptance criteria
1. `GET /api/config` (public, stateless) → `{app_name, version}` from
settings — exactly those two keys (no secrets, no other settings);
unit + integration tested.
2. `frontend/assets/brand.js` (classic script, loaded first on all five
pages): sets `window.BOR_BRAND` synchronously (default "Brain of
Reese"), fetches `/api/config` (`cache: "no-store"`), and applies the
name — `document.title` (global replace of the literal), every
`.brand-text` (bold split: a name starting "Brain of " bolds the
remainder, else plain; the name is HTML-escaped), every text node and
the `aria-label` / `placeholder` / meta-`content` attributes containing
the literal; a fetch failure falls back to the default (console.warn,
the page never breaks).
3. The JS hard-codes move off the literal: `app.js` (status labels, the
typing label, the elapsed-hint aria) + `document.js` (page titles) read
`window.BOR_BRAND` (default "Brain of Reese" if unset).
4. `Containerfile`: an esbuild line for brand.js next to the others.
5. The story E2E boots its **own** app instance with `BOR_APP_NAME`
overridden (distinct port; the shared conftest server keeps the default
name so the existing title assertions stay green) and asserts
title/brand/greeting/aria/label.
6. `.env.example` + README document `BOR_APP_NAME` (what it affects, the
default, the bold-split rule).
7. Unit + integration green, `app/` coverage >90%, story E2E green in
isolation, ruff + pyright clean, one `--no-gpg-sign` commit.
## Playwright Mapping Rule
`tests/e2e/test_configurable_brand.py` — one story, one file, run in
isolation: the overridden-name instance shows the new brand in the title,
the header `.brand-text` (with the bold split), the empty-state greeting,
the messages aria-label, and the chat status label; the default-name
shared server still renders "Brain of Reese" (the no-op regression).