Files
kite/.planning/phases/03-document-migration-multi-user-isolation/03-VALIDATION.md
T
curo1305 3cc4a5335d docs(phase-03): update VALIDATION.md — Nyquist-compliant (partial)
15 automated tests green, 4 manual-only (PostgreSQL/migration infra).
Added 4 previously unlisted passing tests to task map (D-15, D-16, D-09×2).
Audit trail appended. Status: nyquist_compliant: true, status: partial.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:07:23 +02:00

104 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 3
slug: document-migration-multi-user-isolation
status: partial
nyquist_compliant: true
wave_0_complete: true
created: 2026-05-23
audited: 2026-05-31
---
# Phase 3 — Validation Strategy
> Per-phase validation contract for feedback sampling during execution.
---
## Test Infrastructure
| Property | Value |
|----------|-------|
| **Framework** | pytest + pytest-asyncio (existing in codebase) |
| **Config file** | `backend/pytest.ini` or `backend/pyproject.toml` |
| **Quick run command** | `cd backend && pytest tests/test_documents.py tests/test_quota.py tests/test_topics.py -x -q` |
| **Full suite command** | `cd backend && pytest -v` |
| **Estimated runtime** | ~3060 seconds |
---
## Sampling Rate
- **After every task commit:** Run `cd backend && pytest tests/test_documents.py tests/test_quota.py tests/test_topics.py -x -q`
- **After every plan wave:** Run `cd backend && pytest -v`
- **Before `/gsd:verify-work`:** Full suite must be green
- **Max feedback latency:** 60 seconds
---
## Per-Task Verification Map
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
| Atomic quota enforce | 02 | 2 | STORE-03 | STORE-03 | No double-spend on concurrent uploads | unit+integration | `pytest tests/test_quota.py::test_quota_increment_atomic -x` | ✅ | ✅ green |
| Quota exceeded response | 02 | 2 | STORE-05 | STORE-05 | 413 with {used_bytes, limit_bytes, rejected_bytes} | unit | `pytest tests/test_quota.py::test_quota_exceeded_response -x` | ✅ | ✅ green |
| Upload-url endpoint | 02 | 2 | D-05 | SEC-04 | Creates pending Document row + returns presigned URL | unit | `pytest tests/test_documents.py::test_upload_url_endpoint -x` | ✅ | ✅ green |
| Confirm endpoint | 02 | 2 | D-05 | STORE-03 | stat_object size used, status=uploaded set | unit | `pytest tests/test_documents.py::test_confirm_endpoint -x` | ✅ | ✅ green |
| Quota bar endpoint | 02 | 2 | STORE-04 | — | GET /api/me/quota returns {used_bytes, limit_bytes} | unit | `pytest tests/test_documents.py::test_get_quota -x` | ✅ | ✅ green |
| Cross-user access | 03 | 3 | SEC-04 | SEC-04 | Cross-user document access returns 404 | unit | `pytest tests/test_documents.py::test_cross_user_access_404 -x` | ✅ | ✅ green |
| Admin 403 on documents | 03 | 3 | SEC-04 (SC4) | SEC-04 | Admin JWT on /api/documents/* returns 403 | unit | `pytest tests/test_documents.py::test_admin_cannot_access_documents -x` | ✅ | ✅ green |
| Topic namespace isolation | 03 | 3 | DOC-04 | — | Topic list = system topics + own topics only | unit | `pytest tests/test_topics.py::test_topic_namespace -x` | ✅ | ✅ green |
| Per-user AI provider | 04 | 4 | DOC-03/DOC-05 | — | Classifier uses user's assigned provider not global | unit | `pytest tests/test_classifier.py::test_per_user_provider -x` | ✅ | ✅ green |
| Celery task provider lookup | 04 | 4 | DOC-05 | — | Celery task resolves provider from document owner's DB | unit | `pytest tests/test_classifier.py::test_celery_task_uses_user_provider -x` | ✅ | ✅ green |
| Settings endpoint removed | 04 | 4 | D-12 | — | /api/settings returns 404 | unit | `pytest tests/test_settings.py::test_settings_endpoint_removed -x` | ✅ | ✅ green |
| Default provider fallback | 04 | 4 | D-15 | — | Classifier falls back to app_settings defaults when user has no provider | unit | `pytest tests/test_classifier.py::test_default_provider_fallback -x` | ✅ | ✅ green |
| Documents require auth | 02 | 2 | D-16 | SEC-04 | Unauthenticated requests to /api/documents/* return 401 | unit | `pytest tests/test_documents.py::test_documents_require_auth -x` | ✅ | ✅ green |
| Admin create system topic | 03 | 3 | D-09 | — | Admin can create is_system=true topics | unit | `pytest tests/test_topics.py::test_admin_create_system_topic -x` | ✅ | ✅ green |
| User cannot create system topic | 03 | 3 | D-09 | — | Regular user POST with is_system=true returns 403 | unit | `pytest tests/test_topics.py::test_regular_user_cannot_create_system_topic -x` | ✅ | ✅ green |
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
---
## Manual-Only Tasks
> These tasks require infrastructure not available in the unit test environment.
> They must be verified manually before phase sign-off.
| Task ID | Plan | Requirement | Why Manual | Verification Step |
|---------|------|-------------|------------|-------------------|
| Migration null-user cleanup | 01 | D-02 | Alembic upgrade requires a real PostgreSQL instance + migration scripts | `INTEGRATION=1 pytest tests/test_alembic.py::test_migration_0003 -x` against real DB |
| Quota reconciliation | 01 | D-03 | Same migration test; verifies used_bytes matches SUM(size_bytes) post-migration | `INTEGRATION=1 pytest tests/test_alembic.py::test_migration_0003 -x` against real DB |
| Concurrent quota race | 02 | STORE-03 SC2 | PostgreSQL row-level locking required; SQLite cannot emulate concurrent atomic UPDATE | `INTEGRATION=1 pytest tests/test_quota.py::test_concurrent_quota_race -x` against PostgreSQL |
| Atomic quota decrement | 02 | STORE-06 | SQLite UUID format mismatch in GREATEST() WHERE clause; real PostgreSQL required | `INTEGRATION=1 pytest tests/test_quota.py::test_delete_decrements_quota -x` against PostgreSQL |
---
## Wave 0 Status
- [x] `backend/tests/test_quota.py` — STORE-03, STORE-05, STORE-06, concurrent race
- [x] `backend/tests/test_alembic.py` — migration 0003 test (manual-only)
- [x] `backend/tests/test_classifier.py` — DOC-03, DOC-05, D-15 per-user provider
- [x] `backend/tests/test_documents.py` — D-05, D-16, STORE-04, SEC-04
- [x] `backend/tests/test_topics.py` — DOC-04, D-09
- [x] `backend/tests/test_settings.py` — D-12
- [x] `backend/tests/conftest.py` — auth_user, admin_user, MinIO mock fixtures
---
## Validation Audit 2026-05-31
| Metric | Count |
|--------|-------|
| Tasks in map | 19 |
| Automated (green) | 15 |
| Manual-only | 4 |
| Gaps found | 10 |
| Resolved (xfail removed) | 2 |
| Added to task map | 4 |
| Escalated to manual-only | 4 |
**Changes made:**
- Removed stale `xfail` markers from `test_quota_increment_atomic` and `test_quota_exceeded_response` (both XPASS → now clean PASSED)
- Added 4 unlisted-but-passing tests to task map: `test_default_provider_fallback` (D-15), `test_documents_require_auth` (D-16), `test_admin_create_system_topic` (D-09), `test_regular_user_cannot_create_system_topic` (D-09)
- Moved 4 infrastructure-blocked tasks to Manual-Only: migration null-user cleanup, quota reconciliation, concurrent quota race, atomic quota decrement