# Peopleops Console Lifecycle Control

> Solve ERP HR "PeopleOps Console" lifecycle/leave/payroll/policy-case/recruitment/document/notice/audit tasks by cross-referencing the remote HTTP API and applying source-precedence, folder-readiness, notice-defect, and audit-scope business rules to emit normalized-label JSON.

- Skill: `prism-shadow/peopleops-console-lifecycle-control` (Agent Skill)
- Install (CLI): `npx skillmds@latest add prism-shadow/peopleops-console-lifecycle-control`
- Raw SKILL.md: https://api.skillmd.com/api/skills/prism-shadow/peopleops-console-lifecycle-control/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: prism-shadow (https://skillmd.com/u/prism-shadow)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/prism-shadow/peopleops-console-lifecycle-control

---


# PeopleOps Console — Lifecycle Control Skill

You answer HR lifecycle questions for the PeopleOps Console by reading a remote
HTTP API and returning a single JSON object that matches the task's
`answer_template.json`. Every value must be either a fact pulled from the API or
the exact **normalized business label** allowed by the template enum. Never write
free-text explanations into label fields, and never invent IDs.

## 1. How to use the remote API

Base URL is given in the environment-access doc. No auth (login text in prompts is
flavor). All responses are JSON. Use HTTP GET; `q=` is a case-insensitive
substring filter over scalar fields, so `q=EMP-118`, `q=CASE-445`, `q=REQ-DA-77`
are effective lookups; omit `q` to list a whole collection.

Endpoints you will rely on:
- `/api/summary`, `/api/manifest` — counts, departments, sanity check.
- `/api/employees?q=` — profile (department, salary_band, `leave_balance_days`, status).
- `/api/payroll-ledgers?q=` — BOTH leave assignments AND salary assignments AND
  accrual/adjustment rows live here, keyed by `record_type`, `status`, `period`.
- `/api/policies` / `/api/policies/{id}` — the governing precedence rules (read these first; they state the tie-break logic verbatim).
- `/api/cases?...` (summaries) and `/api/cases/{id}` (FULL: approvals,
  attachments, comments, embedded audit_events, folder/notice detail).
- `/api/documents?q=` — folders with `files`, `required_files`, `tags`,
  `required_tags`, `ready`.
- `/api/messages?q=` — formal notices delivered as messages, with `quality` and `defects`.
- `/api/recruitment?q=` — openings with `candidates`, `offer_register`,
  `cost_ledger`, `notice_packets`, `payroll_precheck_records`.
- `/api/audit?q=&case_id=` and `/api/audit/{id}` — QA events; their `detail`
  text is frequently the authoritative tie-breaker (see below).

**Workflow for any task:** (1) read the prompt + answer_template to learn which
fields and which enum labels are in play; (2) pull the focal entity by id across
employees, payroll-ledgers, cases/{id}, documents, messages, recruitment, audit;
(3) read the policy doc(s) named in the case's `policy_refs`; (4) apply the rules
below; (5) emit JSON matching the template, using only allowed enum values and
correct types (integers as integers, lists as lists, booleans as booleans).

## 2. Core source-precedence rules

These come from the policy documents and are the heart of most tasks.

**Leave source precedence (LEAVE-SRC-001).** The latest **approved or submitted**
leave assignment for the period controls entitlement. Draft, voided, superseded,
and obsolete rows are EXCLUDED even when the employee profile summary disagrees.
- `leave_source` = `leave_assignment_history` (not `employee_profile_summary`).
- `leave_precedence_source` = `approved_assignment_current_period`
  (NOT `profile_summary_current_period`).
- When a case is specifically a profile-vs-assignment dispute:
  `precedence_source` = `approved_assignment_over_profile`,
  `profile_policy_ignored` = `true`, and the next action is to update the stale
  summary (`update_employee_summary`).
- List every excluded leave ledger id (draft + superseded/obsolete) in the
  excluded-leave field.

**Payroll/salary source (PAY-SRC-001).** Use the **current submitted** salary
assignment for base salary and readiness. Draft planning assignments do NOT count
and must be excluded; superseded rows are excluded too.
- `payroll_status` / `payroll_source_status` = `submitted`.
- `draft_exclusion_rule` = `exclude_draft_assignment`; `draft_payroll_allowed` = `false`.
- Put the draft (and any superseded) salary id in the excluded-payroll field.

**Accrual readiness.** A submitted salary assignment is accrual-ready when it
matches the relevant accrual batch (the assignment row carries the
`accrual_batch_id`, and an audit `payroll.ready` event confirms it).
- `accrual_ready` = `true` in that case; take `accrual_batch_id` from the
  submitted assignment row.
- `control_result` for payroll readiness = `ready_with_monitoring` — NOT
  `approve_closeout` (that label is reserved for onboarding-close with clean records).

## 3. Folder readiness, missing files, and required tags

From the lifecycle folder checklist (POL-DOCS-2026): a folder is ready ONLY when
**every** required file AND **every** required tag is present.
- `folder_ready` = the document's `ready` flag; verify it by diffing
  `required_files` minus `files` and `required_tags` minus `tags`.
- `missing_files` = required_files not present in files (exact filenames).
- `required_tag_present` = whether the required tag(s) are all in `tags`.
- If the required tag is already present, `folder_required_tag_action` =
  `no_tag_action`; only use `add_required_tag` when a required tag is missing.
- `closeout_blockers` is driven by the actual gaps: include
  `missing_required_files` only if a file is missing, `missing_required_tags`
  only if a tag is missing, `defective_formal_notice` only if the notice is
  defective. Do not list a blocker that does not apply (e.g. tag present ⇒ no
  `missing_required_tags`).

## 4. Formal-notice quality and defect codes

Notices are inspected from the **notice packet** (recruitment `notice_packets`)
or the message record (`/api/messages`), which carry `quality` and `defects`.
- `notice_quality` = `valid` or `defective` straight from the record.
- `notice_quality_source` / `notice_evidence_source` = `notice_packet_inspection`
  (assess the formal notice packet; this is the right label even when the notice
  is delivered through a message channel — do not pick `message_notice_inspection`
  or `case_summary_only`).
- Defect codes come from the controlled vocabulary and must match the record's
  `defects` exactly: `missing_ack_deadline`, `missing_appeal_instructions`,
  `missing_waitlist_status`, `missing_correct_policy`. Copy the listed defects;
  do not infer extra ones.
- Remediation: a defective notice ⇒ `reissue_defective_notices` /
  `block_close_and_reissue_notice`. A waitlist notice that was wrongly omitted or
  mislabeled is reissued as a waitlist notice, not a rejection
  (`reissue_waitlist_notice_not_rejection`); a not-yet-sent waitlist/rejection
  notice is a fresh send (`send_waitlist_notice` / `send_rejection_notice`).

## 5. Approval / closeout gate and final control result

Approval alone is not enough to close.
- `approval_closeout_gate` = `approval_sufficient_when_records_clean` ONLY when
  the folder is ready AND the notice is valid (no defects). If any folder file/tag
  gap or notice defect exists, it is
  `approval_not_sufficient_when_folder_or_notice_defective`.
- `final_control_result`:
  - clean records (no folder/notice defect) ⇒ `approve_closeout`;
  - any folder/notice defect ⇒ `hold_for_folder_and_notice_defects`;
  - `ready_with_monitoring` is the payroll-readiness verdict, not an
    onboarding-close verdict.
- `closeout_action` / `next_action` follows the same logic: clean ⇒
  `approve_onboarding_close`; notice defect ⇒ `block_close_and_reissue_notice`; a
  missing required FILE is a records issue ⇒ `open_records_remediation`. When both
  a file is missing and the notice is defective, the immediate `next_action`
  addresses the notice (`block_close_and_reissue_notice`) while the
  `escalation_action` opens records remediation for the file
  (`open_records_remediation`) — these two fields can legitimately differ.
- `evidence_source_order` for a closeout review =
  `approval_history_folder_notice_audit` (approvals first, then folder, notice, audit).
- `records_remediation_owner` for a single case's missing folder file = `Records`
  (owner of folder/required evidence). `People Ops Compliance` owns the
  cross-module escalation package, not single-case file remediation.

## 6. Audit correlation and scope (very point-sensitive)

Each task has ONE audit scope; set `audit_scope` to match the task:
`leave_source_precedence_only`, `payroll_assignment_readiness`, or
`document_notice_findings_only`.

- `audit_event_id` / `supporting_audit_event_ids` = the audit event(s) whose
  `event`/`detail` are IN the current scope (e.g. the `leave.profile_mismatch`
  event for a leave task, the `payroll.ready` event for an accrual task, the
  `notice.defect` / folder event for a doc/notice task).
- `excluded_audit_event_ids` = **same-case** audit events that belong to a
  DIFFERENT scope and must be kept out of this decision (e.g. on a leave-scope
  task, exclude the same case's folder/notice audit event). Rules learned the
  hard way:
  - Do NOT dump every other case's audit ids into the exclusion list — only
    same-case, out-of-scope events belong there.
  - If the case has no other-scope audit event, `excluded_audit_event_ids` = `[]`.
  - Omitting a genuinely adjacent same-case out-of-scope event costs points, so
    always check the full `/api/cases/{id}.audit_events` list for siblings.
- **The audit `detail` text is an authoritative tie-breaker.** When a leave or
  payroll task has several "Approved"/"Submitted" ledger rows, the audit QA detail
  often names the controlling assignment id and the resulting balance/policy —
  trust that named record rather than guessing the latest or largest row.
- The cross-module escalation package event lists the related event ids and the
  control owner; treat it as the routing record, not as in-scope evidence for a
  single entity's leave/payroll decision.

## 7. Recruitment reconciliation

- Candidate outcomes come from committee decision + offer confirmation:
  `candidate_status_source` = `interview_feedback_and_offer`,
  `candidate_outcome_control` = `committee_decision_with_offer_confirmation`.
  Map `committee_decision` to selected / waitlisted / rejected arrays
  (arrays hold candidate IDs only).
- The selected candidate's offer status comes from `offer_register`
  (`accepted` / `draft` / `withdrawn`); `offer_id` and `offer_base_salary` from
  that register row.
- `recruitment_cost_total` = **sum of this opening's `cost_ledger` items only**.
  Do not add other openings' ledgers. `cost_source` = `recruitment_cost_ledger`.
- Notice follow-up: list candidates whose notices are not yet sent / are
  defective; choose send vs reissue per §4.
- Waitlisted candidates are excluded from the payroll/offer handoff because they
  have `no_accepted_status_or_offer`.
- Payroll handoff gate (PAY-SRC-001): a handoff is created only after a selected
  candidate has an **accepted** offer, and the handoff/assignment must be
  **submitted** — a draft precheck never satisfies the gate
  (`draft_payroll_allowed` = `false`). When an offer is accepted, a submitted
  handoff/assignment is required after acceptance; when no offer is accepted,
  there is no handoff. (The exact normalized label among the close gate/status
  variants depends on the template's enum wording — read the allowed values and
  pick the option that states "submitted, after acceptance"; verify against the
  policy text rather than assuming.)

## 8. Output discipline / common misjudgments that cost points

- Return ONLY the JSON object matching the template — no markdown, no commentary.
- Use the EXACT allowed enum strings; respect types (int vs number vs string,
  list vs scalar, boolean not string).
- Dates in dedicated date fields are usually `YYYY-MM-DD` (derive from
  `period`/`updated_at`), not full timestamps.
- Authoritative state spans modules: never answer a leave/payroll question from
  the employee profile or a case summary alone — confirm with the ledger, the
  policy doc, and the audit detail.
- Mistakes that previously lowered scores, now avoided:
  - using `profile_summary` precedence instead of `approved_assignment`;
  - calling a payroll-readiness result `approve_closeout` instead of `ready_with_monitoring`;
  - listing unrelated cases' audit ids as "excluded", or conversely forgetting to
    exclude a same-case out-of-scope audit event;
  - choosing `message_notice_inspection` instead of `notice_packet_inspection`;
  - assigning single-case file remediation to People Ops Compliance instead of Records;
  - summing cost ledgers across openings instead of the one opening in scope;
  - flagging `missing_required_tags` when the required tag is actually present.

NOTE: There is no judge or scoring API available at test time. Do not attempt to
call any feedback/scoring endpoint when solving real tasks — derive the answer
from the read-only PeopleOps API and the rules above.

