refactor(agents): migrate .agent/ planning tree to .agents/
Standardize on the .agents/ directory (shared with project skills): phases/, user_stories/, reports/, screenshots/, validate.sh, and phase-sessions/ + pipeline.log all move to .agents/ (git mv preserves history; runtime artifacts move alongside). Updates every reference in AGENTS.md, README.md, .gitignore, app docstrings, and test story headers. Historical KB content in data/ and the runtime pipeline.log transcript are left untouched.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# Phase 61 — Stale UI Copy (retire the homelab-era text)
|
||||
|
||||
**Source:** `TODO.md` L4 — "Clean up the UI, there's text that references old features or talks about the way BOR used to work. For example the page-sub text in knowledge base references !/Homelab and ~/Deployments but those aren't the only sources and sometimes aren't included."
|
||||
**Story:** n/a (TODO-derived — owner roadmap confirmation 2026-09-01)
|
||||
**Context:** Verified copy inventory (audited 2026-09-01, all line numbers as of this writing):
|
||||
- `frontend/index.html` L6 — meta description "Ask Brain of Reese anything about the homelab and deployments."; L199–201 — empty-state sub "I've read through the homelab and deployment notes — ask me anything, and I'll point you at the exact doc. You've got this."; L231 — composer `placeholder="Ask me about the homelab…"`.
|
||||
- `app/config.py` L265–270 — the DEFAULT suggestion chips: 3 of 4 are owner-corpus-specific ("How is my Kubernetes cluster set up?", "What's my backup strategy?", "How do I deploy a new service?", "What's currently running in the homelab?"). Rendered as empty-state chips by `app.js` from `GET /api/suggestions`.
|
||||
- `frontend/sources.html` L110–114 — the KB page-sub cited in the TODO: "Every `*.md` file indexed from `~/Homelab` and `~/Deployments`. Press **Sync sources** to clone the repos and re-import." Stale on three counts: sources are now git repos + local directories + uploaded archives (phases 28/38/49); import extensions are configurable, not only `*.md` (phase 56); Sync pulls the configured git repos and imports local dirs — it does not clone "the repos" in general.
|
||||
- `frontend/git-sources.html` L175 — form example `placeholder="https://github.com/you/homelab.git"`.
|
||||
- ALL 9 pages — footer `<span>Powered by Reese's self-hosted models</span>` (`index.html` L245, `sources.html` L186, `tuning.html` L148, `document.html` L150, `git-sources.html` L243, `history.html` L173, `login.html` L131, `shared.html` L147, `doc-edit.html` L118).
|
||||
- OUT OF SCOPE (owner-locked A3): code/HTML *comments* mentioning "homelab" (`frontend/assets/app.js` L180/L1398/L1419, `frontend/assets/history.js` L39/L244, `frontend/index.html` L176) — not user-visible; left untouched to keep the diff minimal.
|
||||
- The phase-39 brand layer (`frontend/assets/brand.js`) already rewrites every occurrence of the literal "Brain of Reese" (titles, `.brand-text`, text nodes, aria/placeholder/meta attributes) — so strings that embed the BRAND name (e.g. the visually-hidden label "Ask Brain of Reese a question", `index.html` ~L227) stay as-is: the layer keeps them in sync when `BOR_APP_NAME` is set.
|
||||
- No existing test pins the exact default chip text (`tests/integration/test_api.py` L75–81 asserts only shape: a list, `len >= 3`, non-empty strings).
|
||||
- `.agents/` is UNTRACKED (owner instruction, commit 281f355) — the phase commit stages `frontend/ tests/ app/` only.
|
||||
- The E2E shared conftest server boots with the default env — this phase's E2E asserts the NEW neutral copy against that shared server.
|
||||
|
||||
## Objective
|
||||
Every user-visible string in the app describes how BOR works TODAY (any configured sources — git, local directories, uploads — with configurable extensions) instead of the owner's original `~/Homelab` + `~/Deployments` deployment: accurate, neutral defaults on all pages, with the exact replacement copy locked below.
|
||||
|
||||
## Dependencies
|
||||
- `60_sticky_navbar` (complete, preceding — no functional dependency; ordering by number)
|
||||
|
||||
## Tasks
|
||||
1. `01_chat_page_copy.md` — neutralize the chat page (`index.html` meta description, empty-state sub, composer placeholder) + the default suggestion chips in `app/config.py`.
|
||||
2. `02_sources_pages_copy.md` — rewrite the KB page-sub + review the remaining page-subs and the git-sources example URL against current behavior.
|
||||
3. `03_footer_defaults.md` — all 9 footers → neutral default text, tagged `class="footer-text"` (the hook phase 62's env var drives).
|
||||
4. `04_tests_and_commit.md` — unit text pins, dedicated E2E `tests/e2e/test_stale_ui_copy.py`, regression suites, one atomic commit.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit pins (house style, `tests/unit/test_frontend_brand.py` pattern — read the HTML/`config.py` as text): the old literals are GONE, the locked replacements are present, all 9 pages carry `.footer-text`.
|
||||
- E2E (mandatory, house rule): `tests/e2e/test_stale_ui_copy.py`, run in isolation against the shared conftest server — no visible page text contains "homelab"/"deployment" (case-insensitive), placeholder/meta/footer/chips match the locked copy.
|
||||
- Coverage: **>90%** on `app/` (validate.sh gate — this phase changes one Settings default, so the gate is meaningful, not ceremonial).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] No user-visible "homelab"/"deployment(s)" text on any of the 9 pages (case-insensitive; code comments excepted per A3) — proven by the E2E body-text scan on chat + sources pages and the DOM assertions.
|
||||
- [ ] KB page-sub describes the CURRENT source model (git repos + local directories + uploaded archives; Sync pulls/imports).
|
||||
- [ ] All 9 footers read the locked neutral default inside `<span class="footer-text">`.
|
||||
- [ ] `uv run pytest` green; coverage TOTAL >90%; `uv run ruff check . && uv run pyright` clean.
|
||||
- [ ] `uv run pytest tests/e2e/test_stale_ui_copy.py -v --no-cov` green in isolation (DB up).
|
||||
- [ ] Regression E2E suites green in isolation: `test_smoke.py`, `test_configurable_brand.py`, `test_header_consistency.py`, `test_dark_tech_theme.py`.
|
||||
- [ ] One `--no-gpg-sign` commit; phase dir moved to `.agents/phases/complete/` (`.agents/` stays untracked).
|
||||
|
||||
## Locked decisions
|
||||
- **Owner-locked (2026-09-01, roadmap confirmation, A1):** exact replacement copy —
|
||||
- meta description (`index.html` L6): `Ask anything about your indexed documents — every answer cites the exact doc.`
|
||||
- empty-state sub (`index.html` L199–201): `I've read through your documents — ask me anything, and I'll point you at the exact doc. You've got this.`
|
||||
- composer placeholder (`index.html` L231): `Ask me anything…`
|
||||
- KB page-sub (`sources.html` L110–114): `Every file indexed from your configured sources — git repositories, local directories, and uploaded archives. Press <strong>Sync sources</strong> to pull the latest and re-import.`
|
||||
- footer (all 9 pages): `Powered by self-hosted models`
|
||||
- **Owner-locked (2026-09-01, roadmap confirmation, A2):** the four default suggestion chips become —
|
||||
1. `What documents are in the knowledge base?`
|
||||
2. `Which source does each answer come from?`
|
||||
3. `How do I add a new source?`
|
||||
4. `Summarize the most recent document.`
|
||||
|
||||
(operators keep `BOR_SUGGESTIONS` for their own corpus).
|
||||
- **Owner-locked (2026-09-01, roadmap confirmation, A3):** the git-sources example becomes `https://github.com/you/your-repo.git`; code/HTML comments mentioning "homelab" are left untouched (not user-visible).
|
||||
|
||||
## Commit
|
||||
```bash
|
||||
git add frontend/ tests/ app/ && git commit --no-gpg-sign -m "fix(web): retire the stale homelab-era copy — neutral, accurate defaults on every page"
|
||||
```
|
||||
@@ -0,0 +1,39 @@
|
||||
# Task 01 — Neutralize the chat page copy + default suggestion chips
|
||||
|
||||
**Phase:** `61_stale_ui_copy` · **Source:** `TODO.md:4` — "Clean up the UI, there's text that references old features or talks about the way BOR used to work…"
|
||||
**Story:** n/a (TODO-derived)
|
||||
|
||||
## Objective
|
||||
The chat page (the app's front door) and the default onboarding chips describe the app generically — "your documents / your knowledge base" — instead of the owner's homelab, so a first-time deployer sees copy that fits THEIR corpus from the first render.
|
||||
|
||||
## Work
|
||||
1. `frontend/index.html`:
|
||||
- L6 — the `<meta name="description">` content becomes exactly (A1):
|
||||
`Ask anything about your indexed documents — every answer cites the exact doc.`
|
||||
- L199–201 — the `.empty-state-sub` paragraph text becomes exactly (A1):
|
||||
`I've read through your documents — ask me anything, and I'll point you at the exact doc. You've got this.`
|
||||
(keep the surrounding markup; the "You've got this." closer survives by design).
|
||||
- L231 — the `#message-input` `placeholder` becomes exactly (A1): `Ask me anything…`
|
||||
- Leave UNTOUCHED: the visually-hidden `<label>` "Ask Brain of Reese a question" (~L227) and any string embedding the literal "Brain of Reese" — the phase-39 brand layer (`brand.js` attribute pass) keeps those in sync with `BOR_APP_NAME`.
|
||||
2. `app/config.py` L265–270 — the `suggestions` default list becomes exactly (A2):
|
||||
```python
|
||||
suggestions: list[str] = [
|
||||
"What documents are in the knowledge base?",
|
||||
"Which source does each answer come from?",
|
||||
"How do I add a new source?",
|
||||
"Summarize the most recent document.",
|
||||
]
|
||||
```
|
||||
(the `BOR_SUGGESTIONS` JSON env override is unchanged — operators still override per corpus).
|
||||
3. No other file changes in this task (sources pages and footers are tasks 02/03; the unit pins land in task 04).
|
||||
|
||||
## Testing & Quality
|
||||
- No existing test pins the old default chip text (`tests/integration/test_api.py` L75–81 asserts shape only: list, `len >= 3`, non-empty strings — the new 4-chip default satisfies it).
|
||||
- `uv run pytest` green (full unit + integration); `uv run ruff check . && uv run pyright` clean.
|
||||
- Coverage: **>90%** on `app/` (validate.sh gate).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -n "homelab" frontend/index.html` matches ONLY the L176 code comment (A3) — no user-visible homelab text remains in the chat template.
|
||||
- [ ] `grep -n "Ask me anything" frontend/index.html` shows the new placeholder (exactly one user-visible occurrence).
|
||||
- [ ] `app/config.py` default chips == the four locked (A2) strings; `uv run pytest tests/integration/test_api.py -v` green.
|
||||
- [ ] Full suite green, lint + types clean, coverage >90%.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Task 02 — Rewrite the Knowledge-base copy to the current source model
|
||||
|
||||
**Phase:** `61_stale_ui_copy` · **Source:** `TODO.md:4` — "…the page-sub text in knowledge base references !/Homelab and ~/Deployments but those aren't the only sources and sometimes aren't included."
|
||||
**Story:** n/a (TODO-derived)
|
||||
|
||||
## Objective
|
||||
The Sources/KB page — the page the TODO cites by name — and the remaining page-subs describe the source model as BOR implements it TODAY: configured git repositories, local directories, and uploaded archives (phases 28/38/49), with import extensions set by `BOR_IMPORT_EXTENSIONS` (phase 56) — not "every `*.md` in `~/Homelab` and `~/Deployments`".
|
||||
|
||||
## Work
|
||||
1. `frontend/sources.html` L110–114 — the `<p class="page-sub">` becomes exactly (A1), keeping the `<strong>` around Sync sources:
|
||||
```html
|
||||
<p class="page-sub">
|
||||
Every file indexed from your configured sources — git repositories,
|
||||
local directories, and uploaded archives. Press <strong>Sync sources</strong>
|
||||
to pull the latest and re-import.
|
||||
</p>
|
||||
```
|
||||
(line-wrapped as in the original; the `<code>` tags for `~/Homelab` / `~/Deployments` are deleted, not reworded).
|
||||
2. `frontend/git-sources.html` L175 — the repo-URL form example becomes (A3):
|
||||
`placeholder="https://github.com/you/your-repo.git"`
|
||||
3. Verification read-through (fix only what is factually stale; do not reword accurate copy):
|
||||
- `frontend/sources.html` — the sync result/error copy (`#sync-result` announcer strings in `frontend/assets/sources.js`, the `#sync-error-banner` text): confirm it matches what Sync actually does (pulls configured git repos, imports local directories, re-imports; "no sources configured" loud failure). The phase-35+ error strings already name the real failure modes — expect no change; record the outcome in the commit message body only if something was fixed.
|
||||
- The remaining page-subs — `tuning.html` L104–108 (Global Tuning), `history.html` L106–110 (Saved chats), `doc-edit.html` L38–42 (Edit doc), `git-sources.html` L135–139 (Git sources): each describes current behavior (verified at audit time) — expect no change; if any is stale against current behavior, fix it with neutral, accurate wording and note it in the commit message.
|
||||
- The anonymous sources gate copy (`frontend/sources.html` `#sources-gate`) — confirms what stays public vs. locked; accurate — expect no change.
|
||||
4. Do NOT touch code/HTML comments mentioning "homelab" anywhere (A3).
|
||||
|
||||
## Testing & Quality
|
||||
- No logic changes in this task — the full suite stays green unchanged; `uv run ruff check . && uv run pyright` clean.
|
||||
- Coverage: **>90%** on `app/` (validate.sh gate).
|
||||
- The text pins for the new copy land in task 04 (unit + E2E).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -n "Homelab\|Deployments" frontend/sources.html` is empty.
|
||||
- [ ] `grep -n "homelab" frontend/git-sources.html` is empty.
|
||||
- [ ] The KB page-sub reads the locked (A1) text, including `<strong>Sync sources</strong>`.
|
||||
- [ ] The verification read-through is done and its outcome (changed / no change per page) is recorded in the task completion report.
|
||||
- [ ] Full suite green, lint + types clean.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Task 03 — Neutral footer default on all 9 pages (+ the `.footer-text` hook)
|
||||
|
||||
**Phase:** `61_stale_ui_copy` · **Source:** `TODO.md:4` — "Clean up the UI, there's text that references old features or talks about the way BOR used to work…"
|
||||
**Story:** n/a (TODO-derived)
|
||||
|
||||
## Objective
|
||||
The footer line — duplicated verbatim on all 9 pages — stops naming the owner ("Powered by **Reese's** self-hosted models") and reads the locked neutral default; each footer span is tagged `class="footer-text"` so phase 62's `BOR_FOOTER_TEXT` env var has one stable selector to drive on every page.
|
||||
|
||||
## Work
|
||||
1. On ALL 9 pages, replace the identical footer span (audit-verified locations):
|
||||
```html
|
||||
<span>Powered by Reese's self-hosted models</span>
|
||||
```
|
||||
with exactly (A1):
|
||||
```html
|
||||
<span class="footer-text">Powered by self-hosted models</span>
|
||||
```
|
||||
Locations: `frontend/index.html` L245 · `frontend/sources.html` L186 · `frontend/tuning.html` L148 · `frontend/document.html` L150 · `frontend/git-sources.html` L243 · `frontend/history.html` L173 · `frontend/login.html` L131 · `frontend/shared.html` L147 · `frontend/doc-edit.html` L118.
|
||||
- The `<span class="footer-version" id="app-version"></span>` siblings (where present) are untouched.
|
||||
- No CSS change: `.footer-inner > span` is unstyled inline text today; adding the class is selector-only.
|
||||
2. Sanity: `grep -rn "Reese's" frontend/` must be empty after this task (the possessive form existed ONLY in these footers — the brand layer's literal is "Brain of Reese", which is a different string and stays).
|
||||
|
||||
## Testing & Quality
|
||||
- No logic changes — full suite green unchanged; `uv run ruff check . && uv run pyright` clean.
|
||||
- Coverage: **>90%** on `app/` (validate.sh gate).
|
||||
- The 9-page `.footer-text` pin lands in task 04's unit test.
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] All 9 pages carry `<span class="footer-text">Powered by self-hosted models</span>` (exactly 9 occurrences: `grep -rc 'class="footer-text"' frontend/*.html`).
|
||||
- [ ] `grep -rn "Reese's" frontend/` is empty.
|
||||
- [ ] The phase-39 brand layer is unaffected: `uv run pytest tests/unit/test_frontend_brand.py tests/e2e/test_configurable_brand.py -v --no-cov` — the unit file green; (the E2E needs DB up — run it in task 04's regression pass instead if the DB is down).
|
||||
- [ ] Full suite green, lint + types clean.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Task 04 — Unit text pins + dedicated E2E + regression pass + atomic commit
|
||||
|
||||
**Phase:** `61_stale_ui_copy` · **Source:** `TODO.md:4` — "Clean up the UI, there's text that references old features or talks about the way BOR used to work…"
|
||||
**Story:** n/a (TODO-derived)
|
||||
|
||||
## Objective
|
||||
The new neutral copy is pinned at two layers so it can never silently regress: unit text pins (no browser, house style) and one dedicated Playwright suite asserting what a visitor actually SEES on the shared default server — then one atomic commit.
|
||||
|
||||
## Work
|
||||
1. `tests/unit/test_stale_ui_copy.py` (NEW — house pattern `tests/unit/test_frontend_brand.py`: read files as text, assert substrings):
|
||||
- Negative pins (GONE): `"the homelab and deployments"` (meta), `"the homelab and deployment notes"` (empty-state sub), `"Ask me about the homelab"` (placeholder), `"~/Homelab"` and `"~/Deployments"` (KB page-sub), `"Reese's self-hosted models"` (footers), the four old default chips incl. `"What's currently running in the homelab?"` — checked against `frontend/index.html`, `frontend/sources.html`, `frontend/git-sources.html`, and `app/config.py` where they lived.
|
||||
- Positive pins (PRESENT, exactly once where asserted): the five locked (A1) strings in their files; the four locked (A2) chips in `app/config.py`; `class="footer-text"` in ALL 9 HTML pages (iterate the same `HTML_PAGES` tuple as `test_frontend_brand.py`).
|
||||
- The old chip strings are asserted absent from `app/config.py` (they may still appear NOWHERE else — they are retired, not relocated).
|
||||
2. `tests/e2e/test_stale_ui_copy.py` (NEW — one story, one file, run in isolation, DB up; shared conftest server, default env — no second instance needed):
|
||||
- Chat page (`/` or `/index.html`):
|
||||
- `#message-input` placeholder === `Ask me anything…`;
|
||||
- `document.querySelector('meta[name="description"]').content` === the locked (A1) meta string;
|
||||
- the first `.footer-text` textContent === `Powered by self-hosted models`;
|
||||
- `document.body.innerText.toLowerCase()` contains neither `homelab` nor `deployment` (the rendered empty-state sub AND the four rendered suggestion chips are covered by this scan — chips come from `GET /api/suggestions`, default list);
|
||||
- the four rendered `.suggestions` chips' texts === the locked (A2) list, in order.
|
||||
- Sources page (`/sources.html`): the `.page-sub` innerText contains neither `Homelab` nor `Deployments` (case-insensitive) and DOES contain `configured sources`; (the page is anonymously viewable — the catalog gate hides the table, not the page-head).
|
||||
- Git sources page (`/git-sources.html`): the repo-URL input's `placeholder` attribute === `https://github.com/you/your-repo.git` (read from the DOM — the element exists even while `#git-sources-content` is `hidden` for anonymous; no sign-in needed).
|
||||
- Determinism: all assertions are settled-state (static HTML + one fetch of /api/suggestions); Playwright `expect` retries ride out chip rendering.
|
||||
3. Regression E2E pass (each in isolation, DB up): `test_smoke.py`, `test_configurable_brand.py`, `test_header_consistency.py`, `test_dark_tech_theme.py`.
|
||||
4. One atomic commit (`.agents/` untracked — owner instruction, commit 281f355):
|
||||
```bash
|
||||
git add frontend/ tests/ app/ && git commit --no-gpg-sign -m "fix(web): retire the stale homelab-era copy — neutral, accurate defaults on every page"
|
||||
```
|
||||
Commit body: the verification read-through outcome from task 02 (which pages needed no change / what was fixed) — one line each.
|
||||
|
||||
## Testing & Quality
|
||||
- `uv run pytest` green (unit + integration); coverage TOTAL **>90%** (validate.sh gate).
|
||||
- `uv run pytest tests/e2e/test_stale_ui_copy.py -v --no-cov` green in isolation.
|
||||
- `uv run ruff check . && uv run pyright` clean.
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `tests/unit/test_stale_ui_copy.py` + `tests/e2e/test_stale_ui_copy.py` exist and are green (E2E in isolation, DB up).
|
||||
- [ ] The four regression E2E suites are green in isolation.
|
||||
- [ ] Full suite green, coverage >90%, lint + types clean.
|
||||
- [ ] Exactly one new commit on `main`, staged paths `frontend/ tests/ app/` only, `--no-gpg-sign`.
|
||||
- [ ] Phase dir moved to `.agents/phases/complete/61_stale_ui_copy/` (`.agents/` stays untracked).
|
||||
Reference in New Issue
Block a user