phase: 174_git_sources_card_rhythm
Build and Push Containers / build-and-push-app (push) Successful in 1m51s
Build and Push Containers / build-and-push-db (push) Successful in 13s

All checks pass. Both docs verified consistent. Final state — no live-infrastructure changes were needed (pure CSS fix; verification ran against the already-running local dev DB).

**Phase 174 final verification pass — report**

- **Verified (no new work needed; both tasks already complete in `complete/`):** the single `#git-sources-content { display:flex; flex-direction:column; gap:1.25rem }` rule in `frontend/assets/styles.css` (with the phase-174 root-cause comment), `.git-sources-shell` untouched, the 4-test unit pin module, and the 4-test Playwright suite.
- **Full suite:** `uv run pytest --cov=app --cov-report=term-missing` → **4116 passed, 99% `app/` coverage** (gate >90% ✓).
- **Lint/types:** `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings.
- **Dedicated E2E in isolation:** `uv run pytest tests/e2e/test_git_sources_card_rhythm.py -v --no-cov` → **4 passed** (1440px + 375px bounding-box rhythm pins 20±2px, hidden-children + revealed-joins-rhythm, anonymous gate, a11y/no-CDN).
- **Regression set, each in isolation:** `test_git_sources_admin.py` **6 passed**, `test_archive_upload_sources.py` **5 passed**, `test_git_source_dates.py` **4 passed**.
- **Completion criteria:** cards stack with uniform ≈20px gap at both viewports ✓; hidden children stay hidden / gate+content flip intact ✓; ≤640px forms column-stack + table scrolls inside its card (no page-level h-scroll) ✓; full suite + coverage + ruff + pyright ✓; dedicated + regression E2E suites ✓.
- **Documentation:** README.md reviewed in full (every `.env.example` var documented; all documented routes/pages/endpoints exist; every config default cross-checked against `app/config.py`; payload-limit table, ports 8123/8901, Containerfile/compose/entrypoint claims all match) — **verified consistent, no changes needed**. AGENTS.md verified (all referenced files/sections exist: PLAN §2/§7.1/§7.4/§9, `response_budget.py`, `debugging.py` conditional import, `.agents/` tracked + gitignore rules, `commit.gpgsign=false`, phase-pinned CSS classes) — **verified consistent, no changes needed**.
- **Notable:** commit + phase-dir move are handled by the harness per pipeline rules (no git history/index touched by this pass); no live-infrastructure changes were required.
- **Next pending phase:** `175_history_pagination` (in `todo/`).
This commit is contained in:
2026-10-11 01:49:49 -04:00
parent da441ea799
commit 938d6cf09d
18 changed files with 1333 additions and 0 deletions
@@ -0,0 +1,46 @@
# Phase 174 — Sources (git sources) page: the card stack regains its 1.25rem rhythm
**Source:** Owner bug report 2026-10-21 (screenshot of `/git-sources.html` — "the bubbles on the sources page are really smooshed together": the "Git sources" header card, the "Add a git source" card, the "Upload a source archive" card, and the sources table card stack flush — only their 1px borders separate them).
**Story:** n/a (owner bug report, this chat 2026-10-21)
**Context:** `frontend/index.html` — `#view-git-sources` (L646): `.container.git-sources-shell` holds TWO children — the anonymous `.sources-gate` (`#git-sources-gate`, L651) and the single `#git-sources-content` wrapper (L672) that wraps **every** visible card: `.page-head`, the `#git-sources-load-error` alert (hidden), the `#git-source-env-note` (hidden), `#git-source-form`, `#archive-upload-form`, and the `.table-wrap#git-sources-table-wrap`; `frontend/assets/styles.css` — `.git-sources-shell` (L3193–3200: `display:flex; flex-direction:column; gap: 1.25rem; flex:1` — the gap only separates the gate from the wrapper), `#git-sources-content` (**no rule at all** — a plain div, so its children stack with zero vertical rhythm — the root of the "smooshed" look), the phase-93 `.page-head` card (L2423–2428), the phase-27/49 form cards `#git-source-form, #archive-upload-form` (L3207+), the ≤640px block (L6400–6403: the forms go column — they compose with the fix unchanged), `frontend/assets/git-sources.js` (L294, L1515–1519: the gate↔content reveal — `contentEl.hidden` flips only); `tests/e2e/auth_helpers.py::login` (the admin E2E sign-in), `tests/e2e/test_admin_settings_layout.py` (the phase-171 bounding-box rhythm E2E — the house pattern this suite copies), `tests/unit/test_git_source_branch_ui.py` (the static CSS/HTML/JS pin style this phase extends).
## Objective
The five stacked cards on the Sources page (the navbar "Sources" link → `/git-sources.html`) get one uniform 1.25rem gap between them — CSS only, reusing the shell's **existing** `gap: 1.25rem` token (the phase-171 `#settings-content` idiom applied to the one remaining admin view whose cards live inside a wrapper div). Nothing else changes: no JS, no `app/` code, no new palette/spacing value, the gate + load-error + env-note reveal lifecycles byte-identical.
## Design (shared by all tasks — the executor reads this, not the chat)
- **D1 — the rhythm (task 01).** `#git-sources-content` becomes `display: flex; flex-direction: column; gap: 1.25rem;` — the **same** token `.git-sources-shell` already uses (L3196) and the value phase 171 gave `#settings-content`. One rule, placed directly after the `.git-sources-shell` rule with a phase-174 comment explaining the wrapper-swallowed-the-shell-gap root cause. The children (page-head card, load-error alert, env note, the two form cards, the table card) then stack with one uniform gap at every viewport.
- **D2 — the hidden children (task 01, pinned in 02).** The two `hidden` children (`#git-sources-load-error`, `#git-source-env-note`) keep the UA `[hidden] → display:none` even inside a flex parent (the parent's `display` never overrides a child's own `display`), so `git-sources.js`'s reveal lifecycle (L1515–1519) is untouched; a revealed error/note simply joins the rhythm. The anonymous gate↔content flip (L1515–1519: `contentEl.hidden = false`) works on a flex element exactly as on a block.
- **D3 — no other changes.** `.git-sources-shell` (its `flex: 1` + gap stay — the gate↔content separation at anonymous), `git-sources.js`, `app/` server code, the form/table card rules, and the ≤640px media queries (L6400–6403) are all untouched; the fix is a single wrapper rule.
## Dependencies
- `171_admin_settings_layout` (complete) — the idiom this phase reuses (wrapper div → flex column + the existing 1.25rem token).
- `93_theme_semantic_completion` (complete) — the `.page-head` card language the rhythm spaces out (context only).
## Tasks
1. `01_content_card_rhythm.md` — `#git-sources-content` becomes the flex-column rhythm wrapper (the one CSS rule); the static pins.
2. `02_e2e_sources_card_rhythm.md` — `tests/e2e/test_git_sources_card_rhythm.py` (the phase's dedicated Playwright suite, AGENTS rule 4), the regression set, the full gates, the atomic commit.
## Testing & Quality
- **Unit:** `tests/unit/test_git_sources_card_rhythm.py` (new module, the `test_git_source_branch_ui.py` pin style): the `#git-sources-content` rule in `styles.css` with `display: flex` / `flex-direction: column` / `gap: 1.25rem` (the exact token — a regression to a different value fails), the `.git-sources-shell` gap staying `1.25rem` (unchanged), the `#git-sources-content` div present in `index.html` inside `.git-sources-shell` with the gate as a sibling (the structural pin — if the cards ever move back to the shell's direct children the rule becomes dead weight and the pin must say so).
- **E2E (AGENTS rule 4, task 02):** `tests/e2e/test_git_sources_card_rhythm.py`, run **in isolation** — the rhythm contract proven in a browser at 1440px and 375px, plus the hidden-children pin and the standard a11y/no-CDN light pass.
- **Coverage:** **>90%** on `app/` (this phase changes no `app/` code — the gate must stay green, not drop).
- **Lint/types:** `uv run ruff check . && uv run pyright`.
- The phase is "Complete" only when the **entire** project test suite passes 100% (every test in the project, not just this phase's) and the gates above are green.
## Documentation & Consistency
- The final pass reviews `README.md` and `AGENTS.md` in full against the project as it stands after this phase — fixing every inconsistency found, **including pre-existing ones not caused by this phase**.
- Tasks update `README.md`/`AGENTS.md` immediately when their own changes are user-visible (this phase is a visual fix with no setup/command/config surface — expected: no doc edits).
## Completion Criteria
- [ ] On `/git-sources.html` (admin), the five cards (page-head → add form → upload form → table, plus a revealed load-error when one is forced) stack with one uniform ≈20px gap — no two card edges touch (the E2E bounding-box pins, at 1440px and 375px).
- [ ] `#git-sources-content`'s hidden children (`#git-sources-load-error`, `#git-source-env-note`) stay hidden in the flex wrapper (E2E pin); the anonymous gate still shows and the content stays hidden for anonymous (regression).
- [ ] The ≤640px mobile layout is intact (the forms column-stack per L6400–6403; the table scrolls inside its card — the E2E mobile pin).
- [ ] `uv run pytest` green, `app/` coverage >90% (`uv run pytest --cov=app --cov-report=term-missing`), ruff + pyright clean.
- [ ] `uv run pytest tests/e2e/test_git_sources_card_rhythm.py -v --no-cov` green **in isolation**; `test_git_sources_admin.py` + `test_archive_upload_sources.py` + `test_git_source_dates.py` green in isolation (the regression set).
- [ ] README.md and AGENTS.md are accurate and consistent with the whole project (verified in the final pass).
- [ ] One atomic `--no-gpg-sign` Conventional Commit; the phase dir moves to `.agents/phases/complete/`.
## Commit
```bash
git add frontend/ tests/ .agents/phases/ && git commit --no-gpg-sign -m "fix(sources): Sources (git sources) page — the card stack regains its 1.25rem rhythm"
```
@@ -0,0 +1,45 @@
# Task 01 — `#git-sources-content` becomes the flex-column rhythm wrapper
**Phase:** `174_git_sources_card_rhythm` · **Story:** n/a (owner bug report 2026-10-21)
## Objective
The one CSS rule that restores the vertical rhythm on the Sources page: `#git-sources-content` becomes a flex column with the shell's existing `1.25rem` gap — so the five stacked cards (page-head, load-error, env-note, add form, upload form, table card) stop stacking flush.
## Work
1. `frontend/assets/styles.css` — directly after the `.git-sources-shell` rule (L3193–3200), add the `#git-sources-content` rule with a phase-174 comment block (the house comment style: root cause + the reused token + the hidden-children behavior):
```css
/* Phase 174 (owner bug report 2026-10-21): the shell's gap only
separates the gate from this wrapper — every visible card
(page-head, the load-error alert, the env note, the two form
cards, the table card) is a child of THIS div, which was a
plain block, so the cards stacked flush (1px borders touching).
The phase-171 #settings-content idiom: the wrapper itself is
the rhythm column, reusing the shell's own 1.25rem token — no
new spacing value. The hidden children (#git-sources-load-error,
#git-source-env-note) keep the UA [hidden] display:none inside
a flex parent, so git-sources.js's reveal lifecycle is
untouched; a revealed one joins the rhythm. */
#git-sources-content {
display: flex;
flex-direction: column;
gap: 1.25rem;
}
```
No other CSS change. Do not touch `.git-sources-shell`, the form/table card rules, or the ≤640px block (L6400–6403 — the forms' column-stacks compose with the new wrapper unchanged).
2. `tests/unit/test_git_sources_card_rhythm.py` — new module (the `test_git_source_branch_ui.py` pin style: `FRONTEND`/`STYLES_CSS`/`SHELL_HTML` path constants, raw text assertions, module docstring citing the phase + the owner report):
- the `#git-sources-content` rule exists in `styles.css` and carries `display: flex`, `flex-direction: column`, and `gap: 1.25rem` **exactly** (extract the rule body with a small regex over the `#git-sources-content { … }` block — a regression to any other gap value or a missing flex line fails);
- the `.git-sources-shell` rule still carries `gap: 1.25rem` (the fix must not have "fixed" the shell — D3);
- the structural pin: in `index.html`, `#git-sources-content` sits inside `.container.git-sources-shell` and the `.sources-gate` (`#git-sources-gate`) is a sibling of it (so the rule is not dead weight — if a future refactor moves the cards to the shell's direct children, this pin names the dead rule);
- `#git-sources-load-error` and `#git-source-env-note` still carry `hidden` in `index.html` (the D2 premise the E2E pin proves in a browser).
## Testing & Quality
- Unit: the pins above; `uv run pytest tests/unit/test_git_sources_card_rhythm.py -v` green.
- Coverage: **>90%** on `app/` (unchanged by this task — the gate must stay green, not drop).
- No `app/` code change; no JS change.
## Completion Criteria
- [ ] `uv run pytest tests/unit/test_git_sources_card_rhythm.py -v` green.
- [ ] `uv run pytest` green (the full unit + integration suite — no pin broke).
- [ ] `uv run ruff check . && uv run pyright` clean.
- [ ] README.md/AGENTS.md need no change for this task (visual-only; the phase's final pass re-checks both project-wide).
- [ ] no behavior change in completed work (the gate reveal, the load-error retry, the env note, the form lifecycles are untouched — the rule only adds inter-card spacing).
@@ -0,0 +1,33 @@
# Task 02 — the phase's dedicated Playwright E2E suite + gates + commit
**Phase:** `174_git_sources_card_rhythm` · **Story:** n/a (owner bug report 2026-10-21)
## Objective
Prove the rhythm in a browser — `tests/e2e/test_git_sources_card_rhythm.py` (the phase's dedicated Playwright suite, AGENTS rule 4): the cards on `/git-sources.html` stack with one uniform gap at 1440px and 375px, the hidden children stay hidden in the flex wrapper, and the anonymous gate is intact. Then the regression set, the full gates, and the atomic commit.
## Work
1. `tests/e2e/test_git_sources_card_rhythm.py` — new module, run **in isolation** (`uv run pytest tests/e2e/test_git_sources_card_rhythm.py -v --no-cov`; DB must be up: `podman compose up -d db`). House shape: module docstring (the owner report + the run command + the test→contract map), the session `mock_llm`/`app_server`/`app_url`/`db_ready`/`page` fixtures from `tests/e2e/conftest.py`, `tests/e2e/auth_helpers.py::login` for the admin sign-in, a per-test `_truncate_kb`-style reset so each test's table state is its own (the `test_git_sources_admin.py` pattern — this suite is UI-only: it needs NO sync, no git, no network; the app can boot plain, the cards render regardless of row count).
Tests (four):
- `test_cards_stack_with_uniform_rhythm_desktop` — 1440×900, admin (`login(page, app_url, next="/git-sources.html")`): `#git-sources-content`'s computed `display` is `flex` and its `gap` resolves to 20px; the bounding boxes of the four visible cards — `.page-head` → `#git-source-form` → `#archive-upload-form` → `#git-sources-table-wrap` — are **pairwise disjoint** and each successive gap is ≈20px (`box_{n+1}.top − box_n.bottom == 20 ± 2`); no two card edges touch (the pre-fix regression: the gaps were ~0 — the 1px borders).
- `test_cards_stack_with_uniform_rhythm_mobile` — 375×720, admin: the same four cards are pairwise disjoint with ≈20px gaps; the two form cards column-stack per the ≤640px block (L6400–6403 — assert `#git-source-form` computed `flex-direction: column`) and the table scrolls **inside** its card (the `#git-sources-table-wrap` horizontal overflow is contained — the card's right edge is left of the viewport, no page-level horizontal scroll: `document.scrollingElement.scrollWidth <= 375`).
- `test_hidden_children_stay_hidden_in_flex_wrapper` — admin: `#git-sources-load-error` and `#git-source-env-note` are not visible (the `[hidden]` UA rule survives the flex parent — `offsetParent is None` / `is_visible() == False`); then force the load-error's `hidden` off via the page (attribute removal) and assert it **joins the rhythm** (visible, and its box sits ≥18px below the element above it) — the D2 both-sides pin; anonymous: `#git-sources-gate` visible, `#git-sources-content` hidden, no `/api/git-sources` call (the `test_git_sources_admin.py` anonymous contract, copied — the gate↔content flip is unchanged by the fix).
- `test_sources_page_a11y_and_no_cdn_basics` — the standard light pass (AGENTS rule 5/6, the `test_git_sources_admin.py` a11y test shape): landmarks on the view, the labeled form controls, the 3px `:focus-visible` outline on a table-row control (keyboard Tab), same-origin assets only (no external `<script src>`/`<link href>`).
2. **Regression set (in isolation, in order):** `uv run pytest tests/e2e/test_git_sources_admin.py -v --no-cov`, then `test_archive_upload_sources.py`, then `test_git_source_dates.py` (the three suites that touch the git-sources view's gate/forms/table — all must be green with the wrapper now flex).
3. **Full gates (the `.agents/validate.sh` set):** `uv run pytest --cov=app --cov-report=term-missing` (the entire project suite 100% passing + `app/` coverage >90% — this phase changes no `app/` code, the floor must hold, not drop), `uv run ruff check .`, `uv run pyright`.
4. **Final documentation & consistency pass:** review `README.md` and `AGENTS.md` in full against the project as it stands after this phase; fix every inconsistency found, **including pre-existing ones** (expected for this phase: no doc edits — visual-only).
5. **Commit + move:** the atomic commit, then move the phase dir to `.agents/phases/complete/` (the `.agents/` tree is tracked — commit it with the phase per AGENTS rule 8).
## Testing & Quality
- E2E: the dedicated suite green **in isolation** + the three-suite regression set green in isolation.
- Coverage: **>90%** on `app/` (unchanged — the floor holds).
- Lint/types: ruff + pyright clean.
## Completion Criteria
- [ ] `uv run pytest tests/e2e/test_git_sources_card_rhythm.py -v --no-cov` green **in isolation** (DB up).
- [ ] `uv run pytest tests/e2e/test_git_sources_admin.py -v --no-cov`, `test_archive_upload_sources.py`, `test_git_source_dates.py` — each green in isolation.
- [ ] `uv run pytest --cov=app --cov-report=term-missing`: the entire project suite 100% passing, `app/` coverage >90%.
- [ ] `uv run ruff check . && uv run pyright` clean.
- [ ] README.md and AGENTS.md accurate and consistent with the whole project (verified in the final pass).
- [ ] one atomic `--no-gpg-sign` Conventional Commit:
`git add frontend/ tests/ .agents/phases/ && git commit --no-gpg-sign -m "fix(sources): Sources (git sources) page — the card stack regains its 1.25rem rhythm"`
- [ ] the phase dir moved to `.agents/phases/complete/174_git_sources_card_rhythm/`.
@@ -0,0 +1,13 @@
All checks pass. Both docs verified consistent. Final state — no live-infrastructure changes were needed (pure CSS fix; verification ran against the already-running local dev DB).
**Phase 174 final verification pass — report**
- **Verified (no new work needed; both tasks already complete in `complete/`):** the single `#git-sources-content { display:flex; flex-direction:column; gap:1.25rem }` rule in `frontend/assets/styles.css` (with the phase-174 root-cause comment), `.git-sources-shell` untouched, the 4-test unit pin module, and the 4-test Playwright suite.
- **Full suite:** `uv run pytest --cov=app --cov-report=term-missing` → **4116 passed, 99% `app/` coverage** (gate >90% ✓).
- **Lint/types:** `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings.
- **Dedicated E2E in isolation:** `uv run pytest tests/e2e/test_git_sources_card_rhythm.py -v --no-cov` → **4 passed** (1440px + 375px bounding-box rhythm pins 20±2px, hidden-children + revealed-joins-rhythm, anonymous gate, a11y/no-CDN).
- **Regression set, each in isolation:** `test_git_sources_admin.py` **6 passed**, `test_archive_upload_sources.py` **5 passed**, `test_git_source_dates.py` **4 passed**.
- **Completion criteria:** cards stack with uniform ≈20px gap at both viewports ✓; hidden children stay hidden / gate+content flip intact ✓; ≤640px forms column-stack + table scrolls inside its card (no page-level h-scroll) ✓; full suite + coverage + ruff + pyright ✓; dedicated + regression E2E suites ✓.
- **Documentation:** README.md reviewed in full (every `.env.example` var documented; all documented routes/pages/endpoints exist; every config default cross-checked against `app/config.py`; payload-limit table, ports 8123/8901, Containerfile/compose/entrypoint claims all match) — **verified consistent, no changes needed**. AGENTS.md verified (all referenced files/sections exist: PLAN §2/§7.1/§7.4/§9, `response_budget.py`, `debugging.py` conditional import, `.agents/` tracked + gitignore rules, `commit.gpgsign=false`, phase-pinned CSS classes) — **verified consistent, no changes needed**.
- **Notable:** commit + phase-dir move are handled by the harness per pipeline rules (no git history/index touched by this pass); no live-infrastructure changes were required.
- **Next pending phase:** `175_history_pagination` (in `todo/`).
@@ -0,0 +1,136 @@
........................................................................ [ 1%]
........................................................................ [ 3%]
........................................................................ [ 5%]
........................................................................ [ 6%]
........................................................................ [ 8%]
........................................................................ [ 10%]
........................................................................ [ 12%]
........................................................................ [ 13%]
........................................................................ [ 15%]
........................................................................ [ 17%]
........................................................................ [ 19%]
........................................................................ [ 20%]
........................................................................ [ 22%]
........................................................................ [ 24%]
........................................................................ [ 26%]
........................................................................ [ 27%]
........................................................................ [ 29%]
........................................................................ [ 31%]
........................................................................ [ 33%]
........................................................................ [ 34%]
........................................................................ [ 36%]
........................................................................ [ 38%]
........................................................................ [ 40%]
........................................................................ [ 41%]
........................................................................ [ 43%]
........................................................................ [ 45%]
........................................................................ [ 47%]
........................................................................ [ 48%]
........................................................................ [ 50%]
........................................................................ [ 52%]
........................................................................ [ 54%]
........................................................................ [ 55%]
........................................................................ [ 57%]
........................................................................ [ 59%]
........................................................................ [ 61%]
........................................................................ [ 62%]
........................................................................ [ 64%]
........................................................................ [ 66%]
........................................................................ [ 68%]
........................................................................ [ 69%]
........................................................................ [ 71%]
........................................................................ [ 73%]
........................................................................ [ 75%]
........................................................................ [ 76%]
........................................................................ [ 78%]
........................................................................ [ 80%]
........................................................................ [ 82%]
........................................................................ [ 83%]
........................................................................ [ 85%]
........................................................................ [ 87%]
........................................................................ [ 89%]
........................................................................ [ 90%]
........................................................................ [ 92%]
........................................................................ [ 94%]
........................................................................ [ 96%]
........................................................................ [ 97%]
........................................................................ [ 99%]
............ [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
--------------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/admin_settings.py 114 0 100%
app/api/auth.py 52 0 100%
app/api/chat.py 280 1 99%
app/api/chat_images.py 50 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 13 0 100%
app/api/doc_drafts.py 99 0 100%
app/api/docs.py 234 1 99%
app/api/git_sources.py 259 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 33 0 100%
app/api/sync.py 204 0 100%
app/api/tokens.py 40 0 100%
app/api/ui_settings.py 55 0 100%
app/config.py 288 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 45 0 100%
app/core/caching.py 124 0 100%
app/core/compression.py 59 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 43 0 100%
app/core/errors.py 5 0 100%
app/core/http_cache.py 22 0 100%
app/core/logging.py 13 0 100%
app/core/rate_limit.py 44 0 100%
app/core/response_budget.py 63 0 100%
app/core/security_headers.py 20 0 100%
app/core/settings_catalog.py 18 0 100%
app/core/settings_migrate.py 32 0 100%
app/core/settings_overlay.py 111 0 100%
app/core/theming.py 38 0 100%
app/core/tokens.py 44 0 100%
app/db.py 22 0 100%
app/main.py 91 0 100%
app/models.py 141 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 454 1 99%
app/rag/archive_upload.py 134 0 100%
app/rag/chunker.py 220 4 98%
app/rag/doc_dates.py 18 0 100%
app/rag/folder_summaries.py 134 0 100%
app/rag/git_sources.py 77 0 100%
app/rag/importer.py 841 4 99%
app/rag/llm.py 253 1 99%
app/rag/md_images.py 63 0 100%
app/rag/overview.py 78 0 100%
app/rag/pdf.py 192 0 100%
app/rag/prompts.py 156 0 100%
app/rag/retriever.py 252 3 99%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 58 0 100%
app/schemas.py 532 0 100%
--------------------------------------------------
TOTAL 6449 17 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
validation OK
@@ -0,0 +1,19 @@
Task 01 complete — all gates green.
**Implemented**
- `frontend/assets/styles.css`: single new rule `#git-sources-content { display: flex; flex-direction: column; gap: 1.25rem; }` directly after the `.git-sources-shell` rule, with the phase-174 comment block (root cause, reused 1.25rem token, hidden-children D2 note). Nothing else touched (D3 verified by pin).
- `tests/unit/test_git_sources_card_rhythm.py` (new, house pin style): exact-rule pin for the wrapper (regex-extracted body — `display: flex` / `flex-direction: column` / `gap: 1.25rem` exact), `.git-sources-shell` unchanged pin (gap + `flex: 1`), structural pin (`#git-sources-content` + `#git-sources-gate` are direct children of the shell via a balanced div/depth scan, gate precedes content), and the `hidden`-attribute pins for `#git-sources-load-error` + the env note.
**Results**
- `uv run pytest tests/unit/test_git_sources_card_rhythm.py -v` → 4 passed
- `uv run pytest` → **4116 passed**, 0 failed
- `uv run pytest --cov=app --cov-report=term-missing` → **99%** on `app/` (gate >90%)
- `uv run ruff check . && uv run pyright` → clean (0 errors)
**Docs** — no doc impact (visual-only fix, no setup/command/config surface), per the task's own note.
**Notable decisions**
- The phase doc's `#git-source-env-note` is the element's *class*; its actual id is `git-sources-env-note` — the pin targets the id and documents the alias.
- Structural pin uses a depth-1 tag scan (handles void `<input>` tags and self-closing SVG children) rather than end-of-shell anchoring, since the shell's last child is the `#git-sources-announcer` region.
**Next pending task** — `02_e2e_sources_card_rhythm.md` (dedicated Playwright suite, regression set, full gates, atomic commit).
@@ -0,0 +1,136 @@
........................................................................ [ 1%]
........................................................................ [ 3%]
........................................................................ [ 5%]
........................................................................ [ 6%]
........................................................................ [ 8%]
........................................................................ [ 10%]
........................................................................ [ 12%]
........................................................................ [ 13%]
........................................................................ [ 15%]
........................................................................ [ 17%]
........................................................................ [ 19%]
........................................................................ [ 20%]
........................................................................ [ 22%]
........................................................................ [ 24%]
........................................................................ [ 26%]
........................................................................ [ 27%]
........................................................................ [ 29%]
........................................................................ [ 31%]
........................................................................ [ 33%]
........................................................................ [ 34%]
........................................................................ [ 36%]
........................................................................ [ 38%]
........................................................................ [ 40%]
........................................................................ [ 41%]
........................................................................ [ 43%]
........................................................................ [ 45%]
........................................................................ [ 47%]
........................................................................ [ 48%]
........................................................................ [ 50%]
........................................................................ [ 52%]
........................................................................ [ 54%]
........................................................................ [ 55%]
........................................................................ [ 57%]
........................................................................ [ 59%]
........................................................................ [ 61%]
........................................................................ [ 62%]
........................................................................ [ 64%]
........................................................................ [ 66%]
........................................................................ [ 68%]
........................................................................ [ 69%]
........................................................................ [ 71%]
........................................................................ [ 73%]
........................................................................ [ 75%]
........................................................................ [ 76%]
........................................................................ [ 78%]
........................................................................ [ 80%]
........................................................................ [ 82%]
........................................................................ [ 83%]
........................................................................ [ 85%]
........................................................................ [ 87%]
........................................................................ [ 89%]
........................................................................ [ 90%]
........................................................................ [ 92%]
........................................................................ [ 94%]
........................................................................ [ 96%]
........................................................................ [ 97%]
........................................................................ [ 99%]
............ [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
--------------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/admin_settings.py 114 0 100%
app/api/auth.py 52 0 100%
app/api/chat.py 280 1 99%
app/api/chat_images.py 50 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 13 0 100%
app/api/doc_drafts.py 99 0 100%
app/api/docs.py 234 1 99%
app/api/git_sources.py 259 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 33 0 100%
app/api/sync.py 204 0 100%
app/api/tokens.py 40 0 100%
app/api/ui_settings.py 55 0 100%
app/config.py 288 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 45 0 100%
app/core/caching.py 124 0 100%
app/core/compression.py 59 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 43 0 100%
app/core/errors.py 5 0 100%
app/core/http_cache.py 22 0 100%
app/core/logging.py 13 0 100%
app/core/rate_limit.py 44 0 100%
app/core/response_budget.py 63 0 100%
app/core/security_headers.py 20 0 100%
app/core/settings_catalog.py 18 0 100%
app/core/settings_migrate.py 32 0 100%
app/core/settings_overlay.py 111 0 100%
app/core/theming.py 38 0 100%
app/core/tokens.py 44 0 100%
app/db.py 22 0 100%
app/main.py 91 0 100%
app/models.py 141 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 454 1 99%
app/rag/archive_upload.py 134 0 100%
app/rag/chunker.py 220 4 98%
app/rag/doc_dates.py 18 0 100%
app/rag/folder_summaries.py 134 0 100%
app/rag/git_sources.py 77 0 100%
app/rag/importer.py 841 4 99%
app/rag/llm.py 253 1 99%
app/rag/md_images.py 63 0 100%
app/rag/overview.py 78 0 100%
app/rag/pdf.py 192 0 100%
app/rag/prompts.py 156 0 100%
app/rag/retriever.py 252 3 99%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 58 0 100%
app/schemas.py 532 0 100%
--------------------------------------------------
TOTAL 6449 17 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
validation OK
@@ -0,0 +1,11 @@
All green. Final report:
**Phase 174 task 02 — complete**
- **E2E suite** `tests/e2e/test_git_sources_card_rhythm.py` (4 tests, isolated): uniform 1.25rem (20px) card rhythm at 1440×900 and 375×720 (pairwise-disjoint boxes, gaps 20±2px, wrapper computed flex/column/20px); ≤640px forms column-stack + table scrolls inside its card (no page-level horizontal scroll); D2 both-sides pin (`[hidden]` children stay hidden in the flex wrapper — `offsetParent` None — and a revealed load-error joins the rhythm ≥18px below page-head); D3 anonymous regression (gate visible, content hidden, zero `/api/git-sources` calls); a11y/no-CDN light pass (landmarks, labeled controls, 3px `:focus-visible` on a table-row control via real Tab walk, same-origin assets only).
- **Defect fixes (rule 8):** task-01's CSS comment named the env note's id as `#git-source-env-note` — the real id is `git-sources-env-note` (that string is the element's *class*); comment corrected in `styles.css`. (Task-01's unit test already handled the id/class distinction correctly.)
- **Gates:** `uv run pytest tests/e2e/test_git_sources_card_rhythm.py -v --no-cov` → 4 passed; regression set in isolation: `test_git_sources_admin.py` 6 passed, `test_archive_upload_sources.py` 5 passed, `test_git_source_dates.py` 4 passed; `uv run pytest --cov=app --cov-report=term-missing` → 4116 passed, `app/` coverage 99% (>90 floor); `uv run ruff check .` + `uv run pyright` → clean (0 errors).
- **Docs:** README.md and AGENTS.md reviewed in full against the project — accurate as-is; no doc edits (visual-only fix, as the phase expected).
- **Decisions:** (1) module-scoped app pinning `BOR_GIT_SOURCES=""` (phase-61 leak guard — this machine's `.env` carries a real value; with the per-test truncated table a leaked CSV would flip the page to env fallback and break the hidden-children pin); (2) the rhythm tests seed one row — `git-sources.js` sets `tableWrap.hidden = !hasRows`, so the table card (part of the 4-card stack the phase pins) only renders with a row; (3) mobile settle gate is `#git-sources-content` visibility (the reveal is the whoami gate) since `#sign-out-btn` hides inside the ≤640px hamburger nav.
- **Commit/phase-move:** not performed by me — per the binding harness rules the harness makes the one atomic `--no-gpg-sign` commit and moves the phase dir on success; all changes left in the working tree.
- **Next pending task:** none in `todo/174` (01 complete, 02 done) — phase 174 is complete.
@@ -0,0 +1,136 @@
........................................................................ [ 1%]
........................................................................ [ 3%]
........................................................................ [ 5%]
........................................................................ [ 6%]
........................................................................ [ 8%]
........................................................................ [ 10%]
........................................................................ [ 12%]
........................................................................ [ 13%]
........................................................................ [ 15%]
........................................................................ [ 17%]
........................................................................ [ 19%]
........................................................................ [ 20%]
........................................................................ [ 22%]
........................................................................ [ 24%]
........................................................................ [ 26%]
........................................................................ [ 27%]
........................................................................ [ 29%]
........................................................................ [ 31%]
........................................................................ [ 33%]
........................................................................ [ 34%]
........................................................................ [ 36%]
........................................................................ [ 38%]
........................................................................ [ 40%]
........................................................................ [ 41%]
........................................................................ [ 43%]
........................................................................ [ 45%]
........................................................................ [ 47%]
........................................................................ [ 48%]
........................................................................ [ 50%]
........................................................................ [ 52%]
........................................................................ [ 54%]
........................................................................ [ 55%]
........................................................................ [ 57%]
........................................................................ [ 59%]
........................................................................ [ 61%]
........................................................................ [ 62%]
........................................................................ [ 64%]
........................................................................ [ 66%]
........................................................................ [ 68%]
........................................................................ [ 69%]
........................................................................ [ 71%]
........................................................................ [ 73%]
........................................................................ [ 75%]
........................................................................ [ 76%]
........................................................................ [ 78%]
........................................................................ [ 80%]
........................................................................ [ 82%]
........................................................................ [ 83%]
........................................................................ [ 85%]
........................................................................ [ 87%]
........................................................................ [ 89%]
........................................................................ [ 90%]
........................................................................ [ 92%]
........................................................................ [ 94%]
........................................................................ [ 96%]
........................................................................ [ 97%]
........................................................................ [ 99%]
............ [100%]
=============================== warnings summary ===============================
.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
/var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.13-final-0 _______________
Name Stmts Miss Cover
--------------------------------------------------
app/__init__.py 1 0 100%
app/api/__init__.py 0 0 100%
app/api/admin_settings.py 114 0 100%
app/api/auth.py 52 0 100%
app/api/chat.py 280 1 99%
app/api/chat_images.py 50 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 13 0 100%
app/api/doc_drafts.py 99 0 100%
app/api/docs.py 234 1 99%
app/api/git_sources.py 259 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 33 0 100%
app/api/sync.py 204 0 100%
app/api/tokens.py 40 0 100%
app/api/ui_settings.py 55 0 100%
app/config.py 288 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 45 0 100%
app/core/caching.py 124 0 100%
app/core/compression.py 59 0 100%
app/core/debugging.py 29 2 93%
app/core/docs_push.py 43 0 100%
app/core/errors.py 5 0 100%
app/core/http_cache.py 22 0 100%
app/core/logging.py 13 0 100%
app/core/rate_limit.py 44 0 100%
app/core/response_budget.py 63 0 100%
app/core/security_headers.py 20 0 100%
app/core/settings_catalog.py 18 0 100%
app/core/settings_migrate.py 32 0 100%
app/core/settings_overlay.py 111 0 100%
app/core/theming.py 38 0 100%
app/core/tokens.py 44 0 100%
app/db.py 22 0 100%
app/main.py 91 0 100%
app/models.py 141 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 454 1 99%
app/rag/archive_upload.py 134 0 100%
app/rag/chunker.py 220 4 98%
app/rag/doc_dates.py 18 0 100%
app/rag/folder_summaries.py 134 0 100%
app/rag/git_sources.py 77 0 100%
app/rag/importer.py 841 4 99%
app/rag/llm.py 253 1 99%
app/rag/md_images.py 63 0 100%
app/rag/overview.py 78 0 100%
app/rag/pdf.py 192 0 100%
app/rag/prompts.py 156 0 100%
app/rag/retriever.py 252 3 99%
app/rag/scaffolding.py 55 0 100%
app/rag/source_removal.py 41 0 100%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 58 0 100%
app/schemas.py 532 0 100%
--------------------------------------------------
TOTAL 6449 17 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
validation OK