Loop #1 Build Plan (v2 — reconciled, architecture re-anchored)¶
Status: L0 closed · L1-entry closed (2026-09-02) — coordination loop awaiting LOOP1_COORDINATION_LOOP_BUILD_PLAN.md approval
Date: 2026-09-02
Supersedes: v1 draft (pre-commit, 17 divergences); v2 pre-re-anchor (last.vet-api-owned VCA, last1.app-primary)
Authorizes: LOOP1_FIRST_BUILD_SPEC.md §8 (+ §3.1 governance rules)
Lens (not backlog): Bible v1.2 §10.4/§10.5, LOOP1_COORDINATION_ARCHITECTURE.md, docs/standards/NON_PRESCRIPTIVE_ACCOUNTABILITY_STANDARD_working_paper_v1.md
0. Plan shape: one sequenced plan, two gated sub-plans¶
Recommendation: one document, two sub-plans with a hard gate — not two independent plans.
| Sub-plan | Name | Repo(s) | Gate to next |
|---|---|---|---|
| L0 | Veteran verification (hub first brick) | last1.id (VCA capability), last.vet-ios + last.vet-api (LastVet primary surface), last1.app (reads gate) |
Veteran holds verification_status = confirmed on last1.id subject (VCA sandbox) |
| L1 | Coordination loop close (three-party placement) | last1.app (+ loop card in LastVet) |
One Λ_verified loop via Path A |
0.1 Architecture re-anchor (2026-09-02 — supersedes inline last.vet-api VCA and last1.app-primary entry)¶
LastVet is the surface area and coordination hub. Veterans entering via last1.app first was records-era drift; L0 changes that, not builds around it.
| Layer | Role in L0 |
|---|---|
| Verification capability | last1.id-owned (Option 2). Sovereign identity spine owns "confirmed Title 38 veteran" via VA Veteran Confirmation API. Reusable by any product. Not buried in last1.app or last.vet-api-only. |
| Primary surface | LastVet. Veteran verifies here first: last1.id login → VCA → confirmed. Hub's first brick, not the full dashboard. |
| last1.app | Consumes verification_status (L0→L1 gate). Owns engine + detailed management/history. May also surface attestation later; LastVet is primary for verification. |
| Loop card in LastVet | L1/post-L0 — not in L0. |
L0 builds: last1.id VCA endpoint + LastVet verification flow + last1.app reads status + graceful not-confirmed UX (DD-214 seam noted, not built).
L0 does not build: full LastVet coordination dashboard, all cards, loop card, records integration, DD-214 workflow.
L1 must not start until L0's minimum verification path works in staging. They share last1.id identity binding but are separable deliverables with separate DoDs — one sequenced critical path.
1. Keystone discipline (Bible v1.2 §10.4 / §10.5)¶
Keystone: ONE job_placement loop closed with three-party verification (WIN + veteran + hiring manager), hash-chained ledger, denominator tracked, placement on timeline.
| Work | Verdict |
|---|---|
| L0: last1.id + VA Veteran Confirmation API (sandbox) | In scope — prerequisite, buildable now |
| L1: Λ state machine + hash-chained ledger + Path A HM close | In scope — after L0 gate |
Extend /member/progress for placement read surface |
In scope — L1 UI |
| Path B (hiring-org session) | Deferred — fast-follow after first close |
| RecruitCRM, seven-stage UI, HM showcase SaaS, public anchor | Out of scope — named enrichment |
| DD-214 / MOS stage instrumentation | Deferred — seam noted, not built |
| Full VA health-records OAuth/PKCE | Gated — anticipation card only |
| Full LastVet onboarding dashboard | Drift — L0 is verification minimum only |
| Loop card in LastVet | L1 — not L0 |
| last1.app as primary verification entry | Superseded — LastVet primary; last1.app consumes gate |
2. Reconciliation log (v1 → v2)¶
| # | v1 divergence | v2 fix |
|---|---|---|
| 1–4 | Invented Λ states (Λ_pending_*, Λ_draft, etc.) |
Committed vocabulary: Λ_open | Λ_partial | Λ_verified | Λ_contradicted | Λ_lapsed |
| 5 | Path B in Loop #1 DoD | Path A only for keystone close |
| 6 | HM onboarding required | Deferred — magic link closes without account |
| 7 | Synthetic ED / LOOP1_ED_TEST_MODE |
Real last1.id — ED creates own account; real session paths |
| 8–9 | Member portal only; ignored architecture read surfaces | L1: extend /member/progress; WIN ops + HM views deferred post-close |
| 10 | Numbered flow treated as order prescription | Order-independent attestations; veteran-first via token rule (spec §3.1) |
| 11–12 | Wrong attestation_token / ledger_event schema |
Match build spec §3 / §5 exactly |
| 13 | Unclear boundary vs milestoneAttestationService |
coordination_* is system of record; milestone service unchanged for legacy WIN mock |
| 14–17 | Stale metadata, pending-commit refs | Updated; cites commits 1f7769a, 4e907ac |
3. Sub-plan L0 — Veteran verification (LastVet hub first brick)¶
3.1 Purpose¶
WIN pipeline entry requires veteran verification before placement coordination. Attestation presupposes a verified veteran identity. Minimum for Loop #1:
last1.id login + VA Veteran Confirmation API returning confirmed = verified for pipeline entry and attestation eligibility.
Reference: VA Veteran Confirmation API — sandbox available now; separate from gated Patient Health FHIR API.
3.2 Scope lock (§10.5)¶
| In L0 | Out of L0 |
|---|---|
| last1.id-owned VCA endpoint (identity-layer capability) | Full LastVet coordination dashboard / all cards |
| LastVet verification flow post-last1.id login (primary surface) | Loop card in LastVet (L1+) |
last1.app reads verification_status (L0→L1 gate) |
DD-214 upload + MOS validation workflow |
| VCA sandbox: name + DOB + zip → confirmed / not confirmed | Health-records OAuth/PKCE integration |
| Graceful "not confirmed" UX + DD-214 seam noted-not-built | Seven-stage WIN pipeline UI |
| Persist outcome on last1.id subject (no PHI in logs) | Records integration |
Existing hooks: last1.id already exposes /api/internal/last1/identity-verifications and veteran_verified credentials; last1.app already consumes via last1VerificationService.ts. L0 wires VCA as the source of truth (replacing LastVet-link-only proxy). last.vet-ios VCA scaffold in VAAuthConfig.swift is separate from this L0 path.
3.3 VCA integration shape (last1.id-owned)¶
| Layer | Responsibility |
|---|---|
| Verification capability | last1.id — holds VA API key; exposes confirm + status APIs to products; persists on identity subject |
| Primary surface | last.vet-ios (+ last.vet-api thin proxy for authenticated veteran session) — minimal verification screen, hub first brick |
| Gate consumer | last1.app — existing fetchIdentityVerifications() / member surfaces; graceful not-confirmed copy |
| Request | Identifiable info: first name, last name, birth date, ZIP (sandbox test users documented by VA). Not stored after VCA call. |
| Response | confirmed | not_confirmed + reason codes (PERSON_NOT_FOUND, MORE_RESEARCH_REQUIRED, NOT_TITLE_38, ERROR) |
| Storage | identity_veteran_confirmations on last1.id + veteran_verified credential when confirmed |
3.4 "Not confirmed" handling (required, graceful)¶
not confirmed ≠ "not a veteran." API returns reasons including:
PERSON_NOT_FOUNDMORE_RESEARCH_REQUIREDNOT_TITLE_38ERROR
UX (Loop #1 minimum):
- Show plain-language outcome: "We couldn't automatically confirm your veteran status."
- Show reason-appropriate next step (e.g. check info, try again, contact WIN).
- Document seam for DD-214 manual fallback (deferred build) — do not dead-end the veteran.
- Do not allow coordination-loop attestation until
confirmed(or future manual override path — out of Loop #1 scope).
3.5 L0 phases¶
| Phase | Deliverable | Repo |
|---|---|---|
| L0-1 | VCA client + confirm/status routes + migration + credential sync | last1.id |
| L0-2 | LastVet verification UI (hub card + confirm screen) post-last1.id link | last.vet-ios |
| L0-3 | Veteran-session proxy routes to last1.id (no VA key in LastVet API) | last.vet-api |
| L0-4 | last1.app consumes updated status; graceful not-confirmed copy | last1.app |
| L0-5 | Staging E2E: sandbox test user → confirmed; negative case → graceful UX |
human sign-off |
L0 Definition of Done: ED (or staging veteran) completes last1.id signup in LastVet + VCA sandbox verification → verification_status = confirmed on last1.id subject, visible to last1.app gate. One negative-path walkthrough documented. STOP — no L1 migrations.
Estimated effort: 3–5 dev days.
4. Sub-plan L1 — Coordination loop (last1.app)¶
4.1 Prerequisite gate¶
L1 starts only when L0 DoD passes. last1.app coordination endpoints reject veteran attestation unless beneficiary is linked to a last1.id subject with verification_status = confirmed (read from last1.id via existing last1VerificationService — no LastVet API dependency).
4.2 Where the ledger lives¶
New coordination_* module in last1.app — system of record for Loop #1. Do not overload milestone_attestation_events for the three-party Λ loop (legacy two-party WIN mock stays separate).
| Component | Location |
|---|---|
| Loop + Λ state | server/services/coordinationLoopService.ts |
| Hash-chained ledger | coordination_ledger_events table |
| Attestation tokens | server/services/attestationTokenService.ts |
| Denominator | coordination_loops.lambda_state + ledger audit |
| Read surface | Extend client/src/pages/member/progress.tsx + /api/member/coordination-loop (new) |
4.3 Data model (coordination_* tables)¶
coordination_loops¶
| Column | Notes |
|---|---|
id |
uuid PK |
organization_id |
WIN |
program_id |
WIN program |
beneficiary_id |
Veteran (must pass L0 verification gate) |
outcome_class |
job_placement |
lambda_state |
open | partial | verified | contradicted | lapsed (maps to Λ_*) |
hiring_manager_email |
Domain-bound; block public mail domains |
hiring_manager_domain |
WIN-vouched employer domain |
last1id_subject |
Veteran identity binding |
opened_at, verified_at, terminal_at |
Timestamps |
attestation_counts |
Optional cache: which of {win, veteran, hm} satisfied |
coordination_ledger_events (build spec §5)¶
| Column | Notes |
|---|---|
event_id |
uuid + monotonic seq per loop |
loop_id |
FK |
event_type |
loop_created | stage_signal | attestation | state_transition |
payload |
PHI-free; zod allowlist |
resulting_lambda |
Λ state after event |
prev_event_hash, event_hash |
SHA-256 chain |
attestation_tokens (build spec §3)¶
| Column | Notes |
|---|---|
token_id |
uuid; store token_hash only |
loop_id |
FK |
verifier_role |
deliverer | recipient | independent |
verifier_binding |
win_session | last1id_subject | hiring_manager_domain_email (Path A Loop #1) |
gate |
session | domain_verified_magic_link |
expected_attestation |
placement_delivered | placement_confirmed | hire_confirmed |
issued_at, expires_at, status, single_use |
Per spec |
coordination_stage_signals (minimal — placement only)¶
| Column | Notes |
|---|---|
loop_id, stage |
placement only in Loop #1 |
signal, attested_by, occurred_at |
PHI-free stage fact |
4.4 Λ state machine (committed vocabulary)¶
States (build spec §2):
| State | Entered when |
|---|---|
Λ_open |
Loop created (WIN identifies veteran + employer) |
Λ_partial |
1–2 of {WIN, veteran, HM} attestations recorded, no contradiction |
Λ_verified |
All three present, no contradiction |
Λ_contradicted |
Required verifiers disagree → human review |
Λ_lapsed |
Attestation window expires before all three |
Transition function: applyTransition(loop, event) — pure, unit-tested. Recompute Λ_partial vs Λ_verified from attestation set, not from attestation order.
Recorded attestations (expected_attestation):
| Verifier | Event | Gate |
|---|---|---|
| WIN (deliverer) | placement_delivered |
WIN org session |
| Veteran (recipient) | placement_confirmed |
last1.id session + L0 verified |
| HM (independent) | hire_confirmed |
Path A: domain magic link (Loop #1) |
4.5 Token-issuance governance (Option B — spec §3.1)¶
Attestation order: not fixed (WIN may attest before or after veteran).
Token issuance policy:
Hiring-manager token MUST NOT be issued until
placement_confirmedis recorded on the ledger.
Implementation:
POST .../issue-hm-tokenreturns 403 until veteran attestation exists.- WIN may request HM token only after veteran confirms (UI enforces; server enforces).
- Does not block HM from attesting if Path B session existed (Path B deferred anyway).
4.6 Attestation flows (endpoints)¶
WIN session (last1.app org auth)¶
| Method | Path | Action |
|---|---|---|
POST |
/api/coordination-loops |
Create loop → Λ_open + loop_created event |
POST |
/api/coordination-loops/:id/attest/deliverer |
WIN → placement_delivered |
POST |
/api/coordination-loops/:id/issue-hm-token |
Mint Path A token (gated by §4.5) |
POST |
/api/coordination-loops/:id/revoke |
WIN revoke → append-only correction event |
Veteran (last1.id session — real accounts only)¶
| Method | Path | Action |
|---|---|---|
POST |
/api/coordination-loops/:id/attest/recipient |
Veteran → placement_confirmed |
GET |
/api/member/coordination-loop |
Read loop state for /member/progress |
Gates: last1.id subject matches loop binding; L0 verification_status = confirmed.
Hiring manager — Path A only (Loop #1)¶
| Method | Path | Action |
|---|---|---|
GET |
/public/hm-attest/:token |
Validate token (single-use, unexpired, domain-bound) |
POST |
/public/hm-attest/:token |
HM → hire_confirmed; consume token |
Path B (POST .../attest/independent via hiring-org session): not built in Loop #1. Fast-follow milestone after first Λ_verified.
4.7 Member portal — extend, don't fork¶
Existing build (last1.app):
- Routes:
/member,/member/progress,/member/timeline,/member/accept-invite/:token - Auth: Supabase + Last1 ID OAuth; invite → beneficiary link
- Attestation:
/api/member/milestones/:id/confirm(legacy two-party loop)
L1 UI approach:
- Add
/api/member/coordination-loopreturning loop Λ state + three-party attestation status + placement stage signal. - Extend
/member/progresswith a Placement close panel (terminal node,Λ_verifiedbadge) — not a new portal. - Add "Progress" to sidebar (
app-sidebar.tsx). - Do not merge legacy
outcome_eventstimeline in Loop #1; optional later.
Architecture note: Long-term beneficiary surface is LastVet (architecture §1). Loop #1 pragmatically uses last1.app member portal because WIN operates here today; LastVet composes the same read API later.
4.8 ED staging walkthrough (real paths)¶
| Step | Actor | Action | Expected Λ |
|---|---|---|---|
| 0 | ED / veteran | last1.id signup + VCA sandbox → confirmed |
(L0 gate) |
| 1 | ED (WIN) | Create loop for enrolled beneficiary | Λ_open |
| 2 | ED (WIN) | placement_delivered attestation |
Λ_partial |
| 3 | Veteran (real last1.id) | placement_confirmed attestation |
Λ_partial |
| 4 | ED (WIN) | Issue HM token (now allowed per §4.5) | — |
| 5 | HM (Path A) | Magic link on verified employer domain | Λ_verified |
| 6 | Any | /member/progress shows closed placement |
read surface |
| 7 | Ops | Denominator: 1 open, 1 verified | audit |
No LOOP1_ED_TEST_MODE. No synthetic identity bypass. ED may use own last1.id for veteran step only in a second real account if playing both roles in staging.
4.9 L1 phases¶
| Phase | Deliverable |
|---|---|
| L1-1 | Migrations: coordination_* tables |
| L1-2 | coordinationLoopService + Λ transition tests + hash-chain verifier script |
| L1-3 | WIN + veteran attestation routes + L0 verification gate |
| L1-4 | Path A HM token + public attest routes + §4.5 enforcement |
| L1-5 | Denominator queries + WIN admin read (minimal) |
| L1-6 | Extend /member/progress coordination panel |
| L1-7 | Staging E2E script + ED sign-off |
L1 Definition of Done: build spec §8 — one placement closed three-party verified, hash chain valid, denominator correct, Path A only.
Estimated effort: 5–7 dev days (after L0).
5. Combined staging E2E checklist¶
L0 gate¶
- [ ] Sandbox test user → VCA
confirmedvia last1.id flow - [ ]
not confirmedpaths show graceful UX (each reason code smoke-tested) - [ ] DD-214 fallback seam documented in copy (not built)
- [ ] Verification status readable by last1.app eligibility check
L1 gate (build spec §8)¶
- [ ] One loop →
Λ_verifiedwith WIN + veteran + HM (Path A) on ledger - [ ] Hash chain validates end-to-end
- [ ] HM token blocked until veteran attestation recorded
- [ ] HM token rejects gmail/public domains
- [ ] Path B routes not present in Loop #1 build
- [ ] Real last1.id sessions only (no ED_TEST_MODE)
- [ ] Denominator: every
Λ_open+ terminal state counted - [ ]
/member/progressshows placement close only (no seven-stage nav) - [ ] No RecruitCRM in code paths
6. Decisions locked (Ryan, 2026-09-02)¶
| Decision | Resolution |
|---|---|
| Attestation ordering | Option B via token rule — spec §3.1 updated; Λ vocabulary unchanged |
| Veteran staging auth | Real last1.id — ED creates own account |
| HM path | Path A first — Path B fast-follow |
| Table naming | coordination_* |
| Timeline host | Extend /member/progress |
| Build sequence | L0 verification → L1 loop |
| VCA | Sandbox now — not blocked on health-records production access |
| DD-214 / MOS | Deferred — seam noted |
7. Citation chain¶
| Doc | Role | Commit / path |
|---|---|---|
| Bible v1.2 | Why coordination is keystone | d793a34 · docs/lastvet/LastVet_Bible_v1_2_AMENDMENT.md |
| SSRN standard | Formal accountability framework | 4e907ac · docs/standards/NON_PRESCRIPTIVE_ACCOUNTABILITY_STANDARD_working_paper_v1.md |
| Loop architecture | How the loop proves itself | 1f7769a · docs/architecture/LOOP1_COORDINATION_ARCHITECTURE.md |
| Loop build spec | Authorized increment (+ §3.1) | 1f7769a · docs/architecture/LOOP1_FIRST_BUILD_SPEC.md (§3.1 amended) |
| This plan (v2) | Sequenced implementation map | docs/architecture/LOOP1_BUILD_PLAN.md |
8. Open items (unchanged / new)¶
- Which veteran is loop #1 in production? WIN identifies when ready (after L0+L1 proven in staging).
- WSGR — referral/placement vs payment structure (Ryan → counsel).
- VCA prod API key — sandbox for build; prod key when deploying real veterans.
- L0 ↔ L1 verification claim — exact mechanism (LastVet API endpoint vs JWT claim from last1.id) — resolve at L1-1 design review.
- Platform utility — consolidate VCA proxy at
verify.last1.enterprises(muster tracker) vs inline inlast.vet-apifor Loop #1 — smallest path wins unless Ryan prefers shared utility now.
L0 + L1-entry closed. Coordination loop: review LOOP1_COORDINATION_LOOP_BUILD_PLAN.md before L1-1.