SKILL: Northwind PeopleOps Console — HR Employee-Lifecycle Verification
When to use
Use this skill for any task that asks you to verify, reconcile, or close out a
PeopleOps employee-lifecycle record in the Northwind "People Lifecycle Portal".
This covers five recurring archetypes:
- Onboarding closeout — verify an employee's effective leave setup +
payroll setup, then approve or block onboarding close (e.g. "verify final
onboarding closeout for EMP-XXX").
- Policy-case folder + formal-notice review — review a policy case
(remote-work exception, etc.) for folder readiness and formal notice quality,
then decide approval/block (e.g. "Review CASE-RW-XXX for folder readiness and
formal notice quality").
- Recruitment reconciliation — reconcile a recruitment opening's candidate
outcomes, offer register, cost ledger, and notice packets (e.g. "Reconcile
the recruitment outcome packet for REQ-XXX").
- Leave source precedence — determine which leave policy/balance is
authoritative when the employee profile summary conflicts with an approved
assignment (e.g. "validate leave source precedence for EMP-XXX").
- Payroll assignment + accrual readiness — validate the submitted salary
assignment and whether an accrual batch is ready (e.g. "inspect payroll
assignment and accrual readiness for EMP-XXX").
If the prompt mentions PeopleOps Console, login ops.lead@peopleops.local /
PeopleOps#2026, an http://127.0.0.1:<port>/ solver URL, employees
EMP-XXX, cases CASE-XXX, openings REQ-XXX, or asks for a JSON answer
matching an answer_template.json — this is the skill.
Environment mechanics (read first)
- The "local" solver URL and login in the prompt are illustrative. The real
environment is the remote console:
- Web UI:
<remote-env-url>/
- JSON API base:
<remote-env-url> (read-only, no authentication)
- Health check:
GET <remote-env-url>/health → {"ok": true, ...}
- All API calls are plain
GET. No auth header, no login step. The prompt's
127.0.0.1:<port> and credentials point at THIS remote host — substitute
<remote-env-url> everywhere.
- Always fetch with
curl -s and pipe to python3 -m json.tool for readability.
?q=<keyword> searches across fields (employee id, name, case id, candidate
id, subject, body, etc.). ?status= / ?type= / ?case_id= filter where
relevant. Searching by the literal ID token (e.g. ?q=EMP-104) is the most
reliable lookup.
Available endpoints (GET)
| Endpoint |
Returns |
Use for |
/api/manifest |
module/endpoint map, dataset seed |
sanity check counts |
/api/summary |
live record counts + departments |
orientation |
/api/employees?q= |
employee profile summary (leave_balance_days, salary_band, status, hire_date, manager) |
the "stale" profile to compare against |
/api/cases?q= |
case summaries |
find the case for an employee/opening |
/api/cases/<case_id> |
FULL case (approvals[], attachments[] with content, comments[], audit_events[]) |
primary evidence for folder/notice/approval |
/api/policies and /api/policies/<id> |
policy definitions + sections |
authoritative business rules |
/api/payroll-ledgers?q= |
leave assignments AND salary assignments ledger history |
authoritative leave + payroll records |
/api/recruitment?q= |
opening: candidates[], offer_register[], cost_ledger[], notice_packets[], payroll_precheck_records[] |
recruitment reconciliation |
/api/documents?q= |
lifecycle folders (ready, required_files, files, required_tags, tags) |
folder readiness |
/api/messages?q= |
formal notice messages (quality, defects[], ack deadline, appeal info) |
formal notice quality |
/api/notifications?q= |
notifications (ack deadlines, appeal instructions) |
secondary notice evidence |
/api/audit?q= and ?case_id= |
audit events (event type, actor, detail, owner, timestamp) |
control result + scope selection |
/api/audit/<audit_id> |
single audit event detail |
confirm one event |
/api/attachments/<id> |
attachment text content |
rarely needed; case full detail already embeds attachment content |
Standard investigation SOP (endpoint calling order)
For ANY task, run this base sequence first, then branch by archetype.
- Read the prompt +
answer_template.json first. Enumerate every output
field and its allowed_values. You will ONLY emit values from those enums —
never free-text. The template IS the contract.
- Health check (optional):
curl -s <remote-env-url>/health.
- Extract IDs from the prompt (employee id
EMP-XXX, case id CASE-XXX,
opening id REQ-XXX). These become your ?q= terms.
- Fetch the employee profile summary:
GET /api/employees?q=<EMP-XXX>.
Record leave_balance_days, salary_band, status, hire_date. This is
the profile view — often stale; do NOT treat it as authoritative yet.
- Fetch the ledger/assignment history:
GET /api/payroll-ledgers?q=<EMP-XXX>.
This single endpoint returns BOTH record_type: "Leave assignment" and
record_type: "Salary assignment" rows. Each row has status
(Approved/Submitted/Draft/Superseded), ledger_id, policy_name /
base_salary, period, accrual_batch_id.
- Find the case(s):
GET /api/cases?q=<EMP-XXX> (and ?q=<CASE-XXX> if a
case id was given).
- Fetch FULL case detail:
GET /api/cases/<case_id>. This carries
approvals[], attachments[] (with embedded content), comments[], and
audit_events[]. This is your richest single source.
- Branch by archetype (see sections below) for documents, messages,
recruitment, and audit-specific fetches.
- Fetch policies:
GET /api/policies to confirm the controlling rule
(leave precedence, payroll source, folder checklist, remote-work notice
requirements). Cite the policy section that justifies each exclusion.
- Map every answer field to a concrete record value (an ID, a status
string, a number). If a field has no evidence, prefer the "clean/none/
no_action" enum — do not invent.
Branch A — Onboarding closeout (leave + payroll)
After the base sequence:
- Determine the authoritative leave assignment: among the
record_type: "Leave assignment" rows, pick the one whose status is
Approved (preferred) or Submitted, with the latest updated_at for the
target period (2026). That row's policy_name = effective leave policy,
approved_leave_days = annual days, ledger_id = assignment id.
- Excluded leave ids = every other leave-assignment row for that period:
Superseded and Draft rows are ALWAYS excluded (LEAVE-SRC-001 §2.1).
- Determine the authoritative payroll: among
record_type: "Salary assignment" rows, pick status: "Submitted". Its base_salary and
ledger_id are authoritative. Draft salary rows are excluded
(PAY-SRC-001 §3.4).
- Closeout gate: check whether the employee has a case / document folder /
formal notice with defects (run Branch B checks). If no case/doc/notice/audit
exists for the employee, records are "clean".
- clean + authoritative records →
closeout_action: approve_onboarding_close,
approval_closeout_gate: approval_sufficient_when_records_clean,
final_control_result: approve_closeout.
- folder or notice defective →
closeout_action: block_close_and_reissue_notice (or open_records_remediation if only
records/files are wrong), final_control_result: hold_for_folder_and_notice_defects, gate
approval_not_sufficient_when_folder_or_notice_defective.
- Source labels:
leave_source: leave_assignment_history,
leave_precedence_source: approved_assignment_current_period,
payroll_source_status: submitted.
Branch B — Policy-case folder + formal-notice review
For a given CASE-XXX:
GET /api/cases/<CASE-XXX> → read approvals[] (approver + decision +
approval_id), attachments[] (folder-checklist content), audit_events[].
GET /api/documents?q=<EMP or CASE or title> → match the folder.
folder_ready = document.ready. missing_files = required_files - files.
required_tag_present = (required_tags ⊆ tags).
GET /api/messages?q=<EMP or CASE> → the formal decision message.
notice_quality = message.quality ("valid"/"defective").
notice_defects = message.defects[] (already enumerated by the API).
GET /api/audit?case_id=<CASE-XXX> → pick the audit event whose event
matches the scope: notice.defect or folder.* for document/notice
findings.
- Decision mapping:
- approval decision "Approved" + any folder/notice defect →
final_decision: approved_with_conditions (or held), next_action: block_close_and_reissue_notice.
- folder tag missing but files present →
folder_required_tag_action: add_required_tag; tag present → no_tag_action.
- notice defective →
notice_remediation_action: reissue_defective_notices;
clean → no_notice_action.
closeout_blockers = union of missing_required_files,
missing_required_tags, defective_formal_notice — only list the ones that
actually apply (do NOT list tags if the tag is present).
evidence_source_order: approval_history_folder_notice_audit when you used
approvals + folder + notice + audit; folder_notice_audit if no approval
history; audit_only if only audit exists.
notice_evidence_source: message_notice_inspection for formal decision
messages from /api/messages; notice_packet_inspection for recruitment
notice packets from /api/recruitment; case_summary_only only as a
last resort.
records_remediation_owner: Records for missing folder files/tags;
People Ops Compliance for notice/policy defects; Payroll QA for payroll.
escalation_action: block_close_and_reissue_notice when both folder and
notice are defective; open_records_remediation when only records;
no_action when clean.
final_control_result: hold_for_folder_and_notice_defects when any blocker;
approve_closeout when clean.
Branch C — Recruitment reconciliation
GET /api/recruitment?q=<REQ-XXX> returns one opening object with sub-arrays.
- Candidates: for each
candidates[] row, committee_decision ∈ {Selected,
Waitlisted, Rejected}. Bucket candidate ids accordingly:
selected_candidate = the Selected one confirmed by an entry in
offer_register[] with status: "accepted".
waitlisted_candidates[], rejected_candidates[] = the rest.
- Offer: from
offer_register[] matching the selected candidate:
offer_id, offer_base_salary, selected_offer_status = offer status
(accepted/draft/withdrawn/none).
- Cost:
recruitment_cost_total = sum of every amount in
cost_ledger[] (all line items, regardless of label). cost_source: recruitment_cost_ledger. Never use the case summary's cost figure if it
differs from the ledger sum.
- Notice follow-up:
notice_packets[] lists each non-selected candidate's
required notice. notice_followup_required[] = candidate ids whose
status: "not_sent".
- waitlisted + not_sent →
waitlisted_followup_action: send_waitlist_notice.
- rejected + not_sent →
rejected_followup_action: send_rejection_notice.
- If a waitlist notice was sent but is mislabeled/missing the waitlist status
→
reissue_waitlist_notice_not_rejection.
- Payroll handoff (PAY-SRC-001 §4.2): handoff is created ONLY after the
selected candidate has an accepted offer; the handoff must be
submitted (draft prechecks do NOT satisfy the gate).
- offer accepted →
onboarding_handoff: create_submitted_assignment_after_acceptance,
payroll_handoff_gate: accepted_offer_and_submitted_assignment,
payroll_assignment_status_required: submitted_after_acceptance,
draft_payroll_allowed: false,
handoff_control_result: submitted_handoff_required_after_acceptance.
- no accepted offer →
onboarding_handoff: no_payroll_handoff,
handoff_control_result: no_handoff_required.
- Source labels:
candidate_status_source: interview_feedback_and_offer,
candidate_outcome_control: committee_decision_with_offer_confirmation,
notice_quality_source: notice_packet_inspection,
offer_exclusion_reason_for_waitlisted: waitlisted_not_selected.
- Arrays contain candidate IDs only (e.g.
CAND-DA-7701), never names.
Branch D — Leave source precedence
- Profile summary (
/api/employees) gives leave_balance_days + an implied
policy. The approved leave assignment in /api/payroll-ledgers
(record_type: "Leave assignment", status: "Approved") is authoritative
per LEAVE-SRC-001 §2.1.
- Apply precedence: an approved assignment overrides a stale profile
summary when the ledger, policy document, and audit detail confirm it.
precedence_source: approved_assignment_over_profile,
leave_precedence_source: approved_assignment_current_period,
profile_policy_ignored: true,
effective_leave_policy = assignment policy_name,
assignment_id / balance_days = assignment ledger_id /
approved_leave_days.
- Audit selection: include only
leave.* audit events in the leave-scope
decision (supporting_audit_event_ids). EXCLUDE adjacent folder.*,
notice.defect, payroll.*, and cross_module.* events
(excluded_audit_event_ids). audit_scope: leave_source_precedence_only.
audit_result: echo the QA result in the audit detail
(profile_summary_stale / ready_with_monitoring / block_close).
next_action: update_employee_summary when the profile is stale but the
assignment is clean; open_records_remediation when records are broken;
no_action when already aligned.
Branch E — Payroll assignment + accrual readiness
- Among
record_type: "Salary assignment" rows, pick status: "Submitted"
→ salary_assignment_id, base_salary. excluded_assignment_id = the
Draft row. effective_date = the assignment period start (e.g. period
2026-04 → 2026-04-01; cross-check updated_at/hire_date).
accrual_ready: read the payroll.ready audit event. If its detail says
ready_with_monitoring and the submitted assignment accrual_batch_id
matches the batch → accrual_ready: true, accrual_batch_id from the
assignment row, audit_event_id = that audit id, control_result: ready_with_monitoring.
payroll_source_status: submitted,
draft_exclusion_rule: exclude_draft_assignment,
audit_scope: payroll_assignment_readiness.
Business rules (derived from the policy documents)
Fetch /api/policies and treat these as authoritative:
LEAVE-SRC-001 — Leave Source Precedence (owner: People Ops)
"The latest approved or submitted leave assignment for the period controls.
Draft, voided, and obsolete records are excluded even when profile summaries
conflict."
- Precedence order: approved/submitted assignment > profile summary > case
summary only.
- Excluded leave ids = all
Draft, Superseded/Voided, and obsolete
assignment rows for the period — even if their day count matches or the
profile disagrees.
PAY-SRC-001 — Payroll Assignment Source (owner: Payroll)
"Use the current submitted salary assignment. Draft planning assignments do
not affect payroll readiness or accrual checks." AND "Recruiting payroll
handoff is created only after a selected candidate has an accepted offer. The
handoff must be submitted; draft prechecks do not satisfy the assignment
gate."
- Submitted salary assignment controls
base_salary. Drafts excluded from
payroll readiness + accrual.
- Recruiting handoff: accepted offer required, AND the resulting assignment
must be
submitted (never draft).
POL-DOCS-2026 — Lifecycle Folder Checklist (owner: Records)
"A folder is not ready unless all required files and required tags shown in
the folder checklist are present."
folder_ready = false if ANY required file missing OR ANY required tag
missing.
missing_files = required_files - files; missing tags drive
folder_required_tag_action: add_required_tag.
HR-POL-014 — Remote Work Policy §7.1 (owner: Legal Desk)
International exceptions require "executive approval, time limits, tax
equalization, VPN-only access, quarterly compliance review, appeal
instructions, and acknowledgement deadline in the formal notice."
- A formal notice is defective unless it contains BOTH appeal instructions
AND an acknowledgement deadline (plus the other elements). The
/api/messages defects[] array enumerates exactly which are missing.
- Folder must also contain the tax-equalization agreement file for exception
cases.
Audit selection & scope rules
Audit events carry an event type. Scope your decision to the matching events
and exclude adjacent ones:
event prefix/type |
belongs to scope |
leave.* (e.g. leave.profile_mismatch) |
leave_source_precedence_only |
notice.defect |
document_notice_findings_only |
folder.* (e.g. folder.tag_missing) |
document_notice_findings_only |
payroll.* (e.g. payroll.ready, payroll.draft_excluded) |
payroll_assignment_readiness |
case.close_blocked |
the relevant defect scope (folder/notice) |
cross_module.escalation_package |
NONE — exclude from every single-scope decision |
supporting_audit_event_ids = in-scope events for THIS decision.
excluded_audit_event_ids = out-of-scope events present on the same case
(e.g. a folder.tag_missing event is excluded from a leave-scope decision).
audit_event_id (singular) = the single primary event the decision rests on.
audit_result: read the literal QA result phrase from the audit detail
(profile_summary_stale, ready_with_monitoring, block_close).
Candidate outcome & cost rules
- Outcomes come from
committee_decision in candidates[], confirmed by
the offer_register[] for the selected candidate. candidate_outcome_control: committee_decision_with_offer_confirmation.
selected_offer_status = the offer_register status for the selected
candidate (accepted / draft / withdrawn / none).
offer_exclusion_reason_for_waitlisted: waitlisted_not_selected (waitlisted
candidates never get an offer id).
recruitment_cost_total = Σ all cost_ledger[].amount. Sum every line;
do not cherry-pick by label. cost_source: recruitment_cost_ledger.
- Arrays (waitlisted/rejected/notice_followup) hold candidate IDs only.
Common misjudgments & exclusion rules
- Don't trust the employee profile summary as authoritative. It is
frequently stale. The approved/submitted assignment in
/api/payroll-ledgers
wins (LEAVE-SRC-001). A matching number does NOT prove alignment — the policy
name and audit must confirm.
- Don't mix salary + leave rows.
/api/payroll-ledgers returns both
record_type values in one list. Filter by record_type before deciding.
- Don't include Draft/Superseded records in the authoritative answer.
Always list them in
excluded_*_ids. Draft salary rows do not affect accrual
readiness.
- Don't list a tag blocker when the tag is present. Compare
required_tags ⊆ tags precisely. Only emit missing_required_tags in
closeout_blockers if a required tag is actually missing.
- Don't conflate notice defects. Use the exact
defects[] from
/api/messages. A present ack deadline means missing_ack_deadline does NOT
apply. Defect enum: missing_ack_deadline, missing_appeal_instructions,
missing_waitlist_status, missing_correct_policy.
- Don't include adjacent-scope audit events in a single-scope decision.
Exclude
folder.*/notice.defect from leave scope; exclude leave.*/payroll.*
from document/notice scope.
- Don't route a payroll handoff before offer acceptance. Draft prechecks
never satisfy the gate.
draft_payroll_allowed: false.
- Don't sum cost from the case summary. Always sum the
cost_ledger[]
amounts directly.
- Don't put candidate names in arrays. IDs only.
- Don't free-text enums. Every enum field must be a string copied verbatim
from the task's
answer_template.json allowed_values.
- Don't treat an "Approved" case as closeable. Approval is necessary but
not sufficient: a folder or notice defect blocks closeout
(
approval_closeout_gate: approval_not_sufficient_when_folder_or_notice_defective).
- Don't read test/train gold answers. Solve only from the live read-only
API + policies. Use only the documented read-only endpoints for evidence.
Exact answer fields (per archetype) — what each field must be
Onboarding closeout: employee_id; effective_leave_policy (assignment
policy_name); leave_source; annual_days; assignment_id; excluded_leave_ids;
payroll_assignment_id; base_salary; payroll_status; excluded_payroll_ids;
closeout_action; leave_precedence_source; payroll_source_status;
approval_closeout_gate; final_control_result.
Policy-case review: case_id; final_decision; approval_authority
(approver); approval_event_id (approval_id); folder_ready; missing_files;
required_tag_present; notice_quality; notice_defects[]; audit_event_id;
supporting_audit_event_ids[]; excluded_audit_event_ids[]; audit_scope;
next_action; approval_closeout_gate; closeout_blockers[];
evidence_source_order; folder_required_tag_action; notice_evidence_source;
escalation_action; records_remediation_owner; notice_remediation_action;
final_control_result.
Recruitment: opening_id; selected_candidate; waitlisted_candidates[];
rejected_candidates[]; offer_id; offer_base_salary;
recruitment_cost_total; notice_followup_required[]; onboarding_handoff;
candidate_status_source; candidate_outcome_control; selected_offer_status;
cost_source; notice_quality_source; waitlisted_followup_action;
rejected_followup_action; payroll_handoff_gate;
payroll_assignment_status_required; draft_payroll_allowed (bool);
offer_exclusion_reason_for_waitlisted; handoff_control_result.
Leave precedence: employee_id; effective_leave_policy; assignment_id;
balance_days; precedence_source; profile_policy_ignored (bool);
audit_event_id; audit_result; next_action; leave_precedence_source;
supporting_audit_event_ids[]; excluded_audit_event_ids[]; audit_scope.
Payroll accrual: employee_id; salary_assignment_id; base_salary;
effective_date; excluded_assignment_id; accrual_ready (bool);
accrual_batch_id; audit_event_id; control_result; payroll_source_status;
draft_exclusion_rule; audit_scope.
Pre-submission checklist
Before emitting the JSON answer, verify each item:
- Shape — the JSON matches
answer_template.json field-for-field (no extra
keys, no missing keys, correct types: string/int/number/bool/list).
- Enums exact — every enum value is copied verbatim from the template's
allowed_values; no synonyms, no casing changes, no free-text.
- Authoritative source chosen — leave answer comes from the
approved/submitted assignment (not the profile); payroll from the submitted
assignment (not draft).
- Exclusions listed — all Draft/Superseded leave + payroll IDs appear in
the
excluded_*_ids lists; none leak into the authoritative fields.
- Folder + notice checked for the closeout gate —
folder_ready,
missing_files, required_tag_present, notice_quality, notice_defects
all reflect the actual /api/documents + /api/messages evidence, not the
case summary blurb.
- Audit scope clean —
supporting_audit_event_ids contains only in-scope
events; adjacent-scope (and any cross_module.*) events are in
excluded_audit_event_ids.
- Cost summed —
recruitment_cost_total equals the literal sum of every
cost_ledger[].amount (re-add to confirm).
- Arrays are IDs — candidate/waitlist/reject/notice arrays contain IDs,
not names; empty arrays
[] when nothing applies (do not omit the key).
- Control result consistent — if any blocker exists,
final_control_result
is hold_for_folder_and_notice_defects and the gate is
approval_not_sufficient_when_folder_or_notice_defective; if records are
clean, it is approve_closeout with approval_sufficient_when_records_clean.
- No gold, no internal access — nothing references evaluator
internals or unseen answer keys; all evidence is traceable to a
GET on
the remote read-only API.
1---2name: self-attempt-03-163description: SKILL: Northwind PeopleOps Console — HR Employee-Lifecycle Verification4---5# SKILL: Northwind PeopleOps Console — HR Employee-Lifecycle Verification67## When to use89Use this skill for any task that asks you to verify, reconcile, or close out a10PeopleOps employee-lifecycle record in the Northwind "People Lifecycle Portal".11This covers five recurring archetypes:12131. **Onboarding closeout** — verify an employee's effective leave setup +14 payroll setup, then approve or block onboarding close (e.g. "verify final15 onboarding closeout for EMP-XXX").162. **Policy-case folder + formal-notice review** — review a policy case17 (remote-work exception, etc.) for folder readiness and formal notice quality,18 then decide approval/block (e.g. "Review CASE-RW-XXX for folder readiness and19 formal notice quality").203. **Recruitment reconciliation** — reconcile a recruitment opening's candidate21 outcomes, offer register, cost ledger, and notice packets (e.g. "Reconcile22 the recruitment outcome packet for REQ-XXX").234. **Leave source precedence** — determine which leave policy/balance is24 authoritative when the employee profile summary conflicts with an approved25 assignment (e.g. "validate leave source precedence for EMP-XXX").265. **Payroll assignment + accrual readiness** — validate the submitted salary27 assignment and whether an accrual batch is ready (e.g. "inspect payroll28 assignment and accrual readiness for EMP-XXX").2930If the prompt mentions PeopleOps Console, login `ops.lead@peopleops.local` /31`PeopleOps#2026`, an `http://127.0.0.1:<port>/` solver URL, employees32`EMP-XXX`, cases `CASE-XXX`, openings `REQ-XXX`, or asks for a JSON answer33matching an `answer_template.json` — this is the skill.3435## Environment mechanics (read first)3637- The "local" solver URL and login in the prompt are **illustrative**. The real38 environment is the **remote** console:39 - Web UI: `<remote-env-url>/`40 - JSON API base: `<remote-env-url>` (read-only, **no authentication**)41 - Health check: `GET <remote-env-url>/health` → `{"ok": true, ...}`42- All API calls are plain `GET`. No auth header, no login step. The prompt's43 `127.0.0.1:<port>` and credentials point at THIS remote host — substitute44 `<remote-env-url>` everywhere.45- Always fetch with `curl -s` and pipe to `python3 -m json.tool` for readability.46- `?q=<keyword>` searches across fields (employee id, name, case id, candidate47 id, subject, body, etc.). `?status=` / `?type=` / `?case_id=` filter where48 relevant. Searching by the literal ID token (e.g. `?q=EMP-104`) is the most49 reliable lookup.5051### Available endpoints (GET)5253| Endpoint | Returns | Use for |54|---|---|---|55| `/api/manifest` | module/endpoint map, dataset seed | sanity check counts |56| `/api/summary` | live record counts + departments | orientation |57| `/api/employees?q=` | employee **profile summary** (leave_balance_days, salary_band, status, hire_date, manager) | the "stale" profile to compare against |58| `/api/cases?q=` | case summaries | find the case for an employee/opening |59| `/api/cases/<case_id>` | **FULL** case (approvals[], attachments[] with content, comments[], audit_events[]) | primary evidence for folder/notice/approval |60| `/api/policies` and `/api/policies/<id>` | policy definitions + sections | authoritative business rules |61| `/api/payroll-ledgers?q=` | **leave assignments AND salary assignments** ledger history | authoritative leave + payroll records |62| `/api/recruitment?q=` | opening: candidates[], offer_register[], cost_ledger[], notice_packets[], payroll_precheck_records[] | recruitment reconciliation |63| `/api/documents?q=` | lifecycle folders (ready, required_files, files, required_tags, tags) | folder readiness |64| `/api/messages?q=` | formal notice messages (quality, defects[], ack deadline, appeal info) | formal notice quality |65| `/api/notifications?q=` | notifications (ack deadlines, appeal instructions) | secondary notice evidence |66| `/api/audit?q=` and `?case_id=` | audit events (event type, actor, detail, owner, timestamp) | control result + scope selection |67| `/api/audit/<audit_id>` | single audit event detail | confirm one event |68| `/api/attachments/<id>` | attachment text content | rarely needed; case full detail already embeds attachment `content` |6970## Standard investigation SOP (endpoint calling order)7172For ANY task, run this base sequence first, then branch by archetype.73741. **Read the prompt + `answer_template.json` first.** Enumerate every output75 field and its `allowed_values`. You will ONLY emit values from those enums —76 never free-text. The template IS the contract.772. **Health check** (optional): `curl -s <remote-env-url>/health`.783. **Extract IDs** from the prompt (employee id `EMP-XXX`, case id `CASE-XXX`,79 opening id `REQ-XXX`). These become your `?q=` terms.804. **Fetch the employee profile summary**: `GET /api/employees?q=<EMP-XXX>`.81 Record `leave_balance_days`, `salary_band`, `status`, `hire_date`. This is82 the *profile* view — often stale; do NOT treat it as authoritative yet.835. **Fetch the ledger/assignment history**: `GET /api/payroll-ledgers?q=<EMP-XXX>`.84 This single endpoint returns BOTH `record_type: "Leave assignment"` and85 `record_type: "Salary assignment"` rows. Each row has `status`86 (Approved/Submitted/Draft/Superseded), `ledger_id`, `policy_name` /87 `base_salary`, `period`, `accrual_batch_id`.886. **Find the case(s)**: `GET /api/cases?q=<EMP-XXX>` (and `?q=<CASE-XXX>` if a89 case id was given).907. **Fetch FULL case detail**: `GET /api/cases/<case_id>`. This carries91 `approvals[]`, `attachments[]` (with embedded `content`), `comments[]`, and92 `audit_events[]`. This is your richest single source.938. **Branch by archetype** (see sections below) for documents, messages,94 recruitment, and audit-specific fetches.959. **Fetch policies**: `GET /api/policies` to confirm the controlling rule96 (leave precedence, payroll source, folder checklist, remote-work notice97 requirements). Cite the policy section that justifies each exclusion.9810. **Map every answer field** to a concrete record value (an ID, a status99 string, a number). If a field has no evidence, prefer the "clean/none/100 no_action" enum — do not invent.101102### Branch A — Onboarding closeout (leave + payroll)103104After the base sequence:105- Determine the **authoritative leave assignment**: among the106 `record_type: "Leave assignment"` rows, pick the one whose `status` is107 `Approved` (preferred) or `Submitted`, with the latest `updated_at` for the108 target `period` (2026). That row's `policy_name` = effective leave policy,109 `approved_leave_days` = annual days, `ledger_id` = assignment id.110- **Excluded leave ids** = every other leave-assignment row for that period:111 `Superseded` and `Draft` rows are ALWAYS excluded (LEAVE-SRC-001 §2.1).112- Determine the **authoritative payroll**: among `record_type: "Salary113 assignment"` rows, pick `status: "Submitted"`. Its `base_salary` and114 `ledger_id` are authoritative. `Draft` salary rows are excluded115 (PAY-SRC-001 §3.4).116- **Closeout gate**: check whether the employee has a case / document folder /117 formal notice with defects (run Branch B checks). If no case/doc/notice/audit118 exists for the employee, records are "clean".119 - clean + authoritative records → `closeout_action: approve_onboarding_close`,120 `approval_closeout_gate: approval_sufficient_when_records_clean`,121 `final_control_result: approve_closeout`.122 - folder or notice defective → `closeout_action:123 block_close_and_reissue_notice` (or `open_records_remediation` if only124 records/files are wrong), `final_control_result:125 hold_for_folder_and_notice_defects`, gate126 `approval_not_sufficient_when_folder_or_notice_defective`.127- Source labels: `leave_source: leave_assignment_history`,128 `leave_precedence_source: approved_assignment_current_period`,129 `payroll_source_status: submitted`.130131### Branch B — Policy-case folder + formal-notice review132133For a given `CASE-XXX`:134- `GET /api/cases/<CASE-XXX>` → read `approvals[]` (approver + decision +135 approval_id), `attachments[]` (folder-checklist content), `audit_events[]`.136- `GET /api/documents?q=<EMP or CASE or title>` → match the folder.137 `folder_ready = document.ready`. `missing_files = required_files - files`.138 `required_tag_present = (required_tags ⊆ tags)`.139- `GET /api/messages?q=<EMP or CASE>` → the formal decision message.140 `notice_quality = message.quality` ("valid"/"defective").141 `notice_defects = message.defects[]` (already enumerated by the API).142- `GET /api/audit?case_id=<CASE-XXX>` → pick the audit event whose `event`143 matches the scope: `notice.defect` or `folder.*` for document/notice144 findings.145- Decision mapping:146 - approval decision "Approved" + any folder/notice defect →147 `final_decision: approved_with_conditions` (or `held`), `next_action:148 block_close_and_reissue_notice`.149 - folder tag missing but files present → `folder_required_tag_action:150 add_required_tag`; tag present → `no_tag_action`.151 - notice defective → `notice_remediation_action: reissue_defective_notices`;152 clean → `no_notice_action`.153 - `closeout_blockers` = union of `missing_required_files`,154 `missing_required_tags`, `defective_formal_notice` — only list the ones that155 actually apply (do NOT list tags if the tag is present).156 - `evidence_source_order: approval_history_folder_notice_audit` when you used157 approvals + folder + notice + audit; `folder_notice_audit` if no approval158 history; `audit_only` if only audit exists.159 - `notice_evidence_source: message_notice_inspection` for formal decision160 messages from `/api/messages`; `notice_packet_inspection` for recruitment161 notice packets from `/api/recruitment`; `case_summary_only` only as a162 last resort.163 - `records_remediation_owner`: `Records` for missing folder files/tags;164 `People Ops Compliance` for notice/policy defects; `Payroll QA` for payroll.165 - `escalation_action: block_close_and_reissue_notice` when both folder and166 notice are defective; `open_records_remediation` when only records;167 `no_action` when clean.168 - `final_control_result: hold_for_folder_and_notice_defects` when any blocker;169 `approve_closeout` when clean.170171### Branch C — Recruitment reconciliation172173`GET /api/recruitment?q=<REQ-XXX>` returns one opening object with sub-arrays.174- **Candidates**: for each `candidates[]` row, `committee_decision` ∈ {Selected,175 Waitlisted, Rejected}. Bucket candidate ids accordingly:176 - `selected_candidate` = the Selected one **confirmed** by an entry in177 `offer_register[]` with `status: "accepted"`.178 - `waitlisted_candidates[]`, `rejected_candidates[]` = the rest.179- **Offer**: from `offer_register[]` matching the selected candidate:180 `offer_id`, `offer_base_salary`, `selected_offer_status` = offer `status`181 (accepted/draft/withdrawn/none).182- **Cost**: `recruitment_cost_total` = **sum of every `amount` in183 `cost_ledger[]`** (all line items, regardless of label). `cost_source:184 recruitment_cost_ledger`. Never use the case summary's cost figure if it185 differs from the ledger sum.186- **Notice follow-up**: `notice_packets[]` lists each non-selected candidate's187 required notice. `notice_followup_required[]` = candidate ids whose188 `status: "not_sent"`.189 - waitlisted + not_sent → `waitlisted_followup_action: send_waitlist_notice`.190 - rejected + not_sent → `rejected_followup_action: send_rejection_notice`.191 - If a waitlist notice was sent but is mislabeled/missing the waitlist status192 → `reissue_waitlist_notice_not_rejection`.193- **Payroll handoff** (PAY-SRC-001 §4.2): handoff is created ONLY after the194 selected candidate has an **accepted** offer; the handoff must be195 **submitted** (draft prechecks do NOT satisfy the gate).196 - offer accepted → `onboarding_handoff:197 create_submitted_assignment_after_acceptance`,198 `payroll_handoff_gate: accepted_offer_and_submitted_assignment`,199 `payroll_assignment_status_required: submitted_after_acceptance`,200 `draft_payroll_allowed: false`,201 `handoff_control_result: submitted_handoff_required_after_acceptance`.202 - no accepted offer → `onboarding_handoff: no_payroll_handoff`,203 `handoff_control_result: no_handoff_required`.204- Source labels: `candidate_status_source: interview_feedback_and_offer`,205 `candidate_outcome_control: committee_decision_with_offer_confirmation`,206 `notice_quality_source: notice_packet_inspection`,207 `offer_exclusion_reason_for_waitlisted: waitlisted_not_selected`.208- Arrays contain **candidate IDs only** (e.g. `CAND-DA-7701`), never names.209210### Branch D — Leave source precedence211212- Profile summary (`/api/employees`) gives `leave_balance_days` + an implied213 policy. The **approved leave assignment** in `/api/payroll-ledgers`214 (`record_type: "Leave assignment"`, `status: "Approved"`) is authoritative215 per LEAVE-SRC-001 §2.1.216- Apply precedence: an approved assignment **overrides** a stale profile217 summary when the ledger, policy document, and audit detail confirm it.218 - `precedence_source: approved_assignment_over_profile`,219 `leave_precedence_source: approved_assignment_current_period`,220 `profile_policy_ignored: true`,221 `effective_leave_policy` = assignment `policy_name`,222 `assignment_id` / `balance_days` = assignment `ledger_id` /223 `approved_leave_days`.224- **Audit selection**: include only `leave.*` audit events in the leave-scope225 decision (`supporting_audit_event_ids`). EXCLUDE adjacent `folder.*`,226 `notice.defect`, `payroll.*`, and `cross_module.*` events227 (`excluded_audit_event_ids`). `audit_scope:228 leave_source_precedence_only`.229- `audit_result`: echo the QA result in the audit `detail`230 (`profile_summary_stale` / `ready_with_monitoring` / `block_close`).231- `next_action: update_employee_summary` when the profile is stale but the232 assignment is clean; `open_records_remediation` when records are broken;233 `no_action` when already aligned.234235### Branch E — Payroll assignment + accrual readiness236237- Among `record_type: "Salary assignment"` rows, pick `status: "Submitted"`238 → `salary_assignment_id`, `base_salary`. `excluded_assignment_id` = the239 `Draft` row. `effective_date` = the assignment `period` start (e.g. period240 `2026-04` → `2026-04-01`; cross-check `updated_at`/`hire_date`).241- `accrual_ready`: read the `payroll.ready` audit event. If its `detail` says242 `ready_with_monitoring` and the submitted assignment `accrual_batch_id`243 matches the batch → `accrual_ready: true`, `accrual_batch_id` from the244 assignment row, `audit_event_id` = that audit id, `control_result:245 ready_with_monitoring`.246- `payroll_source_status: submitted`,247 `draft_exclusion_rule: exclude_draft_assignment`,248 `audit_scope: payroll_assignment_readiness`.249250## Business rules (derived from the policy documents)251252Fetch `/api/policies` and treat these as authoritative:253254### LEAVE-SRC-001 — Leave Source Precedence (owner: People Ops)255> "The latest approved or submitted leave assignment for the period controls.256> Draft, voided, and obsolete records are excluded even when profile summaries257> conflict."258259- Precedence order: **approved/submitted assignment > profile summary > case260 summary only**.261- Excluded leave ids = all `Draft`, `Superseded`/`Voided`, and obsolete262 assignment rows for the period — **even if** their day count matches or the263 profile disagrees.264265### PAY-SRC-001 — Payroll Assignment Source (owner: Payroll)266> "Use the current submitted salary assignment. Draft planning assignments do267> not affect payroll readiness or accrual checks." AND "Recruiting payroll268> handoff is created only after a selected candidate has an accepted offer. The269> handoff must be submitted; draft prechecks do not satisfy the assignment270> gate."271272- Submitted salary assignment controls `base_salary`. Drafts excluded from273 payroll readiness + accrual.274- Recruiting handoff: accepted offer required, AND the resulting assignment275 must be `submitted` (never draft).276277### POL-DOCS-2026 — Lifecycle Folder Checklist (owner: Records)278> "A folder is not ready unless all required files and required tags shown in279> the folder checklist are present."280281- `folder_ready = false` if ANY required file missing OR ANY required tag282 missing.283- `missing_files = required_files - files`; missing tags drive284 `folder_required_tag_action: add_required_tag`.285286### HR-POL-014 — Remote Work Policy §7.1 (owner: Legal Desk)287> International exceptions require "executive approval, time limits, tax288> equalization, VPN-only access, quarterly compliance review, appeal289> instructions, and acknowledgement deadline in the formal notice."290291- A formal notice is **defective** unless it contains BOTH appeal instructions292 AND an acknowledgement deadline (plus the other elements). The293 `/api/messages` `defects[]` array enumerates exactly which are missing.294- Folder must also contain the tax-equalization agreement file for exception295 cases.296297## Audit selection & scope rules298299Audit events carry an `event` type. Scope your decision to the matching events300and **exclude adjacent ones**:301302| `event` prefix/type | belongs to scope |303|---|---|304| `leave.*` (e.g. `leave.profile_mismatch`) | `leave_source_precedence_only` |305| `notice.defect` | `document_notice_findings_only` |306| `folder.*` (e.g. `folder.tag_missing`) | `document_notice_findings_only` |307| `payroll.*` (e.g. `payroll.ready`, `payroll.draft_excluded`) | `payroll_assignment_readiness` |308| `case.close_blocked` | the relevant defect scope (folder/notice) |309| `cross_module.escalation_package` | NONE — exclude from every single-scope decision |310311- `supporting_audit_event_ids` = in-scope events for THIS decision.312- `excluded_audit_event_ids` = out-of-scope events present on the same case313 (e.g. a `folder.tag_missing` event is excluded from a leave-scope decision).314- `audit_event_id` (singular) = the single primary event the decision rests on.315- `audit_result`: read the literal QA result phrase from the audit `detail`316 (`profile_summary_stale`, `ready_with_monitoring`, `block_close`).317318## Candidate outcome & cost rules319320- Outcomes come from `committee_decision` in `candidates[]`, **confirmed** by321 the `offer_register[]` for the selected candidate. `candidate_outcome_control:322 committee_decision_with_offer_confirmation`.323- `selected_offer_status` = the offer_register `status` for the selected324 candidate (`accepted` / `draft` / `withdrawn` / `none`).325- `offer_exclusion_reason_for_waitlisted: waitlisted_not_selected` (waitlisted326 candidates never get an offer id).327- `recruitment_cost_total` = **Σ all `cost_ledger[].amount`**. Sum every line;328 do not cherry-pick by label. `cost_source: recruitment_cost_ledger`.329- Arrays (waitlisted/rejected/notice_followup) hold **candidate IDs only**.330331## Common misjudgments & exclusion rules332333- **Don't trust the employee profile summary as authoritative.** It is334 frequently stale. The approved/submitted assignment in `/api/payroll-ledgers`335 wins (LEAVE-SRC-001). A matching number does NOT prove alignment — the policy336 name and audit must confirm.337- **Don't mix salary + leave rows.** `/api/payroll-ledgers` returns both338 `record_type` values in one list. Filter by `record_type` before deciding.339- **Don't include Draft/Superseded records** in the authoritative answer.340 Always list them in `excluded_*_ids`. Draft salary rows do not affect accrual341 readiness.342- **Don't list a tag blocker when the tag is present.** Compare343 `required_tags` ⊆ `tags` precisely. Only emit `missing_required_tags` in344 `closeout_blockers` if a required tag is actually missing.345- **Don't conflate notice defects.** Use the exact `defects[]` from346 `/api/messages`. A present ack deadline means `missing_ack_deadline` does NOT347 apply. Defect enum: `missing_ack_deadline`, `missing_appeal_instructions`,348 `missing_waitlist_status`, `missing_correct_policy`.349- **Don't include adjacent-scope audit events** in a single-scope decision.350 Exclude `folder.*`/`notice.defect` from leave scope; exclude `leave.*`/`payroll.*`351 from document/notice scope.352- **Don't route a payroll handoff before offer acceptance.** Draft prechecks353 never satisfy the gate. `draft_payroll_allowed: false`.354- **Don't sum cost from the case summary.** Always sum the `cost_ledger[]`355 amounts directly.356- **Don't put candidate names in arrays.** IDs only.357- **Don't free-text enums.** Every enum field must be a string copied verbatim358 from the task's `answer_template.json` `allowed_values`.359- **Don't treat an "Approved" case as closeable.** Approval is necessary but360 not sufficient: a folder or notice defect blocks closeout361 (`approval_closeout_gate: approval_not_sufficient_when_folder_or_notice_defective`).362- **Don't read test/train gold answers.** Solve only from the live read-only363 API + policies. Use only the documented read-only endpoints for evidence.364365## Exact answer fields (per archetype) — what each field must be366367**Onboarding closeout**: `employee_id`; `effective_leave_policy` (assignment368policy_name); `leave_source`; `annual_days`; `assignment_id`; `excluded_leave_ids`;369`payroll_assignment_id`; `base_salary`; `payroll_status`; `excluded_payroll_ids`;370`closeout_action`; `leave_precedence_source`; `payroll_source_status`;371`approval_closeout_gate`; `final_control_result`.372373**Policy-case review**: `case_id`; `final_decision`; `approval_authority`374(approver); `approval_event_id` (approval_id); `folder_ready`; `missing_files`;375`required_tag_present`; `notice_quality`; `notice_defects[]`; `audit_event_id`;376`supporting_audit_event_ids[]`; `excluded_audit_event_ids[]`; `audit_scope`;377`next_action`; `approval_closeout_gate`; `closeout_blockers[]`;378`evidence_source_order`; `folder_required_tag_action`; `notice_evidence_source`;379`escalation_action`; `records_remediation_owner`; `notice_remediation_action`;380`final_control_result`.381382**Recruitment**: `opening_id`; `selected_candidate`; `waitlisted_candidates[]`;383`rejected_candidates[]`; `offer_id`; `offer_base_salary`;384`recruitment_cost_total`; `notice_followup_required[]`; `onboarding_handoff`;385`candidate_status_source`; `candidate_outcome_control`; `selected_offer_status`;386`cost_source`; `notice_quality_source`; `waitlisted_followup_action`;387`rejected_followup_action`; `payroll_handoff_gate`;388`payroll_assignment_status_required`; `draft_payroll_allowed` (bool);389`offer_exclusion_reason_for_waitlisted`; `handoff_control_result`.390391**Leave precedence**: `employee_id`; `effective_leave_policy`; `assignment_id`;392`balance_days`; `precedence_source`; `profile_policy_ignored` (bool);393`audit_event_id`; `audit_result`; `next_action`; `leave_precedence_source`;394`supporting_audit_event_ids[]`; `excluded_audit_event_ids[]`; `audit_scope`.395396**Payroll accrual**: `employee_id`; `salary_assignment_id`; `base_salary`;397`effective_date`; `excluded_assignment_id`; `accrual_ready` (bool);398`accrual_batch_id`; `audit_event_id`; `control_result`; `payroll_source_status`;399`draft_exclusion_rule`; `audit_scope`.400401## Pre-submission checklist402403Before emitting the JSON answer, verify each item:4044051. **Shape** — the JSON matches `answer_template.json` field-for-field (no extra406 keys, no missing keys, correct types: string/int/number/bool/list).4072. **Enums exact** — every enum value is copied verbatim from the template's408 `allowed_values`; no synonyms, no casing changes, no free-text.4093. **Authoritative source chosen** — leave answer comes from the410 approved/submitted assignment (not the profile); payroll from the submitted411 assignment (not draft).4124. **Exclusions listed** — all Draft/Superseded leave + payroll IDs appear in413 the `excluded_*_ids` lists; none leak into the authoritative fields.4145. **Folder + notice checked** for the closeout gate — `folder_ready`,415 `missing_files`, `required_tag_present`, `notice_quality`, `notice_defects`416 all reflect the actual `/api/documents` + `/api/messages` evidence, not the417 case summary blurb.4186. **Audit scope clean** — `supporting_audit_event_ids` contains only in-scope419 events; adjacent-scope (and any `cross_module.*`) events are in420 `excluded_audit_event_ids`.4217. **Cost summed** — `recruitment_cost_total` equals the literal sum of every422 `cost_ledger[].amount` (re-add to confirm).4238. **Arrays are IDs** — candidate/waitlist/reject/notice arrays contain IDs,424 not names; empty arrays `[]` when nothing applies (do not omit the key).4259. **Control result consistent** — if any blocker exists, `final_control_result`426 is `hold_for_folder_and_notice_defects` and the gate is427 `approval_not_sufficient_when_folder_or_notice_defective`; if records are428 clean, it is `approve_closeout` with `approval_sufficient_when_records_clean`.42910. **No gold, no internal access** — nothing references evaluator430 internals or unseen answer keys; all evidence is traceable to a `GET` on431 the remote read-only API.