---
title: "Interview Result Capture"
slug: interview-result-capture
section: Applicant Journey
status: stable
description: "How Globus tracks interviews as Work Types — non-status-changing operational activities — and captures their result at the applicant level."
last-updated: 2026-10-07
---

# Interview Result Capture

How Globus tracks interviews as Work Types — non-status-changing operational activities — and captures their result at the applicant level. Globus does not host or schedule the interview itself; it configures the activity per program, records the outcome with timestamp and interviewer, keeps a chronological history, and lets staff filter the applicant list by outcome. This page makes the documented Host Interview / Work Type model (Phase 3, P11.3) explicit and implementable.

## As-Built Implementation (2026-07-04)

> **The feature shipped — on the generic work_items model, not the tables specced below**
>
> Interview result capture is live in Globus, but the implementation is built on the generic work_items table rather than the dedicated InterviewOutcome / work_type_definitions tables in the original P11.3 contract below. Treat this section as ground truth and the remainder of the page as the historical design contract (its intent — outcome capture, history, status independence, readiness linkage — all shipped).

| Aspect | As built (BackOfficePrototype, verified 2026-07-04) |
| --- | --- |
| Storage | Rows on the generic work_items table keyed by work_type_key ('sponsor_interview' \| 'host_interview'). Columns: interview_type, scheduled_at, interviewer_id, status (pending \| in_progress \| completed), completed_at, outcome. No dedicated InterviewOutcome table; work types are seeded (server/seed/workTypes.ts config.outcomeOptions), not a per-program work_type_definitions table. |
| Write endpoint | One route for both surfaces: PATCH /api/work-items/:id (server/routes/workItems.ts), gated requirePermission('applications.manage'). There is no separate host endpoint. |
| Outcome vocabulary | Host: accepted \| rejected \| reschedule. Sponsor: passed \| failed \| reschedule. accepted/passed are one-click; the rest are confirm-gated. There is NO no_show outcome on the sponsor or host interview (the phone and in-person interview work types do allow no_show). |
| English proficiency | PATCH /api/work-items/:id also accepts englishProficiencyLevel (excellent \| very_good \| good \| fair \| fail; shared/workItemVocabulary.ts), valid ONLY on the sponsor interview (400 ENGLISH_RATING_SPONSOR_INTERVIEW_ONLY otherwise) and only alongside a passed outcome, either in the same request or as a late write once already passed (400 ENGLISH_RATING_REQUIRES_PASSED). When the program's sponsor interview has an interview sheet bound, the sheet is the sole writer and the manual rating is rejected with 409 ENGLISH_RATING_SHEET_IS_AUTHORITATIVE (server/services/workItems/englishProficiency.ts). The server stores it under the reserved metadata.englishProficiency key (client copies are stripped) and it resolves into the fact screening.sponsor_interview.english.overall_level when no sheet value exists; a late write audits as applicant.work_item.english_rating_recorded. The legacy POST /api/work-items/:id/complete route now returns 409 SCREENING_OUTCOME_USE_PATCH for screening work items (all screening outcomes go through PATCH). |
| Transitions | server/services/screening/outcomeEngine.ts — ONE generic, config-driven transition builder. Task #1626 Phase 2 replaced the per-type modules (hostInterviewTransition.ts / sponsorInterviewTransition.ts / modalityInterviewTransition.ts), which were deleted on 2026-07-13 (#1444) and no longer exist. Behaviour comes from a ScreeningTransitionConfig resolved by server/services/screening/configResolver.ts (pinned blueprint version → published blueprint → shared v1 defaults), so custom activity types need zero engine changes. The work-type key constants moved to shared/workItemVocabulary.ts (SPONSOR_INTERVIEW_WORK_TYPE, HOST_INTERVIEW_WORK_TYPE, PHONE_INTERVIEW_WORK_TYPE, IN_PERSON_INTERVIEW_WORK_TYPE). Scheduling sets status to in_progress; a terminal outcome sets completed + completed_at; reschedule returns to pending and clears timestamps. The engine returns a partial work_items column map only — it never writes applicant lifecycle status, and scripts/checkers/stage-write-guard.cjs enforces that at build time. |
| Auto-generation | server/services/sponsorInterviewAutoGenerate.ts (ensureSponsorInterviewWorkItem), idempotent via partial unique index idx_work_items_sponsor_interview_unique ON work_items(application_id) WHERE work_type_key='sponsor_interview'; wired into lifecycleReconciliation.ts. |
| Rule gating | interview_requirement rule type with interviewer param (host \| sponsor, default host) — shared/ruleParameterSchemas.ts + ruleTemplates.ts. Facts: hostInterviewOutcome, sponsorInterviewOutcome, interviewCompleted. |
| Readiness | journeyPositionResolver.ts WorkItemSignals (hostInterviewCompleted/Passed, sponsorInterviewCompleted/Passed) + lifecycleReconciliation.ts fetchWorkItemSignals. |
| Queue linkage | Queue next-action record_interview_outcome (shared/queueReason.ts). |
| Staff UI | screening-section.tsx (ScreeningSection, using useInterviewOutcomeMutation from use-interview-outcome.ts), rendered from applicant-profile.tsx. |
| Audit | applicant.work_item.created and applicant.next_action.invoked (plus route-level outcome audit). The applicant.interview_outcome.* / program.work_type.* names below were never implemented. |
| Host Portal capture | NOT built. host_user roles carry zero permissions in server/seed/rbac.ts, so PATCH /api/work-items/:id returns 403 for hosts — the 'two entry points, one record' model remains aspirational; today all outcomes are entered by sponsor staff. |

> **Scope — operational tracking & result capture, not hosting**
>
> Globus configures the interview Work Type, captures its outcome, and tracks it for completeness and accountability. It does not host video calls, send calendar invites, or schedule the meeting itself. The record is the structured artifact left behind around an interview, wherever the conversation actually takes place.

## Purpose & Scope

Interviews (Sponsor Interview, Host Interview, and any program-defined variant such as Phone Interview or In-Person Interview) are tracked as Work Types — operational activities layered beneath the applicant's pipeline status, not status changes themselves. The lifecycle docs describe this model; this page defines it end to end so it is implementable: program-level configuration, the outcome record shape, lifecycle states and outcomes, SLA tracking, the two capture surfaces, status independence, the applicant-profile history view, applicant-list filtering, readiness/placement linkage, and audit.

In scope: the spec for all of the above. Out of scope: hosting/scheduling interviews inside Globus, and the runtime/backend implementation itself — the live applicant list, program-configuration UI, and outcome storage are owned by Globus-core under P11.3 (see Ownership & Routing). This docs page is the build contract that work is filed against.

## Work Type Model — Operational Activity Tracking

A Work Type is a per-applicant operational activity tracked for completeness and accountability. It is not an applicant status, and recording one never mutates the pipeline status (see Status Independence). An applicant can hold several activity records at once — e.g. one interview per host / job order, plus a sponsor interview.

> **The interview is a behind-the-scenes Workflow Studio step node**
>
> Every interview tracked here corresponds to a behind-the-scenes step node in the program’s step tree — authored and visible to admins in the builder, flagged staff-only (sponsor) or host-only (host) by role assignment, and never rendered on the applicant stepper. Recording the outcome on this surface is what completes that step node. Through the Step &rarr; Fact Contract the node emits an outcome fact (sponsorInterviewOutcome / hostInterviewOutcome) that gates the phase, and a host interview’s outcome keeps its job_order_id so the passed result still feeds placement. See P11.3 Work Type for the lifecycle framing.

Is

- A per-applicant operational activity
- Configured per program
- SLA-tracked for accountability
- Many-per-applicant
Is Not

- An applicant-level status field
- A status change when recorded
- A hosted/scheduled meeting
- One-per-applicant
Surfaces In

- Sponsor Host Interviews queue + SLA timers
- Applicant profile history (chronological)
- Applicant-list filters (by outcome)
## Program-Level Configuration

A program_manager configures which Work Types exist for a program. Adding a Work Type (e.g. Phone Interview, In-Person Interview) makes it available for tracking on applicants in that program. Each configured Work Type is a WorkTypeDefinition.

| Field | Type | Notes |
| --- | --- | --- |
| field | type | notes |

_(row above is a template, repeated for each data row)_

> **Program-scoped, deactivate over delete**
>
> Work Types are configured per program, so program A can offer a Phone Interview while program B does not. Deactivating (active = false) removes a Work Type from new activities while preserving every historical record that referenced it — history is never orphaned.

## Data Model — InterviewOutcome

One row per interview activity on an applicant. Every field is required unless its type admits null.

| Field | Type | Notes |
| --- | --- | --- |
| field | type | notes |

_(row above is a template, repeated for each data row)_

> **reason_code comes from the catalog**
>
> The reason_code value is bound to the structured Reason Code Catalog — never an ad-hoc string. A failed outcome requires a code; a passed outcome may carry one but does not require it. Free-text colour belongs in notes.

## Lifecycle States & Outcomes

The activity moves through states derived from the data (presence of scheduled_at / conducted_at and the value of outcome), not stored as a separate enum.

The recorded outcome is one of:

> **Failed is terminal for this attempt, not the applicant**
>
> A failed or no_show outcome closes this interview attempt. The applicant remains eligible to interview with other hosts or in a follow-up activity — each interview carries its own record.

## SLA Tracking

When a Work Type defines sla_hours, opening the activity starts an SLA timer. The timer is for accountability and never changes pipeline status — a breach raises the activity's visibility (sort/flag) in the sponsor Host Interviews queue and feeds last-touch staleness, but the applicant's status is untouched. The timer stops when an outcome is recorded; a rescheduled outcome restarts it against the new scheduled_at.

> **SLA timers live in P16**
>
> The queue buckets, SLA timers, and staleness model are owned by P16 — Queue System & SLA Management. This page only defines the per-activity sla_hours input and the events the queue consumes.

## Capture Surface

There are two entry points writing the same record. Whichever surface captures it, the outcome surfaces identically in the sponsor Host Interviews queue, on the applicant profile history, and in the applicant-list filters. The recorded_by field distinguishes host vs. sponsor-staff capture.

### 1. Host Portal

*Status: API built, no Host Portal screen found. The Hub exposes `POST /api/partner/host/work-items/:id/interview` (gated by `host.positions.manage` and the `job_orders.write` scope, with job-order ownership checked), but `host_user` roles carry no staff permissions (`server/seed/rbac.ts`) and no Host Portal UI calling that route was found in HostPortalPrototype; in practice outcomes are entered by sponsor staff (see the as-built table above).*

The host records the outcome for an applicant they interviewed, directly in the Host Portal against the job order. recorded_by resolves to the host user; interviewer defaults to that user but can name a different host contact who actually conducted the interview. For host-decision interviews the portal shows accepted / rejected labels, stored as passed / failed.

### 2. Globus (Sponsor Staff)

Sponsor staff can schedule and record the result directly on Globus — for example when the host relays it offline, by phone, or staff record it on the host's behalf, or for sponsor-conducted interviews. This writes the same record; recorded_by resolves to the staff actor while interviewer names whoever conducted it.

> **One record, two writers**
>
> Both surfaces write the identical InterviewOutcome shape against the same applicant / Work Type. There is no separate "staff outcome" vs. "host outcome" model — only recorded_by tells the two apart, and the queue, history, and filters treat them the same.

## Status Independence

> **Recording an outcome never mutates pipeline status**
>
> Work Type activities are tracked for completeness and accountability; they do not modify the applicant's pipeline status. If an applicant is in_review and an interview outcome is recorded, the applicant stays in_review. Any downstream phase advancement is a separate staff or rules-engine decision that may read outcomes as a readiness signal (see Readiness & Placement Linkage) but is never triggered as a side effect of writing the record.

## Interview History on the Applicant Profile

The applicant profile shows all interview records for the applicant in chronological order (most recent first), each row rendering the Work Type label, host / job order (when set), interviewer, scheduled and conducted timestamps, the outcome chip, the reason code (when present), and notes. Multiple interviews — across hosts or repeated attempts — are all retained; nothing is overwritten. This is the accountability trail: every attempt and result is visible after the fact.

## Applicant List Filtering

The applicant list exposes a Work Type outcome filter so staff can, for example, select "interview passed" and see only applicants with a matching recorded outcome. The filter matches on work_type_id + outcome; an applicant matches if any of their interview records satisfies the selected criteria. Like the rest of the ecosystem, the filter is applied server-side and scoped to the caller's permission (brand → program → season) so counts and rows agree.

## Readiness & Placement Linkage

Open required activities are a readiness signal

A required interview Work Type still in pending_outcome shows as an open readiness item on the applicant and in the Interview phase readiness. It is a signal staff and the rules engine read, not a status the activity writes.

Passed feeds placement confirmation

A passed (accepted) host-interview outcome is an input toward moving the corresponding placement match from reserved → confirmed. It is a necessary signal, not the sole one — the placement engine owns the actual transition and may require other gates (Wave 2 documents, capacity).

Failed releases the match

A failed (rejected) outcome resolves this host's interview but does not confirm a placement; the reserved match for that job order is freed for re-matching.

## Audit Vocabulary

Every mutation — program configuration and per-applicant capture — writes through recordAudit() using applicant- and queue-scoped vocabulary, surfaced in the Audit Console.

| Action | When |
| --- | --- |
| action | when |

_(row above is a template, repeated for each data row)_

> **Best-effort, never blocking**
>
> Audit writes follow the ecosystem rule: they run after the success response and never fail the underlying mutation. Actor resolution uses resolveActor(req), so program-manager, host-user, and sponsor-staff actions are attributable in the same log.

## Acceptance Criteria

The implementation (owned by P11.3, see below) is complete when all of the following Gherkin scenarios pass.

## Ownership & Routing

> **Owned by P11.3 — Work Types / Interview Tracking**
>
> Implementation of Work Type configuration and interview capture is owned by P11.3 — Work Types / Interview Tracking, part of the Globus Phase 1 / Workflow Studio family — not On-Program. It is pipeline/intake mechanics, so tickets are filed against the Globus Phase 1 portfolio. The runtime (program-config UI, applicant-list filter, outcome storage) lives in Globus-core; this page is the docs-site spec only.

## Cross-References
