phase: 187_sync_peak_memory_line
**Phase 187 — final verification pass: all criteria met, repo 100% green.**
Verified (all four tasks already in `complete/`)
- `app/core/memory.py`: `rss_mb` / `rss_peak_mb` / `cgroup_peak_mb` / `fmt_mb`, pure stdlib, never-raise, **100%** coverage, 24 branch tests.
- Lifecycle lines append-only: `sync: started … rss_mb=`, all three terminals `… rss_mb= rss_peak_mb=` (failed = sanitized one-liner beside the surviving `logger.exception`), `import: summary … rss_mb=`; prefixes byte-identical.
- `GET /api/sync/status`: additive `rss_mb`/`rss_peak_mb` (`int|null`), keyed off the ONE `_sample_rss` (run start, phase transitions, forced terminals, 5 s-throttled hook), `peak >= current` invariant, anonymous 403.
- `sources.js` `fmtSyncPeakClause`: ` · peak <N> MB` trailing the counts line / "Sync cancelled", nothing when null, no new control/live region.
Gates (exact commands)
- `uv run pytest --cov=app --cov-report=term-missing` → **4570 passed**, TOTAL **99%**, `app/api/sync.py` **100%**, `app/core/memory.py` **100%**
- `uv run ruff check .` → clean · `uv run pyright` → **0 errors**
- `uv run pytest tests/e2e/test_sync_peak_memory_visible.py -v --no-cov` → **5 passed in isolation** (ran twice)
- All 27 touched E2E families re-run **in isolation**, all green (progress_box 8, cancel 3, status_freshness 4, summary_visibility 3, sync_button 3, session_reset 4, git_freeze 2, git_log_stream_dates 5, PDF/image suites, …)
Completion criteria: every checkbox ✅ except the commit + phase-dir move, which belong to the harness.
Documentation
- README reviewed in full (pages, commands, config tables cross-checked against `app/config.py` — 85 env rows, all defaults match; phase-187 ops section, greps, process-vs-cgroup caveat): consistent, no changes needed.
- `AGENTS.md`: **fixed one pre-existing inconsistency** — rule 6 claimed the no-CDN test covers "the index page"; it actually parametrizes 10 pages (all but `/doc-edit.html`).
Notable
- Two failures early in the pass were self-inflicted by running the E2E module concurrently with the full suite on the shared Postgres (TRUNCATE deadlock + one order-dependent `test_overview` flake); both vanish under the documented serial isolation — no code defect, no change made.
- **PLAN §9 still needs the owner's reconciliation** (phase 187 adds the sync memory fields + two status keys; PLAN is never agent-edited — AGENTS rule 10 carries the spec). `TODO.md` holds an unrelated owner note, left untouched.
Next pending phase: `188_chunks_hnsw_index`.
This commit is contained in:
@@ -4,12 +4,19 @@ Runs the real import pipeline (walk → chunk → embed → upsert) into the
|
||||
local compose Postgres, then checks the DB state *and* the API shape a
|
||||
browser would consume. Embeddings come from a deterministic in-process
|
||||
fake, so no network is needed.
|
||||
|
||||
Phase 187 (task 02) pins the PLAN §9 cron-safe summary line's ONE new
|
||||
trailing field (``rss_mb=``) on both the initial import and the
|
||||
idempotent re-run, with every earlier field byte-identical.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import func, select, text
|
||||
|
||||
from app.models import Chunk, Document
|
||||
@@ -36,9 +43,22 @@ EXPECTED_DOCS = {
|
||||
}
|
||||
|
||||
|
||||
def test_import_fixtures_end_to_end(admin_client, db) -> None:
|
||||
#: Phase 187 (task 02): the ONE rendering :func:`app.core.memory.fmt_mb`
|
||||
#: allows for an MB field — ``?`` when the platform cannot know, else a
|
||||
#: positive integer (never ``None``, never a float or a negative).
|
||||
MB = r"(?:\?|[1-9][0-9]*)"
|
||||
|
||||
|
||||
def test_import_fixtures_end_to_end(
|
||||
admin_client, db, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
db.execute(text("TRUNCATE chunks, documents, query_log"))
|
||||
db.commit()
|
||||
# Phase 187 (task 02): the PLAN §9 cron-safe summary line gains a
|
||||
# trailing ``rss_mb=`` — captured for BOTH runs below (the initial
|
||||
# import and the idempotent re-run), the level set once so every
|
||||
# ``import_sources`` call of this test logs at INFO.
|
||||
caplog.set_level(logging.INFO, logger="app.importer")
|
||||
llm = FakeEmbedder()
|
||||
|
||||
summary = asyncio.run(import_sources([FIXTURES], llm, session=db))
|
||||
@@ -111,5 +131,28 @@ def test_import_fixtures_end_to_end(admin_client, db) -> None:
|
||||
assert s2.unchanged == 13 and s2.added == 0
|
||||
assert len(llm.calls) == calls_before # unchanged → no embedding requests
|
||||
|
||||
# Phase 187 (task 02): every run's summary line ends with the ONE
|
||||
# appended memory field, and the pre-phase fields are byte-identical
|
||||
# (LOCKED A2 — append-only, so every existing grep keeps working).
|
||||
summary_lines = [
|
||||
r.getMessage()
|
||||
for r in caplog.records
|
||||
if r.getMessage().startswith("import: summary files=")
|
||||
]
|
||||
assert len(summary_lines) == 2, summary_lines
|
||||
for line in summary_lines:
|
||||
assert re.search(rf" rss_mb={MB}$", line), line
|
||||
assert summary_lines[0].startswith(
|
||||
"import: summary files=13 added=13 updated=0 unchanged=0 pruned=0 errors=0 "
|
||||
)
|
||||
assert re.search(
|
||||
rf"formats=md:5,container:1,j2:1,json:1,network:1,py:1,txt:1,volume:1,yaml:1"
|
||||
rf" rss_mb={MB}$",
|
||||
summary_lines[0],
|
||||
), summary_lines[0]
|
||||
assert summary_lines[1].startswith(
|
||||
"import: summary files=13 added=0 updated=0 unchanged=13 pruned=0 errors=0 "
|
||||
)
|
||||
|
||||
db.execute(text("TRUNCATE chunks, documents, query_log"))
|
||||
db.commit()
|
||||
|
||||
Reference in New Issue
Block a user