Skip to content

Fix News Realtime Monitor safeoutputs session expiry via analysis-only Heartbeat PR#1903

Merged
pethers merged 2 commits intomainfrom
copilot/fix-news-realtime-monitor-failure
Apr 21, 2026
Merged

Fix News Realtime Monitor safeoutputs session expiry via analysis-only Heartbeat PR#1903
pethers merged 2 commits intomainfrom
copilot/fix-news-realtime-monitor-failure

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 21, 2026

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 found on its first create_pull_request call. 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

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-monitor was the sole workflow with an articles-in-PR-1 design. The shared-rule update in SHARED_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

Before (broken) After
PR #1 content EN + SV articles + Pass 1 analysis Pass 1 analysis artifacts only
PR #1 deadline minute 25 (unreachable) minute 18 (always reachable — files already on disk)
Article writing before PR #1 (blocks session) between PR #1 and PR #2 (session already refreshed)
Session-expiry risk High — 15+ min idle window None — PR #1 fires <60 s after Pass 1 completes

Copilot AI linked an issue Apr 21, 2026 that may be closed by this pull request
@github-actions github-actions Bot added the size-xs Extra small change (< 10 lines) label Apr 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🏷️ Automatic Labeling Summary

This PR has been automatically labeled based on the files changed and PR metadata.

Applied Labels: size-xs

Label Categories

  • 🗳️ Content: news, dashboard, visualization, intelligence
  • 💻 Technology: html-css, javascript, workflow, security
  • 📊 Data: cia-data, riksdag-data, data-pipeline, schema
  • 🌍 I18n: i18n, translation, rtl
  • 🔒 ISMS: isms, iso-27001, nist-csf, cis-controls
  • 🏗️ Infrastructure: ci-cd, deployment, performance, monitoring
  • 🔄 Quality: testing, accessibility, documentation, refactor
  • 🤖 AI: agent, skill, agentic-workflow

For more information, see .github/labeler.yml.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@github-actions github-actions Bot added documentation Documentation updates workflow GitHub Actions workflows ci-cd CI/CD pipeline changes news News articles and content generation agentic-workflow Agentic workflow changes size-m Medium change (50-250 lines) labels Apr 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copilot AI changed the title [WIP] Fix workflow failure for News Realtime Monitor Fix News Realtime Monitor safeoutputs session expiry via analysis-only Heartbeat PR Apr 21, 2026
Copilot AI requested a review from pethers April 21, 2026 13:48
@pethers pethers marked this pull request as ready for review April 21, 2026 13:49
Copilot AI review requested due to automatic review settings April 21, 2026 13:49
@pethers pethers merged commit cb0aff9 into main Apr 21, 2026
13 checks passed
@pethers pethers deleted the copilot/fix-news-realtime-monitor-failure branch April 21, 2026 13:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-monitor workflow 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 #2improvements 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. |
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
| **🫀 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. |

Copilot uses AI. Check for mistakes.
Comment on lines +327 to +332
| **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. |
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
| **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. |

Copilot uses AI. Check for mistakes.
Comment on lines +2675 to +2679
> 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`.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
> 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`.

Copilot uses AI. Check for mistakes.
Comment on lines +337 to 339
> ⚠️ **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.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentic-workflow Agentic workflow changes ci-cd CI/CD pipeline changes documentation Documentation updates news News articles and content generation size-m Medium change (50-250 lines) size-xs Extra small change (< 10 lines) workflow GitHub Actions workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw] News Realtime Monitor failed

3 participants