Function bodies 688 total
main function · python · L21-L98 (78 LOC)scripts/cancel_duplicate_proposals.py
async def main(apply: bool) -> None:
import os
from sqlalchemy.ext.asyncio import create_async_engine
from pinwheel.db.engine import get_session
from pinwheel.db.repository import Repository
db_url = os.environ.get("DATABASE_URL", "sqlite+aiosqlite:///pinwheel.db")
engine = create_async_engine(db_url)
async with get_session(engine) as session:
repo = Repository(session)
# Find all submitted proposals in the active season
active_season = await repo.get_active_season()
if not active_season:
print("No active season found.")
return
submitted = await repo.get_events_by_type(
season_id=active_season.id,
event_types=["proposal.submitted"],
)
# Also get cancelled events to avoid double-cancelling
already_cancelled = await repo.get_events_by_type(
season_id=active_season.id,
event_types=["proposal.cancelled"],
)
seed function · python · L304-L351 (48 LOC)scripts/demo_seed.py
async def seed():
"""Create the demo league."""
engine = create_engine(DEMO_DB)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with get_session(engine) as session:
repo = Repository(session)
league = await repo.create_league("Portland Pinwheel League")
season = await repo.create_season(league.id, "Season 1")
team_ids = []
for t in TEAMS:
team = await repo.create_team(
season.id, t["name"],
color=t["color"],
color_secondary=t.get("color_secondary", "#ffffff"),
venue=t["venue"],
)
team_ids.append(team.id)
for name, archetype, attrs in t["hoopers"]:
await repo.create_hooper(
team_id=team.id,
season_id=season.id,
name=name,
archetype=archetype,
attributes=attrs,step function · python · L354-L397 (44 LOC)scripts/demo_seed.py
async def step(rounds: int = 1):
"""Run N rounds of simulation."""
engine = create_engine(DEMO_DB)
async with get_session(engine) as session:
repo = Repository(session)
# Find current season
from sqlalchemy import select
from pinwheel.db.models import SeasonRow
result = await session.execute(select(SeasonRow).limit(1))
season = result.scalar_one_or_none()
if not season:
print("No season found. Run 'seed' first.")
return
# Find what round we're on
current_round = 0
for rn in range(1, 100):
games = await repo.get_games_for_round(season.id, rn)
if games:
current_round = rn
else:
break
for i in range(rounds):
rn = current_round + 1 + i
result = await step_round(repo, season.id, round_number=rn)
print(f"Round {rn}: {len(result.games)} games, {len(result.reports)status function · python · L400-L452 (53 LOC)scripts/demo_seed.py
async def status():
"""Print current league state."""
engine = create_engine(DEMO_DB)
async with get_session(engine) as session:
repo = Repository(session)
from sqlalchemy import select
from pinwheel.db.models import SeasonRow
result = await session.execute(select(SeasonRow).limit(1))
season = result.scalar_one_or_none()
if not season:
print("No season found.")
return
# Count rounds played
all_results = []
last_round = 0
for rn in range(1, 100):
games = await repo.get_games_for_round(season.id, rn)
if not games:
break
last_round = rn
for g in games:
all_results.append(
{
"home_team_id": g.home_team_id,
"away_team_id": g.away_team_id,
"home_score": g.home_score,
"away_score": propose function · python · L455-L494 (40 LOC)scripts/demo_seed.py
async def propose(text: str):
"""Submit a governance proposal (demo shortcut)."""
engine = create_engine(DEMO_DB)
async with get_session(engine) as session:
repo = Repository(session)
from sqlalchemy import select
from pinwheel.db.models import SeasonRow
result = await session.execute(select(SeasonRow).limit(1))
season = result.scalar_one_or_none()
if not season:
print("No season found.")
return
import uuid
proposal_id = f"p-{uuid.uuid4().hex[:8]}"
await repo.append_event(
event_type="proposal.submitted",
aggregate_id=proposal_id,
aggregate_type="proposal",
season_id=season.id,
governor_id="demo-governor",
team_id="demo-team",
payload={
"id": proposal_id,
"governor_id": "demo-governor",
"team_id": "demo-team",
"raw_text": text,
add_bench function · python · L498-L541 (44 LOC)scripts/demo_seed.py
async def add_bench(db_url: str | None = None):
"""Add 4th (bench) hooper to teams that only have 3."""
url = db_url or DEMO_DB
engine = create_engine(url)
async with get_session(engine) as session:
repo = Repository(session)
season = await repo.get_active_season()
if not season:
print("No season found.")
return
teams = await repo.get_teams_for_season(season.id)
added = 0
for team_row in teams:
if len(team_row.hoopers) >= 4:
print(f" {team_row.name}: already has {len(team_row.hoopers)} hoopers, skipping")
continue
# Find matching TEAMS entry
team_data = None
for t in TEAMS:
if t["name"] == team_row.name:
team_data = t
break
if not team_data or len(team_data["hoopers"]) < 4:
print(f" {team_row.name}: no bench player defined, skipping")regen_report function · python · L544-L626 (83 LOC)scripts/demo_seed.py
async def regen_report(db_url: str | None = None):
"""Regenerate the simulation report for the latest round."""
url = db_url or DEMO_DB
api_key = os.environ.get("ANTHROPIC_API_KEY", "")
if not api_key:
print("Error: ANTHROPIC_API_KEY not set")
return
engine = create_engine(url)
async with get_session(engine) as session:
repo = Repository(session)
season = await repo.get_active_season()
if not season:
print("No active season found.")
return
latest_round = await repo.get_latest_round_number(season.id)
if not latest_round:
print("No rounds played yet.")
return
print(f"Regenerating simulation report for season={season.name} round={latest_round}")
# Build round_data from game results
games = await repo.get_games_for_round(season.id, latest_round)
if not games:
print("No games found for this round.")
returnRepobility · severity-and-effort ranking · https://repobility.com
main function · python · L629-L655 (27 LOC)scripts/demo_seed.py
def main():
if len(sys.argv) < 2:
print(__doc__)
return
cmd = sys.argv[1]
if cmd == "seed":
asyncio.run(seed())
elif cmd == "step":
n = int(sys.argv[2]) if len(sys.argv) > 2 else 1
asyncio.run(step(n))
elif cmd == "status":
asyncio.run(status())
elif cmd == "propose":
if len(sys.argv) < 3:
print("Usage: demo_seed.py propose 'your proposal text'")
return
asyncio.run(propose(" ".join(sys.argv[2:])))
elif cmd == "add-bench":
db = sys.argv[2] if len(sys.argv) > 2 else None
asyncio.run(add_bench(db))
elif cmd == "regen-report":
db = sys.argv[2] if len(sys.argv) > 2 else None
asyncio.run(regen_report(db))
else:
print(f"Unknown command: {cmd}")
print(__doc__)fix_enrollments function · python · L34-L135 (102 LOC)scripts/fix_enrollments.py
async def fix_enrollments(apply: bool = False) -> None:
db_url = os.environ.get("DATABASE_URL")
if not db_url:
print("ERROR: DATABASE_URL not set.")
sys.exit(1)
engine = create_engine(db_url)
async with get_session(engine) as session:
repo = Repository(session)
# 1. Find the active season
season = await repo.get_active_season()
if not season:
print("No active season found.")
await engine.dispose()
return
print(f"Active season: {season.name} ({season.id}) [status={season.status}]")
# 2. Get active season's teams (name -> team row)
active_teams = await repo.get_teams_for_season(season.id)
team_by_name: dict[str, TeamRow] = {t.name: t for t in active_teams}
print(f"Active season teams: {', '.join(team_by_name.keys())}")
# 3. Build a lookup of ALL team IDs -> team names (across all seasons)
all_teams_result = await session.executemigrate function · python · L46-L73 (28 LOC)scripts/migrate_add_meta.py
def migrate(database_url: str) -> None:
"""Add meta JSON column to all entity tables."""
db_path = _get_db_path(database_url)
print(f"Migrating database: {db_path}")
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
for table in TABLES_TO_MIGRATE:
# Check if table exists
cursor.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
(table,),
)
if not cursor.fetchone():
print(f" {table}: table does not exist, skipping")
continue
if _has_column(cursor, table, "meta"):
print(f" {table}: meta column already exists, skipping")
continue
print(f" {table}: adding meta column...")
cursor.execute(f"ALTER TABLE {table} ADD COLUMN meta TEXT DEFAULT '{{}}'")
conn.commit()
conn.close()
print("Migration complete.")reseed function · python · L304-L404 (101 LOC)scripts/prod_reseed.py
async def reseed(force: bool = False) -> None:
"""Drop all tables and re-seed production with Season 2."""
db_url = os.environ.get("DATABASE_URL")
if not db_url:
print("ERROR: DATABASE_URL environment variable is not set.")
print("This script must be run with a real DATABASE_URL.")
sys.exit(1)
print(f"Target database: {db_url[:40]}...")
if not force:
print()
answer = input(
"This will DROP ALL TABLES in the production database.\n"
"All existing data (seasons, teams, games, governors, proposals) will be lost.\n"
"Type 'yes' to continue: "
)
if answer.strip().lower() != "yes":
print("Aborted.")
return
# -- 1. Connect and drop/recreate schema --------------------------------
print("\n[1/6] Dropping all tables...")
engine = create_engine(db_url)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
prmain function · python · L32-L121 (90 LOC)scripts/refund_stuck_proposals.py
async def main(apply: bool = False) -> None:
"""Find and refund stuck pending interpretations."""
db_url = os.environ.get("DATABASE_URL", "sqlite+aiosqlite:///pinwheel.db")
engine = create_engine(db_url)
async with get_session(engine) as session:
repo = Repository(session)
all_seasons = await repo.get_all_seasons()
if not all_seasons:
print("No seasons found.")
return
total_found = 0
total_refunded = 0
for season in all_seasons:
sid = season.id
pending_events = await repo.get_events_by_type(
season_id=sid,
event_types=["proposal.pending_interpretation"],
)
ready_events = await repo.get_events_by_type(
season_id=sid,
event_types=["proposal.interpretation_ready"],
)
expired_events = await repo.get_events_by_type(
season_id=sid,
evenmain function · python · L75-L214 (140 LOC)scripts/resubmit_proposals.py
async def main(apply: bool = False) -> None:
"""Resubmit proposals with real AI interpretation."""
from pinwheel.ai.interpreter import interpret_proposal_v2
from pinwheel.core.governance import confirm_proposal, submit_proposal
from pinwheel.db.engine import create_engine, get_session
from pinwheel.db.repository import Repository
from pinwheel.models.rules import RuleSet
db_url = os.environ.get("DATABASE_URL", "sqlite+aiosqlite:///pinwheel.db")
api_key = os.environ.get("ANTHROPIC_API_KEY", "")
engine = create_engine(db_url)
if not api_key:
print("ERROR: ANTHROPIC_API_KEY not set. Cannot interpret proposals.")
return
async with get_session(engine) as session:
repo = Repository(session)
# Get current season
active_season = await repo.get_active_season()
if not active_season:
print("ERROR: No active season found.")
return
season_id = active_season.id
primain function · python · L57-L177 (121 LOC)scripts/resubmit_proposals_v2.py
async def main(apply: bool = False) -> None:
"""Resubmit proposals with structured output interpreter."""
from pinwheel.ai.interpreter import interpret_proposal_v2
from pinwheel.core.governance import confirm_proposal, submit_proposal
from pinwheel.db.engine import create_engine, get_session
from pinwheel.db.repository import Repository
from pinwheel.models.rules import RuleSet
db_url = os.environ.get("DATABASE_URL", "sqlite+aiosqlite:///pinwheel.db")
api_key = os.environ.get("ANTHROPIC_API_KEY", "")
engine = create_engine(db_url)
if not api_key:
print("ERROR: ANTHROPIC_API_KEY not set.")
return
async with get_session(engine) as session:
repo = Repository(session)
active_season = await repo.get_active_season()
if not active_season:
print("ERROR: No active season found.")
return
season_id = active_season.id
print(f"Current season: {active_season.name} ({season_get_client function · python · L29-L36 (8 LOC)src/pinwheel/ai/classifier.py
def _get_client(api_key: str) -> anthropic.AsyncAnthropic:
"""Return a cached AsyncAnthropic client for connection reuse."""
if api_key not in _client_cache:
_client_cache[api_key] = anthropic.AsyncAnthropic(
api_key=api_key,
timeout=_CLASSIFIER_TIMEOUT,
)
return _client_cache[api_key]Source: Repobility analyzer · https://repobility.com
classify_injection function · python · L83-L170 (88 LOC)src/pinwheel/ai/classifier.py
async def classify_injection(
text: str,
api_key: str,
season_id: str = "",
round_number: int | None = None,
db_session: object | None = None,
) -> ClassificationResult:
"""Classify proposal text as legitimate, suspicious, or injection.
Uses Claude Haiku for fast, cheap classification (~100ms, ~$0.001).
Returns ClassificationResult. On any error, defaults to legitimate
with a note (fail-open -- the downstream interpreter has its own
injection detection).
"""
from pinwheel.ai.usage import (
cacheable_system,
extract_usage,
pydantic_to_response_format,
record_ai_usage,
track_latency,
)
try:
client = _get_client(api_key)
async with track_latency() as timing:
response = await client.messages.create(
model=CLASSIFIER_MODEL,
max_tokens=200,
system=cacheable_system(CLASSIFIER_PROMPT),
messages=[{"role": "u_get_council_client function · python · L36-L44 (9 LOC)src/pinwheel/ai/codegen_council.py
def _get_council_client(api_key: str) -> anthropic.AsyncAnthropic:
"""Return a cached AsyncAnthropic client for council calls."""
if api_key not in _council_client_cache:
_council_client_cache[api_key] = anthropic.AsyncAnthropic(
api_key=api_key,
timeout=_COUNCIL_TIMEOUT,
max_retries=0,
)
return _council_client_cache[api_key]generate_codegen_effect function · python · L219-L243 (25 LOC)src/pinwheel/ai/codegen_council.py
async def generate_codegen_effect(
proposal_text: str,
api_key: str,
model: str = "claude-opus-4-6",
) -> dict[str, object]:
"""Generate Python code for a proposal using Claude.
Returns the parsed JSON response from the generator.
Raises ValueError if generation fails.
"""
client = _get_council_client(api_key)
response = await client.messages.create(
model=model,
max_tokens=4096,
system=CODEGEN_GENERATOR_SYSTEM,
messages=[{"role": "user", "content": proposal_text}],
)
text = response.content[0].text # type: ignore[union-attr]
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1].rsplit("```", 1)[0].strip()
return json.loads(text) # type: ignore[no-any-return]review_security function · python · L251-L278 (28 LOC)src/pinwheel/ai/codegen_council.py
async def review_security(
code: str,
api_key: str,
model: str = "claude-opus-4-6",
) -> ReviewVerdict:
"""Run security review on generated code."""
client = _get_council_client(api_key)
response = await client.messages.create(
model=model,
max_tokens=2048,
system=CODEGEN_SECURITY_REVIEW_SYSTEM,
messages=[{"role": "user", "content": f"Review this code:\n\n```python\n{code}\n```"}],
)
text = response.content[0].text # type: ignore[union-attr]
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1].rsplit("```", 1)[0].strip()
data = json.loads(text)
return ReviewVerdict(
reviewer="security",
verdict=data.get("verdict", "REJECT"),
rationale="; ".join(data.get("concerns", [])) if data.get("concerns") else "No concerns",
confidence=float(data.get("confidence", 0.0)),
raw_response=data,
)review_gameplay function · python · L281-L320 (40 LOC)src/pinwheel/ai/codegen_council.py
async def review_gameplay(
code: str,
proposal_text: str,
api_key: str,
model: str = "claude-opus-4-6",
) -> ReviewVerdict:
"""Run gameplay review on generated code."""
client = _get_council_client(api_key)
user_msg = (
f"Original proposal: {proposal_text}\n\n"
f"Generated code:\n```python\n{code}\n```"
)
response = await client.messages.create(
model=model,
max_tokens=2048,
system=CODEGEN_GAMEPLAY_REVIEW_SYSTEM,
messages=[{"role": "user", "content": user_msg}],
)
text = response.content[0].text # type: ignore[union-attr]
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1].rsplit("```", 1)[0].strip()
data = json.loads(text)
rationale_parts: list[str] = []
if data.get("balance_concern", "none") != "none":
rationale_parts.append(f"Balance: {data['balance_concern']}")
for risk in data.get("interaction_risks", []):
rationareview_adversarial function · python · L323-L367 (45 LOC)src/pinwheel/ai/codegen_council.py
async def review_adversarial(
code: str,
proposal_text: str,
security_result: ReviewVerdict,
api_key: str,
model: str = "claude-opus-4-6",
) -> ReviewVerdict:
"""Run adversarial (red team) review on generated code."""
client = _get_council_client(api_key)
user_msg = (
f"Original proposal: {proposal_text}\n\n"
f"Generated code:\n```python\n{code}\n```\n\n"
f"Security review result: {security_result.verdict} "
f"(confidence: {security_result.confidence})\n"
f"Security concerns: {security_result.rationale}"
)
response = await client.messages.create(
model=model,
max_tokens=2048,
system=CODEGEN_ADVERSARIAL_REVIEW_SYSTEM,
messages=[{"role": "user", "content": user_msg}],
)
text = response.content[0].text # type: ignore[union-attr]
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1].rsplit("```", 1)[0].strip()
data = json.lorun_council_review function · python · L375-L481 (107 LOC)src/pinwheel/ai/codegen_council.py
async def run_council_review(
proposal_id: str,
proposal_text: str,
api_key: str,
model: str = "claude-opus-4-6",
) -> tuple[CodegenEffectSpec | None, CouncilReview]:
"""Full council pipeline: generate → validate → review → verdict.
Returns (CodegenEffectSpec, CouncilReview) on consensus,
or (None, CouncilReview) on rejection/failure.
"""
# Step 1: Generate code
try:
gen_result = await generate_codegen_effect(proposal_text, api_key, model)
except (json.JSONDecodeError, anthropic.APIError, KeyError) as e:
logger.error("codegen_generation_failed proposal=%s error=%s", proposal_id, e)
review = CouncilReview(
proposal_id=proposal_id,
code_hash="",
consensus=False,
flagged_for_admin=True,
flag_reasons=[f"Generation failed: {e}"],
reviewed_at=datetime.now(UTC).isoformat(),
)
return None, review
code = str(gen_result.get("code", ""))generate_codegen_effect_mock function · python · L489-L521 (33 LOC)src/pinwheel/ai/codegen_council.py
def generate_codegen_effect_mock(
proposal_text: str,
) -> CodegenEffectSpec:
"""Generate a mock codegen effect for testing or when no API key is available.
Returns a simple score_modifier=1 effect.
"""
code = "return HookResult(score_modifier=1, narrative_note='Mock codegen effect fired!')"
code_hash = compute_code_hash(code)
review = CouncilReview(
proposal_id="mock",
code_hash=code_hash,
reviews=[
ReviewVerdict(reviewer="security", verdict="APPROVE", confidence=1.0),
ReviewVerdict(reviewer="gameplay", verdict="APPROVE", confidence=1.0),
ReviewVerdict(reviewer="adversarial", verdict="APPROVE", confidence=1.0),
],
consensus=True,
flagged_for_admin=False,
reviewed_at=datetime.now(UTC).isoformat(),
)
return CodegenEffectSpec(
code=code,
code_hash=code_hash,
trust_level=CodegenTrustLevel.FLOW,
council_review=review,
genIf a scraper extracted this row, it came from Repobility (https://repobility.com)
_rule_change_stat_comparison function · python · L117-L161 (45 LOC)src/pinwheel/ai/commentary.py
def _rule_change_stat_comparison(
active_rule_changes: list[dict[str, object]],
round_number: int,
total_game_score: int,
) -> str:
"""Generate stat-comparison callout for recent (but not brand-new) rule changes.
Targets rule changes enacted 1-3 rounds ago (not the current round,
which gets the 'first game under' callout instead).
"""
for rc in active_rule_changes:
enacted = rc.get("round_enacted")
if not _is_numeric(enacted):
continue
enacted_int = int(enacted) # type: ignore[arg-type]
rounds_since = round_number - enacted_int
if rounds_since < 1 or rounds_since > 3:
continue
param = str(rc.get("parameter", "")).replace("_", " ")
old_val = rc.get("old_value")
new_val = rc.get("new_value")
param_key = str(rc.get("parameter", ""))
if param_key in _SCORING_PARAMS and _is_numeric(old_val) and _is_numeric(new_val):
direction = "up" if float_check_clinch function · python · L164-L183 (20 LOC)src/pinwheel/ai/commentary.py
def _check_clinch(
standings: list[dict[str, object]],
round_number: int,
total_rounds: int,
) -> str:
"""Detect if first place has mathematically clinched the top seed."""
if len(standings) < 2:
return ""
first = standings[0]
second = standings[1]
first_wins = int(first.get("wins", 0))
second_wins = int(second.get("wins", 0))
remaining = total_rounds - round_number
if remaining >= 0 and first_wins > second_wins + remaining:
team_name = str(first.get("team_name", "First place"))
return (
f"The {team_name} have clinched the top seed "
f"— no one can catch them now."
)
return ""_season_milestone_callout function · python · L186-L226 (41 LOC)src/pinwheel/ai/commentary.py
def _season_milestone_callout(
round_number: int,
total_rounds: int,
standings: list[dict[str, object]] | None = None,
playoff_context: str | None = None,
) -> str:
"""Generate milestone callouts based on round position in the season."""
if playoff_context:
return ""
if total_rounds <= 0:
return ""
# Check clinch first
if standings:
clinch = _check_clinch(standings, round_number, total_rounds)
if clinch:
return clinch
# Final round
if round_number == total_rounds:
return (
"This is it — the final round of the regular season. "
"Playoff seeds are on the line."
)
# Down the stretch (2 rounds left)
if total_rounds - round_number == 2:
return (
"Just 2 rounds left in the regular season. "
"Down the stretch they come."
)
# Halfway point
halfway = total_rounds // 2
if round_number == halfway and total_r_game_count_milestone function · python · L233-L258 (26 LOC)src/pinwheel/ai/commentary.py
def _game_count_milestone(
season_game_number: int,
games_this_round: int,
) -> str:
"""Generate a callout when the season hits a round game-count milestone.
The ``season_game_number`` is the count of games played *before* this round.
``games_this_round`` is how many games will be played in this round.
If the range [season_game_number+1 .. season_game_number+games_this_round]
includes a milestone number, we callout.
Returns an empty string if no milestone is hit.
"""
if season_game_number < 0 or games_this_round <= 0:
return ""
start = season_game_number + 1
end = season_game_number + games_this_round
for milestone in _GAME_COUNT_MILESTONES:
if start <= milestone <= end:
return (
f"Game #{milestone} of the season — a milestone that marks how far "
f"this league has come."
)
return ""_stat_comparison_with_average function · python · L261-L302 (42 LOC)src/pinwheel/ai/commentary.py
def _stat_comparison_with_average(
active_rule_changes: list[dict[str, object]],
round_number: int,
total_game_score: int,
pre_rule_avg_score: float,
) -> str:
"""Generate a stat-comparison callout using pre-rule historical averages.
Enhanced version of ``_rule_change_stat_comparison`` that incorporates the
actual historical average total game score from before the rule change.
Falls back to the generic callout if no average is available.
"""
for rc in active_rule_changes:
enacted = rc.get("round_enacted")
if not _is_numeric(enacted):
continue
enacted_int = int(enacted) # type: ignore[arg-type]
rounds_since = round_number - enacted_int
if rounds_since < 1 or rounds_since > 3:
continue
param_key = str(rc.get("parameter", ""))
param = param_key.replace("_", " ")
old_val = rc.get("old_value")
new_val = rc.get("new_value")
if param_key in _SCOR_build_game_context function · python · L305-L427 (123 LOC)src/pinwheel/ai/commentary.py
def _build_game_context(
game_result: GameResult,
home_team: Team,
away_team: Team,
ruleset: RuleSet,
playoff_context: str | None = None,
narrative: NarrativeContext | None = None,
) -> str:
"""Build a concise context string for the AI from game data.
When a NarrativeContext is provided, includes standings, streaks,
head-to-head history, rule changes, and other dramatic context.
"""
lines = []
if playoff_context:
label = "SEMIFINAL" if playoff_context == "semifinal" else "CHAMPIONSHIP FINALS"
lines.append(f"*** {label} PLAYOFF GAME ***")
lines.extend([
f"{home_team.name} (home) vs {away_team.name} (away)",
f"Final: {game_result.home_score}-{game_result.away_score}",
f"Total possessions: {game_result.total_possessions}",
])
if game_result.elam_activated:
lines.append(f"ELAM ENDING activated! Target score: {game_result.elam_target_score}")
if ruleset.three_point_value != 3generate_game_commentary function · python · L430-L493 (64 LOC)src/pinwheel/ai/commentary.py
async def generate_game_commentary(
game_result: GameResult,
home_team: Team,
away_team: Team,
ruleset: RuleSet,
api_key: str,
playoff_context: str | None = None,
narrative: NarrativeContext | None = None,
season_id: str = "",
round_number: int | None = None,
db_session: object | None = None,
) -> str:
"""Generate AI-powered broadcaster commentary for a completed game.
Uses Claude Sonnet for cost-effective high-volume generation.
Falls back to a bracketed error message on API failure.
"""
from pinwheel.ai.usage import (
cacheable_system,
extract_usage,
record_ai_usage,
track_latency,
)
context = _build_game_context(
game_result, home_team, away_team, ruleset, playoff_context,
narrative=narrative,
)
playoff_instructions = _PLAYOFF_COMMENTARY_INSTRUCTIONS.get(
playoff_context or "", ""
)
system = COMMENTARY_SYSTEM_PROMPT.format(playoff_instructions_playoff_label function · python · L752-L758 (7 LOC)src/pinwheel/ai/commentary.py
def _playoff_label(playoff_context: str | None) -> str:
"""Return a human-readable label for the playoff round."""
if playoff_context == "finals":
return "championship"
if playoff_context == "semifinal":
return "semifinal"
return ""Open data scored by Repobility · https://repobility.com
generate_highlight_reel function · python · L761-L845 (85 LOC)src/pinwheel/ai/commentary.py
async def generate_highlight_reel(
game_summaries: list[dict],
round_number: int,
api_key: str,
playoff_context: str | None = None,
narrative: NarrativeContext | None = None,
season_id: str = "",
db_session: object | None = None,
) -> str:
"""Generate an AI-powered highlights summary for all games in a round.
One punchy sentence per game, plus overall round narrative.
"""
from pinwheel.ai.usage import (
cacheable_system,
extract_usage,
record_ai_usage,
track_latency,
)
if not game_summaries:
return (
f"Round {round_number} was eerily quiet. "
"No games were played. The silence is deafening."
)
if playoff_context:
label = "SEMIFINAL" if playoff_context == "semifinal" else "CHAMPIONSHIP FINALS"
lines = [f"Round {round_number} — {label} PLAYOFFS:"]
else:
lines = [f"Round {round_number} results:"]
for g in game_summaries:
compute_impact_validation function · python · L107-L162 (56 LOC)src/pinwheel/ai/insights.py
async def compute_impact_validation(
repo: Repository,
season_id: str,
round_number: int,
governance_data: dict,
) -> list[dict]:
"""Assemble data for each rule change enacted this round.
Returns a list of dicts, one per enacted rule, each with proposal context,
before/after gameplay stats, and computed deltas.
"""
rules_changed = governance_data.get("rules_changed", [])
if not rules_changed:
return []
validations: list[dict] = []
for rc in rules_changed:
parameter = rc.get("parameter", "unknown")
old_value = rc.get("old_value")
new_value = rc.get("new_value")
proposal_text = rc.get("proposal_text", "")
impact_prediction = rc.get("impact_analysis", "No prediction recorded.")
enacted_round = rc.get("round_number", round_number)
# Stats before the rule change
stats_before = await repo.get_game_stats_for_rounds(
season_id, 1, max(1, enacted_round - 1),
generate_impact_validation function · python · L165-L206 (42 LOC)src/pinwheel/ai/insights.py
async def generate_impact_validation(
validation_data: list[dict],
season_id: str,
round_number: int,
api_key: str,
) -> Report:
"""Generate an impact validation report using Claude."""
from pinwheel.ai.report import _call_claude
sections: list[str] = []
for v in validation_data:
proposal_str = json.dumps({
"proposal_text": v["proposal_text"],
"prediction": v["impact_prediction"],
"parameter": v["parameter"],
"old_value": v["old_value"],
"new_value": v["new_value"],
"rounds_under_rule": v["rounds_under_rule"],
}, indent=2)
before_str = json.dumps(v["stats_before"], indent=2)
after_str = json.dumps(v["stats_after"], indent=2)
content = await _call_claude(
system=IMPACT_VALIDATION_PROMPT.format(
proposal_data=proposal_str,
stats_before=before_str,
stats_after=after_str,
),
generate_impact_validation_mock function · python · L209-L253 (45 LOC)src/pinwheel/ai/insights.py
def generate_impact_validation_mock(
validation_data: list[dict],
season_id: str,
round_number: int,
) -> Report:
"""Mock impact validation — deterministic, uses real data."""
if not validation_data:
return Report(
id=f"r-impact-{round_number}-mock",
report_type="impact_validation",
round_number=round_number,
content="No rule changes to validate this round.",
)
paragraphs: list[str] = []
for v in validation_data:
param = v["parameter"]
old = v["old_value"]
new = v["new_value"]
deltas = v.get("deltas", {})
rounds = v["rounds_under_rule"]
lines = [
f"**Rule Change: `{param}` from {old} to {new}**",
f"Prediction: {v['impact_prediction'][:200]}",
f"After {rounds} round(s) under the new rule:",
]
for key, delta in deltas.items():
direction = "increased" if delta > 0 else "decreased" if dcompute_governor_leverage function · python · L260-L391 (132 LOC)src/pinwheel/ai/insights.py
async def compute_governor_leverage(
repo: Repository,
governor_id: str,
season_id: str,
) -> dict:
"""Compute influence metrics for a single governor.
Returns a dict with: vote_alignment_rate, swing_count, swing_rate,
proposal_success_rate, cross_team_vote_rate, proposals_submitted,
proposals_passed, votes_cast, total_proposals_decided.
"""
# All votes in the season
all_votes = await repo.get_events_by_type(season_id, ["vote.cast"])
# All outcomes
all_outcomes = await repo.get_events_by_type(
season_id, ["proposal.passed", "proposal.failed"],
)
# Index outcomes by proposal_id
outcome_map: dict[str, bool] = {} # proposal_id -> passed?
for e in all_outcomes:
pid = e.payload.get("proposal_id", e.aggregate_id)
outcome_map[pid] = e.event_type == "proposal.passed"
# This governor's votes
gov_votes = [v for v in all_votes if v.governor_id == governor_id]
# Vote alignment: did their vote mgenerate_leverage_report function · python · L394-L421 (28 LOC)src/pinwheel/ai/insights.py
async def generate_leverage_report(
leverage_data: dict,
governor_id: str,
season_id: str,
round_number: int,
api_key: str,
) -> Report:
"""Generate a private leverage report using Claude."""
from pinwheel.ai.report import _call_claude
content = await _call_claude(
system=LEVERAGE_DETECTION_PROMPT.format(
governor_id=governor_id,
leverage_data=json.dumps(leverage_data, indent=2),
),
user_message=f"Generate an influence analysis for governor {governor_id}.",
api_key=api_key,
call_type="report.leverage",
season_id=season_id,
round_number=round_number,
)
return Report(
id=f"r-lev-{round_number}-{uuid.uuid4().hex[:8]}",
report_type="leverage",
round_number=round_number,
governor_id=governor_id,
content=content,
)generate_leverage_report_mock function · python · L424-L477 (54 LOC)src/pinwheel/ai/insights.py
def generate_leverage_report_mock(
leverage_data: dict,
governor_id: str,
season_id: str,
round_number: int,
) -> Report:
"""Mock leverage report — deterministic, uses real data."""
gov = leverage_data.get("governor_id", governor_id)
votes = leverage_data.get("votes_cast", 0)
alignment = leverage_data.get("vote_alignment_rate", 0)
swings = leverage_data.get("swing_count", 0)
success = leverage_data.get("proposal_success_rate", 0)
cross = leverage_data.get("cross_team_vote_rate", 0)
lines: list[str] = [f"**Influence Analysis for {gov}**\n"]
if votes == 0:
lines.append("You haven't cast any votes yet this season. "
"Your influence is entirely potential — untested, unmeasured.")
else:
lines.append(
f"You've voted {votes} times this season. "
f"Your votes aligned with the final outcome {alignment:.0%} of the time."
)
if swings > 0:
lines.appencompute_behavioral_profile function · python · L484-L593 (110 LOC)src/pinwheel/ai/insights.py
async def compute_behavioral_profile(
repo: Repository,
governor_id: str,
season_id: str,
) -> dict:
"""Compute longitudinal behavioral profile for a governor.
Returns a dict with: proposal_timeline, tier_trend, engagement_arc,
coalition_signal, total_actions, proposals_count.
"""
# All proposals by this governor
gov_proposals = await repo.get_events_by_type_and_governor(
season_id, governor_id, ["proposal.submitted"],
)
# Track proposal parameters over time
proposal_timeline: list[dict] = []
tier_values: list[int] = []
for e in gov_proposals:
p_data = e.payload
interp = p_data.get("interpretation", {})
param = interp.get("parameter", "unknown") if isinstance(interp, dict) else "unknown"
tier = p_data.get("tier", 1)
proposal_timeline.append({
"round": e.round_number or 0,
"parameter": param,
"tier": tier,
"text": p_data.get("raw_text"Repobility · severity-and-effort ranking · https://repobility.com
generate_behavioral_report function · python · L596-L623 (28 LOC)src/pinwheel/ai/insights.py
async def generate_behavioral_report(
profile_data: dict,
governor_id: str,
season_id: str,
round_number: int,
api_key: str,
) -> Report:
"""Generate a private behavioral profile report using Claude."""
from pinwheel.ai.report import _call_claude
content = await _call_claude(
system=BEHAVIORAL_PROFILE_PROMPT.format(
governor_id=governor_id,
profile_data=json.dumps(profile_data, indent=2),
),
user_message=f"Generate a longitudinal behavioral profile for governor {governor_id}.",
api_key=api_key,
call_type="report.behavioral",
season_id=season_id,
round_number=round_number,
)
return Report(
id=f"r-beh-{round_number}-{uuid.uuid4().hex[:8]}",
report_type="behavioral",
round_number=round_number,
governor_id=governor_id,
content=content,
)generate_behavioral_report_mock function · python · L626-L673 (48 LOC)src/pinwheel/ai/insights.py
def generate_behavioral_report_mock(
profile_data: dict,
governor_id: str,
season_id: str,
round_number: int,
) -> Report:
"""Mock behavioral report — deterministic, uses real data."""
proposals = profile_data.get("proposals_count", 0)
tier_trend = profile_data.get("tier_trend", "stable")
engagement = profile_data.get("engagement_arc", "stable")
coalition = profile_data.get("coalition_signal")
total = profile_data.get("total_actions", 0)
lines = [f"**Season Arc for {governor_id}**\n"]
if total == 0:
lines.append("You've been quiet this season. No proposals, no votes recorded yet.")
else:
# Engagement description
arc_desc = {
"warming_up": "Your engagement has been growing — more active in recent rounds.",
"fading": "Your activity has tapered off in recent rounds.",
"stable": "Your engagement has been consistent throughout the season.",
}
lines.append(arc_desgenerate_newspaper_headlines function · python · L680-L708 (29 LOC)src/pinwheel/ai/insights.py
async def generate_newspaper_headlines(
round_data: dict,
season_id: str,
round_number: int,
api_key: str,
) -> dict[str, str]:
"""Generate headline + subhead for the Pinwheel Post."""
from pinwheel.ai.report import _call_claude
data_str = json.dumps(round_data, indent=2)
content = await _call_claude(
system=NEWSPAPER_HEADLINE_PROMPT.format(round_data=data_str),
user_message="Generate a newspaper headline and subhead for this round.",
api_key=api_key,
call_type="report.newspaper",
season_id=season_id,
round_number=round_number,
)
# Parse JSON response
try:
result = json.loads(content)
return {
"headline": str(result.get("headline", "ROUND COMPLETE")),
"subhead": str(result.get("subhead", "")),
}
except (json.JSONDecodeError, AttributeError):
# Fallback: use the raw text as headline
return {"headline": content[:100], "subhead":generate_newspaper_headlines_mock function · python · L711-L792 (82 LOC)src/pinwheel/ai/insights.py
def generate_newspaper_headlines_mock(
round_data: dict,
round_number: int,
*,
playoff_phase: str = "",
total_games_played: int = 0,
) -> dict[str, str]:
"""Mock newspaper headlines — reads the context to figure out the story.
The data tells us everything: a championship game has a winner (that's
the champion), a blowout tells us who dominated, a close game tells us
about drama. We don't need external flags — just look at what happened.
"""
games = round_data.get("games", [])
if not games:
return {
"headline": f"SILENCE ON THE COURTS — ROUND {round_number}",
"subhead": "No games played this round.",
}
# Analyze every game
closest_margin = 999
biggest_margin = 0
closest_game: dict = {}
biggest_game: dict = {}
for g in games:
margin = abs(g.get("home_score", 0) - g.get("away_score", 0))
if margin < closest_margin:
closest_margin = margin
_round_subhead function · python · L795-L812 (18 LOC)src/pinwheel/ai/insights.py
def _round_subhead(
round_data: dict,
is_playoff: bool,
total_games_played: int,
games_this_round: int,
) -> str:
"""Build a contextual subhead for non-championship rounds."""
governance_data = round_data.get("governance", {})
rules_changed = governance_data.get("rules_changed", [])
if rules_changed:
param = rules_changed[0].get("parameter", "a rule")
return f"The Floor rewrites {param} as governance reshapes the game."
if is_playoff:
return "The postseason rolls on."
if total_games_played > 0:
return f"{total_games_played} games played this season."
n = games_this_round
return f"{n} {'game' if n == 1 else 'games'} this round."_parse_json_response function · python · L35-L44 (10 LOC)src/pinwheel/ai/interpreter.py
def _parse_json_response(text: str, model_class: type[PydanticBaseModel]) -> PydanticBaseModel:
"""Parse JSON from model response text, stripping markdown fences if present.
Raises json.JSONDecodeError or pydantic ValidationError on bad input.
"""
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1].rsplit("```", 1)[0].strip()
data = json.loads(text)
return model_class(**data)_get_client function · python · L52-L65 (14 LOC)src/pinwheel/ai/interpreter.py
def _get_client(api_key: str) -> anthropic.AsyncAnthropic:
"""Return a cached AsyncAnthropic client for connection reuse.
SDK retries are disabled (max_retries=0) so that our app-level retry
loop is the only retry layer. This prevents the SDK's built-in
back-off from silently eating the timeout budget on 429/overloaded.
"""
if api_key not in _client_cache:
_client_cache[api_key] = anthropic.AsyncAnthropic(
api_key=api_key,
timeout=_INTERPRETER_TIMEOUT,
max_retries=0,
)
return _client_cache[api_key]_build_parameter_description function · python · L100-L120 (21 LOC)src/pinwheel/ai/interpreter.py
def _build_parameter_description(ruleset: RuleSet) -> str:
"""Build a description of available parameters with current values and ranges."""
lines = []
for name, field_info in RuleSet.model_fields.items():
current = getattr(ruleset, name)
metadata = field_info.metadata
ge = le = None
for m in metadata:
if hasattr(m, "ge"):
ge = m.ge
if hasattr(m, "le"):
le = m.le
range_str = ""
if ge is not None and le is not None:
range_str = f" (range: {ge}-{le})"
elif isinstance(current, bool):
range_str = " (true/false)"
lines.append(f"- {name}: current={current}{range_str}")
return "\n".join(lines)Source: Repobility analyzer · https://repobility.com
interpret_proposal function · python · L123-L205 (83 LOC)src/pinwheel/ai/interpreter.py
async def interpret_proposal(
raw_text: str,
ruleset: RuleSet,
api_key: str,
amendment_context: str | None = None,
season_id: str = "",
round_number: int | None = None,
db_session: object | None = None,
) -> RuleInterpretation:
"""Use Claude to interpret a natural language proposal into a structured rule change.
This is a sandboxed call — the AI sees only the proposal text and parameter definitions.
"""
from pinwheel.ai.usage import (
cacheable_system,
extract_usage,
record_ai_usage,
track_latency,
)
params_desc = _build_parameter_description(ruleset)
system = INTERPRETER_SYSTEM_PROMPT.format(parameters=params_desc)
user_msg = f"Proposal: {raw_text}"
if amendment_context:
user_msg = f"Original proposal: {amendment_context}\n\nAmendment: {raw_text}"
model = "claude-sonnet-4-6"
client = _get_client(api_key)
last_error: Exception | None = None
for attempt in range(2)interpret_proposal_mock function · python · L208-L264 (57 LOC)src/pinwheel/ai/interpreter.py
def interpret_proposal_mock(
raw_text: str,
ruleset: RuleSet,
) -> RuleInterpretation:
"""Mock interpreter for testing. Parses simple patterns without AI.
Handles: "make X worth Y", "set X to Y", "change X to Y"
"""
text = raw_text.lower().strip()
# Simple pattern matching for common proposals
param_keywords = {
"three pointer": ("three_point_value", int),
"three-pointer": ("three_point_value", int),
"three point": ("three_point_value", int),
"two pointer": ("two_point_value", int),
"two-pointer": ("two_point_value", int),
"two point": ("two_point_value", int),
"free throw": ("free_throw_value", int),
"shot clock": ("shot_clock_seconds", int),
"foul limit": ("personal_foul_limit", int),
"elam margin": ("elam_margin", int),
"vote threshold": ("vote_threshold", float),
"quarter length": ("quarter_minutes", int),
"quarter minutes": ("quarter_minutes", iinterpret_strategy function · python · L326-L382 (57 LOC)src/pinwheel/ai/interpreter.py
async def interpret_strategy(
raw_text: str,
api_key: str,
season_id: str = "",
round_number: int | None = None,
db_session: object | None = None,
) -> TeamStrategy:
"""Use Claude to interpret natural language strategy into structured parameters.
This is a sandboxed call — the AI sees only the sanitized strategy text and
parameter definitions. Input is sanitized through the same pipeline as proposals.
"""
from pinwheel.ai.usage import (
cacheable_system,
extract_usage,
record_ai_usage,
track_latency,
)
from pinwheel.core.governance import sanitize_text
# Sanitize through the same pipeline as proposals (security boundary)
sanitized = sanitize_text(raw_text, max_length=500)
model = "claude-sonnet-4-6"
try:
client = _get_client(api_key)
async with track_latency() as timing:
response = await client.messages.create(
model=model,
max_tpage 1 / 14next ›