diff --git a/README.md b/README.md
index 43ecd1a..b366f12 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://fastapi.tiangolo.com/)
[](https://react.dev/)
[](LICENSE)
-[](#test-suite)
+[](#test-suite)
---
@@ -38,10 +38,16 @@
`API_KEY` is for scripts and services only; the browser never holds it. The
API refuses to start outside `dev` without `API_KEY`. Requests that use the
key reach the default schemas, not any tenant's.
+ Users change their own password from the header; a tenant admin can reset
+ members of their own tenant only. A user who belongs to more than one tenant
+ can be reset only by an operator with `scripts/reset_password.py` (#117).
+- **Upload failure reasons:** the per-row reasons and step log for an upload
+ are kept in the uploading browser's Import history, not on the server; the
+ server keeps only the counts. Server-side storage is planned for M3 (#107).
- **Rate limiting:** in-process only, so it suits a single API instance.
- **Frontend audit page:** shows this browser's local import history, not the
server audit log (see the naming note under Frontend Features).
-- **Offline install:** procedure in `docs/offline-install.md`, rehearsed with networking off. The clean-VM dry run (#60) is still to do.
+- **Offline install:** procedure in `docs/offline-install.md`, rehearsed with networking off. The clean-VM dry run (#60) is still to do. It targets Ubuntu 24.04 only; an offline container bundle for Windows, macOS and Linux is tracked as #128 (BR-38).
## For Reviewers
@@ -103,7 +109,7 @@ PostgreDataMigrationAppWithCSVLoader/
│ │ ├── export.ts ← CSV / XLSX / PDF export
│ │ ├── mapping-templates.ts ← saved column mapping templates
│ │ └── csv-preview.ts ← CSV parsing utilities
-│ ├── src/__tests__/ ← 102 vitest tests
+│ ├── src/__tests__/ ← 139 vitest tests
│ ├── .env.local ← VITE_API_BASE (not committed)
│ └── package.json
│
@@ -242,7 +248,7 @@ python -m pytest tests\test_te_loader_integration.py -v
python -m pytest tests\environments\ -v
```
-### Frontend tests (102 vitest)
+### Frontend tests (139 vitest)
```powershell
cd csv-table-hub-main
diff --git a/docs/VCRM.md b/docs/VCRM.md
index b9db6d8..666482e 100644
--- a/docs/VCRM.md
+++ b/docs/VCRM.md
@@ -84,6 +84,7 @@ Added by ART Milestone 0 (#53) and approved by the product owner on 2026-10-26.
| **BR-35** | Audit events shall be append-only at database level; reports shall be filterable; exports shall neutralise spreadsheet formula injection. | ART v2, D7 |
| **BR-36** | Users shall authenticate; access shall be role-based; no tenant shall read or affect another tenant's data. | ART v2, D1, ADR-0003, decision 6 |
| **BR-37** | Data shall stay inside the deployment boundary, with no runtime external services, and the stack shall install offline. | ART v2, D6, decision 7 |
+| **BR-38** | The platform shall install and run without internet access on Windows, macOS and Linux hosts that have a container runtime (Docker or Podman) installed. | Product owner, 27 Oct 2026; #128 |
### Out of scope (recorded for completeness)
@@ -135,7 +136,7 @@ The `input_data/` loader has its own implicit requirements — verified end-to-e
| BR-D4 | Duplicate primary keys in source are reported, not silently dropped | 4 (duplicate detection) | ✅ |
| BR-D5 | Loaded data is browsable (sample peek) | 1 (sample rows) | ✅ |
-### ART extension traceability (BR-23 to BR-37)
+### ART extension and later requirements, traceability (BR-23 to BR-38)
Status as assessed on 2026-10-26 at `main` 032b522. None of these is "Verified" until a test run proves it (D5).
@@ -156,6 +157,7 @@ Status as assessed on 2026-10-26 at `main` 032b522. None of these is "Verified"
| BR-35 | ⚠️ Partial | Export formula injection neutralised (M1: #86, `export.test.ts`); audit table still plain, no actor, no filters | DB negative tests + unit | M1, M3, M7 |
| BR-36 | ⚠️ Partial | Done in M2:
• local accounts with lockout (#98, #103)
• OIDC (#105)
• per-tenant schemas, T&E tables included (#100, #104)
• role matrix in `docs/ROLES.md` (#101)
Tests: `tests/test_accounts.py`, `test_tenant_isolation.py`, `test_roles.py`, `test_oidc.py`, `test_password_reset.py`. Each failed with its control removed.
• frontend sign-in; the browser no longer holds the shared key (#115)
• password change, admin reset and break-glass reset (#117; `tests/test_password_reset.py`)
Open: the shared key still grants non-tenant access to scripts and services; security review (#112); real-IdP OIDC check (#113) | Cross-tenant negative tests; role matrix tests | M2 |
| BR-37 | ⚠️ Partial | No external calls found; no automated check; no offline doc (#60) | Egress-blocked run + offline dry run | M7 |
+| BR-38 | ❌ Not started | No container bundle for the application yet (`infra/Dockerfile` is the schema and evals runner only) | Offline smoke test 7/7 on Windows, macOS and Linux | #128 |
---
@@ -178,9 +180,11 @@ Status as assessed on 2026-10-26 at `main` 032b522. None of these is "Verified"
|--------|-------|-------------|
| ✅ Verified | 19 | BR-01, BR-03, BR-04, BR-05, BR-06, BR-07, BR-08, BR-09, BR-10, BR-11, BR-12, BR-13, BR-14, BR-15, BR-16, BR-17, BR-18, BR-19, BR-20 |
| ⚠️ Partial | 11 | BR-23, BR-25, BR-28, BR-29, BR-30, BR-31, BR-33, BR-34, BR-35, BR-36, BR-37 (ART, added 2026-10-26) |
-| ❌ Not started | 4 | BR-24, BR-26, BR-27, BR-32 (ART, added 2026-10-26) |
+| ❌ Not started | 5 | BR-24, BR-26, BR-27, BR-32 (ART, added 2026-10-26); BR-38 (added 2026-10-27) |
| ⏸ Deferred by decision | 3 | BR-02, BR-21, BR-22 |
+**Headline (2026-10-27):** with BR-38 added (cross-platform offline install, #128), **19 of 38 (50 %)** are verified, 3 are deferred by decision, and the other 16 are partial or not started.
+
**Headline (2026-10-26):** with the 15 ART requirements added, **19 of 37 (51 %)** are verified, 3 are deferred by decision, and the other 15 are partial or not started.
**Headline before ART:** **19 of 22 (86 %)** business requirements are fully verified by at least one automated test condition, up from 17 of 22 (77 %).
diff --git a/docs/offline-install.md b/docs/offline-install.md
index 7eec83b..c08db5a 100644
--- a/docs/offline-install.md
+++ b/docs/offline-install.md
@@ -118,7 +118,7 @@ Once that evidence is on #60, the README can move to the "fully offline" wording
sudo bash -c 'set -a; . /opt/te-migration/env; set +a; runuser -u te-app -- /opt/te-migration/venv/bin/python scripts/reset_password.py --username admin'
```
- **The API address is fixed at install.** It's written into the frontend files. To change it, re-run the install.
-- **Ubuntu 24.04 x86_64 only.** Other operating systems need different packages and wheels.
+- **Ubuntu 24.04 x86_64 only.** Other operating systems need different packages and wheels. An offline container bundle for Windows, macOS and Linux is tracked as #128 (BR-38).
## How it was rehearsed