diff --git a/docs/README.md b/docs/README.md
index f9eae49b..b560f1e0 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -26,6 +26,7 @@ This directory contains SeedPass project documentation.
- `tui_v2_plan.md`
- `tui_v2_parity_checklist.md`
- `tui_v2_cutover_decision.md`
+- `tui_v2_large_vault_validation.md`
- `security.md`
- `nostr_setup.md`
- `nostr_namespace_reset.md`
diff --git a/docs/tui_v2_large_vault_validation.md b/docs/tui_v2_large_vault_validation.md
new file mode 100644
index 00000000..26730602
--- /dev/null
+++ b/docs/tui_v2_large_vault_validation.md
@@ -0,0 +1,48 @@
+# TUI v2 Large-Vault Validation
+
+Status: Added on `beta` (March 1, 2026).
+
+This document defines a deterministic, CI-like validation pass for TUI v2 behavior at large vault sizes.
+
+## What Is Validated
+
+- Pagination behavior across large deterministic datasets.
+- Detail preview truncation behavior for large document content.
+
+## Test Module
+
+- `src/tests/test_tui_v2_large_vault_validation.py`
+
+## Deterministic Data Profile
+
+- Standard profile: `10,000` entries.
+- Stress profile: `50,000` entries (`--stress`).
+- Labels are deterministic (`Entry-000000` style).
+
+## Runtime Thresholds
+
+Pagination scan budget (wall-clock for scan loop):
+- `10,000` rows: `<= 2.0s`
+- `50,000` rows: `<= 8.0s`
+
+Detail truncation checks:
+- Confirms bounded preview behavior at large content sizes.
+
+## Commands
+
+Standard CI-like run:
+
+```bash
+.venv/bin/python -m pytest -q src/tests/test_tui_v2_large_vault_validation.py
+```
+
+Extended stress run:
+
+```bash
+.venv/bin/python -m pytest -q --stress src/tests/test_tui_v2_large_vault_validation.py
+```
+
+## Notes
+
+- Stress tests are opt-in in this repository (require `--stress`).
+- Thresholds are intentionally conservative to reduce environment flakiness while still catching regressions.
diff --git a/docs/tui_v2_parity_checklist.md b/docs/tui_v2_parity_checklist.md
index 250367d4..e68f9f43 100644
--- a/docs/tui_v2_parity_checklist.md
+++ b/docs/tui_v2_parity_checklist.md
@@ -39,7 +39,7 @@ This checklist tracks readiness to switch default interactive mode from legacy T
- Incomplete parity for legacy-only interactive operations not yet mapped into TUI v2.
- Textual runtime/version behavior can vary by environment.
-- No dedicated Textual interaction test suite yet for pagination and graph traversal.
+- Large-vault validation is bounded to deterministic pagination/preview checks and should be expanded with full end-to-end sync workloads.
## Validation Checklist Before Cutover
@@ -48,5 +48,7 @@ This checklist tracks readiness to switch default interactive mode from legacy T
- `src/tests/test_tui_v2_textual_interactions.py` (skips when `textual` is unavailable).
- [x] Add non-UI unit tests for TUI v2 helper logic.
- `src/tests/test_tui_v2_helpers.py` covers command parsing, pagination, and detail truncation.
-- [ ] Verify large vault behavior with realistic data volume in CI-like environment.
+- [x] Verify large vault behavior with realistic data volume in CI-like environment.
+ - `src/tests/test_tui_v2_large_vault_validation.py`
+ - standard: `10,000` rows, stress: `50,000` rows (`--stress`)
- [ ] Confirm help text and docs match shipped keybindings and palette commands.
diff --git a/landing/docs.html b/landing/docs.html
index 1b5a5d52..ea4343a9 100644
--- a/landing/docs.html
+++ b/landing/docs.html
@@ -59,6 +59,7 @@
> TUI v2 Plan
> TUI v2 Parity
> TUI v2 Cutover
+ > TUI v2 Large Vault
> Security
> Security Readiness
> Agent Security Plan
diff --git a/memory-update.md b/memory-update.md
index 98d419c8..7c0bac65 100644
--- a/memory-update.md
+++ b/memory-update.md
@@ -194,3 +194,5 @@
- Added `src/tests/test_tui_v2_helpers.py` with coverage for palette parsing edge cases, pagination normalization, and large-vault pagination smoke sizes up to 50k rows.
- 2026-03-01: Added Textual interaction tests in `src/tests/test_tui_v2_textual_interactions.py` for pagination/search, document edit+save, link add/remove + neighbor open, and retry-after-failure.
- Introduced a test hook in `launch_tui2(..., app_hook=...)` so tests can capture and pilot the Textual app instance without starting a live terminal run.
+- 2026-03-01: Added CI-like large-vault validation with explicit thresholds in `src/tests/test_tui_v2_large_vault_validation.py` (10k rows standard, 50k rows under `--stress`).
+- Added docs `docs/tui_v2_large_vault_validation.md` with exact commands and budgets; parity checklist now marks large-vault CI-like validation complete.
diff --git a/src/tests/test_tui_v2_large_vault_validation.py b/src/tests/test_tui_v2_large_vault_validation.py
new file mode 100644
index 00000000..02d49c6a
--- /dev/null
+++ b/src/tests/test_tui_v2_large_vault_validation.py
@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+from time import perf_counter
+
+import pytest
+
+from seedpass.tui_v2.app import pagination_window, truncate_entry_for_display
+
+
+def _deterministic_labels(rows: int) -> list[str]:
+ return [f"Entry-{i:06d}" for i in range(rows)]
+
+
+@pytest.mark.parametrize(
+ ("rows", "max_seconds"),
+ [
+ (10000, 2.0),
+ pytest.param(50000, 8.0, marks=pytest.mark.stress),
+ ],
+)
+def test_large_vault_pagination_validation(rows: int, max_seconds: float) -> None:
+ """CI-like pagination scan over deterministic large-vault datasets."""
+ labels = _deterministic_labels(rows)
+
+ start = perf_counter()
+ total_seen = 0
+ page = 0
+ seen_first = None
+ seen_last = None
+ while True:
+ page, start_idx, end_idx, total_pages = pagination_window(rows, 200, page)
+ if start_idx >= end_idx:
+ break
+ batch = labels[start_idx:end_idx]
+ assert len(batch) <= 200
+ if seen_first is None:
+ seen_first = batch[0]
+ seen_last = batch[-1]
+ total_seen += len(batch)
+ if page >= total_pages - 1:
+ break
+ page += 1
+
+ elapsed = perf_counter() - start
+
+ assert total_seen == rows
+ assert seen_first == "Entry-000000"
+ assert seen_last == f"Entry-{rows - 1:06d}"
+ assert (
+ elapsed <= max_seconds
+ ), f"Large-vault pagination scan exceeded budget: {elapsed:.3f}s > {max_seconds:.3f}s"
+
+
+@pytest.mark.parametrize(
+ ("content_size", "limit", "expected_truncated"),
+ [
+ (4096, 4000, True),
+ (1000, 4000, False),
+ pytest.param(200000, 4000, True, marks=pytest.mark.stress),
+ ],
+)
+def test_large_document_detail_truncation_validation(
+ content_size: int, limit: int, expected_truncated: bool
+) -> None:
+ """Ensure large document previews remain bounded and deterministic."""
+ payload = truncate_entry_for_display(
+ {
+ "kind": "document",
+ "label": "Big Doc",
+ "content": "X" * content_size,
+ },
+ limit,
+ )
+
+ assert payload["label"] == "Big Doc"
+ assert payload["kind"] == "document"
+ assert ("content_truncated" in payload) is expected_truncated
+ if expected_truncated:
+ assert payload["content"].startswith("X" * limit)
+ assert "truncated" in payload["content"]
+ else:
+ assert payload["content"] == "X" * content_size