# Leave Program Authoring

Draft handwritten helpers for authoring company leave programs in Rippling
Functions.

This library is intended to be the customer-facing authoring surface for
company-specific leave policy. A customer should be able to write a Rippling
Function that imports this package, describes their company leave program, and
returns a constrained program result that Rippling can evaluate later.

This is not the leave engine itself. It does not register programs, hydrate
employee or payroll facts, run statutory programs, calculate payroll outputs, or
build leave plans. Those responsibilities stay in `rippling-main`.

## Intended Flow

```text
Customer Function imports @rippling/rippling-sdk/lib/leave-programs
  -> customer defines a company leave policy
  -> library emits CompanyLeaveProgramResult IR
  -> rippling-main validates and compiles the IR
  -> leave engine runs the company program alongside statutory programs
  -> leave engine composes the final leave plan and program outputs
```

The important boundary is that customer code describes policy intent. It does
not emit raw `LeaveProgramResult`, payroll directives, earning lines, balance
adjustments, or internal leave engine objects.

## What Customers Can Express

Company policies should be able to express a small set of leave-domain concepts:

- Applicability, such as employee country or jurisdiction.
- Eligibility, such as leave reason, parental relationship, tenure tiers, and
  required evidence.
- Entitlement, such as a paid leave bank in weeks, days, or hours.
- Pay intent, such as no company pay, fixed pay, percent of contractual pay, or
  make-whole top-up.
- Coordination with Rippling-owned statutory or insurance wage replacement
  programs.
- Admin requirements that Rippling can surface during review.

Pay is intentionally constrained. For example, a customer can say "top the
employee up to 100% of contractual weekly pay, net of CA-PFL." They cannot say
"create this payroll earning line with this internal earning code on this
payrun."

## What Rippling Still Owns

`rippling-main` remains responsible for:

- Program registration, activation, versioning, effective dates, and company
  scope.
- Deciding which statutory, insurance, and company programs run for a claim.
- Dependency ordering between statutory programs and company policies.
- Hydrating sanitized facts from HRIS, Payroll, PTO, Benefits, and other source
  systems.
- Validating the program result IR returned by customer code.
- Missing evidence handling.
- Payroll-safe pay phase construction, rounding, currency handling, earning type
  mapping, caps, and offsets.
- Conversion to internal `LeaveProgramResult`, directives, and leave plan
  outputs.

## Example: Common Recipe

Recipes are the simplest authoring lane. They cover common company policies
without requiring customers to write lower-level policy composition code.

```ts
import { defineCompanyLeaveProgram, parentalTopUpPolicy } from '@rippling/rippling-sdk/lib/leave-programs';

export default defineCompanyLeaveProgram(
  parentalTopUpPolicy({
    code: 'ACME_US_PARENTAL_TOPUP',
    displayName: 'Acme US parental top-up',
    jurisdiction: { country: 'US' },
    appliesTo: { employeeCountry: 'US' },
    qualifyingLeaveReasons: ['BONDING', 'PREGNANCY_DISABILITY'],
    paidWeeksByParentalRelationship: {
      birthingParent: 16,
      nonBirthingParent: 6,
      adoptionParent: 10,
      fosterParent: 10,
    },
    pay: {
      type: 'MAKE_WHOLE_TOPUP',
      targetPercentOfPay: 100,
      offsetByPrograms: ['CA-SDI', 'CA-PFL', 'INSURANCE-STD'],
    },
  }),
);
```

This emits policy IR that says:

- The program applies to US employees.
- Bonding and pregnancy disability are qualifying leave reasons.
- The paid leave bank depends on parental relationship.
- Company pay tops up statutory or insurance wage replacement to 100% of
  contractual weekly pay.
- The backend should coordinate this policy after `CA-SDI`, `CA-PFL`, and
  `INSURANCE-STD`.

## Example: Composable Builder

Builders are for company policies that do not fit a recipe cleanly, but still
use supported leave-policy primitives.

```ts
import { defineCompanyLeaveProgram, percentOfPay, weeks } from '@rippling/rippling-sdk/lib/leave-programs';

export default defineCompanyLeaveProgram({
  code: 'ACME_TENURE_PARENTAL_TOPUP',
  displayName: 'Acme tenure parental top-up',
  jurisdiction: { country: 'US' },
  dependsOn: ['CA-PFL'],

  evaluate(ctx) {
    const paidWeeks = ctx.employee.tenure.monthsAt(ctx.leave.startDate).match([
      { gte: 0, lt: 6, value: weeks(4) },
      { gte: 6, lt: 12, value: weeks(8) },
      { gte: 12, value: weeks(12) },
    ]);

    return ctx
      .policy()
      .eligibleWhen(ctx.employee.country.is('US'))
      .eligibleWhen(ctx.leave.reason.isParental())
      .grantPaidLeave(paidWeeks, { leaveType: 'EMPLOYER_PARENTAL_TOPUP' })
      .topUpTo(percentOfPay(100), {
        base: ctx.pay.contractualWeeklyPay,
        offsetBy: ctx.programs.wageReplacement(['CA-PFL']),
        earningType: 'EMPLOYER_TOPUP_MAKE_WHOLE',
      })
      .build();
  },
});
```

The builder still returns the same constrained `CompanyLeaveProgramResult` IR.
It does not expose raw payroll, PTO, HRIS, Benefits, ZObject, or leave-engine
records.

## Current Draft Scope

This package currently provides the SDK-side authoring shape only:

- `defineCompanyLeaveProgram`
- duration helpers such as `weeks`, `days`, and `hours`
- pay helpers such as `percentOfPay` and `fixedAmount`
- the `parentalTopUpPolicy` recipe
- constrained `CompanyLeaveProgramResult` types
- draft advanced and testing entry points

Backend registration, activation, validation, Function execution, and leave
engine compilation are intentionally out of scope for this package. Those pieces
must be implemented in `rippling-main` before a customer-authored Function can
run in production alongside Rippling-owned statutory programs.
