# Comprehensive Handoff Report: HAD Digital MVP Test & Verification Framework

**Agent ID:** explorer_survey_3  
**Date:** 2026-09-05T10:36:00Z  
**Target Milestone:** HAD Digital MVP Test & Verification Architecture (Tiers 1–5 & Programmatic Verification Script)  
**Parent Agent:** orchestrator_1 (`8c700e5d-87a4-4452-ab59-6fc2e8946b0d`)  
**Output Path:** `c:\AI Projects\Kais Project\.agents\explorer_survey_3\handoff.md`  

---

## 1. Observation

### 1.1 Test Asset Survey in `05_Test`
- Directory `c:\AI Projects\Kais Project\05_Test` was inspected via `list_dir`. Result: **Empty directory** (0 files, 0 subdirectories, 0 bytes).
- In `c:\AI Projects\Kais Project\00_Governance\Project_Status.md` (lines 137–140), the current test posture is explicitly recorded:
  ```markdown
  ### Automated Testing
  No automated tests are implemented in the MVP. This is a gap that should be addressed before production deployment.
  ```
- In `c:\AI Projects\Kais Project\MVP_EXECUTION_PLAN.md` (lines 187–193, 238–240), Phase 4G calls for `test_ctcae.py`, `test_auth.py`, `test_api.py`, and `test_integration.py`, and Phase 7 calls for clean-VM smoke tests, but none of these test scripts currently exist in the codebase.

### 1.2 Existing MVP Prototype Assets in `c:\AI Projects\Kais Project\MVP`
Inspection of `c:\AI Projects\Kais Project\MVP` revealed a complete Python web application:
- **Backend**: Pure Python standard library HTTP server (`http.server.BaseHTTPRequestHandler`) in `MVP/app.py` (550 lines) implementing 19 REST API endpoints.
- **Database**: SQLite database manager in `MVP/database.py` (325 lines) configured with WAL mode (`PRAGMA journal_mode=WAL`), foreign keys, and busy timeout (`PRAGMA busy_timeout=5000`). Tables include: `users`, `patients`, `episodes`, `treatment_plans`, `toxicity_reports`, `toxicity_grades`, `alerts`, `messages`, `timeline_events`, and `audit_log`.
- **Authentication**: `MVP/user_store.py` (214 lines) implementing password hashing via `hashlib.scrypt` (N=16384, r=8, p=1, dklen=64) with 32-byte hexadecimal salts, 5-failure lockout (locks account for 30 minutes in `locked_until`), and session management using `uuid.uuid4()`.
- **Clinical Grading**: `MVP/ctcae_engine.py` (7.5 KB) driven by `MVP/data/ctcae_rules.json` (14 KB) covering 12 prioritized oncology symptoms.
- **Alert Engine**: `MVP/alert_engine.py` (10 KB) mapping grades to Routine, Urgent (30-min delay), and Emergency (0-min delay).
- **Data Seeder**: `MVP/seed_demo.py` (430 lines) providing idempotent auto-seeding of 3 patients, 10 users across 8 roles, treatment regimens, sample reports, and timeline events.
- **Standalone Windows Executable**: Built artifact in `MVP/dist/HAD Digital/HAD Digital.exe` (1,870,401 bytes) bundled via PyInstaller using `MVP/HAD Digital.spec` (onedir mode with embedded `static`, `data`, `guidance`, `adapters`).

### 1.3 Local Environment Tooling Survey
A probe of the host operating environment (Windows 11 / PowerShell, Python 3.14.6) established that the following testing packages are installed and functional:
- `pytest` (v9.1.1), `pytest-asyncio` (v1.4.0), `pytest-cov` (v7.1.0), `coverage` (v7.16.0)
- `requests` (v2.33.0), `httpx` (v0.28.1), `aiohttp` (v3.14.3), `urllib3` (v2.7.0)
- `playwright` (v1.62.0), `beautifulsoup4` (v4.15.0)
- `psutil` (v7.2.2), `pyinstaller` (v6.22.2), `jsonschema` (v4.26.0)
- Target executable runtime constraint: `HAD Digital.exe` is self-contained and requires **zero external runtime dependencies** on host machines.

### 1.4 Empirical Verification Results: Server Lifecycle & Core Flow
Empirical verification scripts were executed against both the Python source server (`MVP/app.py`) and the compiled binary (`MVP/dist/HAD Digital/HAD Digital.exe`) using dynamic port allocation and isolated temporary SQLite databases.

#### Test 1: Python Source Lifecycle & E2E Verification (`app.py`)
- **Port Allocation**: Bound ephemeral socket to port 0; acquired port `49919`.
- **Process Launch**: `subprocess.Popen([sys.executable, 'MVP/app.py', '--port', '49919'], env={'HAD_DB_PATH': temp_db, 'HAD_PORT': '49919'})`.
- **Health Check Ping**: `GET http://127.0.0.1:49919/api/whoami` responded with HTTP 401 within 1.0s (indicating server online and unauthenticated).
- **Invalid Auth Rejection**: `POST /api/login` with bad credentials returned HTTP 401.
- **Patient Authentication**: `POST /api/login` (`patient.durand` / `demo123`) returned HTTP 200, `role: 'patient'`, and set `HAD_SESSION` cookie.
- **Patient Toxicity Report Submission**: `POST /api/reports` with payload `{'patient_id': 1, 'symptom_id': 'nausea', 'symptom_category': 'gastrointestinal', 'severity_score': 2, 'notes': 'Moderate nausea post-infusion'}` returned HTTP 201 with `report_id: 8` and CTCAE `grading`.
- **Direct SQLite DB Assertion**: Querying `temp_db` verified row insertion in `toxicity_reports` (`id=8, patient_id=1, symptom_id='nausea', severity_score=2.0`) and `toxicity_grades` (`grade=1, provisional=0`).
- **Clinician Authentication**: `POST /api/login` (`dr.martin` / `demo123`) returned HTTP 200, `role: 'oncologist'`.
- **Clinician Timeline Verification**: `GET /api/timeline?patient_id=1` returned HTTP 200 with matching event: `Toxicity report: nausea - Grade 1 - Loss of appetite without alteration in eating habits`.
- **Clinician Report List Verification**: `GET /api/reports?patient_id=1` returned HTTP 200 containing report `id=8`.
- **Graceful Shutdown**: `proc.terminate()` followed by `proc.wait(timeout=5)` completed with exit code 1 (standard Windows SIGTERM return code), releasing port `49919`.

#### Test 2: Standalone Binary Lifecycle & E2E Verification (`HAD Digital.exe`)
- **Port Allocation**: Ephemeral port `52358`.
- **Process Launch**: `subprocess.Popen([exe_path, '--port', '52358'], cwd='MVP/dist/HAD Digital', env={'HAD_DB_PATH': temp_db, 'HAD_PORT': '52358'})`.
- **Health Ping**: `GET http://127.0.0.1:52358/api/whoami` responded with HTTP 401 in 1.0s.
- **Patient Login & Submit Report**: Succeeded with HTTP 201, `report_id: 8`.
- **Direct SQLite Inspection**: Confirmed `toxicity_reports` row persisted to disk.
- **Clinician Login & Timeline Verification**: Succeeded; `dr.martin` verified report `id: 8` on care timeline.
- **Process Shutdown**: Terminated cleanly and freed port.

#### Test 3: Adversarial Hardening Verification (Tier 5)
- **Path Traversal**: `GET /static/../../app.py` returned HTTP 404 / route rejection; source files outside `/static` were inaccessible.
- **Brute Force Lockout**:
  - Submitted 5 consecutive invalid login attempts for `patient.durand`: attempts 1 through 5 returned HTTP 401.
  - On the 6th attempt with the **correct password** (`demo123`), the request was rejected with HTTP 401: `{"error": "Invalid credentials or account locked"}`. Lockout enforcement succeeded.

### 1.5 Defect Discovered in Web Frontend (`MVP/static/app.js`)
In `MVP/static/app.js` (lines 77–83):
```javascript
const data = await api('POST', '/login', {
  username: document.getElementById('username').value,
  password: document.getElementById('password').value
});
if (data && data.ok) { currentUser = data.user; navigate('dashboard'); }
else document.getElementById('login-error').textContent = data.error || 'Login failed';
```
However, in `MVP/app.py` (line 199):
```python
self._json_response({"message": "Login successful", "user": {k: user[k] for k in ("id", "username", "role", "display_name")}})
```
The backend returns `message` and `user`, but does **not** include an `ok: true` key. In `app.js`, `data.ok` evaluates to `undefined` (falsy), causing valid logins to hit the `else` branch and display `"Login failed"` in the browser UI.

---

## 2. Logic Chain

1. **Premise 1 (Acceptance Criteria per `ORIGINAL_REQUEST.md`)**:
   The MVP acceptance criteria demand:
   - Packaging as a standalone `.exe` using PyInstaller.
   - A programmatic verification script testing process launch, authentication, health checks, and zero external runtime dependencies.
   - Patient login, toxicity report submission, SQLite persistence, and clinician login + care timeline verification.

2. **Premise 2 (Gap in Existing Assets)**:
   Observation 1.1 confirms that `05_Test` is empty and automated tests were deferred in Phase 4G. Therefore, a complete test infrastructure, test tier hierarchy, and verification script must be formally designed and delivered to `05_Test`.

3. **Premise 3 (Feasibility of Dual-Target Verification)**:
   Observations 1.4 (Test 1 and Test 2) prove empirically that both `MVP/app.py` and `MVP/dist/HAD Digital/HAD Digital.exe` accept CLI port flags (`--port`), respect environment variable overrides (`HAD_PORT`, `HAD_DB_PATH`), auto-seed baseline users in fresh SQLite databases, and support identical HTTP API contracts.
   - *Inference*: A single unified programmatic verification script (`verify_mvp.py`) can test both source code and the compiled `.exe` using standard Python library primitives (`urllib.request`, `http.client`, `sqlite3`, `subprocess`), guaranteeing that testing introduces zero runtime dependencies on the target `.exe`.

4. **Premise 4 (Test Tier Hierarchy Necessity)**:
   Simple happy-path testing is insufficient for medical software (oncology toxicity monitoring). A 5-tier testing structure is necessary:
   - *Tier 1*: Covers all 19 endpoints and 8 user roles (functional parity).
   - *Tier 2*: Covers CTCAE boundary thresholds (e.g. lab value cutoffs, severity 0–4), missing fields, and query bounds.
   - *Tier 3*: Covers the 8-role x 19-endpoint RBAC permission matrix and concurrent multi-symptom submission.
   - *Tier 4*: Simulates end-to-end clinical oncology patient journeys (e.g. Febrile Neutropenia emergency flow).
   - *Tier 5*: Proves resilience against adversarial attacks (5-fail lockout, path traversal, SQL injection, XSS/CSP, SQLite WAL concurrency).

5. **Premise 5 (Frontend Rectification Requirement)**:
   Observation 1.5 revealed that while the backend REST API functions perfectly, the vanilla JS frontend fails on login due to `data.ok`. Resolving this discrepancy must be scheduled as a high-priority bug fix in Milestone M2.

---

## 3. Caveats

1. **Browser GUI Automation vs API Testing**: Playwright (v1.62.0) is installed in the Python environment, but headless browser binaries (e.g. Chromium) were not executed to avoid creating heavy background browser processes during read-only survey. The primary verification framework is designed around headless HTTP/API testing, which is fast, deterministic, and does not require GPU/browser runtimes.
2. **PyInstaller Antivirus / Code Signing**: `HAD Digital.exe` compiles and runs cleanly on this Windows 11 host. However, in corporate or clinical environments, unsigned PyInstaller binaries can trigger false positives in Windows Defender or enterprise EDRs. Code-signing or folder bundle mode (Mode B) remains a deployment consideration post-MVP.
3. **AI Adapter Mocking**: The AI chat endpoint `/api/chat` currently uses `StubAdapter`. External LLM providers (e.g., GLM-4) require network API keys and should be tested via mock adapters during offline automated test runs.
4. **Scope Boundaries**: As an explorer agent, no source code or test files were written to `05_Test` or `MVP/`. All architectures, specifications, and scripts are documented in this report for immediate implementation by Builder agents.

---

## 4. Conclusion

1. **Feasibility Confirmed**: The HAD Digital MVP is structurally sound. The compiled `HAD Digital.exe` and source `app.py` both satisfy the core acceptance criteria of autonomous launch, role-based authentication, toxicity report submission, SQLite persistence, and clinician timeline display.
2. **Deliverable Architecture for `05_Test`**:
   - `05_Test/verify_mvp.py`: A standalone, zero-external-dependency programmatic verification script that validates the full acceptance lifecycle against either `app.py` or `HAD Digital.exe`.
   - `05_Test/pytest.ini` & `05_Test/conftest.py`: A robust test harness supporting test tiers 1 through 5, dynamic port allocation, database isolation, and role-based session fixtures.
   - Full test suites organized under `05_Test/unit/`, `05_Test/integration/`, `05_Test/e2e/`, and `05_Test/security/`.
3. **Critical Defect Logged**: `MVP/static/app.js` line 81 requires a one-line update (`if (data && (data.ok || data.user))` or backend returning `{"ok": True, ...}`) to enable UI login.

---

## 5. Architectural Blueprints & Test Specifications

### 5.1 Recommended `05_Test` Directory Structure

```text
05_Test/
├── README.md                          # Testing architecture, tier definitions, and runner guide
├── conftest.py                        # Pytest fixtures: dynamic port, server process, temp DB, auth sessions
├── pytest.ini                         # Pytest configuration with custom tier markers
├── verify_mvp.py                      # Standalone programmatic verification script (Zero external deps)
├── unit/                              # Component-level unit tests
│   ├── test_ctcae_engine.py           # CTCAE grading rules and boundary logic
│   ├── test_alert_engine.py           # Alert routing, delay thresholds, and escalation
│   ├── test_user_store.py             # scrypt hashing, lockout logic, user CRUD
│   ├── test_database.py               # Schema creation, WAL mode, migrations
│   └── test_config_manager.py         # Config loading, deep merge, env var overrides
├── integration/                       # Multi-component integration tests
│   ├── test_api_auth.py               # All auth endpoints (/login, /logout, /whoami)
│   ├── test_api_reports.py            # Report submission, CTCAE grading integration, persistence
│   ├── test_api_timeline.py           # Timeline event generation and filtering
│   ├── test_api_alerts.py             # Alert creation, listing, acknowledgment
│   └── test_rbac_matrix.py            # Role-based access control matrix across all 8 roles & 19 endpoints
├── e2e/                               # End-to-end user journeys & standalone verification
│   ├── test_core_workflow.py          # Primary acceptance criteria (Patient submit -> DB -> Clinician view)
│   ├── test_exe_package.py            # Standalone HAD Digital.exe launch, health check, and workflow validation
│   └── test_clinical_journeys.py      # Real-world clinical scenarios (febrile neutropenia, routine nurse visit)
└── security/                          # Tier 5 hardening and adversarial security tests
    ├── test_brute_force_lockout.py    # 5-fail lockout validation
    ├── test_path_traversal.py         # Static file containment and traversal prevention
    ├── test_injection_resilience.py   # SQL injection & XSS payload resilience
    └── test_concurrency_stress.py     # SQLite concurrent access and WAL recovery
```

---

### 5.2 Programmatic Verification Script Design (`verify_mvp.py`)

The verification script must be completely self-contained and run on any machine with Python standard library. Below is the complete implementation design:

```python
"""HAD Digital MVP - Standalone Programmatic Verification Script.

Validates the complete acceptance criteria per ORIGINAL_REQUEST.md:
1. Automated launch of application (Source or .exe) with dynamic port allocation
2. Startup health check and unauthenticated ping
3. Invalid credential rejection
4. Patient authentication and session cookie issuance
5. Patient toxicity report submission with auto-grading
6. Programmatic SQLite direct database inspection (persistence verification)
7. Clinician authentication (Oncologist)
8. Clinician care timeline verification
9. Graceful process shutdown and port cleanup

Usage:
    python verify_mvp.py --mode source [--app-path MVP/app.py]
    python verify_mvp.py --mode exe    [--exe-path "MVP/dist/HAD Digital/HAD Digital.exe"]
"""

import argparse
import http.client
import json
import os
import shutil
import socket
import sqlite3
import subprocess
import sys
import tempfile
import time
from urllib.parse import urlparse


class VerificationRunner:
    def __init__(self, mode="source", target_path=None, timeout=30):
        self.mode = mode
        self.target_path = target_path
        self.timeout = timeout
        self.port = self._find_free_port()
        self.temp_dir = tempfile.mkdtemp(prefix="had_verify_")
        self.temp_db = os.path.join(self.temp_dir, "test_had.db")
        self.proc = None
        self.results = []

    def _find_free_port(self) -> int:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("127.0.0.1", 0))
        port = s.getsockname()[1]
        s.close()
        return port

    def log_step(self, step_name: str, passed: bool, message: str = ""):
        status = "PASS" if passed else "FAIL"
        print(f"[{status}] {step_name}: {message}")
        self.results.append({"step": step_name, "status": status, "message": message})
        if not passed:
            raise RuntimeError(f"Step failed: {step_name} - {message}")

    def start_server(self):
        env = os.environ.copy()
        env["HAD_DB_PATH"] = self.temp_db
        env["HAD_PORT"] = str(self.port)
        env["HAD_DEBUG"] = "false"

        if self.mode == "source":
            script = self.target_path or "MVP/app.py"
            cmd = [sys.executable, script, "--port", str(self.port)]
            cwd = os.path.abspath(os.path.dirname(script) or ".")
        else:
            exe = self.target_path or "MVP/dist/HAD Digital/HAD Digital.exe"
            cmd = [exe, "--port", str(self.port)]
            cwd = os.path.abspath(os.path.dirname(exe) or ".")

        self.proc = subprocess.Popen(
            cmd, cwd=cwd, env=env,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
        )

        # Health ping loop
        start_time = time.time()
        online = False
        while time.time() - start_time < self.timeout:
            time.sleep(0.3)
            try:
                conn = http.client.HTTPConnection("127.0.0.1", self.port, timeout=2)
                conn.request("GET", "/api/whoami")
                resp = conn.getresponse()
                conn.close()
                if resp.status == 401:  # Expected unauthenticated status
                    online = True
                    break
            except Exception:
                pass

        if not online:
            raise TimeoutError(f"Server failed to start on port {self.port} within {self.timeout}s")
        self.log_step("Server Startup & Health Check", True, f"Online on port {self.port} in {time.time()-start_time:.2f}s")

    def http_request(self, method: str, path: str, body: dict = None, cookie: str = None) -> tuple[int, dict, str]:
        conn = http.client.HTTPConnection("127.0.0.1", self.port, timeout=5)
        headers = {"Content-Type": "application/json"}
        if cookie:
            headers["Cookie"] = cookie
        payload = json.dumps(body) if body else None
        conn.request(method, path, body=payload, headers=headers)
        resp = conn.getresponse()
        resp_body = resp.read().decode("utf-8")
        set_cookie = resp.getheader("Set-Cookie")
        conn.close()
        try:
            data = json.loads(resp_body)
        except Exception:
            data = {"raw": resp_body}
        return resp.status, data, set_cookie

    def run_verification(self):
        try:
            self.start_server()

            # 1. Unauthenticated whoami
            st, data, _ = self.http_request("GET", "/api/whoami")
            self.log_step("Unauthenticated Access Check", st == 401, f"Returned HTTP {st}")

            # 2. Invalid Login Rejection
            st, data, _ = self.http_request("POST", "/api/login", {"username": "patient.durand", "password": "wrongpassword"})
            self.log_step("Invalid Credentials Rejection", st == 401, f"Returned HTTP {st}")

            # 3. Patient Authentication
            st, data, cookie = self.http_request("POST", "/api/login", {"username": "patient.durand", "password": "demo123"})
            self.log_step("Patient Login", st == 200 and data.get("user", {}).get("role") == "patient", f"Logged in as {data.get('user')}")
            patient_cookie = cookie.split(";")[0] if cookie else ""

            # 4. Patient Report Submission
            report_payload = {
                "patient_id": 1,
                "symptom_id": "nausea",
                "symptom_category": "gastrointestinal",
                "severity_score": 2,
                "notes": "Moderate nausea post-infusion"
            }
            st, data, _ = self.http_request("POST", "/api/reports", report_payload, cookie=patient_cookie)
            report_id = data.get("report_id")
            self.log_step("Toxicity Report Submission", st == 201 and report_id is not None, f"Report ID: {report_id}, Grading: {data.get('grading')}")

            # 5. Direct SQLite Persistence Inspection
            conn = sqlite3.connect(self.temp_db)
            cur = conn.cursor()
            cur.execute("SELECT id, patient_id, symptom_id, severity_score FROM toxicity_reports WHERE id = ?", (report_id,))
            rep_row = cur.fetchone()
            cur.execute("SELECT grade, provisional FROM toxicity_grades WHERE report_id = ?", (report_id,))
            grade_row = cur.fetchone()
            conn.close()
            self.log_step("SQLite Direct Persistence Check", rep_row is not None and grade_row is not None, f"DB Report: {rep_row}, Grade: {grade_row}")

            # 6. Clinician Authentication (Oncologist)
            st, data, cookie = self.http_request("POST", "/api/login", {"username": "dr.martin", "password": "demo123"})
            self.log_step("Clinician Login", st == 200 and data.get("user", {}).get("role") == "oncologist", f"Logged in as {data.get('user')}")
            clinician_cookie = cookie.split(";")[0] if cookie else ""

            # 7. Clinician Care Timeline Verification
            st, data, _ = self.http_request("GET", "/api/timeline?patient_id=1", cookie=clinician_cookie)
            events = data.get("events", [])
            found = any("nausea" in e.get("title", "").lower() for e in events)
            self.log_step("Care Timeline Verification", st == 200 and found, f"Verified report event in {len(events)} timeline items")

            print("\n========================================================")
            print("  ALL CORE ACCEPTANCE CRITERIA VERIFIED SUCCESSFULLY!  ")
            print("========================================================\n")
            return 0

        except Exception as ex:
            print(f"\n[FATAL ERROR] Verification aborted: {ex}")
            return 1

        finally:
            self.cleanup()

    def cleanup(self):
        if self.proc:
            try:
                self.proc.terminate()
                self.proc.wait(timeout=5)
            except Exception:
                self.proc.kill()
        shutil.rmtree(self.temp_dir, ignore_errors=True)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="HAD Digital MVP Verification Script")
    parser.add_argument("--mode", choices=["source", "exe"], default="source")
    parser.add_argument("--target-path", default=None)
    args = parser.parse_args()
    runner = VerificationRunner(mode=args.mode, target_path=args.target_path)
    sys.exit(runner.run_verification())
```

---

### 5.3 Test Tier Hierarchy Specification (Tiers 1 to 5)

#### Tier 1: Feature Coverage (Nominal Contract & Happy-Path Validation)
*Objective*: Validate that 100% of core features and all 19 REST endpoints behave strictly per `API_Contract.md`.
- **T1.1: Multi-Role Authentication Matrix**: Test login, session cookie (`HAD_SESSION`), and logout for all 8 roles: `admin`, `oncologist`, `had_nurse`, `community_nurse`, `gp`, `pharmacist`, `patient`, `caregiver`.
- **T1.2: Patient Toxicity Reporting**: Submit symptom reports across all 5 CTCAE domains (GI, hematologic, constitutional, dermatologic, neurologic). Validate return of HTTP 201 with `report_id` and CTCAE grading.
- **T1.3: Direct SQLite Persistence**: Verify that submitted reports, grades, and alerts write to `had.db` with proper timestamps and foreign keys.
- **T1.4: Clinician Care Timeline Feed**: Verify that newly submitted reports appear on `/api/timeline` in chronological order with correct symptom summary and grade.
- **T1.5: Automated CTCAE Rule Engine**: Verify severity-to-grade mapping across all 12 prioritized terms (e.g. Nausea: severity 1 -> Grade 1, severity 2 -> Grade 2 provisional).
- **T1.6: Tiered Alerting System**:
  - Grade 1 -> Routine (timeline event only).
  - Grade 2 -> Urgent (alert generated for care team).
  - Grade 3+ -> Emergency (alert generated with immediate oncologist dispatch).
  - Clinician alert acknowledgement via `POST /api/alerts/{id}/acknowledge`.
- **T1.7: Patient Guidance Lookup**: Validate `GET /api/guidance?symptom_id=nausea&grade=2` returns appropriate clinical advice in French.
- **T1.8: Static Asset Delivery**: Verify HTTP 200 and MIME headers for `index.html`, `app.css`, and `app.js`.

#### Tier 2: Boundary & Corner Cases (Extreme Inputs & Edge Conditions)
*Objective*: Validate input validation, boundary handling, and error resilience without application panics.
- **T2.1: Severity Score Boundary Conditions**:
  - Severity scores at boundaries: 0 (asymptomatic), 1 (mild), 3 (severe), 4 (life-threatening), 5 (fatal).
  - Invalid scores: -1, 6, "extreme", `null` -> HTTP 400 Bad Request.
- **T2.2: CTCAE Lab Value Cutoff Thresholds**:
  - Absolute Neutrophil Count (ANC): 1500 (normal) vs 1499 (Grade 1/2) vs 499 (Grade 4).
  - Platelet counts: 75000 vs 74999 (Grade 3 threshold).
- **T2.3: Missing & Partial JSON Payloads**:
  - Missing mandatory fields (`patient_id`, `symptom_id`, `symptom_category`) -> HTTP 400 with descriptive error message.
  - Empty notes string `""`, `null` notes, missing `lab_values` -> Handled gracefully with defaults.
- **T2.4: Query Limits & Pagination Boundaries**:
  - `GET /api/timeline?limit=0`, `limit=1`, `limit=500`.
  - Non-existent IDs: `GET /api/patients/99999` -> HTTP 404.
  - Negative IDs: `GET /api/patients/-1` -> HTTP 404 / 400.
- **T2.5: Character Encoding & Unicode Robustness**:
  - French accents (`é, è, ê, à, ç, ï, œ`) in notes, display names, and messages.
  - Ultra-long clinical notes (10,000 characters) -> Ensure SQLite TEXT column handles without truncation.

#### Tier 3: Combinations & Matrix Testing (Multi-Dimensional RBAC & Concurrency)
*Objective*: Validate multi-user interactions, role boundaries, and concurrent event handling.
- **T3.1: 8-Role x 19-Endpoint RBAC Matrix**:
  - Positive tests: Each role accessing authorized endpoints.
  - Negative tests: Unauthorized role access rejection:
    - Patient attempting `GET /api/audit-log` -> HTTP 403 or filtered out.
    - Patient attempting `GET /api/patients` -> Returns only their own record, not other patients.
    - Patient 1 attempting to view Patient 2's reports -> Scoped filtering blocks access.
- **T3.2: Concurrent Multi-Symptom Reporting**:
  - Simulating patient submitting 3 symptom reports simultaneously (e.g. Nausea, Neuropathy, Fatigue).
  - Verify SQLite WAL mode prevents database locks and ensures all 3 reports receive unique IDs, grades, and timeline entries.
- **T3.3: Alert Lifecycle & Multi-Clinician Interaction**:
  - Patient reports Grade 3 fever -> Emergency alert created -> Oncologist and Nurse both view alert -> Nurse acknowledges alert -> Alert status changes to `acknowledged` -> Oncologist verifies updated status.

#### Tier 4: Real-World Clinical Scenarios (End-to-End Persona Journeys)
*Objective*: Replicate complete clinical workflows across chemotherapy cycles.
- **T4.1: Acute Febrile Neutropenia Emergency Journey**:
  - *Context*: Jeanne Durand (Patient 1, on AC-T protocol) experiences chills and fever (38.7°C) on Day 8 of Cycle 4.
  - *Flow*:
    1. Patient logs in on mobile web view.
    2. Submits constitutional symptom report: Fever, severity 3, notes "Temperature 38.7°C, frissons intenses".
    3. Backend immediately evaluates CTCAE Grade 3, creates Emergency Alert.
    4. API response provides emergency patient guidance: "Contactez immédiatement votre oncologue ou appelez le 15".
    5. Dr. Martin logs in to dashboard, sees Emergency Alert pop up.
    6. Dr. Martin reviews timeline, acknowledges alert, sends direct message to Nurse Moret to dispatch emergency home antibiotics.
    7. System audit log records all actions with UTC timestamps and user attribution.
- **T4.2: Routine Home Nurse Clinical Observation & Summary Export**:
  - *Context*: Nurse Moret conducts scheduled home visit.
  - *Flow*:
    1. Nurse Moret logs in, reviews Jeanne's reported symptom history.
    2. Enters clinical observations: Blood pressure 125/80, pulse 72, skin assessment: Grade 1 hand-foot syndrome.
    3. Events appended to timeline.
    4. Nurse accesses `/api/export/summary?patient_id=1` to generate formatted JSON summary for hospital record integration.
- **T4.3: USB Plug-and-Play Offline Cold-Start**:
  - Binary and static data copied to isolated folder.
  - Clean launch with no internet connection and no pre-existing database.
  - Verifies auto-initialization of schema, demographic data seeding, and local-first execution.

#### Tier 5: Adversarial Hardening (Security & Chaos Testing)
*Objective*: Probe system boundaries against malicious exploitation, brute force, and crash conditions.
- **T5.1: Brute-Force Password Spraying & 5-Fail Lockout**:
  - Execute 5 failed password attempts on a single account.
  - Verify account is locked for 30 minutes.
  - Attempt 6th login with correct password -> Assert rejection (`{"error": "Invalid credentials or account locked"}`).
  - Verify audit log entry `login_failed`.
- **T5.2: Directory Traversal & Static Containment**:
  - Probe static handler with URL-encoded and raw traversal payloads: `/static/../../app.py`, `/static/..%2f..%2fdata/had.db`.
  - Assert that all requests outside `static/` return HTTP 403 / 404.
- **T5.3: SQL Injection Hardening**:
  - Inject SQL payloads in username field, report notes, search parameters: `' OR '1'='1`, `'; DROP TABLE users; --`, `admin'--`.
  - Assert that all database access uses parameterized queries (`?`) and queries do not execute arbitrary SQL.
- **T5.4: Cross-Site Scripting (XSS) & Content Security Policy (CSP)**:
  - Submit report notes containing `<script>alert('xss')</script>` or `<img src=x onerror=alert(1)>`.
  - Assert response headers enforce strict CSP: `Content-Security-Policy: default-src 'self'`.
  - Assert `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: strict-origin-when-cross-origin`.
- **T5.5: Session Hijacking & Cookie Tampering**:
  - Attempt API requests with invalid UUID session tokens, forged cookies, and expired sessions.
  - Assert that session IDs are cryptographically random (`uuid.uuid4()`) and regenerated on every login.
- **T5.6: SQLite Concurrency Stress & WAL Recovery**:
  - Spawn 20 concurrent threads writing reports simultaneously to test SQLite concurrency under `PRAGMA busy_timeout=5000`.
  - Simulate abrupt process kill (`proc.kill()`) during database transactions; restart and verify that SQLite WAL auto-recovery restores database integrity without corruption.

---

### 5.4 Implementation Plan for Testing Infrastructure in `05_Test`

To operationalize this design, the following action items are assigned to Phase 1 / Implementation Workers:
1. **Scaffold `05_Test` layout**: Create directories `unit/`, `integration/`, `e2e/`, `security/`.
2. **Deploy `verify_mvp.py`**: Write the zero-dependency verification script into `05_Test/verify_mvp.py` and create root symlink or wrapper `verify_acceptance.py`.
3. **Deploy Pytest Framework**:
   - Write `05_Test/conftest.py` with fixtures for `isolated_db`, `server_port`, `server_process`, and `api_client`.
   - Write `05_Test/pytest.ini` with custom markers (`tier1`, `tier2`, `tier3`, `tier4`, `tier5`, `exe`).
4. **Fix Frontend UI Bug**: Update `MVP/static/app.js` (line 81) to accept `(data && (data.ok || data.user))` or update `MVP/app.py` line 199 to return `{"ok": True, ...}`.

---

## 6. Verification Method

To independently verify the findings in this report, execute the following commands in the workspace root:

1. **Verify Empty `05_Test` Directory**:
   ```powershell
   Get-ChildItem -Path "c:\AI Projects\Kais Project\05_Test"
   # Confirms 0 files exist
   ```

2. **Verify Python & Standalone Executable Existence**:
   ```powershell
   python --version
   Test-Path "c:\AI Projects\Kais Project\MVP\app.py"
   Test-Path "c:\AI Projects\Kais Project\MVP\dist\HAD Digital\HAD Digital.exe"
   # Both return True
   ```

3. **Verify Programmatic Acceptance Criteria on Python Source**:
   Run the inline probe validating launch, patient submit, SQLite DB row, and clinician timeline:
   ```powershell
   python -c "
   import socket, subprocess, time, sys, requests, os, tempfile, shutil, sqlite3
   td = tempfile.mkdtemp(); db = os.path.join(td, 't.db')
   s = socket.socket(); s.bind(('127.0.0.1', 0)); p = s.getsockname()[1]; s.close()
   proc = subprocess.Popen([sys.executable, 'MVP/app.py', '--port', str(p)], cwd='.', env=dict(os.environ, HAD_DB_PATH=db, HAD_PORT=str(p)))
   try:
       time.sleep(1)
       sp = requests.Session()
       assert sp.post(f'http://127.0.0.1:{p}/api/login', json={'username':'patient.durand','password':'demo123'}).status_code == 200
       r = sp.post(f'http://127.0.0.1:{p}/api/reports', json={'patient_id':1,'symptom_id':'nausea','symptom_category':'gastrointestinal','severity_score':2}).json()
       rid = r['report_id']
       conn = sqlite3.connect(db); assert conn.cursor().execute('SELECT id FROM toxicity_reports WHERE id=?', (rid,)).fetchone(); conn.close()
       so = requests.Session()
       assert so.post(f'http://127.0.0.1:{p}/api/login', json={'username':'dr.martin','password':'demo123'}).status_code == 200
       tl = so.get(f'http://127.0.0.1:{p}/api/timeline', params={'patient_id':1}).json()
       assert any('nausea' in e['title'].lower() for e in tl['events'])
       print('VERIFICATION SUCCESSFUL')
   finally:
       proc.terminate(); proc.wait(5); shutil.rmtree(td, ignore_errors=True)
   "
   ```

4. **Verify Programmatic Acceptance Criteria on Standalone Binary**:
   Run the identical probe with the target pointing to `MVP/dist/HAD Digital/HAD Digital.exe`. Confirms identical pass results.

5. **Verify Front-End Mismatch**:
   Inspect line 81 of `MVP/static/app.js` and line 199 of `MVP/app.py` to confirm the `data.ok` vs `{"message": ...}` discrepancy.
