Session state — 2026-07-16¶
Purpose: Committed handoff so work can resume cold (Monday, new agent, or Ryan with no chat memory).
Scope: What changed on 2026-07-15/16, current environment truth, gates, parallel tracks, planned work, open items, accepted limitations.
Do not infer from this doc: Start RLS batch 2 implementation, reopen Gate 0.5 A1, or rewrite closed gate docs (D11, D12).
1. What changed today (by repo and commit)¶
last.vet-api (main)¶
| Commit | What it actually did |
|---|---|
5b1eaaf |
Inbox OTP harness: Fixed Gmail IMAP parsing (untagged SEARCH/FETCH + literals); pre-open UID baseline to ignore stale OTPs; default E2E recipient e2e-harness@last1.enterprises. |
005bc4e |
OTP logging teardown: Removed SECURE_LINK_E2E_LOG_OTP from Terraform, SM lastvet-prod/app, API code, and CloudWatch harness fallback. Parallel-track E2E run log. Prod task def :7. |
da11726 |
Migration pre-flight: migrate.js --list-pending, --expect; prod run-ecs-db-setup.sh lists pending then requires explicit expect set. Security posture doc committed. |
1b046a8 |
Prod boot DDL gate: ensureCoreSchema skipped when APP_ENV=production. RLS batch 2 plan doc (RLS_BATCH2_PLAN.md). |
Earlier context (same sprint, pre–Jul-16 session tail):
| Commit | What it actually did |
|---|---|
790e188 |
P0.7 Phase B API: fhir_sync_manifest migration 050, sync gate, provider manifest alerts backend. |
228ddef |
VA production cutover runbook; Railway prod teardown recorded. |
0960c65 / dd69928 |
Gate 0 A1 re-earned on AWS prod (scripted + human TestFlight). |
last.vet-provider (main)¶
| Commit | What it actually did |
|---|---|
b6ebe1b |
Phase B: FHIR sync manifest warning UI on provider Record view. |
last.vet-ios (local — not shipped)¶
Hardened client code exists locally (P0.1–7, Phase B: FHIRSyncPlanner, sync gate, ROI informed consent). Not on TestFlight as of this doc. Parallel-track human leg blocked on Ryan shipping a build.
2. Current environment truth¶
| Fact | State |
|---|---|
| Production API | AWS ECS lastvet-prod-cluster / lastvet-prod-api, RDS lastvet-prod-postgres, api.last.vet |
| Staging API | AWS ECS lastvet-staging-*, api-staging.last.vet |
| Railway prod | Gone (2026-07-15). pg_dump: backups/railway-lastvet-prod-2026-07-15.dump (gitignored, local only). |
| Railway staging | May still exist as rollback net per DEV_STAGING.md — clients must use api-staging.last.vet, not .railway.app. |
| Prod auto-migrate | No. aws-start.sh skips when APP_ENV=production. Migrations only via run-ecs-db-setup.sh prod 'file1,file2'. |
| Prod boot DDL | No. ensureCoreSchema skipped when APP_ENV=production (verified in CloudWatch: production_skipping_boot_schema, no schema_ready). |
| Prod OTP logging | No. Inbox-only harness (e2e-harness@last1.enterprises + Bitwarden E2E_OTP_IMAP_*). |
| Real veteran PHI | None in any environment. All data synthetic / VA sandbox. |
| VA production Lighthouse access | Not approved. Case #00015000 in review. |
3. Gate 0.5 and Gate 0¶
| Item | Status |
|---|---|
| Gate 0.5 engineering exit | ✅ Complete (A–C + B7). See docs/runbooks/gate-0.5/GATE_0.5_STATUS.md. |
| Gate 0 earned | On D11 + D12 alone (Ryan-owned). D11 closed 2026-07-16; D12 filled 2026-07-16. |
| D11 | CLOSED — lastvet-gates/gates/GATE_1_TRACTION_THRESHOLD.md; pointer at docs/planning/GATE_1_THRESHOLD.md. |
| D12 | docs/compliance/VA_PRODUCTION_ACCESS_TRACKER.md — Ryan's. Do not edit. |
| A1 | Closed. E2E_RUN_LOG_2026-07-15.md. Parallel track does not reopen A1. |
4. VA production readiness — parallel track¶
Not Gate 0.5 exit criteria. Required before Gate 1 production pilot, not before Gate 0 declaration.
| Item | Status |
|---|---|
| P0.1–7 + Phase B API | ✅ Shipped prod (790e188 + prior P0 commits) |
| P0.1–7 + Phase B provider | ✅ Shipped (b6ebe1b) |
| P0.1–7 + Phase B iOS | ✅ TestFlight human E2E 2026-07-21 |
| Inbox OTP harness | ✅ Prod proven 2026-07-16 |
| OTP logging teardown | ✅ 2026-07-16 |
| Migration pre-flight | ✅ Built 2026-07-16 |
| Prod boot DDL gate | ✅ 2026-07-16 |
| Scripted E2E on hardened API | ✅ E2E_RUN_LOG_2026-07-16_VA_PARALLEL_TRACK.md |
| Human E2E on hardened iOS | ✅ E2E_RUN_LOG_2026-07-21_VA_PARALLEL_TRACK_HUMAN.md |
Exit criterion: Fresh scripted + human E2E on hardened code on AWS. Both legs complete (2026-07-21). Parallel track exited.
5. Planned — not built (decide before starting)¶
5.1 Staging should rehearse prod (schema path)¶
Problem: Prod no longer runs ensureCoreSchema or boot migrations. Staging still does both (APP_ENV=staging → boot DDL runs; RUN_MIGRATIONS_ON_BOOT=true → boot migrate without --expect). Staging schema_migrations can lie the same way prod's did until 2026-07-16. Batch 2's safety story is "staging proof before prod" — if staging gets schema differently, that claim is weaker.
Proposed end state:
| Environment | ensureCoreSchema |
Migrations |
|---|---|---|
| Local / dev | ✅ On boot (fast iteration, empty DB recovery) | Optional local migrate.js |
| Staging | ❌ Off (same gate as prod) | Same as prod: run-ecs-db-setup.sh staging lists pending; apply via explicit one-off; use --expect when rehearsing prod discipline |
| Production | ❌ Off (shipped) | run-ecs-db-setup.sh prod '049_….sql,050_….sql' only |
Implementation sketch (when approved):
- Change
src/index.tsgate: skipensureCoreSchemawhenAPP_ENVisproductionorstaging. - Remove or set
RUN_MIGRATIONS_ON_BOOT=falsein Secrets Managerlastvet-staging/app. - Update
docs/deployment/DEV_STAGING.md— staging deploy checklist becomes: push image → list pending → apply with expect (or staging-apply-all-pending if you deliberately relax expect on staging only). - One-time: reconcile staging
schema_migrationsvs actual schema (list pending; apply any gap).
What breaks if we gate staging:
| Dependency | Impact |
|---|---|
RUN_MIGRATIONS_ON_BOOT=true (documented in DEV_STAGING.md) |
Stops working. New migrations no longer apply on ECS rollout alone. Ops must run run-ecs-db-setup.sh staging after deploy when image contains new migration files. |
| Boot DDL healing ledger drift | Stops. If pending migration not applied, app may fail on missing column — same as prod now. That's the point: failures surface in staging first. |
| Deploy-only workflow (push image, force rollout, done) | Broken for schema changes. Becomes: push image → migrate one-off → rollout (mirror prod order). |
| Fresh empty staging RDS | Requires post-apply-db.sh staging + full migration chain; no boot self-heal. |
| Local dev | Unchanged if APP_ENV/NODE_ENV is development. |
What does NOT break:
| Item | Why |
|---|---|
| Runtime API on existing staging DB | Schema already present; gate only affects boot path for new/changed DDL. |
ConsentEngine.ensureMinimalSchema() |
Separate legacy path: runs on lastvet_app pool only after 42P01 (missing table). Not owner boot DDL. Rare on staging with populated DB; dev/test concern. |
RLS / lastvet_app |
Unaffected. |
Objection to keeping boot DDL on staging:
There is no rehearsal value — it masks the same ledger drift that burned us on prod (049 behind 050). Migrations are a verified superset at column/index level; pre-flight --list-pending exposes drift. Keeping boot DDL on staging optimizes convenience over fidelity.
Decision deadline: Before RLS batch 2 step 1b (consent RLS migration). Step 1a (context refactor) can proceed on staging as-is, but 1b staging proof is not credible until staging matches prod schema authority.
Status: ⏳ Plan only — not implemented.
5.2 RLS batch 2¶
Doc: docs/api/RLS_BATCH2_PLAN.md
Not Gate 0.5. Required before real veteran data, not before Gate 0.
| Phase | Scope |
|---|---|
| 1a — Refactor | Wire applyRequestDbContext through consent paths (consent/engine.ts + part2.ts, roi-sign.service.ts, provider routes, etc.). No RLS, no migration. Staging proof. |
| 1b — Migration | RLS + FORCE on part2_consents, consent_grants. Only after 1a + staging rehearsal decision. |
| 2 — Credentials/tokens | secure_access_*, oauth_* |
| 3 — Remaining data | consent_audit_log, connection_requests, preferences, etc. |
Staging proof requirements: Cross-veteran consent negative test; multi-veteran health-record bypass regression. See plan doc.
Unblocks: 1a → engineering; 1b → 1a proven + staging schema rehearsal aligned with prod.
5.3 Pentest retest¶
After RLS batch 2 on staging; before first real veteran on prod. Shannon + ~1 day eng for staging deploy/fixtures. Not scheduled.
6. Parked¶
| Item | Why |
|---|---|
| P0.7 Phase C | Point-in-time manifest on consent grants / secure-link sidecar. Hogan Lovells, not engineering. |
7. Open on Ryan¶
| Item | Notes |
|---|---|
| D11 | CLOSED (2026-07-16) — was Gate 1 threshold doc; canonical: lastvet-gates/gates/GATE_1_TRACTION_THRESHOLD.md. |
| D12 | CLOSED (2026-07-16) — docs/compliance/VA_PRODUCTION_ACCESS_TRACKER.md filled. |
| TestFlight / parallel human E2E | CLOSED 2026-07-21 — E2E_RUN_LOG_2026-07-21_VA_PARALLEL_TRACK_HUMAN.md. |
| Bitwarden | E2E_OTP_IMAP_* + Google app password for e2e-harness@last1.enterprises — done. |
8. Known limitations — accepted and tracked¶
| Limitation | Reasoning |
|---|---|
app.bypass_rls on health records |
Provider multi-veteran reads need one query across consented veterans. Policy bypass is deliberate, code-controlled, documented in SECURITY_POSTURE_DATABASE_ACCESS.md. Staging must prove it still works after batch 2. |
| Consent engine without request context | Not wired through applyRequestDbContext yet. App-layer SQL filters today; batch 2 step 1a fixes before RLS. Without 1a, RLS would fail closed and break consent flows. |
| Dual schema authority on staging (today) | Prod fixed (boot DDL off). Staging still runs boot DDL + boot migrate — weak rehearsal. Tracked in §5.1; decide before 1b. |
schema_migrations ledger can lag reality |
Was true when boot DDL created objects before migrate ran (049/privacy_notice_campaigns). Prod mitigated: boot DDL off + pre-flight. Staging mitigated when §5.1 ships. |
13 veteran_id tables without RLS |
Batch 2 scoped; consent + credentials first. Documented in security posture doc. |
ConsentEngine.ensureMinimalSchema |
Legacy dev recovery on app pool; not prod boot path. Separate from owner DDL issue. |
9. Key doc index¶
| Doc | Use |
|---|---|
docs/security/SECURITY_POSTURE_DATABASE_ACCESS.md |
RLS truth, Jul-12 sentence correction, shareable §8 |
docs/api/RLS_BATCH2_PLAN.md |
Batch 2 phases, 1a/1b split, staging proof |
docs/runbooks/VA_PRODUCTION_CUTOVER_RUNBOOK.md |
Cutover, migration pre-flight, Appendix B inbox OTP |
docs/runbooks/gate-0.5/GATE_0.5_STATUS.md |
Gate 0.5 checklist + parallel track |
docs/runbooks/gate-0.5/E2E_RUN_LOG_2026-07-16_VA_PARALLEL_TRACK.md |
Parallel scripted pass (not A1) |
docs/runbooks/gate-0.5/E2E_RUN_LOG_2026-07-21_VA_PARALLEL_TRACK_HUMAN.md |
Parallel human TestFlight pass; track exit |
docs/runbooks/gate-0.5/E2E_RUN_LOG_2026-07-15.md |
A1 closed |
docs/security/SECURITY_PENTEST_STATUS.md |
B7 note + posture link |
docs/deployment/DEV_STAGING.md |
Staging ops (will need update when §5.1 ships) |
10. Prod ops quick reference¶
# Deploy API (after code push)
./infra/scripts/deploy-api-image.sh prod
aws ecs update-service --cluster lastvet-prod-cluster --service lastvet-prod-api \
--task-definition lastvet-prod-api:N --force-new-deployment
# Migrate (prod — list only first via script, then expect set)
./infra/scripts/run-ecs-db-setup.sh prod '050_fhir_sync_manifest.sql'
# Scripted E2E (Bitwarden E2E_OTP_IMAP_* + VETERAN_SESSION_EXCHANGE_SECRET)
API_BASE=https://api.last.vet/api ./scripts/e2e-roi-gate0-full.sh
Last updated: 2026-07-16 end of session. Do not start RLS batch 2 from this doc without explicit approval.