phase: 179_git_clone_server_freeze
Build and Push Containers / build-and-push-app (push) Successful in 1m43s
Build and Push Containers / build-and-push-db (push) Successful in 13s

All gates green; working tree holds exactly the phase's changes for the harness to commit.

## Phase 179 — Final verification report

- **Verified (all 3 tasks already complete in `complete/`)**: repro + CONFIRMED verdict, `asyncio.to_thread` fix, dedicated E2E suite.
- `app/api/sync.py::_run_sync`: both git ops (`clone_or_pull`, `file_commit_dates`) now `await asyncio.to_thread(...)`; phase-134 boundary note + module docstring document worker-thread-runs-to-completion and the A3 DB-calls-stay-on-loop note.
- **Tests / lint / coverage** (full suite 100% green):
  - `uv run pytest tests/integration/test_sync_git_freeze.py -v` → **4 passed** (post-fix probe <1.5 s during 3 s stub)
  - `uv run pytest tests/e2e/test_sync_git_freeze.py -v --no-cov` → **2 passed in 25.65 s in isolation** (wall guard 120 s holds)
  - `uv run pytest --cov=app --cov-report=term-missing` → **4173 passed**, `app/` coverage **99%** (`app/api/sync.py` 100%)
  - `uv run ruff check .` → All checks passed; `uv run pyright` → **0 errors**
- **Completion criteria**: ① integration probe green + verdict (CONFIRMED, mechanism, measured 3.04 s→0.003 s) in docstring — **met**; ② off-loop git ops + boundary/A3 notes — **met**; ③ full suite green, coverage 99% >90%, ruff+pyright clean — **met**; ④ E2E green in isolation (responsive-poll + cancel-during-clone contracts) — **met**; ⑤ atomic commit + move to `complete/` — **harness-owned** (pipeline rule overrides per-phase self-commit; all changes staged-ready in the working tree).
- **Documentation**: full README (1526 l) + AGENTS.md review — phase-179 bullets present and accurate (verified against fixture constants, `.env.example` fully covered by the config reference, pages table matches `app/main.py` shell routes, quick-reference commands/artifacts exist); **consistent — no further changes needed**.
- **Notable**: task-03 pipeline sessions died on context overflow but their harness validation passed; this pass independently re-ran every gate to confirm. No live infra touched; no git index commands run.
- **Next pending phase**: `180_markdown_inline_links_images`.
This commit is contained in:
2026-10-14 13:06:39 -04:00
parent 2b57180998
commit 3d82a72b6f
31 changed files with 2326 additions and 28 deletions
+21 -1
View File
@@ -527,11 +527,21 @@ whole git-source refresh in one click:
client-side timeout — a clone + embed can legitimately take minutes.
- One sync at a time: a second trigger while a run is in flight gets a
`409`.
- **A long clone never freezes the server** (phase 179). The run's git
steps (`clone_or_pull` / `file_commit_dates`, the blocking
`subprocess` calls) execute in a worker thread
(`asyncio.to_thread`), so the event loop keeps serving the whole
HTTP surface for their duration — every page, `GET /api/health`, and
above all the 2 s `GET /api/sync/status` poll that watches the run.
Before this a big first clone stalled the loop thread and the entire
app looked dead until git returned.
- **Cancel**: while a run is in flight, a **Cancel** button appears
next to the sync button; clicking it posts `POST /api/sync/cancel`
(admin only) and registers a cooperative cancel (`202`) — the run
stops at the next pipeline boundary (a git clone/pull already in
flight runs to completion) and settles into a neutral `cancelled`
flight runs to completion in its worker thread — the request is not
held, and the rest of the app keeps answering meanwhile) and settles
into a neutral `cancelled`
terminal state (`error: null` — intent, not failure: a "Sync
cancelled" result line, no error banner or modal, the button
retry-ready) that the status endpoint reports; with no run in
@@ -1372,6 +1382,16 @@ uv run pytest tests/e2e/test_chat_rag.py -v --no-cov
for f in tests/e2e/test_*.py; do uv run pytest "$f" --no-cov -q || echo "FAIL $f"; done
```
**`git` on `PATH` is an E2E prerequisite** (phase 28): the git-source
suites drive real `clone_or_pull` / `file_commit_dates` calls against
generated local `file://` fixture repos. The heaviest is phase 179's
`tests/e2e/test_sync_git_freeze.py`: it builds a ~150 MiB pack-free repo
(30 commits × 5 MiB of seeded pseudo-random bytes) so a fresh
`git clone` genuinely costs ≈ 9 s — that clone IS the timing fixture for
"a long clone must not freeze the server". It is mock-only
(`E2E_REAL_LLM=1` is skipped there: the clone, not the LLM import, is
what the suite times).
**Retrieval regression battery.** `tests/fixtures/retrieval_battery.txt` is
the tracked retrieval gate (phases 119 + 162): the name-your-tool questions,
the versioned-name (`qwen 3.8 27b`) regression, the out-of-KB deflection