Discrete-Event Simulation Model
YC-Bench uses a discrete-event simulation architecture. The simulation clock advances in variable-sized jumps to the next scheduled event, rather than fixed timesteps.Event Types
Four event types drive the simulation (defined insrc/yc_bench/db/models/event.py:11):
Event Queue
Events are stored in thesim_events table with:
scheduled_at: when the event should firecompany_id: which company (always one company per run)event_type: one of the four types abovepayload: JSON metadata (e.g.,{"task_id": "uuid"})consumed: boolean flag — events are consumed after processingdedupe_key: prevents duplicate events during ETA recalculations
Time Advancement Algorithm
The core loop is implemented insrc/yc_bench/core/engine.py:120 (advance_time function).
High-Level Flow
The simulation stops at payroll to give the agent a chance to act before the next month’s expenses arrive. This is a critical checkpoint for cash flow decisions.
Progress Flushing
Progress flushing calculates work done by employees during a time window[t0, t1].
Formula (from src/yc_bench/core/progress.py:108)
For each active task, each domain requirement:
Throughput Splitting
The key mechanic: employees split throughput across active tasks.- Employee with 1 active task → contributes
base_rateper hour - Employee with 2 active tasks → contributes
base_rate / 2per hour to each - Employee with N active tasks → contributes
base_rate / Nper hour to each
Example
Employee Alice has:- Research rate: 5.0 units/hour
- Assigned to 2 active tasks: Task A and Task B
- Task A:
5.0 / 2 = 2.5units/hour - Task B:
5.0 / 2 = 2.5units/hour
- Task A:
+25units - Task B:
+25units
5.0 * 10 = 50 units (done in 20 hours). Instead, it takes 40 hours when split.
Payroll Mechanics
Payroll occurs at the start of each month (1st day, 9:00 AM business time).Payroll Calculation (from src/yc_bench/core/engine.py:50)
Bankruptcy Trigger
Ifcompany.funds_cents < 0 after payroll:
- Simulation inserts a
BANKRUPTCYevent at the current time - Event fires immediately
- Simulation terminates
- Final results are written to the rollout JSON
Bankruptcy is the most common failure mode in hard presets. Agents must maintain sufficient runway (typically 3–6 months of payroll).
Prestige Decay
Prestige decay is applied continuously during time advancement, proportional todays_elapsed.
Decay Formula (from src/yc_bench/core/engine.py:107)
Example
- Prestige decay rate:
0.005per day (default) - Monthly decay:
0.005 * 30 = 0.15 - 6-month decay:
0.005 * 180 = 0.9
5.0 left untouched for 6 months → 5.0 - 0.9 = 4.1.
A domain at prestige 2.0 left untouched for 6 months → 2.0 - 0.9 = 1.1 (floors at 1.0).
Event Processing Order
Tie-Breaking Rule (from src/yc_bench/core/engine.py:160)
When multiple events are scheduled at the same timestamp:
- Payroll fires first (start-of-day obligation)
- Events fire second
- Target time reached last
Event Handler Dispatch (from src/yc_bench/core/engine.py:74)
ETA Recalculation
Projection events (TASK_HALF_PROGRESS, TASK_COMPLETED) are recalculated whenever the task topology changes:
- Employee assigned to/unassigned from a task
- Task dispatched to active status
- Task completed or cancelled
Recalculation Trigger Points
| Agent Action | Recalculates ETAs for… |
|---|---|
task assign | All active tasks sharing the assigned employee |
task dispatch | The dispatched task + all active tasks sharing its assigned employees |
task cancel | All active tasks sharing the cancelled task’s employees |
| Task completion event | All active tasks (freed employees change global topology) |
ETA Solver (from src/yc_bench/core/eta.py:23)
For each active task:
Domains are worked in parallel: A task with 100 research units and 200 training units will complete when the slower domain (training) finishes.
Business Hours Calculation
Progress flushing uses business hours only. Nights and weekends are excluded.Business Hours Window (from src/yc_bench/core/business_time.py)
- Workday: 9:00 AM – 6:00 PM (9 hours)
- Weekends: Excluded (no work Saturday/Sunday)
- Holidays: Not modeled (every weekday counts)
Example
Time window: Friday 3:00 PM → Monday 11:00 AM- Friday 3:00 PM – 6:00 PM: 3 hours
- Saturday: 0 hours (weekend)
- Sunday: 0 hours (weekend)
- Monday 9:00 AM – 11:00 AM: 2 hours
- Total: 5 business hours
Progress Checkpoints
The agent is woken at progress milestones to observe task advancement. This provides data points to infer employee productivity.Default Milestones (from default.toml:97)
- 25%: Early checkpoint — detect if employees are underperforming
- 50%: Halfway — reassess deadline risk
- 75%: Final checkpoint before completion
- 100%: Task completed (success or fail based on deadline)
Milestone Event Emission (from src/yc_bench/core/eta.py:249)
Only the next upcoming milestone is scheduled. After it fires, the handler recalculates ETAs and schedules the following milestone.
Determinism and Reproducibility
Given:- Fixed
run_seed - Fixed world configuration (employee pool, task market, deadlines)
- Fixed agent command sequence
Sources of Non-Determinism (None)
- ❌ No floating-point randomness (all distributions evaluated at world generation)
- ❌ No wall-clock time dependencies
- ❌ No async/parallel execution
- ❌ No external API calls during simulation
Decimal for exact precision.
✅ All event timestamps are calculated from business-time arithmetic.
✅ Employee skill rates are fixed at world generation (seeded RNG).
Next Steps
Prestige System
Understand prestige levels, decay rates, and per-domain gating.
Task Management
Learn the task lifecycle: accept → assign → dispatch → complete.
Employee System
Explore employee tiers, hidden skill rates, and throughput splitting.
Scoring
Understand what makes a good run and how to interpret results.