Taxi rule: canon vs every application path

Audit against current main (2026-10-21). The rule is canon’s; nothing here changes it. Fixes are in draft PR #1364 (worker, phone, Game Day, legacy roster workbench; canon wording in a separate commit for approval) and in draft #1353 (Front Office panel and Move to Taxi). Earlier side-by-side evidence: /taxi/evidence/.

Matrix

Rule (canon)Canon textWorker eligibility (/roster-workbench)Promote / demote write guardDesktop Front Office + #1353 panelLegacy roster workbench (fallback embed)Phone Taxi / Contracts / player sheetGame DayCap-free cut pricingTests / Rules data
UPS Rookie Draft round/year decide it, never NFL fields§A1 L97/L104, §B2 L344. L362 said NFL fields✓✓✓✓✓✓✓L362 corrected in the canon commit
Round 1 never; Round 2+ for the first 3 league years§A1 L97/L104/L106, §B2 L344/L360✓✓✓✓✓✓✓✓ (new boundary tests)
Activations 1–3 temporary, cumulative across the window§B2 L347–354, T2.4 L943✓n/a✓✓✓✓✓✓ (0,1,2,3,4 + pending tests)
Demotion allowed after each of activations 1–3§B2 L350, T2.4 L943✓✓✓✗ hid Demote after the 1st call-up (taxiDemoteLikelyForbidden) → fixed✓✓n/a✓ new
4th activation permanent; never eligible again§B2 L351, T2.4 L944, §G14 L1219✗ taxi_eligible ignored permanence (40 players) → fixed✗ checked used≥4 only; missed marked rows and prior-season promotions; let the demote through when D1 failed → fixed✓✓✗ a failed call-up read counted as “never promoted” → fixed✓✓✓ new
Cut/release ends it; re-acquiring doesn’t restore itNot in canon (Keith 2026-08-03, code comments only)✓✓ rule, ✗ an unreadable rosters read was reported as “dropped” → fixed✓ rule, ✗ panel said “released” for expired rookie deals outside the window → fixed✓✓✓✓gap → drafted
A trade keeps itNot in canon (same ruling)✓✓✓✓✓✓✓gap → drafted
Rookie who ended a prior season active/IR = permanent (pre-tracking)Not in canon (Keith 2026-05-19 / 2026-09-17)✓✗ not checked → fixed✓✗ guessed from acquisition year → replaced by the worker verdict✓✓✓gap → drafted
Cap-free cut follows ELIGIBILITY, not the slot (ruled 2026-10-21)§B2 L357–358, §D2 L692n/an/a✓✓✓✓✗ exempted the taxi slot alone and charged an eligible player cut from the active roster without call-ups → fixed: the one rule decides (eligible → $0; not eligible → normal formula even on taxi; unknown → held)✓
Owner-facing copy / Rules dataRules data is generated from canonn/an/an/an/an/a✗ said “UPS draft R2–5” → fixedn/aregenerated with the drafted clarification

One shared result

worker/src/taxi_rule.js decides eligibility; site/shared/taxi_rule.js is the same body, byte for byte (a test regenerates and compares it). /roster-workbench sends the verdict as taxi_status (eligible / reason / call-ups left / can_demote / whether the next promote is the permanent 4th). The demote write guard, the Front Office, Game Day and the legacy workbench read it; the phone, which reads MFL’s rosters directly, computes the same verdict from the shared file. Anything unreadable is “Unknown” with no Demote — never a guess.

Players whose displayed eligibility changes (2026-10-20 rosters, 481 players)

Canon clarification (drafted, for your approval; documents existing rulings only)

Resolved by your 2026-10-21 ruling

  1. §B2 L361 / L363 (“MFL natively handles taxi eligibility”, MFL flag / NFL fields authoritative): replaced — UPS Rookie Draft history and the shared resolver are authoritative; MFL doesn’t enforce the three-activation budget.
  2. T5.2 vs §D2: T5.2 kept; §D2, the drop pricing and every surface now give the cap-free cut to any player still taxi-eligible immediately before the cut, wherever he sits. One player’s price changes today: Jacob Rodriguez (17586, 0007), cap-free now. Release package: /release/.

Data note (not a rule conflict): the call-up counter keeps counting active weeks after a player is permanent or past the window (58 players above 4, up to 34). Eligibility is unaffected: they read “permanently promoted”.