Skip to content

Thread: iOS I3b-3a — Coordination write contract (confirm + concern)

Not IA 3-5. Not Meridian. Sub-slice 3a of I3b-3 (native coordination write path).

Decisions (Ryan, Sep 14 2026)

Decision Choice
Slice order 3a-first (confirm/concern). 3b (submit/upload) waits for device gate on 3a.
Device cohort MOCK Pipeline e5c80469-5db2-4fcc-a9b0-dae21f07efab, Last1 ID 2a805b21-5352-4316-bb4b-a5d4f02a8173 (continuity with I3b-2 Build 70).
Deploy target R940 only (VM 104 last1.app + VM 90 last.vet-api). Not AWS/ECS.

Problem

Veteran Ω writes exist only on last1.app member routes (POST /api/member/program-coordination/outputs/:eventId/...) with Supabase session auth. LastVet had read-only BFF (I3b-2). I3b-3a adds the first write path without duplicating the engine.

Architecture

LastVet iOS (Build 71)
  → POST api.last.vet/veteran/me/coordination/outputs/:eventId/{confirm|concern}
    → last.vet-api BFF (veteran JWT → last1_identity_id)
      → POST last1.app/api/internal/coordination/outputs/:eventId/{confirm|concern}/by-last1id/:identityId
        → recordMemberConfirmOutput / recordMemberConcernViaCutover (same as web)
        → refresh getVeteranProgramCoordinationByLast1IdentityId

Drift prevention: Same engine functions as web. Golden JSON per action. BFF route tests. Side-by-side parity with last1.app/member/progress?programId=.

UI rule (Build 71)

Show controls only when server says so:

verification.yourTurn == true
&& verification.nextActor == "veteran"
&& verification.veteranTurnAction == "confirm"

Then show Confirm + I have a concern (matching web). No client-side transition logic. No optimistic ladder advances. After success, replace UI from refreshed program + turnCard in write response.

Internal routes (last1.app)

Auth: Authorization: Bearer $LAST1_APP_SECRET (same as I3b-2 reads). Requires live Last1 ID consent link.

POST confirm

POST /api/internal/coordination/outputs/:eventId/confirm/by-last1id/:identityId
Body: {} (optional)

POST concern

POST /api/internal/coordination/outputs/:eventId/concern/by-last1id/:identityId
Body: { "message": "string (required, trimmed non-empty)" }

Success response (both)

{
  "ok": true,
  "message": "Output confirmed." | "Your concern was recorded.",
  "program": { "...VeteranProgramProgressDetail..." },
  "loop": { "...VeteranLoopCardModel | null..." },
  "turnCard": { "...VeteranProgramTurnCard | null..." }
}

Cache-Control: no-store, private

Errors

Same shape as member routes where applicable:

{ "message": "...", "code": "VETERAN_VERIFICATION_REQUIRED" | "OUTPUT_STATE_INVALID" | ... }

403 consent: { "error": "consent_required", "message": "..." }

BFF routes (last.vet-api)

Veteran JWT required. Resolves last1_identity_id from LastVet veteran row.

POST /api/veteran/me/coordination/outputs/:eventId/confirm
POST /api/veteran/me/coordination/outputs/:eventId/concern
Body (concern only): { "message": "..." }

Response: verbatim internal write JSON.

Golden fixtures

Repo Path
last1.app shared/programCoordination/fixtures/coordinationWriteConfirm.golden.json
last.vet-api tests/fixtures/coordinationWriteConfirm.golden.json

Curl verify (prod, agent-run)

# Internal confirm (VM 104 or via last1.app)
curl -sS -X POST \
  -H "Authorization: Bearer $LAST1_APP_SECRET" \
  -H "Content-Type: application/json" \
  "https://last1.app/api/internal/coordination/outputs/$EVENT_ID/confirm/by-last1id/$LAST1_ID" \
  -d '{}' | jq '{ok,message,state:.program.phases[0].events[0].state,turn:.turnCard.headline}'

# BFF confirm (needs veteran JWT)
curl -sS -X POST \
  -H "Authorization: Bearer $VETERAN_JWT" \
  -H "Content-Type: application/json" \
  "https://api.last.vet/api/veteran/me/coordination/outputs/$EVENT_ID/confirm" \
  -d '{}'

Device test checklist (Build 71)

  1. Side-by-side: last1.app/member/progress?programId=e5c80469-... and LastVet program detail for MOCK Pipeline.
  2. When veteranTurnAction == confirm, LastVet shows Confirm + I have a concern (not grey capsule).
  3. Tap Confirm on LastVet → state matches web after refresh (output closed, turn card updates).
  4. Reset cohort if needed; tap I have a concern, enter text, Send concern → ladder pauses, matches web.
  5. Home Your Turn card updates after returning from detail (notification refresh).

Next slices (gated)

Slice Build Actions
3b 72 submit + document upload
3c 73 respond (dialogue)
3d 74 resubmit
3e 75 loop attest (+ BSL if needed)