Crescent Finance Ops SOP
Use this skill to produce one JSON object from the active Finance Ops API. Treat the request memo and answer template as the contract. Do not copy training answers as constants or infer answers from branch/ensemble/production IDs alone.
First Pass
- Read only the task input payloads:
prompt.txt,payloads/environment_access.json,payloads/request_memo.json, andpayloads/answer_template.json. - Use
base_urlfromenvironment_access.json; call only endpoints listed inavailable_endpoints. - Fetch the full endpoint data, then filter client-side by IDs from
request_memo.json. - Build exactly the keys required by
answer_template.json; keep key names and nested shapes unchanged. - Keep calculations unrounded until the final JSON fields. Return JSON numbers, not strings.
For HTTP clients, the API returns raw JSON objects or arrays. Some shells wrap arrays during display; normalize to the raw array before calculating.
Rounding And Ordering
- Round currency and counts-derived currency ratios to 2 decimals.
- Round percent, growth, margin, and ratio fields to 4 decimals.
- Use decimal percentages, not display percentages:
0.0966, not9.66. - Round final per-field values only. Per-person category values and per-person totals may differ by a cent if category fields are rounded independently.
- Sort stable ID lists ascending unless a template says a rank is descending.
- Sort
per_musicianbymusician_id. - Sort
conflict_flagsalphabetically. - For rank ties, prefer stable ascending IDs unless the request/template states another tie-break.
Finance API
Endpoints:
/api/finance/branches: branch metadata withbranch_id,branch_name,region_id,region_name./api/finance/period-map: mapsperiodlabels such asM24tofiscal_year,month_number, andmonth_name./api/finance/accounts: account metadata with categories such asrevenue,cogs,sga,allocations, andoperating./api/finance/records: one row perbranch_idandaccount, with monthly values invalues.M#.
Finance formulas:
revenue = product_revenue + service_revenue.cogs = direct_materials_cogs + direct_labor_cogs.gross_margin = revenue - cogs.sga = sales_sga + admin_sga + occupancy_sga.allocations = shared_service_allocations.ebitda = gross_margin - sga - allocations.ebitda_margin = ebitda / revenue.arpu = revenue / active_customers, using summed monthlyactive_customersover the requested period set.sales_per_labor_headcount = revenue / labor_headcount, using summed monthlylabor_headcount.- Growth percent:
(current - prior) / prior.
Branch close workflow:
- Resolve
target_branch_id,close_period, andprior_periodfrom the memo. - Use the period map to identify current/prior months and fiscal-year period sets.
- Build the current-month income statement from the target branch.
- Compute month-over-month revenue variance from current vs prior period.
- Compute current fiscal-year branch metrics and prior fiscal-year comparison metrics.
- For region context, find the target branch region, list region branches ascending, sum region FY EBITDA, and rank the region by FY EBITDA among all regions descending.
- For branch rankings, compute each branch's fiscal-year revenue growth and ARPU; rank descending and report top branch IDs plus the target branch rank when requested.
Regional workflow:
- Filter branches by
target_region_id. - Aggregate all requested year metrics over every branch in the region.
- Compute
ebitda_marginandsales_per_labor_headcountonly for years requested by the template. - Rank region branches by FY EBITDA for
top_ebitda_branch_idandbottom_ebitda_branch_id. - Reconcile regional EBITDA to the sum of branch-level EBITDA; report
region_reconciliation_variancerounded to 2 decimals.
Compensation API
Endpoints:
/api/compensation/rate-book: current year, minimum weekly scale, pay type order, quarter weeks, seniority bands, title premium percentages, and business rules./api/compensation/rosters: one row per employee withensemble_id,weeks_by_quarter,years_of_service,title,overscale_weekly, andcombined_overscale_includes_title./api/compensation/scenarios: forecast growth assumptions by scenario and future year.
Current-year compensation workflow:
- Filter roster rows by
ensemble_id. - Preserve
pay_typesorder from the rate book. - For each employee and quarter, use that employee's
weeks_by_quarter; do not assume every quarter is 13 weeks. - Minimum scale:
minimum_weekly_scale * weeks. - Title premium:
minimum_weekly_scale * title_premium_pct[title] * weeks. - If
combined_overscale_includes_titleis true, do not add a separate title premium for that employee. - Seniority: choose the rate-book seniority band using
years_of_service, then multiply by weeks. - Overscale:
overscale_weekly * weeks. - Sum quarter totals, pay-type totals, annual total, roster count, and largest pay type by annual amount.
combined_overscale_employee_countcounts roster rows withcombined_overscale_includes_title: true.partial_quarter_employee_countcounts employees whoseweeks_by_quarterdiffers from the rate-bookquarter_weeksin any quarter.
Forecast workflow:
- Compute
currentexactly as the current-year workflow. - For
year_plus_1, add 1 year of service before selecting seniority bands. Apply scenario year-plus-1 growth to minimum weekly scale, overscale, and seniority weekly amounts. - For
year_plus_2, add 2 years of service before selecting seniority bands. Apply growth cumulatively: multiply year-plus-1 and year-plus-2 factors for minimum weekly scale, overscale, and seniority. - Title premium is based on the grown minimum weekly scale and the title premium percentage multiplied by the scenario
title_pct_multiplier. For year plus 2, compound the title multipliers. - Growth rates compare annual totals:
(year_plus_1 - current) / currentand(year_plus_2 - year_plus_1) / year_plus_1. largest_growth_pay_typeis the pay type with the largest relative growth from current to year plus 2, not simply the largest dollar total.
Payroll API
Endpoints:
/api/payroll/rate-book: service rates, premium percentages, service time limits, weekly guarantee, conflict thresholds, and payroll business rules./api/payroll/productions: productions withscheduleservices and rostered musicians.
Weekly payroll workflow:
- Filter productions by
production_id. - Count scheduled services by
service_typeforservice_counts; this is schedule count, not musician assignment count. - For each musician, use only services in
assigned_service_ids. - Base service categories:
performance: service rate for each assignedPerformance.audit: service rate for each assignedAudit.sound_check: service rate for assigned1hr Sound Checkor2hr Sound Check.rehearsal:Rehearsalhourly rate timesmax(duration_hours, 3).
- Apply the observed substitute convention when
substituteis true and the template includessubstitute_adjustment: add twoPerformanceservice-rate units assubstitute_adjustment, include the same amount in the musician'sperformancebase, and do not apply the weekly guarantee to that substitute. - Premiums are additive percentages on base service pay before vacation:
principalorlead:principal_or_lead.quartet:quartet.electronic:electronic.- concertmaster/title signal, if present in the roster:
concertmaster.
- Doubles are a separate
doublescategory: first extra instrument atfirst_double, each additional extra atadditional_double, applied to base service pay. - Weekly guarantee applies only to guaranteed regular players, not substitutes: if base service pay is below
weekly_guarantee, addweekly_guarantee - base_service_payasguarantee_adjustment. - Vacation applies only when
vacation_eligibleis true. Calculate it asvacation_pct * (base service pay + premium + doubles), excluding guarantee adjustments. - Per-musician
categoriesshould include nonzero rounded categories only. Compute each musiciantotalfrom unrounded components, then round. category_totalssums each category across musicians from unrounded components, then rounds.weekly_totalis the unrounded sum of musician totals, rounded once.top_paid_musician_idis the musician with the highest unrounded total.
Conflict flags:
REHEARSAL_EARLY_START: any rehearsal starts beforeconflict_thresholds.rehearsal_earliest_start.REHEARSAL_LATE_END: any rehearsal ends afterconflict_thresholds.rehearsal_latest_end.SERVICE_OVER_TIME_LIMIT: any service duration exceedsservice_time_limits[service_type].SOUND_CHECK_DURATION_MISMATCH: a named sound-check service duration does not match its listed time limit.
Final Validation
Before returning the answer:
- Confirm every required top-level key from
answer_template.jsonis present and no lookup-table training constants slipped in. - Confirm all IDs come from the active API records and memo filters.
- Confirm rank directions, list ordering, and conflict flag sorting match the template.
- Confirm subtotals were computed from unrounded numbers and rounded only for output fields.