Skip to content

P-06 · Internal review & override approvals

SOP: Payroll_Processing.md §6 / Step 4.0 (S7 → S8)Actors: Payroll Executive (PE) for review; Payroll Operations Lead (POL) for overrides. SoD control: PE must not self-approve overrides. Pre-state: Cycle in READY_FOR_INTERNAL_REVIEW. Post-state: All mandatory gate conditions are either green or have a recorded override; cycle ready for export.

This step is mostly procedural — most of its enforcement is automatic via the validation pipeline. The user-facing surface is the cycle detail page's review checklist plus the issue-resolution dialogs.

0. Prerequisites

  • Validation has cleared blocking rules (P-04).
  • Cycle in READY_FOR_INTERNAL_REVIEW.

1. Steps

1.1 Walk the readiness checklist (PE)

On /dashboard/cycles/<id>, the Readiness tab shows:

GateWhat PE checks
Blocking errors resolvedIssues tab is empty (status = OPEN filter returns 0 rows)
Medium-confidence extractions confirmedEach ExtractedField with 0.80 ≤ confidence < 0.95 shows confirmed_at set on the form
Major variance flags identifiedCompare current submission totals to the seeded prior-cycle baseline; flag any > X% delta (configurable per client)
IR21 tasks created where requiredFor every foreign leaver, an IR21-kind file or override is present
CPF ceiling risk flags reviewedThe validation result for CPF_CEILING_RISK is acknowledged (warning-only by default)

1.2 Resolve issues if needed

If a WorkflowIssue is still open (e.g. you intentionally left a duplicate-receipt warning), click Resolve on the row. The dialog asks for a reason; the underlying call is:

http
POST /ops/cycles/<id>/issues/<issueId>/resolve
Authorization: Bearer <staff-jwt>

{ "override": false, "reason": "Duplicate is the same purchase split across two receipts." }

For an override (e.g. proceed without IR21 because the client confirmed in writing the IR21 was already filed externally), POL must do it:

http
POST /ops/cycles/<id>/issues/<issueId>/resolve
Authorization: Bearer <pol-jwt>

{ "override": true, "reason": "IR21 filed externally by client tax agent — confirmed via email 2026-04-23." }

The handler enforces Action.OVERRIDE_ISSUE (only PAYROLL_LEAD or PLATFORM_ADMIN).

1.3 Mark Ready for Export

Once everything is clean, clicking Mark Ready for Export on the cycle header transitions the cycle READY_FOR_INTERNAL_REVIEW → READY_FOR_EXPORT.

Note: under the canonical path you can skip this manual click — Generate Export (P-07) will do it implicitly when validation passes.

2. Verification

Database

sql
SELECT issue_id, resolution_kind, reason, resolved_by, resolved_at
  FROM workflow_issue_resolutions WHERE cycle_id = '<cycleId>';
-- expect resolution_kind ∈ ('RESOLVED', 'OVERRIDDEN')

SELECT status FROM payroll_cycles WHERE id = '<cycleId>';
-- READY_FOR_EXPORT

Audit log

EventNotes
issue.resolvedper resolve click
issue.overriddenper override click; carries actor (must be POL) and reason
cycle.marked_ready_for_exportimplicit transition

3. Negative & edge cases

  • PE attempts an override → 403 "OVERRIDE_ISSUE requires PAYROLL_LEAD or PLATFORM_ADMIN." SoD enforcement.
  • Resolve without a reason → 400 "Reason is required."
  • Cycle already past READY_FOR_EXPORT → 409 "Issue cannot be resolved on a cycle past export." Open a revision round instead (P-10 revision branch).
  • Attempt to mark ready while issues remain → 400 with the open issue ids. The button is hidden in the UI when issues are open.

Next

Proceed to P-07 · Generate Infotech export.

Internal use only — BreezyCorp