| """Pre-written fallbacks — content from AI_PROMPTS.md. The player must never |
| see an error: any Modal timeout or validation failure lands here.""" |
| from __future__ import annotations |
|
|
| import random |
|
|
| REACTIONS = { |
| "brad": { |
| "positive": "Knew you'd see it, boss. This is why we're a great team. I already told two people.", |
| "neutral": "Okay. Noted. Circling back. The window's still open by the way. Brad-window.", |
| "negative": "Wow. Okay. That's a choice. I'm putting this in my book. There's a chapter now.", |
| }, |
| "stacey": { |
| "positive": "Oh thank god. Thank you. I already drafted three apology emails, I'll only send one.", |
| "neutral": "Right, yes, totally — I'll fix it. I know exactly how. Mostly exactly.", |
| "negative": "No that's fair. That's completely fair. I'm so sorry. I'll just— yes. Okay.", |
| }, |
| "kevin": { |
| "positive": "Directionally, this validates everything. I'll add a slide. The slide will be green.", |
| "neutral": "Interesting. The data didn't predict this. I'll adjust the methodology. Quietly.", |
| "negative": "With respect, the numbers disagree. I'll re-run them until they don't.", |
| }, |
| "janet": { |
| "positive": "THIS is leadership with a point of view. I'm putting it in the newsletter. With a metaphor.", |
| "neutral": "Fine. But the brand will remember how this felt.", |
| "negative": "I hear you. The vision doesn't, but I do.", |
| }, |
| "derek": { |
| "positive": "Hm. That's what Margaret would have done. Before the incident.", |
| "neutral": "Noted. We tried that in 2019. Well. Something like it.", |
| "negative": "...Understood.", |
| }, |
| } |
|
|
| _KIND_DELTAS = { |
| "positive": (25_000, 40_000, 2, 2, "npc_happy"), |
| "neutral": (-5_000, 10_000, 0, 0, "npc_confused"), |
| "negative": (-40_000, -15_000, -3, -3, "npc_devastated"), |
| } |
|
|
| NPC_NAMES = {"brad": "Brad", "stacey": "Stacey", "kevin": "Kevin", |
| "janet": "Janet", "derek": "Derek"} |
|
|
|
|
| def kind_for_response(response_type: str) -> str: |
| if response_type in ("quick_fine",): |
| return "negative" |
| if response_type in ("custom", "quick_explain", "quick_quit"): |
| return "neutral" |
| return "positive" |
|
|
|
|
| def crisis_fallback(npc_id: str, response_type: str) -> dict: |
| kind = kind_for_response(response_type) |
| lo, hi, morale, rel, anim = _KIND_DELTAS[kind] |
| delta = random.randint(lo // 1000, hi // 1000) * 1000 |
| name = NPC_NAMES[npc_id] |
| sign = "+" if delta >= 0 else "-" |
| return { |
| "npc_reaction": REACTIONS[npc_id][kind], |
| "consequence": f"{name} handled it. Nobody is entirely sure how, and nobody asked.", |
| "revenue_delta": delta, |
| "animation": anim, |
| "boss_title": "Acting Head of Whatever This Is", |
| "log_entry": f"{name} had a situation. It was handled. {sign}${abs(delta) // 1000}K.", |
| "morale_delta": morale, |
| "npc_id": npc_id, |
| "relationship_delta": rel, |
| "pocket_money_delta": 0, |
| "special_next_event": None, |
| } |
|
|
|
|
| _EVENT_FALLBACKS = [ |
| { |
| "affected_npc": "player", |
| "category": "professional", |
| "headline": "The printer has produced something", |
| "intro": "> inbox: the printer in the kitchen has been printing the same page for twenty minutes. People have seen it. It is a ranking.", |
| "option_a": "Shred everything and declare a paperless office, effective immediately.", |
| "option_b": "Pin it to the corkboard and call it radical transparency.", |
| "urgency": "It is still printing.", |
| "setup_animation": "npc_confused", |
| "morale_preview": -3, |
| }, |
| { |
| "affected_npc": "stacey", |
| "category": "professional", |
| "headline": "Wrong attachment, right energy", |
| "intro": "So the good news is the client got the file on time. The other news is it was the internal nicknames spreadsheet. Their CEO is 'Captain Synergy'. He has replied.", |
| "option_a": "Claim it was an icebreaker initiative and send the rest of the spreadsheet.", |
| "option_b": "Blame a software glitch nobody can name.", |
| "urgency": "He has replied TWICE.", |
| "setup_animation": "npc_crying", |
| "morale_preview": -4, |
| }, |
| { |
| "affected_npc": "brad", |
| "category": "external", |
| "headline": "Mystery package addressed to nobody", |
| "intro": "Boss. Package at reception. No sender. I opened it. That part's done, so. It's five hundred stress balls with a competitor's logo. I have a theory.", |
| "option_a": "Distribute the stress balls. Free is free.", |
| "option_b": "Mail them back with a strongly worded sticky note.", |
| "urgency": "Brad's theory has slides.", |
| "setup_animation": "npc_smug", |
| "morale_preview": 2, |
| }, |
| { |
| "affected_npc": "kevin", |
| "category": "personal", |
| "headline": "It is Kevin's birthday", |
| "intro": "For the record I did not expect anyone to remember. The data suggested a 12 percent chance. I brought my own hat. Directionally, this is fine.", |
| "option_a": "Emergency cake run on company budget. Backdate the enthusiasm.", |
| "option_b": "Declare birthdays a Q4 initiative.", |
| "urgency": "He is wearing the hat.", |
| "setup_animation": "npc_devastated", |
| "morale_preview": -5, |
| }, |
| ] |
|
|
|
|
| def event_fallback(index: int) -> dict: |
| return dict(_EVENT_FALLBACKS[index % len(_EVENT_FALLBACKS)]) |
|
|
|
|
| |
| |
| _SPECIAL_FALLBACKS = { |
| "newspaper": { |
| "affected_npc": "brad", |
| "category": "external", |
| "headline": "The press got hold of it", |
| "intro": "Boss. So. A reporter wrote us up. The headline uses the word " |
| "'reportedly' four times and there's a photo of me mid-sentence. " |
| "It's already being shared. I look powerful though.", |
| "option_a": "Issue a correction so dry nobody finishes reading it.", |
| "option_b": "Lean in and frame the whole thing as bold market disruption.", |
| "urgency": "The comment section has discovered us.", |
| "setup_animation": "npc_hiding", |
| "morale_preview": -5, |
| }, |
| "client_emergency": { |
| "affected_npc": "stacey", |
| "category": "professional", |
| "headline": "A client is on the line, right now", |
| "intro": "I have Northpath Solutions on hold and they are not happy. " |
| "Something about a deliverable we may have described as 'basically " |
| "done'. It was not basically done. It was basically a folder.", |
| "option_a": "Take the call yourself and promise a recovery plan by Friday.", |
| "option_b": "Have Stacey stall with enthusiasm while we invent the thing.", |
| "urgency": "They can hear the hold music looping. So can we.", |
| "setup_animation": "npc_crying", |
| "morale_preview": -6, |
| }, |
| "personal": { |
| "affected_npc": "kevin", |
| "category": "personal", |
| "headline": "Something is going on with the team", |
| "intro": "Not a work thing, technically. But it's bleeding into the work " |
| "thing. There were tears at the printer. The printer is fine. The " |
| "person is, statistically, also fine. Probably.", |
| "option_a": "Check in personally and quietly cover their afternoon.", |
| "option_b": "Declare a surprise team lunch and never address it directly.", |
| "urgency": "The whole floor is pretending to type.", |
| "setup_animation": "npc_devastated", |
| "morale_preview": -4, |
| }, |
| "hr": { |
| "affected_npc": "player", |
| "category": "professional", |
| "headline": "HR would like a quick word", |
| "intro": "> HR has requested a brief, informal, absolutely-not-a-big-deal " |
| "conversation regarding 'recent patterns'. They have used the " |
| "phrase 'just to document it'. There is a folder.", |
| "option_a": "Walk in honest and own whatever this is about.", |
| "option_b": "Bring your own folder. Establish folder dominance.", |
| "urgency": "The meeting room blinds are already closed.", |
| "setup_animation": "npc_suspicious", |
| "morale_preview": -5, |
| }, |
| } |
|
|
|
|
| def special_fallback(kind: str, index: int) -> dict: |
| """A coherent fallback whose theme matches the special-event arrival.""" |
| if kind in _SPECIAL_FALLBACKS: |
| return dict(_SPECIAL_FALLBACKS[kind]) |
| return event_fallback(index) |
|
|
|
|
| def presentation_fallback(round_no: int, last_log: str) -> dict: |
| if round_no >= 3: |
| return { |
| "round": round_no, |
| "board_tone": "neutral", |
| "event_referenced": last_log[:150], |
| "round_difficulty": "standard", |
| "board_dialogue": "The board has reviewed the quarter so far. Specifically this: " |
| f"\"{last_log[:120]}\". Give us your closing statement.", |
| "cumulative_score": 50, |
| } |
| return { |
| "round": round_no, |
| "board_tone": "neutral", |
| "event_referenced": last_log[:150], |
| "round_difficulty": "standard", |
| "option_a": "Own it completely and pivot to the pipeline.", |
| "option_b": "Contextualize it as a learning investment.", |
| "board_dialogue": f"Let's start with this item from the record: \"{last_log[:120]}\". " |
| "Walk us through it.", |
| } |
|
|
|
|
| CHAT_OPENERS = { |
| "brad": "Boss. Glad you stopped by. I'm working on something big. Can't say what. It's big though.", |
| "stacey": "Oh! Hi. Everything's under control. I just triple-checked the recipient field on everything. Twice.", |
| "kevin": "Good timing. The numbers are doing something interesting. Directionally interesting.", |
| "janet": "I've been thinking about our visual language. We need to talk about it. Not now. But soon.", |
| "derek": "Hm. You walk the floor now. Interesting.", |
| } |
|
|
| CHAT_REPLIES = { |
| "brad": "Knew you'd get it, boss. This is why I tell people we're tight.", |
| "stacey": "That actually helps. Thank you. I'll only worry about it a normal amount now.", |
| "kevin": "Noted. I'll factor that into the model. The model appreciates it.", |
| "janet": "See, THIS is the kind of dialogue the brand needs internally.", |
| "derek": "Hm. Noted.", |
| } |
|
|
|
|
| def chat_fallback(npc_id: str, opener: bool) -> dict: |
| return { |
| "npc_line": (CHAT_OPENERS if opener else CHAT_REPLIES)[npc_id], |
| "relationship_delta": 0 if opener else 1, |
| "morale_delta": 0, |
| } |
|
|
|
|
| BANTER_LINES = [ |
| ("brad", "...so I told them, that's not a bug, that's a premium feature. They went quiet. Closing energy."), |
| ("kevin", "The Q3 numbers are directionally fine. Directionally."), |
| ("janet", "The font says reliable. We are not a reliable font company."), |
| ("stacey", "Okay but who do I apologize to if nobody noticed yet?"), |
| ("derek", "We had a printer like that in 2019. Before the incident."), |
| ] |
|
|
|
|
| def banter_fallback(index: int) -> dict: |
| npc_id, line = BANTER_LINES[index % len(BANTER_LINES)] |
| return {"npc_id": npc_id, "line": line} |
|
|
|
|
| EAVESDROP_EXCHANGES = [ |
| [("brad", "Kevin. Buddy. Your chart says we grew 140 percent."), |
| ("kevin", "The chart is directionally accurate, Brad."), |
| ("brad", "I put it in the client deck.")], |
| [("janet", "The newsletter needs a hero image that says resilience."), |
| ("stacey", "Is that why you sent me forty photos of lighthouses?"), |
| ("janet", "Forty OPTIONS, Stacey.")], |
| ] |
|
|
|
|
| def eavesdrop_fallback(index: int) -> dict: |
| exchange = EAVESDROP_EXCHANGES[index % len(EAVESDROP_EXCHANGES)] |
| return {"lines": [{"speaker": s, "line": l} for s, l in exchange]} |
|
|
|
|
| EMAIL_BANK = [ |
| {"sender": "janet", "subject": "BRAND PULSE — week of now", |
| "body": "Team. This week the brand felt like a lighthouse in fog: present, vertical, misunderstood. More on this in my longer email. There will be a longer email."}, |
| {"sender": "kevin", "subject": "Metric of the Day", |
| "body": "Pipeline velocity is up 31% against a baseline I have defined myself. Methodology available upon request. Please do not request it."}, |
| {"sender": "system", "subject": "FACILITIES: regarding the printer", |
| "body": "The third-floor printer has been restored to factory settings. We are not able to explain what it was printing before. Please direct questions nowhere."}, |
| ] |
|
|
|
|
| def email_fallback(index: int) -> dict: |
| return dict(EMAIL_BANK[index % len(EMAIL_BANK)]) |
|
|
|
|
| _ROMANCE_INTROS = { |
| "brad": "Boss. Off the record. I've been thinking — we're a great team, right? Like, a GREAT team. I made you a playlist. It's all walk-on music.", |
| "stacey": "Okay so this is unprofessional and I've rehearsed it four times and deleted three drafts, but — would it be weird if I said I look forward to our one-on-ones? More than the agenda warrants?", |
| "kevin": "I ran the numbers on our working relationship and the trend line is, directionally, very warm. I made a slide. The slide has a heart on it. The x-axis is us.", |
| "janet": "I've been building a mood board. It's about us. It's mostly the color of a sunset and one photo of your stapler. I think it's saying something. I think it's saying a lot.", |
| "derek": "Hm. You stayed late again. So did I. ...That's all. Unless it isn't. It might not be. Hm.", |
| } |
|
|
|
|
| def romance_fallback(npc_id: str) -> dict: |
| npc_id = npc_id or "stacey" |
| return { |
| "affected_npc": npc_id, |
| "category": "personal", |
| "headline": f"{NPC_NAMES[npc_id]} has feelings, apparently", |
| "intro": _ROMANCE_INTROS[npc_id], |
| "option_a": "Lean in. Say you've felt it too. What's the worst that happens.", |
| "option_b": "Smile, keep it warm, and steer firmly back to the quarterly numbers.", |
| "urgency": "The whole floor is pretending not to watch.", |
| "setup_animation": "heart_float", |
| "morale_preview": 4, |
| } |
|
|
|
|
| def verdict_fallback(tier: str) -> dict: |
| verdicts = { |
| "hit_target": "Against every available signal, the number is real. The board has voted to stop asking how.", |
| "above_600k": "Close. The board has expressed this in an emoji, in Slack, three times. You know the one.", |
| "300k_to_600k": "The board wants a call. Not a good call. You already know the energy of the call.", |
| "below_300k": "The board has drafted something. It mentions your continued presence. It is currently unsigned.", |
| } |
| return {"verdict": verdicts[tier]} |
|
|