phase: 154_sync_status_freshness
Build and Push Containers / build-and-push-app (push) Successful in 2m26s
Build and Push Containers / build-and-push-db (push) Successful in 16s

All 4 task files exist in `complete/`, and only `00_phase.md` remains in `todo/`. This is the final verification pass. I'll read through the task files and check the current state of the code.
This commit is contained in:
2026-10-04 14:24:33 -04:00
parent 966c4b0540
commit c275735db4
36 changed files with 2526 additions and 99 deletions
+28 -14
View File
@@ -20,7 +20,8 @@ server-side behind ``GET /api/git-sources/upload/status`` (the
phase-32 ``SyncStatus`` pattern; the phase-64 key set with
``current_file``/``files_done``/``files_total`` null/0/0 for the whole
run — phase 90 A2). The settled result line points at the next step:
"Uploaded <name> — press Sync sources to import it." (phase 90 A3) —
"Uploaded <name> (<stamp>) — press Sync sources to import it."
(phase 90 A3, the phase-154 completion stamp) —
the scan is the RAG page's **Sync sources** button's job, so this
suite asserts **zero indexed documents** after every upload.
@@ -66,8 +67,9 @@ Contract under test:
button then carries the BARE "Processing…" label for the whole
background run (no file, no "(n/m)" — the first status GET is held
so the in-run window outlives the 2 s poll) until the status
``success`` lands: the result line reads "Uploaded e2e-upload —
press Sync sources to import it.", the button restores ("Upload"),
``success`` lands: the result line reads "Uploaded e2e-upload
(<stamp>) — press Sync sources to import it." (the phase-154
completion stamp), the button restores ("Upload"),
the file input clears, the list gains exactly one row for
``e2e-upload`` with the **Local** badge and its "Ignore paths"
control (the phase-89 editor the deferral exists for), the terminal
@@ -139,6 +141,19 @@ SOURCES_URL = "/sources.html"
#: filename minus the archive suffix (the phase's locked naming rule).
SOURCE_NAME = "e2e-upload"
def _ready_for_sync_line(name: str) -> re.Pattern[str]:
"""Phase 154 (task 02): the ready-for-sync line carrying the
completion stamp — "Uploaded <name> (<stamp>) — press Sync sources
to import it." (the fresh 202 settle, the page-local name). In
E2E the stamp is ALWAYS the same-day ``HH:MM`` form — the run
settles within seconds (the date-qualified forms are unit-pinned
on a fixed clock — E2E never depends on the wall clock)."""
return re.compile(
rf"^Uploaded {re.escape(name)} \(\d{{1,2}}:\d{{2}}\)"
r" — press Sync sources to import it\.$"
)
#: v1: two sentinel docs. v2 (same filename): alpha CHANGED, beta DROPPED,
#: gamma ADDED — the in-place-replace subject (the on-disk folder swap).
ALPHA_SENTINEL_V1 = "ALPHA-TOKEN-v1-7f31"
@@ -436,8 +451,9 @@ def test_upload_registers_without_indexing(
then carries the BARE "Processing…" label for the whole background
run (no file, no "(n/m)" — phase 90 A2, proven across a held first
status GET); when the status ``success`` lands the result line
reads "Uploaded <source> — press Sync sources to import it."
(A3), the button restores ("Upload"), the file input clears, the
reads "Uploaded <source> (<stamp>) — press Sync sources to
import it." (A3 — the phase-154 completion stamp), the button
restores ("Upload"), the file input clears, the
list gains exactly ONE row for ``e2e-upload`` (Local badge, the
"Ignore paths" control), the terminal status carries the no-count
``{"message": "uploaded"}`` detail with null/0/0 progress — and
@@ -490,9 +506,7 @@ def test_upload_registers_without_indexing(
# …release: the status success lands → the ready-for-sync line +
# the never-stale restore (input cleared).
expect(result).to_be_visible(timeout=UPLOAD_TIMEOUT_MS)
expect(result).to_have_text(
f"Uploaded {SOURCE_NAME} — press Sync sources to import it."
)
expect(result).to_have_text(_ready_for_sync_line(SOURCE_NAME))
expect(btn).to_be_enabled()
expect(btn).to_have_text("Upload")
expect(page.locator("#archive-upload-file")).to_have_value("")
@@ -560,8 +574,8 @@ def test_reupload_replaces_in_place(
# Baseline: v1 through the page (202 → the ready-for-sync line,
# one row, no index).
assert _upload_via_page(page, tarball_v1) == (
f"Uploaded {SOURCE_NAME} — press Sync sources to import it."
assert _ready_for_sync_line(SOURCE_NAME).fullmatch(
_upload_via_page(page, tarball_v1)
)
expect(page.locator("#git-sources-tbody tr", has_text=SOURCE_NAME)).to_have_count(1)
folder = upload_dir / SOURCE_NAME
@@ -570,8 +584,8 @@ def test_reupload_replaces_in_place(
# Re-upload v2 — SAME basename, different parent dir (the file
# input's selection is replaced wholesale).
assert _upload_via_page(page, tarball_v2) == (
f"Uploaded {SOURCE_NAME} — press Sync sources to import it."
assert _ready_for_sync_line(SOURCE_NAME).fullmatch(
_upload_via_page(page, tarball_v2)
)
# No duplicate: exactly ONE row for that source (and one row total).
@@ -635,8 +649,8 @@ def test_bad_file_inline_error(
# The form is not wedged: a good upload right after still works —
# and indexes nothing (phase 90 A1).
assert _upload_via_page(page, tarball_v1) == (
f"Uploaded {SOURCE_NAME} — press Sync sources to import it."
assert _ready_for_sync_line(SOURCE_NAME).fullmatch(
_upload_via_page(page, tarball_v1)
)
expect(error).to_be_hidden()
expect(page.locator("#git-sources-tbody tr", has_text=SOURCE_NAME)).to_have_count(1)