Skip to content

IMM-04 · Tier-4 submission and acknowledgement

SOP: SOP_Immigration_Applications.md §6 / §8 Step 6Actors: IMM Operator — admin@spade.local (PLATFORM_ADMIN) / IMM_OPERATOR. Pre-state: Run is AWAITING_REVIEW with a tier-4 IMM.SUBMIT_APPLICATION review task (see IMM-03). Post-state: Operator has filed in EP Online / WPOL and approved the gate. A FilingTransaction(MOM, PASS_APPLICATION, ACKNOWLEDGED) + Document(IMM_APPLICATION) + StatutoryDeadline(PASS_RENEWAL) are written; run CLOSED.

0. Prerequisites

  • The application detail (/dashboard/imm/applications/<runId>) shows review.awaitingDecision = true.
  • The operator has the real MOM acknowledgement number obtained by filing manually in the authority portal (the platform never auto-files — FR-IMM-007).

1. Steps

1.1 File with MOM (manual, off-platform)

Using the assembled pack (pack.mappedFields + artifact from the detail response, or the presigned download), the operator keys the application into EP Online / WPOL and obtains the acknowledgement number.

1.2 Approve the gate

The IMM gate reuses the shared review inbox approve endpoint:

http
POST /ops/review-inbox/:reviewTaskId/approve
Content-Type: application/json

{
  "filing": {
    "acknowledgementNumber": "MOM-EP-2026-998877",
    "filedAt": "2026-06-10T09:30:00.000Z",   // optional; defaults to now
    "reference": "internal-ref-001"            // optional
  }
}

The review-inbox handler forwards applyInput.filing (only on approve, only for tier-4 filing actions) to the module apply executor and moves the run AWAITING_REVIEW → APPLYING.

1.3 What the apply executor writes (imm-apply.ts)

In one tenant-scoped transaction (the only writer for this workflow):

  1. Idempotency guard — if a FilingTransaction already exists for the run, returns the existing acknowledgement as a no-op (no double-submit on retry).
  2. FilingTransactionregistry = MOM, transactionType = PASS_APPLICATION, status = ACKNOWLEDGED, the operator's acknowledgementNumber, filedById, filedAt. (Falls back to MOM-ACK-<applicationRef> if no operator filing supplied.)
  3. Persists the W3 pack: a File (real objectKey imm/<runId>/<fileName>, content metadata, sha-256) — bytes PUT to S3 when a storage writer is wired — and a Document(IMM_APPLICATION) pointing at it (status = SENT, filingId, source_run_id).
  4. StatutoryDeadline(PASS_RENEWAL) via the shared upsertStatutoryDeadline — due filedAt + 24 months, or the operator-supplied renewalDueDate.
  5. Emits FILING_OUTCOME (+ DEADLINE_STATE via the deadline upsert).

The run then closes APPLYING → CLOSED.

2. Verification

Database

sql
SELECT registry, transaction_type, status, acknowledgement_number, filed_at
  FROM filing_transactions WHERE run_id = '<runId>';
-- expect MOM / PASS_APPLICATION / ACKNOWLEDGED / <ack number>

SELECT doc_type, status, file_id FROM documents
  WHERE source_run_id = '<runId>' AND doc_type = 'IMM_APPLICATION';
-- expect status = 'SENT', a file_id

SELECT deadline_type, status, due_date FROM statutory_deadlines
  WHERE entity_id = '<entityId>' AND deadline_type = 'PASS_RENEWAL';
-- expect one row, due ≈ filedAt + 24 months (or operator-supplied)

SELECT status, closed_at FROM agent_runs WHERE id = '<runId>';
-- expect 'CLOSED'

S3 / MinIO

  • When a storage writer is wired, the pack bytes land at imm/<runId>/<fileName>. The detail/pack endpoint presigns this for download.

API

  • GET /ops/imm/applications/:runIdfiling and renewal tabs now populated; pack.storedDownloadUrl non-null.
  • GET /ops/imm/applications/:runId/pack200 { downloadUrl, fileName, expiresAt } (presigned, 10-min TTL).

Events

sql
SELECT event_class, outcome FROM events
  WHERE run_id = '<runId>' AND event_class = 'FILING_OUTCOME';
-- outcome = 'ACKNOWLEDGED'

3. Negative & edge cases

  • No acknowledgement in payload → apply falls back to a synthesised MOM-ACK-<applicationRef> (dev/adapter path).
  • Retry after a mid-apply crash → idempotent: returns the existing filing, no second FilingTransaction.
  • Reject / request changes → the run returns to RUNNING (or stays at review) and no filing is written.

Next

Proceed to IMM-05 · Renewal tracking.

Internal use only — BreezyCorp