Conversation
🏷️ Automatic Labeling SummaryThis PR has been automatically labeled based on the files changed and PR metadata. Applied Labels: size-xs Label Categories
For more information, see |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/3ac28289-b972-4cca-a949-fb423b1d06b9 Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
This PR updates the realtime news agentic workflow guidance to prevent Safe Outputs MCP session expiry by requiring an early, analysis-only “Heartbeat” PR before time-consuming article writing begins.
Changes:
- Updated
news-realtime-monitorworkflow prompt to split output into an early analysis-only Heartbeat PR (#1) and a later full-articles PR (#2), with optional PR #3. - Revised shared “Universal Safe Output Rules” to mandate an analysis-only Heartbeat PR early in the run.
- Recompiled the workflow lockfile to the latest gh-aw compile output (incl. dispatch schema changes).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
.github/workflows/news-realtime-monitor.md |
Shifts PR #1 to an earlier analysis-only heartbeat window to keep the safeoutputs session alive before article writing. |
.github/workflows/news-realtime-monitor.lock.yml |
Recompiled lockfile (tool schema/config updates such as aw_context). |
.github/aw/SHARED_PROMPT_PATTERNS.md |
Updates shared safe output rules to enforce the analysis-only heartbeat pattern across workflows. |
| | **PR #2 — improvements batch** | **40–43** | Commit the improved articles + enriched analysis on a fresh branch (`git checkout main` first!), then `safeoutputs___create_pull_request` again (title `🔴 Breaking $HHMM (improved): {headline} - {date}`). This second call also refreshes the session. | | ||
| | Post-PR cleanup | 43–45 | Update repo-memory (`/tmp/gh-aw/repo-memory/default/*.json`) — artifact uploads, NOT PR content, so they run after the final PR call. Optional PR #3 if additional articles exist. | | ||
| | **AI Analysis Pass 1** | **6–13** | **🚨 MANDATORY 7 min minimum for first heartbeat**: Read methodology guides, create per-file analysis stubs for EVERY document with initial Mermaid diagrams, evidence tables, SWOT entries. Full depth iteration continues AFTER the heartbeat PR is safely called. | | ||
| | **🫀 PR #1 — Analysis-only Heartbeat** | **13–18** | 🚨 **HARD MIN: by minute 18.** Commit whatever analysis artifacts exist in `analysis/daily/$ARTICLE_DATE/realtime-$HHMM/` (even partial Pass 1 stubs). **Do NOT write articles yet.** Title: `🫀 Heartbeat - Realtime Monitor - {date} {HHMM}`. Labels: `["analysis-only", "realtime-monitor", "heartbeat"]`. This call refreshes the safeoutputs MCP session (~30–35 min idle lifetime) AND preserves Pass 1 analysis work. After the call succeeds, run `git checkout main` to avoid appending to a frozen patch. | |
There was a problem hiding this comment.
PR #1 instructions specify labels ["analysis-only", "realtime-monitor", "heartbeat"], but the repository’s label bootstrap workflow (.github/workflows/setup-labels.yml) does not define realtime-monitor or heartbeat (and doesn’t define analysis-only either). If these labels aren’t present in the repo, safeoutputs___create_pull_request label application may fail and defeat the heartbeat. Consider either (a) updating label setup to create these labels, or (b) using an existing label set that is guaranteed to exist.
| | **🫀 PR #1 — Analysis-only Heartbeat** | **13–18** | 🚨 **HARD MIN: by minute 18.** Commit whatever analysis artifacts exist in `analysis/daily/$ARTICLE_DATE/realtime-$HHMM/` (even partial Pass 1 stubs). **Do NOT write articles yet.** Title: `🫀 Heartbeat - Realtime Monitor - {date} {HHMM}`. Labels: `["analysis-only", "realtime-monitor", "heartbeat"]`. This call refreshes the safeoutputs MCP session (~30–35 min idle lifetime) AND preserves Pass 1 analysis work. After the call succeeds, run `git checkout main` to avoid appending to a frozen patch. | | |
| | **🫀 PR #1 — Analysis-only Heartbeat** | **13–18** | 🚨 **HARD MIN: by minute 18.** Commit whatever analysis artifacts exist in `analysis/daily/$ARTICLE_DATE/realtime-$HHMM/` (even partial Pass 1 stubs). **Do NOT write articles yet.** Title: `🫀 Heartbeat - Realtime Monitor - {date} {HHMM}`. Labels: none — omit label arguments unless they are confirmed to exist in the repository label set, to avoid `safeoutputs___create_pull_request` failure. This call refreshes the safeoutputs MCP session (~30–35 min idle lifetime) AND preserves Pass 1 analysis work. After the call succeeds, run `git checkout main` to avoid appending to a frozen patch. | |
| | **AI Analysis Pass 1** | **6–13** | **🚨 MANDATORY 7 min minimum for first heartbeat**: Read methodology guides, create per-file analysis stubs for EVERY document with initial Mermaid diagrams, evidence tables, SWOT entries. Full depth iteration continues AFTER the heartbeat PR is safely called. | | ||
| | **🫀 PR #1 — Analysis-only Heartbeat** | **13–18** | 🚨 **HARD MIN: by minute 18.** Commit whatever analysis artifacts exist in `analysis/daily/$ARTICLE_DATE/realtime-$HHMM/` (even partial Pass 1 stubs). **Do NOT write articles yet.** Title: `🫀 Heartbeat - Realtime Monitor - {date} {HHMM}`. Labels: `["analysis-only", "realtime-monitor", "heartbeat"]`. This call refreshes the safeoutputs MCP session (~30–35 min idle lifetime) AND preserves Pass 1 analysis work. After the call succeeds, run `git checkout main` to avoid appending to a frozen patch. | | ||
| | **AI Analysis Pass 2** | **18–25** | **🚨 MANDATORY 7 min minimum**: Read ALL analysis back, improve every section, add cross-references, replace remaining script stubs. Run enrichment verification gate. | | ||
| | Generate + Write articles | 25–35 | Run `generate-news-enhanced.ts`; write the full EN + SV articles (lead-story aligned; zero `AI_MUST_REPLACE` markers). Article writing takes 8–12 minutes — this is now SAFE because PR #1 already refreshed the session. | | ||
| | Validate + fix-refs | 35–38 | Run `validate-news-generation.sh` and `fix-analysis-references.ts`. | | ||
| | **PR #2 — Full articles batch** | **38–43** | Commit finalized EN + SV articles + enriched analysis on a fresh branch (`git checkout main` first!), then `safeoutputs___create_pull_request` (title `🔴 Breaking $HHMM: {headline} - {date}`). This second call also refreshes the session idle timer. | |
There was a problem hiding this comment.
In the new schedule, “AI Analysis Pass 1” is defined as 6–13 with a 7-minute minimum, but earlier “NON-NEGOTIABLE RULES” in this workflow describe Pass 1 as a 15-minute minimum (and Pass 2 as 7 minutes) before articles are generated. Consider renaming this 6–13 block to something like “Pass 1 (initial stubs for heartbeat)” and explicitly budgeting the remaining Pass 1 time after the heartbeat, or update the minimum-pass timing text so the workflow doesn’t give incompatible requirements.
| | **AI Analysis Pass 1** | **6–13** | **🚨 MANDATORY 7 min minimum for first heartbeat**: Read methodology guides, create per-file analysis stubs for EVERY document with initial Mermaid diagrams, evidence tables, SWOT entries. Full depth iteration continues AFTER the heartbeat PR is safely called. | | |
| | **🫀 PR #1 — Analysis-only Heartbeat** | **13–18** | 🚨 **HARD MIN: by minute 18.** Commit whatever analysis artifacts exist in `analysis/daily/$ARTICLE_DATE/realtime-$HHMM/` (even partial Pass 1 stubs). **Do NOT write articles yet.** Title: `🫀 Heartbeat - Realtime Monitor - {date} {HHMM}`. Labels: `["analysis-only", "realtime-monitor", "heartbeat"]`. This call refreshes the safeoutputs MCP session (~30–35 min idle lifetime) AND preserves Pass 1 analysis work. After the call succeeds, run `git checkout main` to avoid appending to a frozen patch. | | |
| | **AI Analysis Pass 2** | **18–25** | **🚨 MANDATORY 7 min minimum**: Read ALL analysis back, improve every section, add cross-references, replace remaining script stubs. Run enrichment verification gate. | | |
| | Generate + Write articles | 25–35 | Run `generate-news-enhanced.ts`; write the full EN + SV articles (lead-story aligned; zero `AI_MUST_REPLACE` markers). Article writing takes 8–12 minutes — this is now SAFE because PR #1 already refreshed the session. | | |
| | Validate + fix-refs | 35–38 | Run `validate-news-generation.sh` and `fix-analysis-references.ts`. | | |
| | **PR #2 — Full articles batch** | **38–43** | Commit finalized EN + SV articles + enriched analysis on a fresh branch (`git checkout main` first!), then `safeoutputs___create_pull_request` (title `🔴 Breaking $HHMM: {headline} - {date}`). This second call also refreshes the session idle timer. | | |
| | **AI Analysis Pass 1A — Initial stubs for heartbeat** | **6–13** | **🚨 MANDATORY 7 min minimum before first heartbeat**: Read methodology guides, create per-file analysis stubs for EVERY document with initial Mermaid diagrams, evidence tables, SWOT entries. This is only the first portion of Pass 1; the remaining Pass 1 time is completed after the heartbeat PR. | | |
| | **🫀 PR #1 — Analysis-only Heartbeat** | **13–18** | 🚨 **HARD MIN: by minute 18.** Commit whatever analysis artifacts exist in `analysis/daily/$ARTICLE_DATE/realtime-$HHMM/` (even partial Pass 1 stubs). **Do NOT write articles yet.** Title: `🫀 Heartbeat - Realtime Monitor - {date} {HHMM}`. Labels: `["analysis-only", "realtime-monitor", "heartbeat"]`. This call refreshes the safeoutputs MCP session (~30–35 min idle lifetime) AND preserves Pass 1 analysis work. After the call succeeds, run `git checkout main` to avoid appending to a frozen patch. | | |
| | **AI Analysis Pass 1B — Complete Pass 1 minimum** | **18–26** | **🚨 MANDATORY 8 min minimum**: Continue and deepen the same analysis so total Pass 1 time reaches the required **15-minute minimum** before any article generation begins. Expand evidence, strengthen Mermaid diagrams, and replace remaining shallow placeholders. | | |
| | **AI Analysis Pass 2** | **26–33** | **🚨 MANDATORY 7 min minimum**: Read ALL analysis back, improve every section, add cross-references, replace remaining script stubs. Run enrichment verification gate. | | |
| | Generate + Write articles | 33–38 | Run `generate-news-enhanced.ts`; write the full EN + SV articles (lead-story aligned; zero `AI_MUST_REPLACE` markers). Article writing begins only after the full Pass 1 minimum and Pass 2 minimum have both been completed; this is SAFE because PR #1 already refreshed the session. | | |
| | Validate + fix-refs | 38–40 | Run `validate-news-generation.sh` and `fix-analysis-references.ts`. | | |
| | **PR #2 — Full articles batch** | **40–43** | Commit finalized EN + SV articles + enriched analysis on a fresh branch (`git checkout main` first!), then `safeoutputs___create_pull_request` (title `🔴 Breaking $HHMM: {headline} - {date}`). This second call also refreshes the session idle timer. | |
| > 1. **Call `safeoutputs___create_pull_request` as EARLY as possible** — the moment you have committed files. The safeoutputs MCP session has a finite lifetime. Successful runs call it by minute ~18. Failed runs that delayed past minute 30 got "session not found" and lost all work. | ||
| > 2. **🫀 Analysis-only Heartbeat PR — MANDATORY first call by minute 18 (`max: 2+`)** — the Streamable-HTTP safeoutputs MCP session has a ~30–35 min idle lifetime (observed in PR #1835, run #24672037751, and **run #24722758908, 2026-04-21, `news-realtime-monitor`**). Every `safeoutputs___create_pull_request` call **resets the session idle timer**. The heartbeat PR MUST contain **only analysis artifacts and/or script-generated stubs that already exist on disk** — it MUST NOT wait for article-writing to complete. Article writing (especially multi-thousand-word EN + SV pieces) routinely takes 8–15 minutes and will blow the idle timer if done before the heartbeat. Pattern: | ||
| > - **PR #1 (analysis-only heartbeat, minute 13–18)**: Commit whatever files exist in `analysis/daily/$ARTICLE_DATE/.../` from Pass 1 (plus any script-generated article skeletons). Title: `🫀 Heartbeat - {workflow} - {date}`. Mark `draft: true` if the workflow supports it. Run `git checkout main` after the call so subsequent commits don't stack onto the frozen patch. | ||
| > - **PR #2 (full content, minute 35–43)**: Commit finalized articles + Pass 2 improvements on a fresh branch. Final title. This supersedes the heartbeat. | ||
| > - `news-committee-reports` (minute 13–15 heartbeat) and `news-translate` (`max: 5`, first batch at minute ~18) have proven this pattern with zero session expiries. `news-realtime-monitor` run #24722758908 FAILED because it tried to include full articles in PR #1 — article writing took minutes 24→34, and the first safeoutputs call at minute 34 got `session not found`. |
There was a problem hiding this comment.
These “UNIVERSAL SAFE OUTPUT RULES” now state a mandatory first heartbeat PR by minute 18 for all workflows, but several workflow prompts still prescribe later heartbeat windows (e.g. .github/workflows/news-motions.md:287 and news-propositions.md:291 use minutes 22–25; news-month-ahead.md:279 uses 19–21). Since all workflows runtime-import this shared file, this introduces conflicting guidance. Either relax this rule to allow per-workflow heartbeat timing (while keeping the “analysis-only before articles” constraint), or update the affected workflow prompts in the same change set.
| > 1. **Call `safeoutputs___create_pull_request` as EARLY as possible** — the moment you have committed files. The safeoutputs MCP session has a finite lifetime. Successful runs call it by minute ~18. Failed runs that delayed past minute 30 got "session not found" and lost all work. | |
| > 2. **🫀 Analysis-only Heartbeat PR — MANDATORY first call by minute 18 (`max: 2+`)** — the Streamable-HTTP safeoutputs MCP session has a ~30–35 min idle lifetime (observed in PR #1835, run #24672037751, and **run #24722758908, 2026-04-21, `news-realtime-monitor`**). Every `safeoutputs___create_pull_request` call **resets the session idle timer**. The heartbeat PR MUST contain **only analysis artifacts and/or script-generated stubs that already exist on disk** — it MUST NOT wait for article-writing to complete. Article writing (especially multi-thousand-word EN + SV pieces) routinely takes 8–15 minutes and will blow the idle timer if done before the heartbeat. Pattern: | |
| > - **PR #1 (analysis-only heartbeat, minute 13–18)**: Commit whatever files exist in `analysis/daily/$ARTICLE_DATE/.../` from Pass 1 (plus any script-generated article skeletons). Title: `🫀 Heartbeat - {workflow} - {date}`. Mark `draft: true` if the workflow supports it. Run `git checkout main` after the call so subsequent commits don't stack onto the frozen patch. | |
| > - **PR #2 (full content, minute 35–43)**: Commit finalized articles + Pass 2 improvements on a fresh branch. Final title. This supersedes the heartbeat. | |
| > - `news-committee-reports` (minute 13–15 heartbeat) and `news-translate` (`max: 5`, first batch at minute ~18) have proven this pattern with zero session expiries. `news-realtime-monitor` run #24722758908 FAILED because it tried to include full articles in PR #1 — article writing took minutes 24→34, and the first safeoutputs call at minute 34 got `session not found`. | |
| > 1. **Call `safeoutputs___create_pull_request` as EARLY as possible** — the moment you have committed files. The safeoutputs MCP session has a finite lifetime. Successful runs commonly call it by minute ~18. Failed runs that delayed past minute 30 got "session not found" and lost all work. | |
| > 2. **🫀 Analysis-only Heartbeat PR — REQUIRED as the first safeoutputs call (`max: 2+`)** — the Streamable-HTTP safeoutputs MCP session has a ~30–35 min idle lifetime (observed in PR #1835, run #24672037751, and **run #24722758908, 2026-04-21, `news-realtime-monitor`**). Every `safeoutputs___create_pull_request` call **resets the session idle timer**. The heartbeat PR MUST contain **only analysis artifacts and/or script-generated stubs that already exist on disk** — it MUST NOT wait for article-writing to complete. Article writing (especially multi-thousand-word EN + SV pieces) routinely takes 8–15 minutes and will blow the idle timer if done before the heartbeat. **Default target window is minute 13–18, unless the workflow prompt explicitly specifies another first-heartbeat window. Workflow-specific timing may vary, but the first PR must still happen before article writing and early enough to avoid session expiry.** Pattern: | |
| > - **PR #1 (analysis-only heartbeat, workflow-specific timing; default minute 13–18)**: Commit whatever files exist in `analysis/daily/$ARTICLE_DATE/.../` from Pass 1 (plus any script-generated article skeletons). Title: `🫀 Heartbeat - {workflow} - {date}`. Mark `draft: true` if the workflow supports it. Run `git checkout main` after the call so subsequent commits don't stack onto the frozen patch. | |
| > - **PR #2 (full content, typically minute 35–43)**: Commit finalized articles + Pass 2 improvements on a fresh branch. Final title. This supersedes the heartbeat. | |
| > - `news-committee-reports` (minute 13–15 heartbeat) and `news-translate` (`max: 5`, first batch at minute ~18) have proven this pattern with zero session expiries. Some other workflows may intentionally use slightly later first-heartbeat windows in their own prompts. `news-realtime-monitor` run #24722758908 FAILED because it tried to include full articles in PR #1 — article writing took minutes 24→34, and the first safeoutputs call at minute 34 got `session not found`. |
| > ⚠️ **Why analysis-only heartbeat answers "keep the session alive":** the safeoutputs MCP Streamable HTTP session dies from idle (~30–35 min observed). Run 24722758908 proved that article writing routinely takes 10+ minutes — attempting to include articles in PR #1 forces a 10+ minute idle window that kills the session. PR #1 = analysis-only = can be committed in <60 seconds because the files already exist on disk from Pass 1. PR #2 = full articles, which the session now survives because PR #1 refreshed the idle timer at minute ~15. This is exactly how the other 11 news workflows work successfully (`news-committee-reports` minute 13–15, `news-motions`/`news-propositions`/`news-interpellations` minute 22–25 with analysis-only heartbeats). | ||
|
|
||
| > ⚠️ **Analysis phase is 22 minutes minimum (Pass 1: 12 min + Pass 2: 7 min + Improvement: 3 min or more) — this is NOT negotiable.** PR #1452 demonstrated that < 10 min produces unacceptable analysis. PR #1794 demonstrated that 15 min total = shallow articles missing SWOT tables, Mermaid diagrams, risk matrices. With rolling PRs, Pass 2 + Improvement run AFTER PR #1 is safely committed — so quality iteration no longer risks losing everything. |
There was a problem hiding this comment.
The time budget table allocates 6–13 (Pass 1) and 18–25 (Pass 2), but this block then states “Analysis phase is 22 minutes minimum (Pass 1: 12 + Pass 2: 7 + Improvement: 3+)”. As written, the schedule doesn’t provide 22 minutes of analysis time before article generation at minute 25, so the prompt becomes internally inconsistent. Please adjust either the minute ranges (so the 22-minute minimum is achievable before “Generate + Write articles”) or update the 22-minute minimum/gate text to match the new heartbeat-driven pacing.
Run 24722758908 produced no safe outputs: the agent idled the safeoutputs MCP session for 22 minutes writing EN/SV articles (minutes 12→34), then got
session not foundon its firstcreate_pull_requestcall. All 8+ retries failed, all work lost — identical outcome to the 2026-04-20 incident (run 24672037751).Root cause: PR #1 was specified to contain initial EN + SV articles + Pass 1 analysis by minute 22–25. Writing 6,000+ words of publication-quality article from scratch takes 8–15 min, which exceeds the ~30–35 min Streamable-HTTP session idle lifetime. The deadline was unreachable by construction.
Changes
.github/aw/SHARED_PROMPT_PATTERNS.md— Universal Safe Output Rules rewritten to mandate an analysis-only Heartbeat PR by minute 18 across all 12 agentic workflows. PR Setup riksdagsmonitor: 14-language Swedish Parliament intelligence platform with ISMS compliance #1 must contain only files already on disk from Pass 1 (analysis artifacts, script stubs) — never wait for article writing. Articles move to PR Sync styles.css from Hack23/homepage #2..github/workflows/news-realtime-monitor.md— Time budget, hard cutoffs, Step 5 required pattern, error-handling row, and safety-net paragraph realigned to the three-phase structure:🫀 Heartbeat - Realtime Monitor - {date} {HHMM}).github/workflows/news-realtime-monitor.lock.yml— recompiled viagh aw compile(v0.69.0).Coverage
The other 11 news workflows already implement the analysis-only Heartbeat pattern (committee-reports at 13–15, motions/propositions/interpellations at 22–25, etc.) and have no reported expiry incidents.
news-realtime-monitorwas the sole workflow with an articles-in-PR-1 design. The shared-rule update inSHARED_PROMPT_PATTERNS.md(referenced by all 12 workflows via{{#runtime-import}}) reinforces the pattern globally on the next run without needing per-workflow recompiles.Before / After time budget