diff --git a/.agents/phases/todo/193_sync_remaining_count/00_phase.md b/.agents/phases/complete/193_sync_remaining_count/00_phase.md similarity index 100% rename from .agents/phases/todo/193_sync_remaining_count/00_phase.md rename to .agents/phases/complete/193_sync_remaining_count/00_phase.md diff --git a/.agents/phases/todo/193_sync_remaining_count/01_remaining_label.md b/.agents/phases/complete/193_sync_remaining_count/01_remaining_label.md similarity index 100% rename from .agents/phases/todo/193_sync_remaining_count/01_remaining_label.md rename to .agents/phases/complete/193_sync_remaining_count/01_remaining_label.md diff --git a/.agents/phases/todo/193_sync_remaining_count/02_update_pinned_e2e.md b/.agents/phases/complete/193_sync_remaining_count/02_update_pinned_e2e.md similarity index 100% rename from .agents/phases/todo/193_sync_remaining_count/02_update_pinned_e2e.md rename to .agents/phases/complete/193_sync_remaining_count/02_update_pinned_e2e.md diff --git a/.agents/phases/todo/193_sync_remaining_count/03_e2e.md b/.agents/phases/complete/193_sync_remaining_count/03_e2e.md similarity index 100% rename from .agents/phases/todo/193_sync_remaining_count/03_e2e.md rename to .agents/phases/complete/193_sync_remaining_count/03_e2e.md diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.err b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.md b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.md new file mode 100644 index 0000000..51e1b47 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.md @@ -0,0 +1,11 @@ +**Phase 193 — final verification pass: all gates green.** + +- **Verified (all 3 tasks already complete in `complete/193_sync_remaining_count/`):** `fmtSyncLabel`'s count part is `total > 0 && total - done > 0 ? \`${total - done} remaining\` : ""` (plain int, hidden at `N==0`, `total===0` → no part); docstrings updated; chunk/image/summaries parts + `counts_line` terminal + `app/` byte-untouched (`git diff --stat`: no `app/` files). +- **Completion criteria:** `N remaining` shape + marker pins ✅ · upload shares the builder (E2E upload arm) ✅ · chunk/image/summaries pins green ✅ · terminal `counts_line` green unedited + A4 title/`#sync-progress` pin ✅ · suite green, coverage 99% ✅ · lint/types clean ✅ · commit + `todo/→complete/` left to the harness (no git index/history commands run). +- `uv run pytest -q --cov=app --cov-report=term-missing` → **exit 0**, junit: **4792 tests, 0 failures/errors/skipped**, `TOTAL 7181 16 → 99%` (>90%) +- `uv run pytest tests/e2e/test_sync_remaining_count.py -v --no-cov` → **3 passed** (isolated, 53 s) +- Isolated `--no-cov` sweep of the 14 sync-lineage suites (label_mobile, upload_progress, chunk_progress, image_progress, progress_box, summary_visibility, archive_upload_sources, status_freshness, upload_no_scan, peak_memory_visible, session_reset, fast_path_deferred_content, git_freeze, smoke) → **14/14 exit 0** +- `uv run ruff check .` → All checks passed · `uv run pyright` → **0 errors** +- **Docs:** README.md reviewed in full (all 2408 lines) + AGENTS.md. Fixed 2 inconsistencies: the sync running-label clause claimed the upload label shows the count — now states it shares the ONE builder/shape but reports no counts since phase 90 (renders bare); phase-190's "the other ~72 rows" → "the other 83 rows of the panel's 86-row catalogue" (mechanically: 86 CATALOG rows, 84 overridable). `N remaining` already in the sync paragraph; task-01's `(n/m)` examples gone. AGENTS.md verified consistent (no clause names the running count part → unchanged per the phase's "do not add if absent"). Mechanically re-verified: all 86 `BOR_*` settings documented + defaults match, `.env.example` 88 vars covered, 0 broken README anchors, all cited file paths exist, 17 palette colors, migrations head `0030`, pages/shell routes, ports 8123/8901, E2E port allocations (new suite's 8211/8914 unique). +- **Notable:** task 02's documented deviation stands — `files_done` is the importer's 1-based *current* file, so the phase doc's `[1-4]` range is unreachable; count-bearing frames are `1 … N−1` (pinned). Pre-existing, untouched: `E2E_APP_PORT_TOOLBUDGET`/`SAVEDOC` both 8129 and `SYNCUP`/`SYCNCEL` both 8133 — harmless under the one-suite-at-a-time rule. +- **Next pending phase:** none — `193_sync_remaining_count` is the last entry in `.agents/phases/todo/`. diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.md.status b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.validate b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.validate new file mode 100644 index 0000000..ef4ee1c --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__00_phase.a1.validate @@ -0,0 +1,150 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 31%] +........................................................................ [ 33%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 76%] +........................................................................ [ 78%] +........................................................................ [ 79%] +........................................................................ [ 81%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 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 301 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/source_labels.py 52 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 332 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/memory.py 32 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 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 107 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 501 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 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 82 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 178 0 100% +app/rag/retriever.py 270 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 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/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 587 0 100% +-------------------------------------------------- +TOTAL 7181 16 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 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.err b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.md b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.md new file mode 100644 index 0000000..92449f6 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.md @@ -0,0 +1,16 @@ +**Task 01 complete — `fmtSyncLabel` count part is now `N remaining` (D1).** + +**Implemented** +- `frontend/assets/sources.js` — `fmtSyncLabel` count: `total > 0 && total - done > 0 ? `${total - done} remaining` : ""` (pre-walk `total > 0` guard kept, hidden at `N == 0`, plain integer, upload shares via the one builder); `fmtSyncLabel` + `fmtSyncPhaseLabel` docstrings updated to the count-down shape (lineage kept; summaries `(n/m)`, `· chunk n/m`, `· image n/m`, terminal `counts_line`, `setSyncLabel`/`#sync-progress` and the server/payload untouched). +- `tests/unit/test_frontend_sync_upload.py` — new marker pins `test_fmt_sync_label_count_part_is_the_n_remaining_part` (exact expression, both guards, no-separator, docstring clauses incl. the hidden-at-final-file edge + upload sharing) and `test_remaining_part_leaves_the_other_parts_byte_identical` (chunk/image/summaries builders + `fmtSyncResult` unchanged); retargeted the `(2/3)` contract/harness pins to `1 remaining`; node harness gained the `import-final` row (count part behaviorally hidden at N == 0) wired into the chunk/image/box/Cancel loops; module docstring + `_doc_above` helper added. +- `README.md` — sync running-label description: "Syncing… (n/m)" → "Syncing… N remaining" with the N = total − done / hidden-at-final-file / upload-sharing clause. `AGENTS.md`: verified no clause names the count part — no change (per phase doc note). + +**Gates (all green)** +- `uv run pytest tests/unit/test_frontend_sync_upload.py` → pass (incl. node harness) +- `uv run pytest --cov=app --cov-report=term-missing` → **4792 passed**, `app/` coverage **99%** (>90%) +- `uv run ruff check .` → clean; `uv run pyright` → clean + +**Decisions / deviations** +- E2E running-label count pins (`test_sync_label_mobile.py`, `test_sync_upload_progress.py`, `test_sync_chunk_progress.py`, `test_sync_image_progress.py`, `test_sync_progress_box.py`) are deliberately left for **task 02** ("the pinned suites move"), per phase 193 D2 — the project's default suite (`testpaths`: unit+integration) is 100% green. + +**Next pending task:** `193_sync_remaining_count/02_update_pinned_e2e.md` diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.md.status b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.validate b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.validate new file mode 100644 index 0000000..ef4ee1c --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__01_remaining_label.a1.validate @@ -0,0 +1,150 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 31%] +........................................................................ [ 33%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 76%] +........................................................................ [ 78%] +........................................................................ [ 79%] +........................................................................ [ 81%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 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 301 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/source_labels.py 52 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 332 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/memory.py 32 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 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 107 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 501 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 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 82 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 178 0 100% +app/rag/retriever.py 270 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 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/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 587 0 100% +-------------------------------------------------- +TOTAL 7181 16 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 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.err b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.md b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.md new file mode 100644 index 0000000..d2d3fe8 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.md @@ -0,0 +1,22 @@ +**Task 02 complete — every running-label count pin now asserts `N remaining`.** + +**Implemented (test-only + doc hygiene)** +- `tests/e2e/test_sync_label_mobile.py`: `IMPORT_COUNT_RE`/`IMPORT_FULL_RE` + both in-browser JS regexes → `[1-3] remaining` (4-file fixture; `files_done` is the importer's **1-based current file**, so N = 4−done ∈ {3,2,1} and the last file renders no part — the phase doc's "`done = i − 1`" arithmetic was wrong); `IMPORT_MAIN_RE` untouched. +- `tests/e2e/test_sync_upload_progress.py`: the 4 box/title count regexes → `(?: [0-9]+ remaining)?` (optional — see deviations). +- `tests/e2e/test_sync_chunk_progress.py`: JS `count.textContent`, `countText`, the composed A4 string → `1 remaining` (big.md = file 1 of 2). +- `tests/e2e/test_sync_progress_box.py`: the 3 JS waits + 2 Python asserts → `2 remaining` (long file = file 1 of 3). +- `tests/e2e/test_sync_image_progress.py`: the single-file fixture's `(1/1)` pin became the **hidden-at-final-file** arm (`no running label carries " remaining"` + the live-file label still pinned). +- Phase-193 lineage sentence added to each retargeted module docstring; stale `(n/m)` prose fixed in `test_archive_upload_sources.py`, `test_sync_status_freshness.py`, `test_upload_no_scan.py`, `tests/unit/test_sync_button.py`, `tests/unit/test_frontend_sync_upload.py`. +- **Untouched and green**: the `· chunk n/m` / `· image n/m` parts, the summaries `(n/3)` folder position, and every `counts_line` terminal pin (`git_freeze`, `session_reset`, `fast_path_deferred_content`). +- Pin list closed: the remaining hits of the phase's grep are bare `"Syncing…"` asserts and the owner's quoted reports. + +**Gates** +- `uv run pytest` → **4792 passed**; `uv run pytest --cov=app --cov-report=term-missing` → **99%** (>90%). +- `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors. +- E2E (`--no-cov`, isolated): `test_sync_label_mobile.py + test_sync_upload_progress.py` 8 passed (the task's combined command); `test_sync_progress_box.py` 8; `test_sync_chunk_progress.py + test_sync_image_progress.py` 4; `+ test_sync_summary_visibility.py` 7; `test_sync_git_freeze.py` 2; `test_archive_upload_sources.py + test_sync_session_reset.py` 9; `test_fast_path_deferred_content.py + test_sync_button.py + test_sync_peak_memory_visible.py` 11; `test_sync_status_freshness.py + test_upload_no_scan.py` in the summary batch. + +**Docs**: README's sync running-label paragraph — removed the stray `— and —` the task-01 edit left and re-flowed the wrap; AGENTS.md has no count-part clause (no doc impact for it; task 03 re-verifies). + +**Deviations**: (1) the phase's D2 range `[1-4] remaining` is impossible — `files_done` includes the in-flight file, so the count-bearing frames are `[1-3]` (kept **mandatory** where the pin's whole point is "the count is in the text"); (2) the upload suite's 25-file box/title pins make the part **optional**, because its 2 s poll can land exactly on the final file where A1 hides the part — the pattern still rejects a pre-phase `(n/m)` tail. + +**Next pending task**: `.agents/phases/todo/193_sync_remaining_count/03_e2e.md`. diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.md.status b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.validate b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.validate new file mode 100644 index 0000000..ef4ee1c --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__02_update_pinned_e2e.a1.validate @@ -0,0 +1,150 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 31%] +........................................................................ [ 33%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 76%] +........................................................................ [ 78%] +........................................................................ [ 79%] +........................................................................ [ 81%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 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 301 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/source_labels.py 52 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 332 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/memory.py 32 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 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 107 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 501 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 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 82 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 178 0 100% +app/rag/retriever.py 270 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 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/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 587 0 100% +-------------------------------------------------- +TOTAL 7181 16 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 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.err b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.md b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.md new file mode 100644 index 0000000..f732b90 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.md @@ -0,0 +1,15 @@ +**Task 03 complete — phase 193's own E2E suite is green in isolation; all gates green.** + +**Implemented** +- `tests/e2e/test_sync_remaining_count.py` (NEW): a real `file://` git fixture (5 docs, first + last multi-chunk) + the slow-LLM proxy, with a MutationObserver that records EVERY value the one label writer lands (`#sync-progress-text`, button `title`/`aria-label`, `.sync-label-count` visibility). Arms: **(a)** the count-down — grammar `^Syncing… [1-4] remaining(?: · chunk n/m)?$`, rendered `N`s strictly decreasing 4→3→2→1, never 0/≥total, chunk part coexisting (its `m` = the file's real `chunk_document` count), NO count part once the final file is named and never returning, the overview + summaries `(n/m)` phases intact, the terminal `counts_line("5 added")` byte-identical, plus the cross-layer invariant that every rendered `N` equals `files_total − files_done` of the untouched payload; **(c)** the pre-walk `phase:null`/`files_total:0` → bare `Syncing…` and the hidden-at-final edge, pinned on served bodies of the endpoint's unchanged key set; **(b)** the upload arm through the same builder (`Importing N remaining`, hidden at its final file). +- Docs pass: the stale `(n/m)` running-label examples became `N remaining` in `frontend/assets/sources.js` (5 header/comment sites), `frontend/assets/styles.css`, `frontend/index.html`, `frontend/assets/git-sources.js`. `README.md` already carried the phase-193 label (task 01); `AGENTS.md` has no clause naming the running count part — unchanged. + +**Gates (final state)** `uv run pytest --cov=app --cov-report=term-missing` → exit 0, `app/` **99%**; `tests/e2e/test_sync_remaining_count.py -v --no-cov` → 3 passed in isolation (twice); regression `test_sync_label_mobile + test_sync_upload_progress + test_sync_chunk_progress + test_sync_summary_visibility` → 13 passed; `ruff check .` clean; `pyright` 0 errors. + +**Decisions / deviations** +1. A2's upload arm is not observable live: since phase 90 the upload status answers `null/0/0` for the whole run (asserted against the live endpoint inside that test), so the shared *shape* is pinned through a served status body (the house `page.route` pattern) — the client's `total > 0` / `total − done > 0` guards are what is under test, the server stays untouched. +2. The upload frame can never carry `· chunk n/m` (that branch receives no status object — phase 129/152), so the coexistence pin sits in the sync arms and the upload test asserts the frame stays chunk-free. +3. Count-bearing frames are `1 … N−1` (`files_done` is the 1-based in-flight file) — task 02's finding, kept here. +4. No git commands run and the phase directory was not moved, per the harness instruction — commit + `todo/ → complete/` left to the harness. + +**Next task:** none pending in `193_sync_remaining_count` (03 is its last). diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.md.status b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.validate b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.validate new file mode 100644 index 0000000..ef4ee1c --- /dev/null +++ b/.agents/reports/193_sync_remaining_count/193_sync_remaining_count__03_e2e.a1.validate @@ -0,0 +1,150 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 31%] +........................................................................ [ 33%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 76%] +........................................................................ [ 78%] +........................................................................ [ 79%] +........................................................................ [ 81%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 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 301 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/source_labels.py 52 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 332 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/memory.py 32 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 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 107 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 501 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 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 82 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 178 0 100% +app/rag/retriever.py 270 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 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/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 587 0 100% +-------------------------------------------------- +TOTAL 7181 16 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 diff --git a/README.md b/README.md index e231b37..dede6fc 100644 --- a/README.md +++ b/README.md @@ -727,12 +727,17 @@ only) runs the whole source refresh in one click: - States: while polling `GET /api/sync/status` every 2 s, the button becomes the spinner (icon only — its label parts are hidden while a run is in flight, and its accessible name is the full live label), - and the full live detail — "Syncing… (n/m)" during the import - phase (the live file, its `(n/m)` file position, and — while a file's - embed batch is in flight — the pinned `· chunk n/m` embed position, - batch granularity: the first chunk of the in-flight batch over the - file's total content chunks; and — while a PDF's images are being - described — the `· image n/m` vision position: the 1-based image + and the full live detail — "Syncing… N remaining" during the + import phase (the live file, its `N remaining` file count — N = + total − done, shown while N ≥ 1 and hidden at the final file, since + the owner reads the distance to the end better than the position in + the whole; the upload's `Importing` label shares the ONE builder and + the same shape, though since phase 90 that run reports no counts, so + today it renders bare; and — while a file's embed batch is in flight + — the pinned `· chunk n/m` embed position, batch granularity: the + first chunk of the in-flight batch over the file's total content + chunks; and — while a PDF's images are being described — the + `· image n/m` vision position: the 1-based image about to be described over the file's total images, ONE continuous counter across the PDF's three vision spans, so a long image pass visibly climbs instead of sitting frozen on the last chunk @@ -2001,11 +2006,12 @@ to the OPEN document through the ONE shared brand pass (`assets/brand.js`'s header brand, the footer line and the chat composer placeholder update on the click, no reload — including a rename of an app whose old name is already on the page. The re-apply runs only when one of those three keys was involved (the -other ~72 rows cost no extra request), never stacks a second fetch while one is -in flight, and a failed one leaves the page exactly as it showed — the save's -own status or error line stays the feedback. The Theme tab runs the same pass -after its Save and its Reset; it no longer edits the strings, so that read is -what keeps an open tab honest about a name the panel changed meanwhile. +other 83 rows of the panel's 86-row catalogue cost no extra request), never +stacks a second fetch while one is in flight, and a failed one leaves the page +exactly as it showed — the save's own status or error line stays the feedback. +The Theme tab runs the same pass after its Save and its Reset; it no longer +edits the strings, so that read is what keeps an open tab honest about a name +the panel changed meanwhile. The whole contract — the incident regression (a color save no longer shadows a later rename) and the live repaint of title / brand / footer / placeholder — is pinned in a real browser by `tests/e2e/test_app_name_settings_fix.py` (run in diff --git a/frontend/assets/git-sources.js b/frontend/assets/git-sources.js index e5ddb05..d987d0b 100644 --- a/frontend/assets/git-sources.js +++ b/frontend/assets/git-sources.js @@ -73,7 +73,7 @@ * disabled, title cleared) plus startUploadPolling(): a 2 s poll * of GET /api/git-sources/upload/status that renders the bare * "Processing…" label for the WHOLE run (phase 90, A2 — the run - * is unpack + register only: no file, no "(n/m)" counts, no + * is unpack + register only: no file, no "N remaining" count, no * title) and settles it: success → the ready-for-sync line * ("Uploaded () — press Sync sources to import * it." — the phase-154 completion stamp, fmtUploadStamp off the @@ -1651,7 +1651,7 @@ export async function mount(root) { * title cleared) + startUploadPolling() own it — a 2 s poll of * GET /api/git-sources/upload/status that renders the bare * "Processing…" label for the WHOLE run (phase 90, A2 — the unpack - * has no file-level progress: no file, no "(n/m)" counts, no title) + * has no file-level progress: no file, no "N remaining" count, no title) * and settles it: success → the ready-for-sync line ("Uploaded * () — press Sync sources to import it." — the * phase-154 completion stamp, fmtUploadStamp off the status's @@ -1786,7 +1786,7 @@ export async function mount(root) { * poll OWNS the button). Each tick fetches * GET /api/git-sources/upload/status: running → the bare * "Processing…" label for the whole run (phase 90, A2 — the unpack - * has no file-level progress: no file, no "(n/m)" counts, the title + * has no file-level progress: no file, no "N remaining" count, the title * stays clear) + reschedule; success → stop + the ready-for-sync * result line + the announcement + the row reload (NO toast — it * fired at the 202, A2); failed → stop + the sanitized server error diff --git a/frontend/assets/sources.js b/frontend/assets/sources.js index 0b8e891..854baa9 100644 --- a/frontend/assets/sources.js +++ b/frontend/assets/sources.js @@ -160,7 +160,8 @@ * (n/m)" (the folder part omitted while * current_summary is null — the phase's first poll), anything else * (the null prelude, "import") → today's "Syncing… (n/m)" - * byte-identical. The UPLOAD job (its status has no phase) keeps the + * byte-identical (the count part's TEXT is `N remaining` — the distance + * to the end — since phase 193). The UPLOAD job (its status has no phase) keeps the * bare label. The untruncated label rides the button title (now set * for EVERY running label, not just file labels) + #sync-progress as * before (A4). @@ -309,7 +310,8 @@ * Phase 128 (task 01) — the sync label becomes PARTS: the running * label's string is split into a shrinks-to-fit MAIN part (prefix + * the file/folder path — the part CSS may ellipsize) and a pinned - * COUNT part ("(n/m)" — the position, NEVER clipped), so on a phone + * COUNT part ("(n/m)" — the position, NEVER clipped — the text is + * `N remaining` since phase 193), so on a phone * the file path ellipsizes to fit while the count stays on-screen * (the phase-64 bug: with max-width lifted, the inline-block sized to * its full content and the count ran off-screen). #sync-label now @@ -332,7 +334,8 @@ * the initSyncButton re-attach — goes through setSyncLabel(main) * (count hidden). The full-string shapes are byte-identical to the * pre-task labels ("Syncing…", "Syncing… ", - * "Syncing… (n/m)", "Importing", "Writing KB overview…", + * "Syncing… (n/m)" — `N remaining` since phase 193, "Importing", + * "Writing KB overview…", * "Summarizing folders… (n/m)"); textContent only — no HTML * strings (the house rule). * @@ -747,7 +750,7 @@ export async function mount(root) { * tree, in order (startSyncPolling): * 1. sync running → the phase-aware label (Phase 98 task 02, D2) * — the null-phase prelude + "import" → - * "Syncing… (n/m)" — bare "Syncing…" + * "Syncing… N remaining" — bare "Syncing…" * until the import's first file (clone/pull, * A4, byte-identical); "overview" → "Writing KB * overview…"; "summaries" → "Summarizing @@ -813,7 +816,8 @@ export async function mount(root) { * Elements: #sync-btn (the button), #sync-label (the text — * Phase 128 (task 01): the PARTS — .sync-label-main, the * shrinks-to-fit prefix + file/folder, + .sync-label-count, the - * pinned "(n/m)" position (hidden when absent); phase 129 (task + * pinned count — the phase-193 "N remaining" (hidden when absent); + * phase 129 (task * 04): + .sync-label-chunk, the pinned "· chunk n/m" embed-batch * position of the in-flight file (hidden in every state but the * import phase after the file's first batch); phase 152 (task 03): @@ -917,7 +921,7 @@ export async function mount(root) { * mainText lands in the MAIN part (.sync-label-main — the * shrinks-to-fit prefix + file/folder, the part CSS ellipsizes); * countText lands in the COUNT part (.sync-label-count — the pinned - * "(n/m)" position, NEVER clipped); chunkText (phase 129) lands in + * phase-193 "N remaining", NEVER clipped); chunkText (phase 129) lands in * the CHUNK part (.sync-label-chunk — the pinned "· chunk n/m" * embed-batch position of the in-flight file); imageText (phase * 152) is the in-flight PDF's "· image n/m" vision-image position — @@ -1034,9 +1038,20 @@ export async function mount(root) { * BARE prefix shows during the clone/pull (sync), before any file * is indexed. Phase 90: the upload run is unpack + register only * (no scan), so its status never carries a file or counts — the - * "Importing" label is always the bare one. The counts — the PINNED - * count part, never clipped (Phase 128) — appear only once the - * import has started (total > 0). The builders return the PARTS + * "Importing" label is always the bare one — and when an upload + * status DOES carry counts the upload job shares this builder and + * the shape (phase 193, A2: the upload's files_total is the + * pre-walk count, the phase-98 contract — the same subtraction + * semantics). The count — the PINNED count part, never clipped + * (Phase 128) — is the phase-193 COUNT-DOWN part (the owner's + * "how many files are left, not how many files out of the + * total"): `N remaining` with N = total - done, shown while + * N >= 1 and HIDDEN at the final file (N == 0 — the main part + * names it; a "0 remaining" next to the last file's name is the + * stale-looking edge); plain integer, no thousands separator. The + * total > 0 guard stays (the phase-64 pre-walk contract — no count + * part before the walk knows the total). The builders return the + * PARTS * ({ main, count }); setSyncLabel writes them (the untruncated full * string — main + " " + count — rides the button title + * #sync-progress, A4). Phase 98 (task 02): the SYNC job's @@ -1053,7 +1068,7 @@ export async function mount(root) { function fmtSyncLabel(kind, currentFile, done, total) { const prefix = kind === "upload" ? "Importing" : "Syncing…"; const main = currentFile ? `${prefix} ${currentFile}` : prefix; - const count = total > 0 ? `(${done}/${total})` : ""; + const count = total > 0 && total - done > 0 ? `${total - done} remaining` : ""; return { main, count }; } @@ -1069,8 +1084,11 @@ export async function mount(root) { * empty (the summaries phase's own (n/m) is its position — the * status's chunk + image fields are cleared at this transition); * anything else (the null prelude, "import") → the phase-64 - * fmtSyncLabel parts, byte-identical (same builder, same fields, - * same order) + the phase-129 CHUNK part: "· chunk n/m" ONLY while + * fmtSyncLabel parts (same builder, same fields, same order — + * since phase 193 its count part reads `N remaining`, N = + * total - done, hidden at the final file; the summaries (n/m) + * folder position and the chunk/image parts below stay as they + * are) + the phase-129 CHUNK part: "· chunk n/m" ONLY while * chunks_total > 0 (a file's embed batch is in flight — n the * 1-based first chunk of the batch, m the file's total content * chunks, batch granularity), empty before the first batch (0/0) so @@ -1099,8 +1117,9 @@ export async function mount(root) { image: "", // the image position belongs to the import phase only }; } - // null phase (the prelude) or "import" — today's byte-identical - // sync label (the phase-64 contract, unchanged) + the phase-129 + // null phase (the prelude) or "import" — the phase-64 label + // shape (since phase 193 its count part reads `N remaining`) + + // the phase-129 // chunk part (hidden before the in-flight file's first batch) + // the phase-152 image part (hidden before the in-flight PDF's // first vision describe call). diff --git a/frontend/assets/styles.css b/frontend/assets/styles.css index ac9e0de..37d4e0f 100644 --- a/frontend/assets/styles.css +++ b/frontend/assets/styles.css @@ -2898,14 +2898,16 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und @media (prefers-reduced-motion: reduce) { .sync-btn .sync-icon.is-spinning { animation: none; } } -/* Phase 64: the live-file label ("Syncing… (n/m)" / "Importing - (n/m)") — a long source/relative/path ellipsizes inside the +/* Phase 64: the live-file label ("Syncing… N remaining" / + "Importing N remaining" — phase 193: the file count is the + distance to the end, `total - done`, hidden on the final file) — a + long source/relative/path ellipsizes inside the pill; the full path lives in the button title + the #sync-progress box (the aria-live announcer — phase 150: the SOLE sync text surface). Phase 128 (task 02): the label is a FLEX ROW of parts — .sync-label-main (the prefix + file/folder: min-width 0, the shrinkable item whose ellipsis engages) + .sync-label-count - (the pinned "(n/m)": flex 0 0 auto, NEVER clipped — the + (the pinned "N remaining": flex 0 0 auto, NEVER clipped — the .sync-progress-text mono language, a position reads as data). Phase 129 (task 04): a THIRD pinned part — .sync-label-chunk (the "· chunk n/m" embed-batch position of the in-flight file, the same pinned @@ -2925,7 +2927,7 @@ a.answer-image:hover { text-decoration: underline; } /* flat — the caption und white-space: nowrap; } .sync-label-count { - flex: 0 0 auto; /* NEVER clipped — the (n/m) position is the point */ + flex: 0 0 auto; /* NEVER clipped — the N remaining count is the point */ white-space: nowrap; font-family: var(--mono); /* the .sync-progress-text mono language (position reads as data) */ } diff --git a/frontend/index.html b/frontend/index.html index 42143e7..e0cd6f9 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -490,7 +490,9 @@