docs(01-02): complete Wave 0 test scaffolds plan — SUMMARY, STATE, ROADMAP
- Create 01-02-SUMMARY.md: 19 total xfail tests across 5 files, 3 task commits documented, no deviations - STATE.md: advance to plan 3/5, update progress to 40%, record decisions for async_client naming and xfail(strict=False) pattern - ROADMAP.md: mark 01-02-PLAN.md complete, update progress table to 2/5
This commit is contained in:
@@ -28,7 +28,7 @@ _Last updated: 2026-05-21_
|
|||||||
|
|
||||||
**Plans**: 5 plans
|
**Plans**: 5 plans
|
||||||
- [x] 01-01-PLAN.md — Docker Compose service topology + Postgres init + Pydantic Settings + requirements
|
- [x] 01-01-PLAN.md — Docker Compose service topology + Postgres init + Pydantic Settings + requirements
|
||||||
- [ ] 01-02-PLAN.md — Wave 0 test scaffolds (xfail/skip stubs) + async pytest fixtures
|
- [x] 01-02-PLAN.md — Wave 0 test scaffolds (xfail/skip stubs) + async pytest fixtures
|
||||||
- [ ] 01-03-PLAN.md — SQLAlchemy ORM models + async engine + Alembic async migration (incl. alembic upgrade head)
|
- [ ] 01-03-PLAN.md — SQLAlchemy ORM models + async engine + Alembic async migration (incl. alembic upgrade head)
|
||||||
- [ ] 01-04-PLAN.md — StorageBackend ABC + MinIO backend + rewritten async services/storage.py
|
- [ ] 01-04-PLAN.md — StorageBackend ABC + MinIO backend + rewritten async services/storage.py
|
||||||
- [ ] 01-05-PLAN.md — Lifespan + /health + API cutover + Celery worker + walking-skeleton e2e verify
|
- [ ] 01-05-PLAN.md — Lifespan + /health + API cutover + Celery worker + walking-skeleton e2e verify
|
||||||
@@ -110,7 +110,7 @@ _Last updated: 2026-05-21_
|
|||||||
|
|
||||||
| Phase | Plans Complete | Status | Completed |
|
| Phase | Plans Complete | Status | Completed |
|
||||||
|-------|----------------|--------|-----------|
|
|-------|----------------|--------|-----------|
|
||||||
| 1. Infrastructure Foundation | 1/5 | In Progress | - |
|
| 1. Infrastructure Foundation | 2/5 | In Progress | - |
|
||||||
| 2. Users & Authentication | 0/? | Not started | - |
|
| 2. Users & Authentication | 0/? | Not started | - |
|
||||||
| 3. Document Migration & Multi-User Isolation | 0/? | Not started | - |
|
| 3. Document Migration & Multi-User Isolation | 0/? | Not started | - |
|
||||||
| 4. Folders, Sharing, Quotas & Document UX | 0/? | Not started | - |
|
| 4. Folders, Sharing, Quotas & Document UX | 0/? | Not started | - |
|
||||||
|
|||||||
+12
-10
@@ -4,13 +4,13 @@ milestone: v1.0
|
|||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
current_phase: 1
|
current_phase: 1
|
||||||
status: executing
|
status: executing
|
||||||
last_updated: "2026-05-22T06:59:23Z"
|
last_updated: "2026-05-22T07:10:00Z"
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 0
|
completed_phases: 0
|
||||||
total_plans: 5
|
total_plans: 5
|
||||||
completed_plans: 1
|
completed_plans: 2
|
||||||
percent: 20
|
percent: 40
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -24,7 +24,7 @@ progress:
|
|||||||
|
|
||||||
| Phase | Name | Status |
|
| Phase | Name | Status |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | Infrastructure Foundation | In Progress (1/5 plans) |
|
| 1 | Infrastructure Foundation | In Progress (2/5 plans) |
|
||||||
| 2 | Users & Authentication | Not Started |
|
| 2 | Users & Authentication | Not Started |
|
||||||
| 3 | Document Migration & Multi-User Isolation | Not Started |
|
| 3 | Document Migration & Multi-User Isolation | Not Started |
|
||||||
| 4 | Folders, Sharing, Quotas & Document UX | Not Started |
|
| 4 | Folders, Sharing, Quotas & Document UX | Not Started |
|
||||||
@@ -33,10 +33,10 @@ progress:
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 1 (Infrastructure Foundation) — EXECUTING
|
Phase: 1 (Infrastructure Foundation) — EXECUTING
|
||||||
Plan: 2 of 5
|
Plan: 3 of 5
|
||||||
**Phase:** 01-infrastructure-foundation
|
**Phase:** 01-infrastructure-foundation
|
||||||
**Plan:** 01-01 COMPLETE → advancing to 01-02
|
**Plan:** 01-02 COMPLETE → advancing to 01-03
|
||||||
**Progress:** ██░░░░░░░░ 20%
|
**Progress:** ████░░░░░░ 40%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Plan: 2 of 5
|
|||||||
| Phases complete | 0 / 5 |
|
| Phases complete | 0 / 5 |
|
||||||
| Requirements mapped | 54 / 54 |
|
| Requirements mapped | 54 / 54 |
|
||||||
| Plans written | 5 (Phase 1) |
|
| Plans written | 5 (Phase 1) |
|
||||||
| Plans complete | 1 |
|
| Plans complete | 2 |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -64,6 +64,8 @@ Plan: 2 of 5
|
|||||||
| Two-DSN PostgreSQL strategy | DATABASE_URL (docuvault_app, DML only) + DATABASE_MIGRATE_URL (docuvault_migrate, DDL only); celery-worker gets only DATABASE_URL |
|
| Two-DSN PostgreSQL strategy | DATABASE_URL (docuvault_app, DML only) + DATABASE_MIGRATE_URL (docuvault_migrate, DDL only); celery-worker gets only DATABASE_URL |
|
||||||
| MinIO healthcheck via mc ready local | curl removed from MinIO Docker image since Oct 2023; mc is the correct in-container healthcheck tool |
|
| MinIO healthcheck via mc ready local | curl removed from MinIO Docker image since Oct 2023; mc is the correct in-container healthcheck tool |
|
||||||
| pydantic-settings v2 SettingsConfigDict | SettingsConfigDict API used (not deprecated class Config form) for env var config |
|
| pydantic-settings v2 SettingsConfigDict | SettingsConfigDict API used (not deprecated class Config form) for env var config |
|
||||||
|
| async_client fixture name | Distinct from legacy sync `client` fixture to avoid collision; both coexist until Plan 05 |
|
||||||
|
| xfail(strict=False) for Wave 0 | All pre-implementation scaffolds use strict=False so unexpected passes don't break CI |
|
||||||
|
|
||||||
### Open Questions
|
### Open Questions
|
||||||
|
|
||||||
@@ -82,6 +84,6 @@ _Updated at each phase transition._
|
|||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Last session | 2026-05-22 — Executed 01-01-PLAN.md (Compose + Config Foundation) |
|
| Last session | 2026-05-22 — Executed 01-02-PLAN.md (Wave 0 test scaffolds + async fixtures) |
|
||||||
| Next action | Execute 01-02-PLAN.md (Wave 0 test scaffolds + async pytest fixtures) |
|
| Next action | Execute 01-03-PLAN.md (SQLAlchemy ORM models + Alembic async migration) |
|
||||||
| Pending decisions | See Open Questions above |
|
| Pending decisions | See Open Questions above |
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
phase: 01-infrastructure-foundation
|
||||||
|
plan: 02
|
||||||
|
subsystem: testing
|
||||||
|
tags:
|
||||||
|
- testing
|
||||||
|
- wave-0
|
||||||
|
- pytest
|
||||||
|
- tdd
|
||||||
|
- xfail
|
||||||
|
dependency_graph:
|
||||||
|
requires:
|
||||||
|
- 01-01 # config.py Pydantic Settings (used in conftest imports)
|
||||||
|
provides:
|
||||||
|
- Wave 0 test scaffolds for Plans 03, 04, 05
|
||||||
|
- Async pytest fixtures (db_session, async_client) ready for Plan 03+
|
||||||
|
affects:
|
||||||
|
- backend/tests/conftest.py
|
||||||
|
- backend/tests/test_health.py
|
||||||
|
- backend/tests/test_documents.py
|
||||||
|
- backend/tests/test_storage.py
|
||||||
|
- backend/tests/test_alembic.py
|
||||||
|
tech_stack:
|
||||||
|
added:
|
||||||
|
- pytest-asyncio (async_mode=auto, already in requirements.txt)
|
||||||
|
- httpx.AsyncClient + ASGITransport (test transport)
|
||||||
|
- sqlalchemy.ext.asyncio create_async_engine + async_sessionmaker (test fixtures)
|
||||||
|
- aiosqlite (in-memory SQLite for unit test engine)
|
||||||
|
patterns:
|
||||||
|
- "@pytest_asyncio.fixture for async test fixtures"
|
||||||
|
- "try/except ImportError: pytest.skip() for graceful degradation before Plan 03"
|
||||||
|
- "xfail(strict=False) for Wave 0 scaffolds targeting future plan deliverables"
|
||||||
|
- "AsyncClient + ASGITransport(app=app) + dependency_overrides[get_db] override"
|
||||||
|
key_files:
|
||||||
|
created:
|
||||||
|
- backend/tests/test_storage.py
|
||||||
|
- backend/tests/test_alembic.py
|
||||||
|
modified:
|
||||||
|
- backend/tests/conftest.py
|
||||||
|
- backend/tests/test_health.py
|
||||||
|
- backend/tests/test_documents.py
|
||||||
|
decisions:
|
||||||
|
- "async_client fixture uses NEW name to avoid collision with legacy sync client fixture"
|
||||||
|
- "All new async fixtures degrade gracefully via pytest.skip(ImportError) before Plan 03"
|
||||||
|
- "Sync fixtures (isolated_data_dir, client, sample_txt, sample_pdf) retained verbatim"
|
||||||
|
- "test_alembic.py uses stdlib sqlite3 (not aiosqlite) for table inspection post-migration"
|
||||||
|
- "test_documents.py keeps all 9 original sync tests AND adds 10 async counterparts"
|
||||||
|
metrics:
|
||||||
|
duration: "~9 minutes"
|
||||||
|
completed: "2026-05-22T07:08:49Z"
|
||||||
|
tasks_completed: 3
|
||||||
|
tasks_total: 3
|
||||||
|
files_created: 2
|
||||||
|
files_modified: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 1 Plan 02: Wave 0 Test Scaffolds — Summary
|
||||||
|
|
||||||
|
**One-liner:** Async SQLAlchemy + httpx fixtures added to conftest; 19 xfail Wave 0 tests across 5 files scaffold Plan 03-05 contracts before implementation.
|
||||||
|
|
||||||
|
## What Was Built
|
||||||
|
|
||||||
|
This plan authored all Wave 0 test scaffolds identified in `01-VALIDATION.md` before any implementation lands. Every test that depends on Plan 03-05 code is marked `xfail(strict=False)` so the suite stays green between waves. Later executors remove the xfail markers as their code lands.
|
||||||
|
|
||||||
|
### Files Created
|
||||||
|
|
||||||
|
| File | Purpose | Tests |
|
||||||
|
|------|---------|-------|
|
||||||
|
| `backend/tests/test_storage.py` | Wave 0 STORE-02 unit tests | 6 xfail tests |
|
||||||
|
| `backend/tests/test_alembic.py` | Wave 0 migration integration tests | 2 xfail tests |
|
||||||
|
|
||||||
|
### Files Modified
|
||||||
|
|
||||||
|
| File | Change | Tests Added |
|
||||||
|
|------|--------|-------------|
|
||||||
|
| `backend/tests/conftest.py` | Added `db_session` + `async_client` async fixtures | 0 (fixture-only) |
|
||||||
|
| `backend/tests/test_health.py` | Added `test_health_checks_postgres_and_minio` | 1 xfail |
|
||||||
|
| `backend/tests/test_documents.py` | Added 9 async port tests + 1 persistence test | 10 xfail |
|
||||||
|
|
||||||
|
### Total Wave 0 xfail Inventory
|
||||||
|
|
||||||
|
| File | xfail count | Unblocked by |
|
||||||
|
|------|-------------|--------------|
|
||||||
|
| test_storage.py | 6 | Plan 04 |
|
||||||
|
| test_alembic.py | 2 | Plan 03 |
|
||||||
|
| test_health.py | 1 | Plan 05 |
|
||||||
|
| test_documents.py | 10 | Plan 05 |
|
||||||
|
| **Total** | **19** | — |
|
||||||
|
|
||||||
|
### Fixture Inventory (conftest.py)
|
||||||
|
|
||||||
|
| Fixture | Type | Scope | Status |
|
||||||
|
|---------|------|-------|--------|
|
||||||
|
| `isolated_data_dir` | sync autouse | function | Retained (Plan 05 removes) |
|
||||||
|
| `client` | sync TestClient | function | Retained (Plan 05 removes) |
|
||||||
|
| `sample_txt` | sync | function | Retained |
|
||||||
|
| `sample_pdf` | sync | function | Retained |
|
||||||
|
| `db_session` | async | function | New — skips until Plan 03 |
|
||||||
|
| `async_client` | async | function | New — skips until Plan 03 |
|
||||||
|
|
||||||
|
### Test Functions Added
|
||||||
|
|
||||||
|
**test_storage.py** (all xfail → Plan 04):
|
||||||
|
- `test_object_key_schema` — regex `^[^/]+/[^/]+/{uuid4}(\.ext)?$` against `put_object` return value
|
||||||
|
- `test_filename_not_in_object_key` — asserts "invoice", "Q3", "secret" not in key
|
||||||
|
- `test_storage_backend_abc_methods` — incomplete subclass raises `TypeError`
|
||||||
|
- `test_get_storage_backend_returns_minio` — factory returns `MinIOBackend`
|
||||||
|
- `test_put_object_uses_asyncio_to_thread` — `asyncio.to_thread` was called with `_client.put_object`
|
||||||
|
- `test_minio_backend_health_check_returns_bool` — returns `True` / `False` on ok/exception
|
||||||
|
|
||||||
|
**test_alembic.py** (all xfail → Plan 03):
|
||||||
|
- `test_migration_creates_all_tables` — all 11 v1 tables: users, quotas, refresh_tokens, folders, documents, topics, document_topics, shares, audit_log, cloud_connections, groups
|
||||||
|
- `test_documents_user_id_nullable` — `PRAGMA table_info(documents)` confirms `notnull=0`
|
||||||
|
|
||||||
|
**test_health.py** (1 xfail → Plan 05):
|
||||||
|
- `test_health_checks_postgres_and_minio` — asserts `checks.postgres == "ok"` and `checks.minio == "ok"`
|
||||||
|
|
||||||
|
**test_documents.py** (10 xfail → Plan 05):
|
||||||
|
- `test_upload_txt_no_classify_async`
|
||||||
|
- `test_upload_pdf_no_classify_async`
|
||||||
|
- `test_list_documents_async`
|
||||||
|
- `test_list_documents_filter_by_topic_async`
|
||||||
|
- `test_get_document_async`
|
||||||
|
- `test_get_document_not_found_async`
|
||||||
|
- `test_delete_document_async`
|
||||||
|
- `test_delete_document_not_found_async`
|
||||||
|
- `test_upload_empty_file_async`
|
||||||
|
- `test_upload_persists_to_postgres_and_minio_async` — UUID id regex + GET round-trip
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
| Hash | Message |
|
||||||
|
|------|---------|
|
||||||
|
| `1f675fc` | feat(01-02): add async db_session and async_client fixtures to conftest.py |
|
||||||
|
| `27fa0d4` | test(01-02): add Wave 0 scaffolds test_storage.py and test_alembic.py |
|
||||||
|
| `d856a2e` | test(01-02): extend test_health.py and port test_documents.py to async client |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan executed exactly as written.
|
||||||
|
|
||||||
|
The `async_client` fixture was named `async_client` (not `client`) as specified in the plan action to avoid collision with the legacy sync `client` fixture. This matches the plan's intent.
|
||||||
|
|
||||||
|
## Known Stubs
|
||||||
|
|
||||||
|
None. All test files reference not-yet-existing modules inside `try/except ImportError: pytest.skip()` blocks — this is intentional Wave 0 scaffold behavior, not stubs.
|
||||||
|
|
||||||
|
## Threat Flags
|
||||||
|
|
||||||
|
None. All test data is synthetic (no real PII). aiosqlite DB lives in `tmp_path` and `:memory:` only (T-01-02-01 mitigated). No new network endpoints introduced.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
Files exist:
|
||||||
|
- `/Users/nik/Documents/Progamming/document_scanner/backend/tests/test_storage.py` — FOUND
|
||||||
|
- `/Users/nik/Documents/Progamming/document_scanner/backend/tests/test_alembic.py` — FOUND
|
||||||
|
- `/Users/nik/Documents/Progamming/document_scanner/backend/tests/conftest.py` — FOUND (modified)
|
||||||
|
- `/Users/nik/Documents/Progamming/document_scanner/backend/tests/test_health.py` — FOUND (modified)
|
||||||
|
- `/Users/nik/Documents/Progamming/document_scanner/backend/tests/test_documents.py` — FOUND (modified)
|
||||||
|
|
||||||
|
Commits verified in git log:
|
||||||
|
- `1f675fc` — FOUND
|
||||||
|
- `27fa0d4` — FOUND
|
||||||
|
- `d856a2e` — FOUND
|
||||||
|
|
||||||
|
xfail count: 19 (>= minimum 18 required)
|
||||||
|
Syntax check: PASSED (all 5 files parsed cleanly by Python AST)
|
||||||
Reference in New Issue
Block a user