phase: 128_sync_label_mobile
Build and Push Containers / build-and-push-app (push) Successful in 2m32s
Build and Push Containers / build-and-push-db (push) Successful in 12s

Everything verified and 100% green. The earlier rejection was a report-format issue, not a test failure — all work is in the working tree. Final report:

**Phase 128 final pass — verified (all 3 tasks complete; no code defects found)**
- Verified: `#sync-label` parts markup, `setSyncLabel` writer, part builders (A4 untruncated title/aria-live), flex-row CSS + mobile media query — all match design 1:1.
- `uv run pytest --cov=app --cov-report=term`: 3024 passed; TOTAL coverage **99%** (>90% gate).
- `uv run pytest tests/e2e/test_sync_label_mobile.py -v --no-cov`: 4 passed (119s, isolated).
- `uv run ruff check .`: clean; `uv run pyright`: 0 errors.
- Criteria: (1) mobile 390×844 label in-viewport, count visible in import+summaries — ✅ E2E; (2) desktop strings/cap/title unchanged — ✅ E2E+unit; (3) E2E isolated green — ✅; (4) full suite green — ✅.
- Docs: README.md fixed 5 pre-existing gaps (PDF phase-126 section + `pdf` token, hidden-folders toggle ph.105, document dates ph.106, private git-source masked tokens ph.121, doc-draft Discard ph.115); AGENTS.md verified consistent — no changes.
- Notable: double-`-q` (addopts `-q` + CLI `-q`) suppresses pytest's summary line — standard `-qq` behavior, not a bug; exit codes confirm green.
- Next pending phase: `129_sync_chunk_progress`.
This commit is contained in:
2026-09-27 23:58:57 -04:00
parent 6e654df387
commit 1139f007cf
34 changed files with 2203 additions and 173 deletions
+32 -4
View File
@@ -604,9 +604,23 @@ def test_upload_toast_then_navigate_away(
expect(page.locator("#sync-error-banner")).to_be_hidden()
# UI layer: the label gains the live file at the page's 2 s poll
# tick ("Syncing… <source/relative/path> (n/m)").
# tick — the file rides the MAIN part, "(n/m)" the pinned COUNT
# span (phase 128: the space between them is the CSS gap, so the
# rendered concatenation carries none — the FULL string with the
# space rides the button title, A4).
expect(page.locator("#sync-label")).to_have_text(
re.compile(rf"Syncing… {re.escape(UPLOAD_NAME)}/.+\.md \(\d+/{N_FILES}\)"),
re.compile(rf"Syncing… {re.escape(UPLOAD_NAME)}/.+\.md\(\d+/{N_FILES}\)"),
timeout=SETTLE_TIMEOUT_MS,
)
# Phase 128: the "(n/m)" is NEVER clipped — it sits in its own
# visible count span, and the button title carries the full
# untruncated string (main + " " + count, A4).
expect(page.locator("#sync-label .sync-label-count")).to_be_visible(
timeout=SETTLE_TIMEOUT_MS
)
expect(btn).to_have_attribute(
"title",
re.compile(rf"^Syncing… {re.escape(UPLOAD_NAME)}/.+\.md \(\d+/{N_FILES}\)$"),
timeout=SETTLE_TIMEOUT_MS,
)
@@ -774,9 +788,23 @@ def test_sync_live_file_label(
expect(page.locator("#sync-error-banner")).to_be_hidden()
# UI layer: the label gains the live file at the page's 2 s poll
# tick ("Syncing… <source/relative/path> (n/m)").
# tick — the file rides the MAIN part, "(n/m)" the pinned COUNT
# span (phase 128: the space between them is the CSS gap, so the
# rendered concatenation carries none — the FULL string with the
# space rides the button title, A4).
expect(page.locator("#sync-label")).to_have_text(
re.compile(rf"Syncing… {re.escape(SYNC_SOURCE_DIR)}/.+\.md \(\d+/{N_FILES}\)"),
re.compile(rf"Syncing… {re.escape(SYNC_SOURCE_DIR)}/.+\.md\(\d+/{N_FILES}\)"),
timeout=SETTLE_TIMEOUT_MS,
)
# Phase 128: the "(n/m)" is NEVER clipped — it sits in its own
# visible count span, and the button title carries the full
# untruncated string (main + " " + count, A4).
expect(page.locator("#sync-label .sync-label-count")).to_be_visible(
timeout=SETTLE_TIMEOUT_MS
)
expect(btn).to_have_attribute(
"title",
re.compile(rf"^Syncing… {re.escape(SYNC_SOURCE_DIR)}/.+\.md \(\d+/{N_FILES}\)$"),
timeout=SETTLE_TIMEOUT_MS,
)