diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d070f77 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +fredagsbar_output/* diff --git a/fredagsbar_output/__init__.py b/fredagsbar_output/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/generator.py b/generator.py new file mode 100644 index 0000000..7581596 --- /dev/null +++ b/generator.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +""" +fredagsbar_ics_generator_v3.py + +Genererer .ics invitationer baseret på JSON stories. +Understøtter nu 'hints' i filnavne og headers. +""" + +import json +import argparse +import sys +from ics import Calendar, Event +from datetime import datetime, date, time, timedelta +from zoneinfo import ZoneInfo +import uuid +import os +import re + +# ====== STANDARD INDSTILLINGER ====== +START_DATE = date(2026, 1, 29) +START_TIME = time(15, 00) +DURATION_MINUTES = 60 +TIMEZONE = ZoneInfo("Europe/Copenhagen") +OUTPUT_BASE_DIR = "fredagsbar_output" +# ==================================== + +def load_story(filepath): + """Indlæser JSON fil og validerer strukturen.""" + try: + with open(filepath, 'r', encoding='utf-8') as f: + data = json.load(f) + return data + except Exception as e: + print(f"Fejl ved indlæsning af {filepath}: {e}") + sys.exit(1) + +def next_or_same_friday(d: date) -> date: + return d + timedelta(days=(4 - d.weekday()) % 7) + +def sanitize_filename(s: str) -> str: + s = re.sub(r"[^\w\s-]", "", s, flags=re.UNICODE) + s = re.sub(r"\s+", "_", s.strip()) + return s[:120] + +def strip_html_tags(text: str) -> str: + clean = re.compile('<.*?>') + return re.sub(clean, '', text) + +def inject_outlook_lines(ical_text: str, html_description: str) -> str: + """Indsætter Outlook-specifikke linjer og HTML beskrivelse.""" + injection_status = "TRANSP:OPAQUE\r\nX-MICROSOFT-CDO-BUSYSTATUS:BUSY\r\n" + # Outlook kræver often at HTML er på én linje eller foldet korrekt + html_oneline = html_description.replace("\n", "") + injection_html = f"X-ALT-DESC;FMTTYPE=text/html:{html_oneline}\r\n" + + def replacer(match): + vevent = match.group(0) + if "X-MICROSOFT-CDO-BUSYSTATUS" not in vevent: + vevent = vevent.replace("\r\nEND:VEVENT", "\r\n" + injection_status + "END:VEVENT") + # Overskriv eller indsæt X-ALT-DESC + if "X-ALT-DESC" in vevent: + # Simpel håndtering: Hvis vi allerede har det, ignorer (eller implementer regex replace af X-ALT-DESC) + pass + else: + vevent = vevent.replace("\r\nEND:VEVENT", "\r\n" + injection_html + "END:VEVENT") + return vevent + + text_crlf = ical_text.replace("\n", "\r\n") + vevent_pattern = re.compile(r"BEGIN:VEVENT[\s\S]*?END:VEVENT", flags=re.IGNORECASE) + return vevent_pattern.sub(replacer, text_crlf) + +def create_event_ics_file(event_data, meta, log_index, total_logs, start_dt, end_dt, out_path): + title = event_data["title"] + story_text = event_data["story"] + hint = event_data.get("hint", "") # Hent hint hvis det findes + + cal = Calendar() + event = Event() + event.uid = str(uuid.uuid4()) + + # Hvis der er et hint, sæt det evt. ind i titlen eller behold titlen ren corporate + event.name = title + event.begin = start_dt + event.end = end_dt + event.status = "CONFIRMED" + event.classification = "PUBLIC" + + # Meta styling + font = meta.get("font", "Arial, sans-serif") + bg_color = meta.get("bg_color", "#f0f0f0") + text_color = meta.get("text_color", "#000000") + theme_color = meta.get("theme_color", "#000000") + log_prefix = meta.get("log_prefix", "LOG") + + # Byg Header strengen + header_text = f"// {log_prefix} {log_index:02d}/{total_logs} // SUBJECT: {title.upper()}" + if hint: + header_text += f" // CODE: {hint}" + + # --- HTML Version (Outlook) --- + html_desc = ( + f"
" + f"{header_text}

" + f"
" + f"{story_text}" # Her indsætter vi story direkte, da den nu indeholder HTML tags fra JSON + f"

" + "
" + "OBS: Dette er en invitation til en fredagsbar.
" + "Dette event er automatisk genereret til Fredagsbar, med en title der giver Nicolaj mulighed for at deltage.
" + "Ingen forberedelse nødvendig.

" + "" + "Vibecoded sourcecode til generering kan findes her: gitea.weircon.dk/{{repo}}" + "" + "
" + ) + + # --- Plain Text Version --- + # Vi erstatter
med \n for læsbarhed i plain text + plain_story = story_text.replace("
", "\n").replace("", "").replace("", "").replace("", "").replace("", "") + plain_desc = ( + f"{header_text}\n\n" + f"{plain_story}\n\n" + "--------------------------------------------------\n" + "OBS: Dette er en invitation til en fredagsbar.\n" + "Ingen forberedelse nødvendig.\n" + "https://gitea.weircon.dk/{{repo}}" + ) + + event.description = plain_desc + cal.events.add(event) + + serialized = cal.serialize() + processed = inject_outlook_lines(serialized, html_desc) + + with open(out_path, "w", encoding="utf-8", newline="\r\n") as f: + f.write(processed) + + print(f"[{log_index}/{total_logs}] '{title}' -> {out_path}") + +def generate_series(json_path): + data = load_story(json_path) + meta = data["meta"] + events = data["events"] + + story_slug = sanitize_filename(meta.get("name", "story")) + output_dir = os.path.join(OUTPUT_BASE_DIR, story_slug) + os.makedirs(output_dir, exist_ok=True) + + print(f"--- Starter generering af: {meta.get('name')} ---") + + first_friday = next_or_same_friday(START_DATE) + total_logs = len(events) + + for idx, event_entry in enumerate(events): + event_date = first_friday + timedelta(weeks=idx) + start_dt = datetime.combine(event_date, START_TIME).replace(tzinfo=TIMEZONE) + end_dt = start_dt + timedelta(minutes=DURATION_MINUTES) + + log_num = idx + 1 + + # Bruger hint i filnavnet hvis det findes + hint_part = "" + if "hint" in event_entry: + hint_part = f"_{sanitize_filename(event_entry['hint'])}" + + fname = f"{event_date.strftime('%Y%m%d')}_Log{log_num}{hint_part}_{sanitize_filename(event_entry['title'])}.ics" + out_path = os.path.join(output_dir, fname) + + create_event_ics_file(event_entry, meta, log_num, total_logs, start_dt, end_dt, out_path) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generer Fredagsbar ICS filer fra JSON historie.") + parser.add_argument("story_file", help="Sti til JSON filen med historien (f.eks. stories/story_scp.json)") + + args = parser.parse_args() + + if not os.path.exists(args.story_file): + print(f"Fejl: Filen '{args.story_file}' findes ikke.") + sys.exit(1) + + generate_series(args.story_file) + print("\nFærdig!") \ No newline at end of file diff --git a/stories/object_87-B.json b/stories/object_87-B.json new file mode 100644 index 0000000..bd87c45 --- /dev/null +++ b/stories/object_87-B.json @@ -0,0 +1,113 @@ +{ + "meta": { + "name": "Objekt 87-B: Containment Breach", + "theme_color": "#000000", + "text_color": "#e0e0e0", + "bg_color": "#333333", + "font": "Consolas, monospace", + "organizer": "Site Administration", + "log_prefix": "LOG" + }, + "events": [ + { + "title": "Initialiserende Synkroniseringsmatrix", + "hint": "INITIALISERING", + "story": "OFFICIELT FORMÅL:
• Opstart af kvartalets synkronisering
• Kaffe og networking

OBSERVATION:
Jeg er ikke sikker på, hvornår jeg ankom. Kalenderen siger uge 1, men kaffen smager af statisk elektricitet.
Ledelsen insisterer på 'social kohærens'.

Vi mødes kl. 15. Det virker sikkert... for nu." + }, + { + "title": "Tværgående Ressource-Allokering", + "hint": "DUPLIKAT", + "story": "OFFICIELT FORMÅL:
• Ressourcefordeling på tværs af teams

OBSERVATION:
Jeg så en kollega gå ind i mødelokale B, men han kom aldrig ud igen. I stedet kom en identisk person ud med et lidt andet slips.

Vi har brug for væske til at stabilisere nerverne og bekræfte hvem der er originaler." + }, + { + "title": "Strategisk Interessent-Dialog", + "hint": "INTERFERENS", + "story": "OFFICIELT FORMÅL:
• Interessentpleje og dialog

OBSERVATION:
Lyden af tastaturer er stoppet i storrummet, men teksten vises stadig på skærmene af sig selv.

Hypotese: Hvis vi samles i grupper og indtager fermenteret korn, lader det til at holde skyggerne i hjørnerne på afstand." + }, + { + "title": "Operationel Effektiviserings-Sprint", + "hint": "LINEARITET", + "story": "OFFICIELT FORMÅL:
• Sprint-planlægning og effektivisering

OBSERVATION:
Kantinen serverer i dag 'biomasse'. Jeg holder mig til flydende fødevarer efter kl. 15.00.

Det er det eneste tidspunkt på ugen, hvor tidsregningen føles lineær og ikke cirkulær." + }, + { + "title": "Vidensdeling: Procedure 734", + "hint": "SMITTE", + "story": "OFFICIELT FORMÅL:
• Vidensdeling om interne procedurer

OBSERVATION:
Fandt en post-it note under mit skrivebord. Der stod: 'Drik ikke vandet, hold dig til dåserne'.
Jeg ved ikke, hvem der skrev det.

Det ligner min egen håndskrift, men blækket er stadig vådt." + }, + { + "title": "Ad hoc Kapacitetsudligning", + "hint": "RESPIRATION", + "story": "OFFICIELT FORMÅL:
• Udligning af arbejdspres

OBSERVATION:
Luftfugtigheden stiger drastisk hver fredag eftermiddag. Det føles som om, bygningen trækker vejret langsommere.

Vi må udligne det atmosfæriske tryk internt med brusende væsker for ikke at få propper i ørerne." + }, + { + "title": "Vertikal Alignment Session", + "hint": "KOLLEKTIV", + "story": "OFFICIELT FORMÅL:
• Alignment mellem ledelse og drift

OBSERVATION:
Ledelsen taler om 'synergi', men jeg tror, de mener 'hive-mind'.

Alkohol synes at forstyrre signalet fra moderskibet. Vi skal drikke for at forblive individer." + }, + { + "title": "Kvalitativt Review af Normalsituationen", + "hint": "GEOMETRI", + "story": "OFFICIELT FORMÅL:
• Review af driften

OBSERVATION:
Mødelokalerne skifter placering, når man ikke kigger. Gangene er længere end bygningen er bred.

Baren er det eneste faste holdepunkt i denne ikke-euklidiske geometri. Mød op for at bekræfte din lokation." + }, + { + "title": "Frivillig Compliance Workshop", + "hint": "ANKER", + "story": "OFFICIELT FORMÅL:
• Workshop om compliance (frivillig)

OBSERVATION:
Vi har observeret fluktuationer i virkelighedsfeltet.
En kold øl i hånden fungerer som et anker mod virkeligheden.

Det er ikke længere en fest, det er en overlevelsesstrategi." + }, + { + "title": "Human Capital Optimering", + "hint": "RESSOURCE", + "story": "OFFICIELT FORMÅL:
• Optimering af human capital

OBSERVATION:
De kalder det 'Human Capital'. Jeg er bange for, at 'Capital' skal tages bogstaveligt som valuta.

Vi må bruge budgettet, før budgettet bruger os." + }, + { + "title": "Systemisk Retrospektiv", + "hint": "ENTROPI", + "story": "OFFICIELT FORMÅL:
• Tilbageblik på systemets performance

OBSERVATION:
Jeg har glemt, hvad vi producerer her. Rapporter? Kode? Eller bare entropi?

Svaret findes muligvis i bunden af en flaske efter kl. 15, eller også glemmer man spørgsmålet." + }, + { + "title": "Agil Proces-Implementering", + "hint": "HASTIGHED", + "story": "OFFICIELT FORMÅL:
• Implementering af agile principper

OBSERVATION:
Agilitet er nøglen. Hvis du bevæger dig hurtigt nok mod køleskabet, kan bevægelsessensorerne ikke nå at registrere din frygt.

Sprint review starter nu. Løb." + }, + { + "title": "Holistisk Værdiskabelse", + "hint": "VÅGEN", + "story": "OFFICIELT FORMÅL:
• Skabelse af værdi på tværs

OBSERVATION:
Værdien er skabt. Men for hvem? Enhederne i habitterne nikker bare.

Jeg har brug for at se et andet menneske i øjnene og skåle for at vide, at jeg ikke drømmer." + }, + { + "title": "Strategisk Baseline-Justering", + "hint": "BASELINE", + "story": "OFFICIELT FORMÅL:
• Justering af strategiske baselines

OBSERVATION:
Baselines flytter sig fysisk. I går var loftet grønt. I dag er det... væk?

Vi samles under de kunstige lysstofrør for at genoprette normaltilstanden gennem fælles konsensus." + }, + { + "title": "Konsolidering af Output", + "hint": "SAFE_ZONE", + "story": "OFFICIELT FORMÅL:
• Konsolidering af ugens output

OBSERVATION:
Outputtet lækker ud på gulvet. Der er glitch i matrixen ved kaffemaskinen.

Fredagsbaren er nu klassificeret som en 'Safe Zone'. Søg dækning og forfriskninger øjeblikkeligt." + }, + { + "title": "Skalerbarheds-analyse", + "hint": "TOMHED", + "story": "OFFICIELT FORMÅL:
• Analyse af skalerbarhed

OBSERVATION:
Problemet skalerer eksponentielt. Vi er nødt til at skalere vores modstandsdygtighed.

Protokollen foreskriver socialt samvær som eneste kendte modgift mod den snigende tomhed i gangene." + }, + { + "title": "Integreret Governance Møde", + "hint": "OVERVÅGNING", + "story": "OFFICIELT FORMÅL:
• Governance og styring

OBSERVATION:
De observerer os gennem PowerPoints. Hvis vi lader som om, vi holder et 'møde' med øl, lader de os være i fred.

Spil med. For din egen skyld. Nik og smil." + }, + { + "title": "Afsluttende KPI-Opfølgning", + "hint": "ATMOSFÆRE", + "story": "OFFICIELT FORMÅL:
• Opfølgning på KPI'er

OBSERVATION:
KPI: 'Keep Panic Inside'. Det lykkes bedst med en promille over 0.

Det er næsten slut nu. Jeg kan mærke en ændring i atmosfærens kemiske sammensætning." + }, + { + "title": "Exit Strategy Formulering", + "hint": "INGEN_UDGANG", + "story": "OFFICIELT FORMÅL:
• Formulering af exit-strategier

OBSERVATION:
Der er ingen udgang. Døren i receptionen er blot et maleri på væggen.

Men så længe der er fredagsbar, er vi i det mindste fanget sammen." + }, + { + "title": "Total System Reboot", + "hint": "GENSTART", + "story": "OFFICIELT FORMÅL:
• Systemvedligeholdelse

OBSERVATION:
Cyklussen er komplet. Hukommelsen vil blive slettet mandag morgen.

Nyd denne sidste stund af klarhed. Vi ses på den anden side af genstarten." + } + ] +} \ No newline at end of file diff --git a/stories/sagen_om_konsulent_n.json b/stories/sagen_om_konsulent_n.json new file mode 100644 index 0000000..8df581e --- /dev/null +++ b/stories/sagen_om_konsulent_n.json @@ -0,0 +1,113 @@ +{ + "meta": { + "name": "Sagen om Konsulent N.", + "theme_color": "#b30000", + "text_color": "#1a1a1a", + "bg_color": "#fff5f5", + "font": "Courier New, monospace", + "organizer": "Internal Audit / Shadow IT", + "log_prefix": "CASE FILE" + }, + "events": [ + { + "title": "Ugentlig tværgående synkronisering", + "hint": "AFVIGELSE", + "story": "OFFICIELT FORMÅL:
• Hurtig synk af ugens løse ender
• Ingen forberedelse nødvendig (seriøst)

FORTROLIGT UDDRAG:
Vi har en afvigelse i kalenderdomænet. Konsulent “N.” har stået som *OPTAGET* siden sidste fredag.
Der findes ingen mødeindkaldelse i historikken — kun en gentagelse.

Bemærkning:
Hvis du hører Outlook-påmindelsen uden at have en påmindelse: ignorer den, og mød op alligevel.
" + }, + { + "title": "Obligatorisk sjov", + "hint": "BADGE", + "story": "OFFICIELT FORMÅL:
• “Teambuilding” uden slide deck
• Interessentpleje (humør)

FORTROLIGT UDDRAG:
Receptionen fandt et adgangskort med teksten: “KONSULENT N.” på gulvet ved køleskabet.
Kortet var lunt, som om det lige var blevet brugt — men ingen har registreret adgang.

Til stedeværende anbefales:
Smil normalt. Lad være med at sige ordet “gentagelse” højt før kl. 15:05.
" + }, + { + "title": "Afsluttende statusmøde (uformelt)", + "hint": "SIGNAL", + "story": "OFFICIELT FORMÅL:
• Uformel status og weekendoverdragelse
• Opsamling på “wins”

FORTROLIGT UDDRAG:
Kl. 15:00 præcis kom der et systemevent:
“Your meeting has been updated.”
Ingen opdaterede noget.

Kort efter: en enkelt linje i beskrivelsesfeltet (nu slettet):
“…jeg kan høre isterningerne, men jeg kan ikke nå dem.”" + }, + { + "title": "Kvalitativ erfaringsudveksling", + "hint": "NOTE", + "story": "OFFICIELT FORMÅL:
• Del en ting der virkede denne uge
• Del en ting der ikke gjorde

FORTROLIGT UDDRAG:
Der cirkulerer en printet mødeagenda med håndskrift nederst:

“Hvis I læser dette, så er jeg ikke forsvundet.
Jeg er bare blevet flyttet til et lokale, der kun findes om fredagen.”

Papiret lugter af citrus og… mødelokale-tæppe." + }, + { + "title": "Strategisk afrunding af arbejdsugen", + "hint": "INDDÆMNING", + "story": "OFFICIELT FORMÅL:
• Strategisk afrunding (aka: “god weekend”)

FORTROLIGT UDDRAG:
IT har forsøgt at “aflyse serien”.
Kalenderen genopretter den inden for 9 sekunder.

Foreløbig inddæmningsprocedure:
• Indkaldelsen må ikke slettes
• Deltagere skal møde fysisk op
• Der må gerne medbringes snacks (observationsmæssigt stabiliserende)" + }, + { + "title": "Tværfaglig alignment-session", + "hint": "STØTTE", + "story": "OFFICIELT FORMÅL:
• Let alignment på tværs (ingen action items)

FORTROLIGT UDDRAG:
HR, IT og Facilities blev spurgt, om der findes et “Mødelokale 4B (uofficielt)”.
Facilities svarede: “Det gør der ikke.”
Så tilføjede de: “Men døren står nogle gange på klem om fredagen.”

Anbefaling:
Kom som du er. Tag evt. en ekstra ven med. (Flere vidner = færre glitch).
" + }, + { + "title": "Ad hoc interessentdialog", + "hint": "KØLESKAB", + "story": "OFFICIELT FORMÅL:
• Løst og socialt touchpoint

FORTROLIGT UDDRAG:
Ny interessent identificeret: Køleskabet.
Det afgiver en svag brummen i en rytme, der minder om en mødepåmindelse.

Ved forsøg på åbning kl. 14:59:
• håndtag koldt
• håndtag “giver sig” først efter en skål

Hypotese:
Køleskabet reagerer på ritualiseret fredagsbar-adfærd." + }, + { + "title": "Intern kapacitetsudligning", + "hint": "KAPACITET", + "story": "OFFICIELT FORMÅL:
• Afbalancering af ugens energiniveau

FORTROLIGT UDDRAG:
Vi har brug for kapacitetsplanlægning:
• 1 person: isterninger
• 1 person: musik
• 1 person: “spørg ikke hvorfor, bare gør det” (koordinator)

Konsulent N. er muligvis låst til en times varighed ad gangen.
Hvis nogen forlader før tid, bliver rummet… mindre." + }, + { + "title": "Letvægts-retrospektiv", + "hint": "RETRO", + "story": "OFFICIELT FORMÅL:
• Hvad skal vi gøre mere af? Mindre af?

FORTROLIGT UDDRAG:
Root cause er sandsynligvis denne handling:
Konsulent N. trykkede “Accepter alle forekomster” uden at læse beskrivelsen.

Der findes nu en gentagende mødeserie, som opfører sig som en beholder.
Og N. er “i mødet” — ikke i bygningen." + }, + { + "title": "Uformel leverancegennemgang", + "hint": "NØGLE", + "story": "OFFICIELT FORMÅL:
• Gennemgang af ugens “leverancer” (uformelt)

FORTROLIGT UDDRAG:
Lost & Found indeholdt én genstand, der ikke burde være der:
En nøgle mærket “FB-LOKAL” i en plastikpose.
Posen var dateret næste fredag.

Bemærkning:
Tid opfører sig dårligt i nærheden af serien.
Vi tester nøglen ved første skål.
" + }, + { + "title": "Operationel efterbearbejdning", + "hint": "EKKO", + "story": "OFFICIELT FORMÅL:
• Efterbearbejdning af ugen (lavt gear)

FORTROLIGT UDDRAG:
Når glas rammer glas, kommer der et ekko, der ikke passer til rummet.
Ekkoet lyder som nogen der prøver at sige:
“…er I her…?”

Hvis du hører ekkoet:
Svar ikke direkte. Skål bare igen. (Det virker mere stabilt)." + }, + { + "title": "Tværorganisatorisk vidensdeling", + "hint": "SITES", + "story": "OFFICIELT FORMÅL:
• Vidensdeling (uformel)

FORTROLIGT UDDRAG:
Andre kontorer rapporterer lignende:
“En fredagsbar-invite der bliver ved med at vende tilbage.”
De kalder det: “Den Tilbagevendende Invitation”.

Fælles observation:
Når folk møder op og hygger, falder antallet af fejl i kalenderen midlertidigt." + }, + { + "title": "Kalibreringsmøde (lav intensitet)", + "hint": "TÆRSKEL", + "story": "OFFICIELT FORMÅL:
• Kalibrering uden intensitet

FORTROLIGT UDDRAG:
Kalibreringsparameter fundet:
Temperatur.
Hvis køleskabet når præcis “fredagskoldt”, bliver lyden i rummet klarere.

Strengt forbudt:
0,0% øl omtalt som “sikkert alternativ”.
Det gjorde rummet… meget stille sidst." + }, + { + "title": "Afrunding af ugens initiativer", + "hint": "ÅBNING", + "story": "OFFICIELT FORMÅL:
• Afrunding af igangværende initiativer

FORTROLIGT UDDRAG:
Nøglen passer i en dør, der normalt ikke har nøglehul.
Døren dukker op bag kaffemaskinen præcis 15:02.

På den anden side:
Et lokale med projektor.
Projektoren viser kun én slide:
“STATUS: OPTAGET”" + }, + { + "title": "Intern koordinering uden agenda", + "hint": "STILHED", + "story": "OFFICIELT FORMÅL:
• Koordinering uden agenda

FORTROLIGT UDDRAG:
Vi opdagede at en agenda gør det værre.
Når nogen skriver “Agenda:” i rummet, forsvinder døren igen.

Så:
• Ingen agenda
• Ingen referat
• Ingen action items
Kun fredagsbar.

(Det føles næsten for corporate til at virke. Men det virker.)" + }, + { + "title": "Eksperimentel samarbejdsramme", + "hint": "RITUAL", + "story": "OFFICIELT FORMÅL:
• Eksperimentel ramme (aka: prøv noget)

FORTROLIGT UDDRAG:
Nyt retrieval-eksperiment:
Kl. 15:07 foretages en synkroniseret skål.
Efterfulgt af: “God weekend” sagt én gang — ikke to.

Da vi testede det, kom der en notifikation:
“Konsulent N. forsøger at deltage.”" + }, + { + "title": "Socialt orienteret statusafstemning", + "hint": "PULS", + "story": "OFFICIELT FORMÅL:
• Social statusafstemning (hvordan går det egentlig?)

FORTROLIGT UDDRAG:
Lyden fra “mødelokalet på den anden side” har nu en puls.
Den synker, når nogen griner.
Den stiger, når nogen siger “lige hurtigt”.

Vi kan muligvis trække N. tættere på ved at gøre rummet… menneskeligt." + }, + { + "title": "Procesmæssig nedlukning af ugen", + "hint": "PORTAL", + "story": "OFFICIELT FORMÅL:
• Luk ugen ned på den rigtige måde

FORTROLIGT UDDRAG:
Portalen er stabil i cirka 58 minutter.
Ved 59:30 begynder projektoren at vise “MØDET ER FORLÆNGET”.

Hvis vi ikke lukker rigtigt:
Serien udvider sig med et ekstra “opfølgningsmøde”.
Ingen ønsker et follow-up til fredagsbar. Ingen." + }, + { + "title": "Konsensusbaseret afrunding", + "hint": "BESLUTNING", + "story": "OFFICIELT FORMÅL:
• Konsensusbaseret afrunding (enighed + hygge)

FORTROLIGT UDDRAG:
Vi skal beslutte:
Åbner vi køleskabet helt?

Sidste gang blev døren på klem, og en hånd (med et tastatur-mærke) nåede ud.
Den slap en Post-it:
“Jeg er her. Jeg er stadig optaget.”

Konsensus kræver tilstedeværelse. (Og måske chips)." + }, + { + "title": "Frivillig deltagelse i fælles kontekst", + "hint": "HJEMKOMST", + "story": "OFFICIELT FORMÅL:
• Frivillig deltagelse, fælles kontekst, afslappet

FORTROLIGT UDDRAG:
Hvis retrieval lykkes, vil N. fremstå normal.
Undtagen:
• Hans Outlook vil muligvis vise 1900 ulæste reminders
• Han vil reagere på ordet “gentagelse” som på en høj lyd

Afsluttende note (fra N., modtaget som kalenderopdatering):
“Tak. Bliv ved med at møde op. Det er sådan man holder virkeligheden på plads om fredagen.”
" + } + ] +} \ No newline at end of file