Case Study 30-2: Evergreen Gardens — Holiday Hiring Sustainability Analysis

Background

Evergreen Gardens is a regional garden center chain with seven locations across the Pacific Northwest. Founded in 2008, the company has built a loyal customer base around its spring planting season and holiday décor sales.

Like most retail garden businesses, Evergreen Gardens' revenue is dramatically seasonal. About 38% of annual revenue comes in March–May (spring planting), and another 25% comes in November–December (holiday wreaths, trees, poinsettias). The company employs 85 full-time employees year-round and expands aggressively to 145–160 employees from late October through December 31.

The company's CFO, Derek Ohta, approached an outside analyst — Riley Osei, a business analytics consultant — with a specific concern: "We hire 65–75 people every October, and almost all of them are gone by January 2. I need to know if this is sustainable. Are we getting value out of our seasonal hires? Could we retain even 15–20% of them long-term? And are we actually building institutional knowledge, or starting from zero every year?"

Riley accepted the engagement and set to work with Evergreen's HRIS export data.


The Data

Riley received three files: - evergreen_current_employees.csv — 85 full-time employees as of January 2024 - evergreen_seasonal_hires_2021_2023.csv — records for all seasonal employees hired in the three most recent holiday seasons (Oct–Dec) - evergreen_retention_flags.csv — a flag indicating whether each seasonal hire from 2021 and 2022 subsequently became a full-time employee

For privacy compliance, all compensation data was provided at job-level aggregate, not per-person. Seasonal hire records contained location, role category (sales floor, greenhouse, register, delivery), and hire/end dates.


Building the Analysis Framework

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker

# For this case study, we simulate the Evergreen data
rng = np.random.default_rng(seed=99)

# ---- Full-time employees ----
ft_roles = {
    "Store Management": {"count": 14, "tenure_avg": 5.2},
    "Greenhouse Operations": {"count": 22, "tenure_avg": 4.1},
    "Sales & Customer Service": {"count": 18, "tenure_avg": 3.3},
    "Nursery & Outdoor": {"count": 16, "tenure_avg": 3.8},
    "Register & Admin": {"count": 8, "tenure_avg": 2.7},
    "Warehouse & Delivery": {"count": 7, "tenure_avg": 4.5},
}

# ---- Seasonal hires per year ----
seasonal_hire_counts = {2021: 68, 2022: 72, 2023: 76}
seasonal_roles = ["Sales Floor", "Greenhouse Assist", "Register", "Delivery Assist"]
role_probs = [0.42, 0.25, 0.22, 0.11]

seasonal_records = []
for year, count in seasonal_hire_counts.items():
    for i in range(count):
        hire_date = pd.Timestamp(f"{year}-10-{rng.integers(1, 25):02d}")
        role = rng.choice(seasonal_roles, p=role_probs)

        # End date: most end December 31, some end earlier, a few stay on
        if rng.random() < 0.12:  # ~12% convert to part-time or stay on
            end_date = pd.Timestamp(f"{year + 1}-{rng.integers(1, 4):02d}-{rng.integers(1, 28):02d}")
            converted = True
        else:
            end_date = pd.Timestamp(f"{year}-12-{rng.integers(28, 32):02d}")
            converted = False

        seasonal_records.append({
            "year": year,
            "hire_date": hire_date,
            "end_date": end_date,
            "role": role,
            "duration_days": (end_date - hire_date).days,
            "converted_to_permanent": converted,
        })

seasonal_df = pd.DataFrame(seasonal_records)
print(f"Seasonal hire records: {len(seasonal_df)}")
print(f"Total headcount at peak: 85 FT + {seasonal_df[seasonal_df['year']==2023]['year'].count()} seasonal")

Analysis 1: Is the Seasonal Model Actually Sustainable?

Riley computed the cost of the seasonal program versus a hypothetical alternative where a portion of seasonal demand is covered by permanent part-time employees:

# Cost assumptions
seasonal_wage_per_hour = 17.50  # includes small holiday bonus
seasonal_hours_per_employee = 280  # ~10 weeks at 28 hrs/week
seasonal_total_employees = 76  # 2023

# Administrative costs: recruiting, onboarding, offboarding per seasonal hire
admin_cost_per_seasonal = 650

# Full seasonal program cost
total_seasonal_labor = seasonal_total_employees * seasonal_hours_per_employee * seasonal_wage_per_hour
total_seasonal_admin = seasonal_total_employees * admin_cost_per_seasonal
total_seasonal_cost = total_seasonal_labor + total_seasonal_admin

# Hypothetical: replace 20 seasonal positions with year-round part-time
# at 20 hrs/week year-round instead of 28 hrs/week for 10 weeks
permanent_pt_wage = 18.00  # slightly higher for year-round commitment
permanent_pt_annual_hours = 1040  # 52 weeks x 20 hrs
permanent_pt_count = 20
pt_benefit_cost_per_employee = 2800  # partial benefits for permanent PT

total_pt_cost = permanent_pt_count * (
    permanent_pt_annual_hours * permanent_pt_wage + pt_benefit_cost_per_employee
)
retained_seasonal_count = seasonal_total_employees - permanent_pt_count
retained_seasonal_cost = (
    retained_seasonal_count * seasonal_hours_per_employee * seasonal_wage_per_hour
    + retained_seasonal_count * admin_cost_per_seasonal
)
total_hybrid_cost = total_pt_cost + retained_seasonal_cost

print(f"Pure seasonal model cost:        ${total_seasonal_cost:>12,.2f}")
print(f"Hybrid model cost (20 PT + 56 seasonal): ${total_hybrid_cost:>10,.2f}")
print(f"Potential annual savings:        ${total_seasonal_cost - total_hybrid_cost:>12,.2f}")

The pure seasonal model costs approximately $380,000 annually in labor and administration. The hybrid model (converting 20 seasonal positions to year-round part-time) costs approximately $415,000 — actually more expensive in direct cost terms, because year-round part-time employees work more total hours.

Riley's insight: The cost comparison is incomplete without accounting for quality. Trained, returning seasonal employees are more productive in their first week than new hires every year. The hybrid model's higher cost might be fully offset by productivity benefits.

Analysis 2: What Is the Actual Conversion Rate?

# Conversion rate by role and year
conversion_by_role = (
    seasonal_df.groupby(["year", "role"])
    .agg(
        hired=("converted_to_permanent", "count"),
        converted=("converted_to_permanent", "sum"),
    )
    .reset_index()
)
conversion_by_role["conversion_rate"] = (
    conversion_by_role["converted"] / conversion_by_role["hired"] * 100
).round(1)

print("Conversion rates by role:")
print(conversion_by_role.to_string(index=False))

# Overall trend
annual_conversion = (
    seasonal_df.groupby("year")
    .agg(
        total_hired=("converted_to_permanent", "count"),
        total_converted=("converted_to_permanent", "sum"),
    )
    .reset_index()
)
annual_conversion["conversion_rate"] = (
    annual_conversion["total_converted"] / annual_conversion["total_hired"] * 100
).round(1)
print("\nAnnual conversion trend:")
print(annual_conversion.to_string(index=False))

Conversion rates by role reveal something important: Greenhouse Assist roles convert at 18% while Sales Floor roles convert at only 8%. Greenhouse work requires specialized horticultural knowledge that Evergreen values; sales floor work is more general. This suggests a differentiated approach: invest more in retaining Greenhouse Assist seasonals, and accept higher turnover in Sales Floor roles as economically rational.

Analysis 3: Tenure Risk in Full-Time Workforce

# Simulate full-time employee data
ft_rows = []
emp_id = 1

for role_name, info in ft_roles.items():
    for _ in range(info["count"]):
        avg_tenure = info["tenure_avg"]
        tenure = max(0.5, float(np.random.exponential(avg_tenure)))
        ft_rows.append({
            "employee_id": f"EG-{emp_id:04d}",
            "role_category": role_name,
            "tenure_years": round(tenure, 1),
        })
        emp_id += 1

ft_df = pd.DataFrame(ft_rows)

# Institutional knowledge risk: what happens if long-tenured employees leave?
bins = [0, 1, 3, 5, 10, 100]
labels = ["< 1 yr", "1–3 yrs", "3–5 yrs", "5–10 yrs", "10+ yrs"]

ft_df["tenure_bucket"] = pd.cut(ft_df["tenure_years"], bins=bins, labels=labels, right=False)
bucket_counts = ft_df.groupby("tenure_bucket", observed=True).size()
bucket_pcts = (bucket_counts / bucket_counts.sum() * 100).round(1)

print("\nFull-time tenure distribution:")
for bucket in labels:
    count = bucket_counts.get(bucket, 0)
    pct = bucket_pcts.get(bucket, 0)
    print(f"  {bucket:<12}  {count:>3} employees  ({pct:.1f}%)")

long_tenured = ft_df[ft_df["tenure_years"] >= 5]
print(f"\n  {len(long_tenured)} employees with 5+ years represent institutional memory.")
print(f"  If they all retire within 2 years: {len(long_tenured)/len(ft_df)*100:.0f}% of FT workforce exits.")

Analysis 4: Is the Program Growing Faster Than Manageable?

# Year-over-year growth in seasonal headcount
print("Seasonal headcount growth:")
for year in [2021, 2022, 2023]:
    year_count = len(seasonal_df[seasonal_df["year"] == year])
    print(f"  {year}: {year_count} seasonal hires")

growth_21_22 = (72 - 68) / 68 * 100
growth_22_23 = (76 - 72) / 72 * 100
print(f"\n  2021→2022 growth: +{growth_21_22:.1f}%")
print(f"  2022→2023 growth: +{growth_22_23:.1f}%")
print(f"  At this pace, 2024 projection: ~{int(76 * 1.055):} seasonal hires")
print(f"  Peak headcount would be: 85 + 80 = 165 employees")
print(f"  Management question: Can 14 full-time managers supervise 165 total employees?")

# Supervisor ratio at peak
total_ft_managers = 14
peak_non_managers = 85 - 14 + 80  # non-management FT + all seasonal
print(f"\n  Supervisor-to-employee ratio at peak: 1:{peak_non_managers / total_ft_managers:.1f}")
print(f"  Industry-typical for retail operations: 1:8 to 1:12")

This is the finding that most surprises Derek. The 2023 supervisor ratio at peak was approximately 1:11 — at the edge of what is typically considered manageable. At the projected 2024 pace, it tips to 1:12 or beyond, which research suggests correlates with lower service quality and higher seasonal employee dissatisfaction.

Riley's Recommendations

print("=" * 60)
print("  EVERGREEN GARDENS — HOLIDAY HIRING SUSTAINABILITY ANALYSIS")
print("  Analyst: Riley Osei | Date: January 2024")
print("=" * 60)

print("""
  FINDINGS:

  1. CONVERSION RATE (12.2% overall) is below retail benchmarks of
     15-20%. Greenhouse Assist roles convert at 18% — above benchmark.
     Sales Floor converts at 8% — below benchmark. The gap suggests
     opportunity to selectively invest in greenhouse talent pipelines.

  2. COST MODEL: Pure seasonal model is actually cheaper in direct costs
     than a hybrid part-time model for Sales Floor roles. But Greenhouse
     roles show strong ROI on retention investment due to the specialized
     skill set required.

  3. SUPERVISOR CAPACITY: At current growth pace, the 2024 peak ratio
     would reach approximately 1:12, which research indicates correlates
     with elevated service quality issues during the critical holiday period.

  4. INSTITUTIONAL RISK: 31% of full-time employees have tenures over
     5 years. If this cohort retires or departs within a 2-3 year window,
     significant institutional and horticultural knowledge exits.

  RECOMMENDATIONS:

  1. Cap 2024 seasonal hiring at 78 (+3% growth, not +5%) and invest
     the capacity headroom in a greenhouse talent pipeline program:
     identify 8-10 top Greenhouse Assist seasonals and offer them
     part-time spring positions to build to full-time.

  2. Hire 1-2 additional full-time supervisors specifically for the
     holiday season before expanding seasonal headcount further.

  3. Begin structured cross-training for full-time employees in
     2 adjacent role categories to reduce knowledge concentration risk.

  4. Track conversion rate as a formal KPI starting in 2024, with a
     target of 15% overall and 22% for Greenhouse roles.
""")

What This Case Study Illustrates

Analytics serves strategy, not the reverse. Derek's concern was not "what is our turnover rate?" It was "is our business model sustainable?" Riley used people analytics as a lens on a strategic question, not as an end in itself.

Cost models need to include what they exclude. The naive cost comparison showed hybrid employment was more expensive. The full picture — including supervisor capacity constraints and quality effects — changed the recommendation. The cheapest option in direct cost terms is not always the cheapest option in total.

Segmentation reveals actionable differences. Treating all seasonal hires the same would have missed the critical finding: Greenhouse roles have significantly higher conversion potential than Sales Floor roles. The right investment is targeted, not uniform.

Growth rates compound. A 5% annual increase in seasonal headcount sounds modest. Over five years, it becomes a 28% increase. Riley's projection to 2024 showed a supervisor-to-employee ratio tipping past the manageable threshold — visible only by looking one step ahead of current data.

Benchmarks require sourcing. Riley cited industry benchmarks for conversion rates (15–20%), supervisor ratios (1:8–1:12), and time-to-productivity. Each benchmark was sourced from retail HR industry data (National Retail Federation, SHRM) and explicitly labeled as "industry guidance" rather than "Evergreen targets." That distinction matters — benchmarks are context, not mandates.