Ron Bronson

Problems are designed

These are examples of my projects, from games to tools and system demos. They show how I use multi-agent orchestration and my own models to bring ideas to life.

MalloOregon HS Tennis Power RankingsPlay To ClinchSuperInningsViperballOccupant IndicesCap BuffetYou Go FirstPensulo CardsRating modelsSimulated worldsProbability enginesMechanism designMatchingScenario playMeasurement

Drag the marker along the techniques, or use the arrow keys.

Under the hood

Marginal Player Line

I wrote a blog post, How Do You Evaluate a (Baseball) Hall of Famer, after reading Michael Mountain’s idea of the marginal player. Count the Hall of Famers at a position, rank everyone there, and the marginal player is the one who would fill the last slot. I was curious what happens when the people the Hall recognizes don’t resemble the people our existing measures say had careers of comparable quality. This chart ranks every retired player at each position by and draws a line where the Hall’s own count runs out.

Career Index = JAWS ÷ Hall standard at the position × 100 the line = the Nth player, where N = Hall of Famers at the position
Source: Baseball Reference JAWS leaderboards for each position and its Hall of Fame list, pulled 8 November 2026. Hall standards are each position’s Hall of Fame average JAWS. People elected as managers or executives don’t count toward a position’s total. Players not yet eligible are left out.

You Go First match score

Scores are asymmetric. What you want, 10 chips across five traits, is scored against what they are, a behavioral quiz: 0.7 × + 0.3 × . Move the chips and both scores change.

score = 0.7 × alignment + 0.3 × temperature temperature = max(0, 100 − 2 × |quiz gap|)
Alex's score for Blake
0
Blake's score for Alex
0
Both scores have to reach 60 before a match is possible.
Source: heypbj/src/data/mockSimulation.ts (calculateCompatibilityScore, sample users Alex and Blake), src/lib/stableMatchingSimulator.ts.

You Go First: a week of matching

Swiping makes attention free, so a like tells you nothing and a few profiles get most of them. Everyone gets 15 picks a week in , and the other person sees the tier.

These are the app’s 14 test profiles in its simulator. Click a person to see who they picked.

People matched0
Average match score0

The textbook algorithm pairs all 14, but only by assuming everyone knows everyone and can propose without limit. Fifteen picks a week matched 12 by week 2.

Source: heypbj/src/lib/stableMatchingSimulator.ts and src/data/mockSimulation.ts, default seed.

Play To Clinch point engine

College tennis is a team sport: three doubles matches make one point, six singles matches are a point each, and the first team to four wins. My engine plays every point, so a small edge per point adds up over a match.

P(server wins rally) = logistic(0.9·Δrally + 0.36 first | 0.10 second + …)

Drag to change the skill gap, on the game’s 20-80 scale.

A wins a point (avg)50%
A holds serve50%
A wins a set50%
A wins the match50%
In a , every match is decided before the first one finishes. Clinching only changes the order you see results in.
Source: tennis-team-manager/engine/rally.py and match.py, NCAA dual format (best of three, no-ad, tiebreak sets). Point odds computed with the engine's own functions; match odds checked against 1,500 simulated matches (73.7% vs 73.7% at a 6-point gap).

Play To Clinch high school careers

The first high school model put seniors in 85.7% of spots. I compared that with six seasons of Oregon boys tennis, then rebuilt development around starting ability, career peak, annual growth, and actual playing time. JV matches count for half the of varsity, so five freshmen with the same ceiling can end up with very different careers.

gain = year's budget × playing time playing time: bench 0.55 · full JV 0.81 · varsity 1.00

Five freshmen from one generated roster, all with the same ceiling. Dashes mark each career peak. Change their playing time.

Who plays No. 1 singles, by grade: Oregon boys over six seasons, and my sim before and after the change.

A player who is ready for No. 1 singles at 14 can now play there at 14. Change the playing-time control to see how four years of exposure alter the result.
Source: tennis-team-manager/app/jhsaa.py (_career_plan, career_ability, exposure odometer). Careers generated with the game's own functions (school "SCHOOL", entry 2040, seats 25, 4, 10, 8, 18); the port here matches career_ability exactly. No. 1 singles shares from "Rebuilding player development in a PC sports sim," August 2026.

Viperball kick decisions

Viperball has six downs to gain 20 yards, and the ball moves by running, , and . A live-play is worth 5 and a place kick 3. Every rule creates a strategy, so on a late down the coach weighs both kicks against going for it.

distance = (100 − field position) + 10 drop kick EV = 5 × P(drop) place kick EV = 3 × P(place)

Drag the marker to change the kick distance. Highlighted line: drop kick. Plain line: place kick.

Drop kick0%EV 0
Place kick0%EV 0

The call: GO FOR IT

Early downs gain about 2 yards against 20 to go, so drives reach fifth and sixth down, where this call gets made. A missed drop kick on the first five downs usually keeps the ball.
Source: viperball/engine/game_engine.py (_drop_kick_success, _place_kick_success, select_kick_decision). Shown with no clock pressure, no coaching traits, style aggression 1.0.

O27 college prospects

In , a prospect’s box-score grade and actual ceiling are different things. Each player has a hidden ceiling and a fixed lens on it, so the grade you see is ceiling times lens. Two scouting reports estimate that ceiling with their own errors. I kept the lens fixed through college: a hidden gem can still look ordinary when draft day arrives. The decision is whether to trust the box score or two imperfect scouting reports. I explain the model in the development write-up.

shown = round(ceiling × lens) lens 0.40–0.95 growth = min(rate × ceiling, cap) cap 15 → 4 scout = ceiling ± fog fog 7–31

Pick the one you’d draft, then sign them and the lens drops. The plain bar is the box score. The highlighted bar is the real grade.

Each player’s development rate is set when he’s generated. Nobody regresses. Everyone develops. The mystery is in who develops fast and how much they can hide it while getting there.
Source: hybrid-baseball/o27v2/college.py and college_potential.py. These four prospects were generated by the game's own generate_college_player and advance_one_year (seeds 330, 245, 20, 219); reports drawn with make_scouting_report. Players get three growth years before they can sign.

Oregon high school tennis rankings

Win-loss records ignore who you played and count every the same, so a coach could stack a lineup to look better. My flight-weighted score weights the eight flights from 1.00 down to 0.10, so depth counts and stacking stops paying. The blends it with an -style strength of schedule.

PI = 0.65·APR + 0.25·FQI + 0.10·oGS FQI = (Σ flight_score·opp_strength + 5×0.5) / (duals + 5)

Drag a bar to change a flight’s weight. All 121 ranked 2026 boys teams re-rank.

    Top 12 by Power Index, with each team’s change from the real weights.

    Grant is No. 1 in the rankings with a lower Power Index than Lincoln, .7399 to .7467. They tied 4-4 on April 22, Grant won the tiebreak on sets, and the head-to-head rule put Grant first.
    Source: or-tennis-data/generate_site.py (FLIGHT_WEIGHTS, TOSS weights, FQI with 5 phantom matches). FQI recomputed here matches the published value for all 121 teams.

    Context-Aware Agents: Designing for Alignment in AX

    February 23, 2025

    Agents operate within existing systems of rules, responsibilities, and decisions. When those relationships are missing from their context, agents can complete a task while misunderstanding its purpose. I examine how context, authority, and oversight shape agent behavior, and why judging task completion alone misses important consequences.

    Bringing AX to Life: Building a Content Schema for Browser Games Developed With Agents

    October 2026

    Building Coalition with AI agents exposed a recurring problem: game rules, interface copy, and narrative kept getting mixed together. I developed a content schema that gives each a defined place, so agents can work on dialogue, game mechanics, or interface language while preserving the relationships between them. The schema is available as a standalone package.

    When an agent should ask you

    January 15, 2026

    I adapted Judgment Routing for the person giving an agent a task. Uncertainty, stakes, authority, and novelty help route an action to execute, verify, approve, or refer. The person sets the limits, and each action leaves a receipt showing which permission allowed it.

    What counts as proof that an agent did its job?

    July 23, 2026

    A tool call proves an attempt, and a provider response establishes only what that provider confirmed. I separate the request, approval, attempted action, acknowledgment, and observed result so a missing confirmation stays visible rather than turning into a generic success message.