HR Lifecycle Clearance/Audit Skill
When to use
Use this skill for any task that asks you to act as an HR control reviewer over the Northwind People Lifecycle Portal (remote PeopleOps console). Signals: a prompt names an employee ID (EMP-###), a policy case ID (CASE-...), a recruitment opening (REQ-...), or a candidate ID, and asks you to return structured fields like leave policy, payroll status, folder readiness, notice defects, audit event, approval closeout gate, or final control result as JSON matching a template.
Environment contract
- Web UI:
<remote-env-url>/(Northwind People Lifecycle Portal). The prompt'shttp://127.0.0.1:<port>/and loginops.lead@peopleops.local / PeopleOps#2026point at THIS remote host. Credentials are illustrative; no auth is needed. - JSON API base:
<remote-env-url>(read-only, no auth). Always use this base. - Health:
GET /health->{"ok": true, ...}. Probe it first if a call hangs. - Use
curl -s --max-time 20 "<base>/api/..."and pipe throughpython3 -m json.tool. Do NOT save remote data to disk.
Endpoints (GET), in the order you typically need them
| Endpoint | Returns | Use for |
|---|---|---|
/api/manifest |
module/endpoint map, file counts, seed | orientation only |
/api/summary |
record counts, departments | orientation only |
/api/employees?q=<term> |
employee records (leave_balance_days, status, department) | identity confirmation, profile-summary comparison |
/api/payroll-ledgers?q=<term> |
both "Leave assignment" and "Salary assignment" records (+ accrual_batch_id, base_salary, period, status) | leave precedence AND payroll/accrual readiness |
/api/cases?q=<term> |
case summaries | case lookup |
/api/cases/<case_id> |
FULL case: approvals[], attachments, comments[], audit_events[], summary | folder evidence, approval history, per-case audit |
/api/documents?q=<term> |
document folders: files[], required_files[], tags[], required_tags[], ready | folder readiness |
/api/messages?q=<term> |
formal notices: quality, defects[], status, channel | notice defect inspection |
/api/notifications?q=<term> |
same shape as messages | notice defect cross-check |
/api/audit?case_id=<id> and /api/audit |
audit events: audit_id, event, detail, actor, employee_id, case_id | audit event selection; /api/audit/<id> for one event |
/api/recruitment?q=<term> |
opening: candidates[], offer_register[], cost_ledger[], notice_packets[], payroll_precheck_records[] | recruitment handoff + cost sum |
/api/policies and /api/policies/<id> |
policy definitions | reference text (e.g. notice requirements) |
/api/attachments/<attachment_id> |
attachment text content | follow from case attachments if folder detail is in an attachment |
Searching: ?q=<keyword> searches across fields. The same keyword (e.g. an employee ID or case ID) often hits multiple endpoints. For payroll-ledgers and audit, q= an employee ID returns that employee's records; audit?case_id= filters by case.
Overall SOP (step-by-step)
- Parse the prompt. Identify the entity the prompt is about (employee / case / opening), the stated decision dimension (leave, payroll+accrual, folder+notice, recruitment handoff, audit), and any explicit rules ("exclude draft", "use submitted", "use the answer-template labels, not free text").
- Identity resolution. Search
/api/employees?q=(or/api/cases?q=//api/recruitment?q=) to confirm the entity ID and name. Recordemployee_id/case_id/opening_idexactly. - Gather evidence by dimension. Call the endpoint(s) for the dimension(s) the prompt names (see decision tables below). Always fetch the FULL case detail for case-based tasks (
/api/cases/<id>) because attachments/comments/audit_events live only there. - Apply precedence / readiness rules (below) to pick the controlling record and the excluded records. Assign the normalized enum labels, never free text.
- Select the audit event whose
event/detailmatches the task'saudit_scope. Exclude out-of-scope events. - Decide the approval closeout gate and final control result from the combined folder + notice + payroll + leave state.
- Fill every field in the provided
answer_template.json. Output strict JSON (numbers as numbers, booleans as booleans, lists as JSON arrays, enums exactly as listed). - Run the pre-submission checklist (below).
Field shape reference
Templates vary per task, but the field families are stable. Populate the union the template asks for:
- Identity:
employee_id|case_id|opening_id(string, exact). - Leave:
effective_leave_policy(policy_name of the winning assignment),annual_days/balance_days(integer = winning assignment's approved_leave_days),assignment_id(winning ledger_id),excluded_leave_ids(list),leave_source,leave_precedence_source,precedence_source,profile_policy_ignored(bool). - Payroll:
salary_assignment_id/payroll_assignment_id(winning ledger_id),base_salary(number),effective_date(string),excluded_assignment_id/excluded_payroll_ids,payroll_status/payroll_source_status,draft_exclusion_rule,accrual_ready(bool),accrual_batch_id. - Folder:
folder_ready(bool),missing_files(list),required_tag_present(bool),folder_required_tag_action. - Notice:
notice_quality(valid/defective),notice_defects(list of defect codes),notice_evidence_source,notice_followup_required(candidate IDs),notice_remediation_action. - Approval:
approval_authority,approval_event_id/approval_id,final_decision. - Audit:
audit_event_id,supporting_audit_event_ids,excluded_audit_event_ids,audit_scope,audit_result. - Closeout/gate:
closeout_action/next_action,approval_closeout_gate,closeout_blockers,escalation_action,records_remediation_owner,final_control_result/control_result,evidence_source_order. - Recruitment:
selected_candidate,waitlisted_candidates,rejected_candidates,offer_id,offer_base_salary,recruitment_cost_total,onboarding_handoff,candidate_status_source,candidate_outcome_control,selected_offer_status,cost_source,waitlisted_followup_action,rejected_followup_action,payroll_handoff_gate,payroll_assignment_status_required,draft_payroll_allowed,offer_exclusion_reason_for_waitlisted,handoff_control_result.
Business rules
A. Leave source precedence (tasks naming leave policy / balance)
- Endpoint:
/api/payroll-ledgers?q=<EMP>, filterrecord_type == "Leave assignment". - Winning record: the "Leave assignment" with
status == "Approved"for the current period. If multiple Approved exist for the current period, take the one whoseperiodmatches the review period and is most recent byupdated_at. (status == "Submitted"for a Leave assignment is also acceptable when no Approved exists — per policy LEAVE-SRC-001 "latest approved or submitted assignment controls".) - Exclude any Leave assignment with
statusin{Draft, Superseded, Voided}— put theirledger_ids inexcluded_leave_ids. - Ignore non-assignment ledger rows: records with
record_typelike "HRMS leave ledger", "People Ops adjustment", "Salary assignment" are NOT leave assignments. They are decoys; never use theirapproved_leave_days/worksheet_leave_daysas the policy figure. - Profile conflict: the employee profile (
/api/employees) has aleave_balance_daysand an implied policy. When the approved assignment's policy/days differs from the profile, the approved assignment wins and the profile is stale. Setleave_source = leave_assignment_history,leave_precedence_source = approved_assignment_current_period(orprecedence_source = approved_assignment_over_profile),profile_policy_ignored = true. - audit_result for a stale profile =
profile_summary_stale; next_action =update_employee_summary. - audit_scope =
leave_source_precedence_only. Only the leave-source audit event (eventlikeleave.profile_mismatch) is supporting; a folder/tag/notice audit event on the same case is OUT of scope and goes inexcluded_audit_event_ids.
B. Payroll source precedence + accrual readiness (tasks naming payroll/accrual)
- Endpoint:
/api/payroll-ledgers?q=<EMP>, filterrecord_type == "Salary assignment". - Winning record: the Salary assignment with
status == "Submitted". (draftandsupersededare excluded.) base_salary= winning assignment'sbase_salary(number).salary_assignment_id/payroll_assignment_id= itsledger_id.payroll_status/payroll_source_status=submitted.excluded_assignment_id/excluded_payroll_ids= the Draft (and any Superseded) salary assignmentledger_ids.draft_exclusion_rule=exclude_draft_assignment.effective_date= the winning assignment's effective date: use theperiod(YYYY-MM->YYYY-MM-01) or itsupdated_atdate portion (they agree).- Accrual: if the winning submitted assignment carries an
accrual_batch_id, thenaccrual_ready = trueandaccrual_batch_id= that value. If noaccrual_batch_idis present on the submitted assignment,accrual_ready = false. - audit_event_id = the payroll audit event for this employee (
eventlikepayroll.readyorpayroll.draft_excluded). audit_scope =payroll_assignment_readiness. - control_result: when the submitted assignment exists and accrual batch is present ->
ready_with_monitoring. (If folder/notice defects also exist on the case, escalate tohold_for_folder_and_notice_defects; otherwise stayready_with_monitoring.) Clean onboarding with submitted payroll and approved leave and clean folder/notice ->approve_closeout.
C. Folder readiness (tasks naming folder / records)
- Endpoint:
/api/documents?q=<case-or-emp>. Also read the case'sattachments[]content text on/api/cases/<id>(folder checklists often describe missing files / tags in plain text). folder_ready= the document record'sreadyboolean (AND confirm against attachments: a checklist attachment saying "Missing X" overrides a staleready:true).missing_files=required_filesminusfiles(set difference). List each missing filename exactly.required_tag_present= true iff every tag inrequired_tagsappears intags.folder_required_tag_action:no_tag_actionif the required tag(s) are present;add_required_tagif any required tag is missing.closeout_blockersgainsmissing_required_files(any missing file) and/ormissing_required_tags(any missing required tag).
D. Notice defect detection (tasks naming notice / formal notice)
- Endpoint:
/api/messages?q=<case>(and/api/notifications?q=<case>as cross-check). The recruitmentnotice_packets[]array is the equivalent for candidate notices. notice_quality= the message'squalityfield (valid/defective).notice_defects= the message'sdefects[]array. Defect code vocabulary (exactly these tokens):missing_ack_deadline— no acknowledgement deadline in the notice body/subject.missing_appeal_instructions— no appeal instructions.missing_waitlist_status— a waitlist notice that fails to state waitlist status.missing_correct_policy— notice cites a wrong/stale policy.
- Do not invent defect codes beyond these four. If the audit
detailtext describes a defect, map it to the closest code only if a message/notice packet actually carries that defect; the message/notice-packetdefects[]is authoritative. notice_evidence_source=notice_packet_inspection(when you read message/notice-packet defects) — preferred overmessage_notice_inspection/case_summary_only.notice_remediation_action:reissue_defective_noticeswhen any defect present;no_notice_actionwhen valid.- A defective notice adds
defective_formal_noticetocloseout_blockersand drivesnext_action = block_close_and_reissue_notice.
E. Approval closeout gate + final control result
- Read approvals from the FULL case (
/api/cases/<id>->approvals[]).approval_authority= the final approver;approval_event_id= itsapproval_id;final_decisionderived fromdecision/note(Approved+ "with conditions" ->approved_with_conditions). - approval_closeout_gate =
approval_sufficient_when_records_cleanwhen folder is ready, all required tags present, and notice is valid. approval_closeout_gate =approval_not_sufficient_when_folder_or_notice_defectivewhen ANY of: missing required file, missing required tag, or defective notice. Approval alone never closes a defective folder/notice. - final_control_result (the master enum, reuse for
control_result):approve_closeout— folder ready, tags present, notice valid, payroll submitted, leave approved.hold_for_folder_and_notice_defects— any folder/notice defect.ready_with_monitoring— payroll submitted + accrual ready, monitored cases where no blocking defect but QA flagged monitoring.
- next_action / closeout_action:
block_close_and_reissue_notice— notice defective.open_records_remediation— missing files/tags.approve_onboarding_close— fully clean.update_employee_summary— leave stale-profile case.
- escalation_action / records_remediation_owner: folder/records defects -> owner
Records; cross-module/notice package ->People Ops Compliance; payroll-only ->Payroll QA.
F. Audit event selection
- For each task,
audit_scopeis determined by the decision dimension:- leave tasks ->
leave_source_precedence_only - payroll/accrual tasks ->
payroll_assignment_readiness - folder/notice tasks ->
document_notice_findings_only
- leave tasks ->
audit_event_id= the single audit event whoseevent/detailmatches the scope for this entity/case (e.g.leave.profile_mismatch,payroll.ready,payroll.draft_excluded,notice.defect,case.close_blocked). Prefer the event whoseemployee_id/case_idmatches the task entity.supporting_audit_event_ids= all in-scope events (usually just the one).excluded_audit_event_ids= audit events on the same case that belong to a DIFFERENT scope (e.g. afolder.tag_missingevent on a leave-scope task). Cross-module "escalation package" events (cross_module.escalation_package) are umbrella events — list their referenced child event IDs only if the task is explicitly cross-module; otherwise exclude the umbrella.- audit_result for leave-stale =
profile_summary_stale; payroll-ready =ready_with_monitoring; folder/notice block =block_close.
G. Recruitment handoff + cost (tasks naming opening/candidates)
- Endpoint:
/api/recruitment?q=<opening>. - Candidate outcome — reconstruct from
candidates[]+offer_register[]:selected_candidate= the candidate withcommittee_decision == "Selected"whose offer inoffer_registerhasstatus == "accepted".waitlisted_candidates=committee_decision == "Waitlisted".rejected_candidates=committee_decision == "Rejected".candidate_status_source=interview_feedback_and_offer;candidate_outcome_control=committee_decision_with_offer_confirmation;selected_offer_status= the offer'sstatus(accepted / draft / withdrawn / none).
- Cost:
recruitment_cost_total= sum of everycost_ledger[].amount.cost_source=recruitment_cost_ledger. Do not use case-summary cost figures. - Notice followup: for each entry in
notice_packets[]withstatus == "not_sent", add itscandidate_idtonotice_followup_required.waitlisted_followup_action= the waitlist packet'srequired_action(e.g.send_waitlist_notice);rejected_followup_action= the rejection packet'srequired_action(e.g.send_rejection_notice).notice_quality_source=notice_packet_inspection. - Payroll handoff: a payroll assignment must be created for the accepted candidate only.
payroll_handoff_gate=accepted_offer_only;payroll_assignment_status_required=submitted_after_acceptance;draft_payroll_allowed= false.offer_exclusion_reason_for_waitlisted=no_accepted_status_or_offer(waitlisted/rejected candidates get no submitted assignment). - onboarding_handoff: if
payroll_precheck_records[]is empty and the selected offer is accepted ->create_payroll_precheck(orcreate_submitted_assignment_after_acceptancewhen a submitted assignment must follow acceptance; pick per the template's wording — the controlling rule is the offer must be accepted before any assignment).no_payroll_handoffonly when no accepted offer exists. - handoff_control_result: accepted offer, assignment not yet submitted ->
submitted_handoff_required_after_acceptance; submitted assignment already present ->submitted_handoff_required; no accepted offer ->no_handoff_required.
Common misjudgments and exclusion rules
- Selecting a Draft or Superseded leave/payroll assignment as controlling. Always exclude Draft and Superseded from the controlling record; still list them in the
excluded_*fields. - Treating "HRMS leave ledger" / "People Ops adjustment" rows as leave assignments. Only
record_type == "Leave assignment"defines the policy. Other rows are decoys. - Trusting the employee profile
leave_balance_daysover the approved assignment. The approved assignment wins; the profile is "stale" when they conflict. - Trusting the case
summarytext for defects. The summary is a hint; the authoritative defects are in/api/messagesdefects[](ornotice_packets[].required_actionfor recruitment). Inspect the packet, don't infer from prose. - Closing out on approval alone when the folder or notice is defective. Approval is NEVER sufficient when a required file is missing, a required tag is missing, or the notice is defective.
- Including out-of-scope audit events as supporting. A folder event on a leave-scope task goes to
excluded_audit_event_ids, not supporting. - Counting the cross-module umbrella audit event as a single entity's finding. It references child events; assign the child event to the relevant entity.
- Free-text enum values. Use the exact normalized labels from the answer template (e.g.
ready_with_monitoring,hold_for_folder_and_notice_defects,exclude_draft_assignment,leave_assignment_history). No spaces, no capitalization variants. - Recruitment cost from a case summary. Always sum the
cost_ledgeramounts; do not rely on any summary number. - Offering a payroll handoff to waitlisted/rejected candidates. Only the accepted selected candidate gets the submitted-after-acceptance assignment.
- Missing the FULL case detail.
/api/cases(list) does NOT include attachments/comments/per-case audit_events; you must call/api/cases/<case_id>.
Pre-submission checklist
- Every field in the provided
answer_template.jsonis present and uses the exact enum token / type from the template. - Identity (
employee_id/case_id/opening_id) matches the prompt and the API record. - Controlling leave assignment = Approved (current period) "Leave assignment" record; Draft/Superseded and non-assignment rows are in
excluded_*and NOT used for figures. - Controlling payroll = Submitted "Salary assignment"; Draft/Superseded excluded.
-
missing_files= required_files minus files;required_tag_presentreflects every required tag. -
notice_defectscome from the message/notification/notice-packetdefects[], mapped to the four codes only. -
approval_closeout_gateis...not_sufficient...if any folder or notice defect exists, regardless of approval. -
final_control_result/control_resultconsistent with the gate: defects ->hold_for_folder_and_notice_defects; clean ->approve_closeout; submitted-payroll+accrual monitor ->ready_with_monitoring. -
audit_scopematches the task dimension;excluded_audit_event_idslists same-case out-of-scope events. -
recruitment_cost_total= sum ofcost_ledgeramounts (number, not string). - Booleans are
true/false; lists are JSON arrays; numbers are unquoted. - Output is strict JSON parseable by
python3 -m json.tool; no trailing commas, no comments.