diff --git a/.github/actions/news-prewarm/action.yml b/.github/actions/news-prewarm/action.yml new file mode 100644 index 0000000000..04651e93b3 --- /dev/null +++ b/.github/actions/news-prewarm/action.yml @@ -0,0 +1,106 @@ +name: 'News workflow pre-warm & pre-flight' +description: | + Shared setup for every `.github/workflows/news-*.md` agentic workflow: + 1. Set up Node.js 25 (matches `runtimes.node.version` in every workflow). + 2. `npm ci --prefer-offline --no-audit`. + 3. Pre-warm the riksdag-regering MCP server (Render.com cold-start mitigation). + 4. Pre-flight DNS + HTTPS reachability + MCP `tools/list` probe for the + upstream services consumed by the news pipeline. + + This action exists to deduplicate ~80 lines of identical YAML across the 11 + news workflow files. Edit it in one place. +inputs: + node-version: + description: 'Node.js version (must match the workflow `runtimes.node.version`).' + required: false + default: '25' + mcp-url: + description: 'Riksdag-regering MCP HTTP endpoint to pre-warm.' + required: false + default: 'https://riksdag-regering-ai.onrender.com/mcp' +runs: + using: 'composite' + steps: + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: ${{ inputs.node-version }} + + - name: Install dependencies + shell: bash + run: npm ci --prefer-offline --no-audit + + - name: Pre-warm MCP server (Render.com cold start mitigation) + shell: bash + env: + MCP_URL: ${{ inputs.mcp-url }} + run: | + echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." + WARM=false + for i in 1 2 3 4 5 6; do + RESP=$(curl -sf --max-time 30 -X POST \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ + "$MCP_URL" 2>/dev/null) || true + if echo "$RESP" | grep -q '"tools"'; then + TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) + echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" + WARM=true + break + fi + echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." + sleep 20 + done + if [ "$WARM" = "false" ]; then + echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" + fi + + - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) + shell: bash + env: + MCP_URL: ${{ inputs.mcp-url }} + run: | + echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" + echo "═══════════════════════════════════════════" + echo "" + echo "πŸ“‘ DNS Resolution Tests:" + for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do + if nslookup "$domain" >/dev/null 2>&1; then + IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') + echo " βœ… $domain β†’ $IP" + else + echo " ❌ $domain β€” DNS FAILED" + fi + done + echo "" + echo "🌐 HTTPS Connectivity Tests:" + for url in \ + "$MCP_URL" \ + "https://api.scb.se/OV0104/v2beta" \ + "https://api.worldbank.org/v2/country/SE?format=json" \ + "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ + ; do + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") + DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) + if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then + echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" + elif [ "$HTTP_CODE" = "000" ]; then + echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" + else + echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" + fi + done + echo "" + echo "πŸ”Œ MCP Server Tool Count:" + TOOL_RESP=$(curl -sf --max-time 15 -X POST \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ + "$MCP_URL" 2>/dev/null) || TOOL_RESP="" + if echo "$TOOL_RESP" | grep -q '"tools"'; then + TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) + echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" + else + echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" + fi + echo "" + echo "═══════════════════════════════════════════" diff --git a/.github/agents/intelligence-operative.md b/.github/agents/intelligence-operative.md index b8f45fdffc..2a8ac8e2e8 100644 --- a/.github/agents/intelligence-operative.md +++ b/.github/agents/intelligence-operative.md @@ -12,7 +12,7 @@ tools: ["*"] 2. [`.github/copilot-mcp.json`](/.github/copilot-mcp.json) β€” MCP servers available 3. [`README.md`](/README.md) β€” project mission, features, architecture 4. [`SECURITY_ARCHITECTURE.md`](/SECURITY_ARCHITECTURE.md) & [`THREAT_MODEL.md`](/THREAT_MODEL.md) -5. [`.github/skills/`](/.github/skills/) β€” auto-loaded skills library (92 skills) +5. [`.github/skills/`](/.github/skills/) β€” auto-loaded skills library (91 skills) --- diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index d9909e89de..24b3261595 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -30,6 +30,11 @@ "version": "v6.3.0", "sha": "53b83947a5a98c8d113130e565377fae1a50d02f" }, + "actions/setup-node@v6.4.0": { + "repo": "actions/setup-node", + "version": "v6.4.0", + "sha": "48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" + }, "actions/upload-artifact@v7": { "repo": "actions/upload-artifact", "version": "v7", diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c4390d8119..e32139cc00 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -3,17 +3,17 @@ ## πŸ“‹ Repository Context **Project**: Riksdagsmonitor β€” Swedish Parliament (Riksdag) monitoring platform -**Stack**: HTML5, CSS3, TypeScript 6.0.2, Vite 8.0.3, Vitest 4.1.2, Cypress 15.13.0 +**Stack**: HTML5, CSS3, TypeScript 6.0.3, Vite 8.0.10, Vitest 4.1.5, Cypress 15.14.1 **Runtime**: Node.js 25, ES2025 target, ESNext modules **Deploy**: GitHub Pages + AWS S3 dual deployment **Languages**: 14-language support (EN, SV, DA, NB, FI, DE, FR, ES, NL, AR, HE, JA, KO, ZH) **Security**: ISO 27001:2022, NIST CSF 2.0, CIS Controls v8.1 compliant **Organization**: Hack23 AB **ISMS**: [Hack23 ISMS-PUBLIC](https://github.com/Hack23/ISMS-PUBLIC) -**Version**: 0.8.17 +**Version**: 0.8.56 **Agents**: 24 agent files (14 persona + 9 workflow-specialist + 1 developer-instructions) in `.github/agents/` **Skills**: 91 skills in `.github/skills/` (including 13 gh-aw skills) -**Workflows**: 45 workflow files (21 standard `.yml` + 12 agentic `.md` sources + 12 compiled `.lock.yml`) +**Workflows**: 43 workflow files (21 standard `.yml` + 11 agentic `.md` sources + 11 compiled `.lock.yml`) **MCP Servers**: 8 configured (riksdag-regering, scb, world-bank, github, filesystem, memory, sequential-thinking, playwright) ## 🎯 Core Rules @@ -112,7 +112,7 @@ Map every security-relevant control to **ISO 27001:2022 Annex A**, **NIST CSF 2. ## πŸ€– GitHub Agentic Workflows -This repo uses [GitHub Agentic Workflows](https://github.github.com/gh-aw/) (gh-aw v0.69.3, pinned via `gh-aw-actions/setup-cli@v0.69.3`) for AI-powered news generation. 12 agentic workflows in `.github/workflows/` produce daily political intelligence articles with five-layer security: +This repo uses [GitHub Agentic Workflows](https://github.github.com/gh-aw/) (gh-aw v0.69.3, pinned via `gh-aw-actions/setup-cli@v0.69.3`) for AI-powered news generation. 11 agentic workflows in `.github/workflows/` produce daily political intelligence articles with five-layer security: 1. **Read-only tokens** β€” Agent gets only read permissions 2. **Zero secrets in agent** β€” Write tokens isolated in separate jobs @@ -289,5 +289,5 @@ tsx scripts/imf-fetch.ts list-indicators --- -**Last Updated**: 2026-04-24 -**Version**: 3.3 +**Last Updated**: 2026-04-26 +**Version**: 3.4 diff --git a/.github/prompts/00-base-contract.md b/.github/prompts/00-base-contract.md index a6b5b8661c..61121e9a5a 100644 --- a/.github/prompts/00-base-contract.md +++ b/.github/prompts/00-base-contract.md @@ -55,11 +55,15 @@ Stage analysis + article.md + news/*.html β†’ Commit β†’ ONE create_pull_request ## Session keepalive requirement -> ⚠️ **Critical**: The Copilot API creates a server-side session when the agent starts. That session is bound to the `github.token` baked in at step start β€” it is **never refreshed** mid-run. The session expires at approximately **60 minutes** (gh-aw issue #24920). After expiry, all tool calls and inference requests fail silently. The workflow appears to run but makes zero progress, and **the PR is never created**. - -To mitigate MCP idle-connection drops, workflows set `sandbox.mcp.keepalive-interval: 300` (5-minute ping). This keeps MCP connections alive but does **not** refresh the Copilot API token. - -**The reliable mitigation is to ensure `safeoutputs___create_pull_request` is called well before the session approaches expiry.** A second, shorter-firing clock β€” the Safe Outputs HTTP MCP idle session (~25–30 min observed) β€” now drives the operative deadline. Plan the run so the PR is created **within 22–27 minutes** (hard deadline **30 minutes**) of agent start. See `07-commit-and-pr.md Β§Deadline enforcement` for the authoritative PR-timing procedure, including the full two-timer explanation; that section supersedes any older ~45-minute guidance that predated the 23-artifact pipeline. +> ⚠️ **Critical β€” three timers**: Plan every run for the **shortest** of the three. +> +> 1. **Job timeout (45 min)** β€” every news workflow declares `timeout-minutes: 45`. After 45 min the GitHub Actions runner kills the agent unconditionally. +> 2. **Copilot API session (~60 min)** β€” bound to the `github.token` baked in at step start; never refreshed mid-run (gh-aw issue #24920). After expiry every tool call and inference fails silently. +> 3. **Safe Outputs MCP idle session (~25–30 min observed)** β€” drops if the agent goes idle toward `safeoutputs___*` for 25+ minutes; every subsequent safe-output call returns `session not found`. +> +> The operative deadline is therefore Timer 3. To mitigate MCP-side idle drops, workflows set `sandbox.mcp.keepalive-interval: 300` (5-minute ping). That keeps upstream MCPs alive but does **not** refresh the Copilot session and does **not** keep the safeoutputs HTTP session alive. + +**The reliable mitigation is to ensure `safeoutputs___create_pull_request` is called well before the safeoutputs idle session approaches expiry.** Plan the run so the PR is created **within 22–27 minutes** (hard deadline **30 minutes**) of agent start. The remaining 15+ minutes of the 45-min job budget exist solely as a safety margin for the safeoutputs runner to publish the PR β€” do **not** schedule additional analysis after the PR call. See `07-commit-and-pr.md Β§Deadline enforcement` for the authoritative PR-timing procedure. Do not add per-phase checkpoint PRs or repo-memory push steps. diff --git a/.github/prompts/02-mcp-access.md b/.github/prompts/02-mcp-access.md index 6ddb9286a2..86ee9fd419 100644 --- a/.github/prompts/02-mcp-access.md +++ b/.github/prompts/02-mcp-access.md @@ -6,29 +6,6 @@ Authoritative per-workflow surface: the `mcp-servers:` + `tools:` blocks in that News workflows declare three data MCP servers + the built-in `github` toolset (via `tools.github.toolsets: [all]`) + `bash` + `agentic-workflows`. -| Server | Transport | Declared in | Tool-name style | Example tools | -|--------|-----------|-------------|-----------------|---------------| -| `riksdag-regering` | HTTP (Render) | workflow `mcp-servers:` | `snake_case` | `get_sync_status`, `search_dokument`, `get_voteringar`, `get_dokument_innehall` | -| `scb` | container (`@jarib/pxweb-mcp`) | workflow `mcp-servers:` | `snake_case` | `search_tables`, `get_table_info`, `query_table` | -| `world-bank` | container (`worldbank-mcp`) | workflow `mcp-servers:` | `kebab-case` | `get-economic-data`, `get-country-info`, `search-indicators` | -| `github` | HTTP (Copilot MCP) | workflow `tools.github` | standard | full GitHub MCP toolset | -| `bash` | local helper | workflow `tools.bash` | standard | shell execution | -| `safeoutputs` | runner | always available | `snake_case` | `safeoutputs___create_pull_request`, `safeoutputs___noop`, `safeoutputs___dispatch_workflow` | - -`filesystem`, `memory`, and `sequential-thinking` are declared in [`.github/copilot-mcp.json`](../copilot-mcp.json) for the **local Copilot / `assign_copilot_to_issue`** channel and are **not** available to news workflows unless the workflow itself declares them under `mcp-servers:`. - -`playwright` must be treated separately: in news workflows it is available as the built-in workflow tool `tools.playwright` when that workflow declares it under `tools:` (e.g. `news-evening-analysis`, `news-realtime-monitor`). In that case it is **not** an MCP server, so do **not** infer its availability from `mcp-servers:` alone and do **not** skip Playwright/browser validation steps when `tools.playwright` is present in workflow frontmatter. - -Authoritative inventory: [`.github/copilot-mcp.json`](../copilot-mcp.json) for the local Copilot MCP surface, and each workflow's `mcp-servers:` plus `tools:` frontmatter for the actual per-run surface. - -# 02 β€” MCP Access - -Authoritative per-workflow surface: the `mcp-servers:` + `tools:` blocks in that workflow's frontmatter. `.github/copilot-mcp.json` is the **local Copilot** surface (used by `assign_copilot_to_issue` / agent files in `.github/agents/`), not by news workflow runs. - -## Servers & tool naming - -News workflows declare three data MCP servers + the built-in `github` toolset (via `tools.github.toolsets: [all]`) + `bash` + `agentic-workflows`. - | Server | Transport | Declared in | Tool-name style | Example tools | |--------|-----------|-------------|-----------------|---------------| | `riksdag-regering` | HTTP (Render) | workflow `mcp-servers:` | `snake_case` | `get_sync_status`, `search_dokument`, `get_voteringar`, `get_dokument_innehall` | diff --git a/.github/prompts/03-data-download.md b/.github/prompts/03-data-download.md index 3c926c6681..071e5b4582 100644 --- a/.github/prompts/03-data-download.md +++ b/.github/prompts/03-data-download.md @@ -7,33 +7,53 @@ Run this check as the **first action** after MCP pre-warm, before any download: ```bash ANALYSIS_DIR="analysis/daily/$ARTICLE_DATE/$SUBFOLDER" -# 23 required artifacts (Families A+B+C+D) β€” every workflow, every run -REQ=( - # Family A β€” Core Synthesis (9) - README.md executive-brief.md synthesis-summary.md significance-scoring.md \ - classification-results.md swot-analysis.md risk-assessment.md \ - threat-analysis.md stakeholder-perspectives.md \ - # Family B β€” Structural Metadata (2) - data-download-manifest.md cross-reference-map.md \ - # Family C β€” Strategic Extensions (5) - scenario-analysis.md comparative-international.md devils-advocate.md \ - intelligence-assessment.md methodology-reflection.md \ - # Family D β€” Electoral & Domain Lenses (7) - election-2026-analysis.md voter-segmentation.md coalition-mathematics.md \ - historical-parallels.md media-framing-analysis.md \ - implementation-feasibility.md forward-indicators.md) - -# Tier-C workflows add no new files β€” all 23 are already mandatory. What Tier-C -# adds is the cross-type synthesis + period multipliers enforced by -# ext/tier-c-aggregation.md and the gate in 05-analysis-gate.md. - SKIP_ANALYSIS=false ALL_PRESENT=true -for f in "${REQ[@]}"; do +EXPECTED=23 +CHECKED=0 +# 23 required artifacts (Families A+B+C+D) β€” every workflow, every run. +# We feed them via a here-doc so the loop never builds an inline bash array +# (the AWF sandbox flags `REQ=(...); for f in "${REQ[@]}"`; see +# 01-bash-and-shell-safety.md Β§Banned expansion patterns). +# The loop short-circuits on the first missing artifact, so $CHECKED is the +# number examined up to that point β€” never larger than $EXPECTED. We log +# both numbers so the difference is unambiguous in the run output. +while IFS= read -r f; do + [ -z "$f" ] && continue + CHECKED=$((CHECKED + 1)) [ -s "$ANALYSIS_DIR/$f" ] || { ALL_PRESENT=false; break; } -done +done <<'REQUIRED_ARTIFACTS' +README.md +executive-brief.md +synthesis-summary.md +significance-scoring.md +classification-results.md +swot-analysis.md +risk-assessment.md +threat-analysis.md +stakeholder-perspectives.md +data-download-manifest.md +cross-reference-map.md +scenario-analysis.md +comparative-international.md +devils-advocate.md +intelligence-assessment.md +methodology-reflection.md +election-2026-analysis.md +voter-segmentation.md +coalition-mathematics.md +historical-parallels.md +media-framing-analysis.md +implementation-feasibility.md +forward-indicators.md +REQUIRED_ARTIFACTS + +# Tier-C workflows add no new files β€” all 23 are already mandatory. What +# Tier-C adds is the cross-type synthesis + period multipliers enforced by +# ext/tier-c-aggregation.md and the gate in 05-analysis-gate.md. + [ "$ALL_PRESENT" = "true" ] && SKIP_ANALYSIS=true -echo "SKIP_ANALYSIS=$SKIP_ANALYSIS (required artifacts present: $ALL_PRESENT, count: ${#REQ[@]})" +echo "SKIP_ANALYSIS=$SKIP_ANALYSIS (required artifacts present: $ALL_PRESENT, checked: $CHECKED of $EXPECTED)" ``` | `SKIP_ANALYSIS` | Behaviour | @@ -60,8 +80,7 @@ Populate `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/` with raw Riksdag/Regering da | news-weekly-review | `weekly-review` | | news-monthly-review | `monthly-review` | | news-evening-analysis | `evening-analysis` | -| news-realtime-monitor | `realtime-$HHMM` | -| news-realtime-monitor | `realtime-pulse` | +| news-realtime-monitor | `realtime-$HHMM` (per-event) or `realtime-pulse` (rolling 4-hour pulse) | If `force_generation=true` is supplied on a day whose base subfolder already contains `synthesis-summary.md` from a prior merged run, auto-suffix the subfolder (`propositions-2`, `propositions-3`, …) so the forced rerun does not overwrite the merged analysis. Under the default `force_generation=false`, the same base subfolder is reused across runs β€” see Β§Pre-flight above. @@ -117,5 +136,3 @@ Always produce `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/data-download-manifest.m ## Next step On success, proceed to `04-analysis-pipeline.md`. Never start analysis while `data-download-manifest.md` is missing or empty. - -After the manifest is written, run the **phase checkpoint** from `00-base-contract.md` with label `phase-03-download` so the download provenance is persisted to repo memory before any analysis begins. diff --git a/.github/prompts/04-analysis-pipeline.md b/.github/prompts/04-analysis-pipeline.md index e46bd91d18..3b556dcc02 100644 --- a/.github/prompts/04-analysis-pipeline.md +++ b/.github/prompts/04-analysis-pipeline.md @@ -154,8 +154,6 @@ For each article with charts, produce accompanying JSON under `analysis/daily/$A Proceed to `05-analysis-gate.md`. Do not start article generation until the gate passes against all 23 artifacts. -After completing Pass 1 (before Pass 2), run the **phase checkpoint** from `00-base-contract.md` with label `phase-04-pass1`. After completing Pass 2 (before the gate), run it again with label `phase-04-pass2`. This guarantees both iterations survive even if the gate, article, or commit phase later fails. - ## External references - gh-aw runtime (v0.69.3): [abridged](https://github.github.com/gh-aw/llms-small.txt) Β· [complete](https://github.github.com/gh-aw/llms-full.txt) Β· [agentic-workflows blog](https://github.github.com/gh-aw/_llms-txt/agentic-workflows.txt) Β· [source](https://github.com/github/gh-aw) diff --git a/.github/prompts/05-analysis-gate.md b/.github/prompts/05-analysis-gate.md index 5d8fac1ef4..7c7a7bb01c 100644 --- a/.github/prompts/05-analysis-gate.md +++ b/.github/prompts/05-analysis-gate.md @@ -33,45 +33,65 @@ This is the **only** gate separating analysis from article generation. If it fai ## Implementation -No dedicated validator script exists yet β€” implement the checks as an inline bash gate. Full implementation (covers checks 1–8): +No dedicated validator script exists yet β€” implement the checks as an inline bash gate. Full implementation (covers checks 1–9, with check 9 conditional where applicable): -``` +```bash set -Eeuo pipefail : "${ARTICLE_DATE:?ARTICLE_DATE must be set}" : "${SUBFOLDER:?SUBFOLDER must be set}" ANALYSIS_DIR="analysis/daily/$ARTICLE_DATE/$SUBFOLDER" [ -d "$ANALYSIS_DIR" ] || { echo "❌ ANALYSIS_DIR does not exist: $ANALYSIS_DIR"; exit 1; } - -FAMILY_A=(README.md executive-brief.md synthesis-summary.md significance-scoring.md \ - classification-results.md swot-analysis.md risk-assessment.md \ - threat-analysis.md stakeholder-perspectives.md) -FAMILY_B=(data-download-manifest.md cross-reference-map.md) -FAMILY_C=(scenario-analysis.md comparative-international.md devils-advocate.md \ - intelligence-assessment.md methodology-reflection.md) -FAMILY_D=(election-2026-analysis.md voter-segmentation.md coalition-mathematics.md \ - historical-parallels.md media-framing-analysis.md \ - implementation-feasibility.md forward-indicators.md) -REQ=("${FAMILY_A[@]}" "${FAMILY_B[@]}" "${FAMILY_C[@]}" "${FAMILY_D[@]}") -SYNTHESIS=(synthesis-summary.md swot-analysis.md risk-assessment.md threat-analysis.md \ - stakeholder-perspectives.md significance-scoring.md classification-results.md \ - cross-reference-map.md executive-brief.md election-2026-analysis.md \ - voter-segmentation.md coalition-mathematics.md historical-parallels.md \ - media-framing-analysis.md implementation-feasibility.md \ - forward-indicators.md) DOK_RE='[Hh][A-Za-z0-9]{3,}[0-9]+' EVIDENCE_RE='[Hh][A-Za-z0-9]{3,}[0-9]+|riksdagen\.se|regeringen\.se|scb\.se|statskontoret\.se|worldbank\.org|api\.imf\.org|data\.imf\.org|www\.imf\.org' FAIL=0 +# Materialise required-file lists via /tmp lists so we never build an inline +# bash array β€” the AWF sandbox rejects `REQ=(...); "${REQ[@]}"` (see +# 01-bash-and-shell-safety.md Β§Banned expansion patterns). +GATE_REQ_LIST="/tmp/gate-req-$$"; GATE_PASS2_LIST="/tmp/gate-pass2-$$" +GATE_SYNTH_LIST="/tmp/gate-synth-$$"; GATE_DOK_LIST="/tmp/gate-doks-$$" +trap 'rm -f "$GATE_REQ_LIST" "$GATE_PASS2_LIST" "$GATE_SYNTH_LIST" "$GATE_DOK_LIST"' EXIT + +write_list() { local out="$1"; shift; printf '%s\n' "$@" > "$out"; } + +write_list "$GATE_REQ_LIST" \ + README.md executive-brief.md synthesis-summary.md significance-scoring.md classification-results.md \ + swot-analysis.md risk-assessment.md threat-analysis.md stakeholder-perspectives.md \ + data-download-manifest.md cross-reference-map.md \ + scenario-analysis.md comparative-international.md devils-advocate.md intelligence-assessment.md methodology-reflection.md \ + election-2026-analysis.md voter-segmentation.md coalition-mathematics.md historical-parallels.md \ + media-framing-analysis.md implementation-feasibility.md forward-indicators.md + +write_list "$GATE_SYNTH_LIST" \ + synthesis-summary.md swot-analysis.md risk-assessment.md threat-analysis.md stakeholder-perspectives.md \ + significance-scoring.md classification-results.md cross-reference-map.md executive-brief.md \ + election-2026-analysis.md voter-segmentation.md coalition-mathematics.md historical-parallels.md \ + media-framing-analysis.md implementation-feasibility.md forward-indicators.md + +# data-download-manifest.md is produced by module 03 and may legitimately be +# unchanged at Pass 2 β€” exclude it from the Pass-2 evidence check. +write_list "$GATE_PASS2_LIST" \ + synthesis-summary.md swot-analysis.md risk-assessment.md threat-analysis.md stakeholder-perspectives.md \ + significance-scoring.md classification-results.md cross-reference-map.md executive-brief.md README.md \ + scenario-analysis.md comparative-international.md devils-advocate.md intelligence-assessment.md methodology-reflection.md \ + election-2026-analysis.md voter-segmentation.md coalition-mathematics.md historical-parallels.md \ + media-framing-analysis.md implementation-feasibility.md forward-indicators.md + # Check 1 β€” artifact existence (all 23) -for f in "${REQ[@]}"; do +while IFS= read -r f; do + [ -z "$f" ] && continue [ -s "$ANALYSIS_DIR/$f" ] || { echo "❌ missing/empty: $f"; FAIL=1; } -done +done < "$GATE_REQ_LIST" # Check 2 β€” per-document coverage against manifest if [ -s "$ANALYSIS_DIR/data-download-manifest.md" ]; then - mapfile -t DOKS < <(grep -oE "$DOK_RE" "$ANALYSIS_DIR/data-download-manifest.md" | sort -u) - [ "${#DOKS[@]}" -gt 0 ] || { echo "❌ manifest has no dok_id entries"; FAIL=1; } - for d in "${DOKS[@]}"; do + # Avoid `mapfile -t … < <(…)` β€” process substitution is best-avoided + # under the AWF sandbox (01-bash-and-shell-safety.md Β§Shell hygiene). + grep -oE "$DOK_RE" "$ANALYSIS_DIR/data-download-manifest.md" | sort -u > "$GATE_DOK_LIST" + DOK_COUNT=$(wc -l < "$GATE_DOK_LIST" | tr -d ' ') + [ "${DOK_COUNT:-0}" -gt 0 ] || { echo "❌ manifest has no dok_id entries"; FAIL=1; } + while IFS= read -r d; do + [ -z "$d" ] && continue d_lc="${d,,}" if [ ! -s "$ANALYSIS_DIR/documents/${d}.md" ] \ && [ ! -s "$ANALYSIS_DIR/documents/${d}-analysis.md" ] \ @@ -80,7 +100,7 @@ if [ -s "$ANALYSIS_DIR/data-download-manifest.md" ]; then echo "❌ documents/${d}.md or documents/${d}-analysis.md missing (any case)" FAIL=1 fi - done + done < "$GATE_DOK_LIST" fi # Check 3 β€” no stubs @@ -136,7 +156,8 @@ awk -v re="$EVIDENCE_RE" ' ' "$ANALYSIS_DIR/significance-scoring.md" || FAIL=1 # Check 5 β€” Mermaid + colour-coded config on core synthesis + key extension files -for f in "${SYNTHESIS[@]}"; do +while IFS= read -r f; do + [ -z "$f" ] && continue p="$ANALYSIS_DIR/$f"; [ -s "$p" ] || continue grep -qE '^```mermaid' "$p" || { echo "❌ $f: missing Mermaid block"; FAIL=1; } if ! grep -qE '^[[:space:]]*style[[:space:]]+' "$p" \ @@ -144,19 +165,11 @@ for f in "${SYNTHESIS[@]}"; do echo "❌ $f: missing Mermaid colour-coded config (no 'style …' directive and no 'themeVariables' / '%%{init …}' block)" FAIL=1 fi -done +done < "$GATE_SYNTH_LIST" # Check 6 β€” Pass-2 evidence (mtime β‰₯ birth + 180s, OR differing pass1 snapshot on disk) -# data-download-manifest.md is produced by module 03 and may legitimately be unchanged. -PASS2_REQ=(synthesis-summary.md swot-analysis.md risk-assessment.md threat-analysis.md \ - stakeholder-perspectives.md significance-scoring.md classification-results.md \ - cross-reference-map.md executive-brief.md README.md \ - scenario-analysis.md comparative-international.md devils-advocate.md \ - intelligence-assessment.md methodology-reflection.md \ - election-2026-analysis.md voter-segmentation.md coalition-mathematics.md \ - historical-parallels.md media-framing-analysis.md \ - implementation-feasibility.md forward-indicators.md) -for f in "${PASS2_REQ[@]}"; do +while IFS= read -r f; do + [ -z "$f" ] && continue p="$ANALYSIS_DIR/$f"; [ -s "$p" ] || continue ok=0 B=$(stat -c %W "$p" 2>/dev/null || echo 0) @@ -164,7 +177,7 @@ for f in "${PASS2_REQ[@]}"; do [ "${B:-0}" -gt 0 ] && [ "${M:-0}" -ge $((B + 180)) ] && ok=1 [ -s "$ANALYSIS_DIR/pass1/$f" ] && ! cmp -s "$ANALYSIS_DIR/pass1/$f" "$p" && ok=1 [ "$ok" -eq 1 ] || { echo "❌ $f: Pass-2 evidence missing (mtime= 2 )) && IS_MULTI_RUN=1 if (( IS_AGGREGATION == 1 || IS_TIER_C == 1 || IS_MULTI_RUN == 1 )); then - SUPP=() + # Avoid building a bash array (`SUPP+=(...)`); materialise the filenames + # via printf into a temp file and loop over that β€” see + # 01-bash-and-shell-safety.md Β§Banned expansion patterns. + SUPP_LIST="/tmp/gate-supp-$$" + : > "$SUPP_LIST" if (( IS_AGGREGATION == 1 || IS_TIER_C == 1 )); then - SUPP+=(analysis-index.md reference-analysis-quality.md mcp-reliability-audit.md workflow-audit.md) + printf '%s\n' analysis-index.md reference-analysis-quality.md mcp-reliability-audit.md workflow-audit.md >> "$SUPP_LIST" fi - (( IS_AGGREGATION == 1 )) && SUPP+=(cross-session-intelligence.md session-baseline.md) - (( IS_MULTI_RUN == 1 )) && SUPP+=(cross-run-diff.md) - for f in "${SUPP[@]}"; do + (( IS_AGGREGATION == 1 )) && printf '%s\n' cross-session-intelligence.md session-baseline.md >> "$SUPP_LIST" + (( IS_MULTI_RUN == 1 )) && printf '%s\n' cross-run-diff.md >> "$SUPP_LIST" + while IFS= read -r f; do + [ -z "$f" ] && continue [ -s "$ANALYSIS_DIR/$f" ] || { echo "❌ supplementary missing (agg=$IS_AGGREGATION tier-c=$IS_TIER_C multi-run=$IS_MULTI_RUN): $f"; FAIL=1; } - done + done < "$SUPP_LIST" + rm -f "$SUPP_LIST" fi ``` diff --git a/.github/prompts/07-commit-and-pr.md b/.github/prompts/07-commit-and-pr.md index a9ae807dac..859c80220a 100644 --- a/.github/prompts/07-commit-and-pr.md +++ b/.github/prompts/07-commit-and-pr.md @@ -107,25 +107,27 @@ In every other case, commit whatever exists and call `create_pull_request` once. ## Deadline enforcement -Two independent timers can kill a run silently. Plan for the **shorter** of the two. +Three independent timers can kill a run silently. Plan for the **shortest** of the three. -> **Timer A β€” Copilot API session (~60 min)**: The Copilot API session is bound to the `github.token` baked in at step start. That token expires at approximately **60 minutes** and is never refreshed mid-run (gh-aw issue #24920). Every tool call and inference request fails silently after that point β€” the agent appears to run but makes no progress and the PR is never created. Setup steps consume ~5 minutes, so the agent has at most **~55 minutes** of usable session time. +> **Timer A β€” Job `timeout-minutes` (45 min)**: every news workflow declares `timeout-minutes: 45`. After 45 minutes GitHub Actions kills the runner unconditionally β€” no retry, no save, no PR. > -> **Timer B β€” Safe Outputs MCP idle session (~25–30 min, observed)**: The local Safe Outputs HTTP MCP tracks a per-agent Streamable HTTP session. If the agent goes **idle toward safeoutputs** for 25+ minutes (e.g. a long Pass 1 that only uses `edit` + `bash`), the session is dropped and every subsequent `safeoutputs___*` call returns `Error POSTing to endpoint: session not found` β€” including the final `safeoutputs___create_pull_request`, `safeoutputs___noop`, and `safeoutputs___report_incomplete`. The `sandbox.mcp.keepalive-interval: 300` setting does **not** prevent this; that knob keeps the `mcp-gateway` upstream MCPs alive, not the safeoutputs HTTP server. Observed failure: run [`24821837975`](https://github.com/Hack23/riksdagsmonitor/actions/runs/24821837975) β€” 23 artifacts committed at ~33 min, all three safe-output calls rejected. +> **Timer B β€” Copilot API session (~60 min)**: The Copilot API session is bound to the `github.token` baked in at step start. That token expires at approximately **60 minutes** and is never refreshed mid-run (gh-aw issue #24920). Every tool call and inference request fails silently after that point β€” the agent appears to run but makes no progress and the PR is never created. +> +> **Timer C β€” Safe Outputs MCP idle session (~25–30 min, observed)**: The local Safe Outputs HTTP MCP tracks a per-agent Streamable HTTP session. If the agent goes **idle toward safeoutputs** for 25+ minutes (e.g. a long Pass 1 that only uses `edit` + `bash`), the session is dropped and every subsequent `safeoutputs___*` call returns `Error POSTing to endpoint: session not found` β€” including the final `safeoutputs___create_pull_request`, `safeoutputs___noop`, and `safeoutputs___report_incomplete`. The `sandbox.mcp.keepalive-interval: 300` setting does **not** prevent this; that knob keeps the `mcp-gateway` upstream MCPs alive, not the safeoutputs HTTP server. + +Timer C fires first and is therefore the operative deadline. The 45-min job budget (Timer A) leaves ~15 minutes of safety margin after the PR call for the safe-outputs runner to publish the PR. ### Keeping the Safe Outputs MCP session warm -Do **not** use safe outputs as a keepalive strategy. In this workflow, `safeoutputs___create_pull_request` is limited to a single successful end-of-run call, and `safeoutputs___noop` is likewise reserved for the final "no files produced" outcome, so neither can be safely spent to keep the Safe Outputs MCP session alive. Some other `safeoutputs___*` tools (e.g. `report_incomplete`, `missing_tool`, `missing_data`) may allow more than one call in compiled workflows, but they are not a documented or reliable heartbeat path for this prompt. **The only reliable mitigation is to reach `safeoutputs___create_pull_request` before Timer B fires.** Plan Pass 1 + gate + commit to finish well inside the 30-minute hard deadline below. If a future gh-aw release publishes a safe touch path for the local safeoutputs HTTP server (for example, an explicitly supported status or `tools/list` endpoint with verified keepalive behaviour), update this section with the concrete command and its observed effect. +Do **not** use safe outputs as a keepalive strategy. In this workflow, `safeoutputs___create_pull_request` is limited to a single successful end-of-run call, and `safeoutputs___noop` is likewise reserved for the final "no files produced" outcome, so neither can be safely spent to keep the Safe Outputs MCP session alive. Some other `safeoutputs___*` tools (e.g. `report_incomplete`, `missing_tool`, `missing_data`) may allow more than one call in compiled workflows, but they are not a documented or reliable heartbeat path for this prompt. **The only reliable mitigation is to reach `safeoutputs___create_pull_request` before Timer C fires.** Plan Pass 1 + gate + commit to finish well inside the 30-minute hard deadline below. If a future gh-aw release publishes a safe touch path for the local safeoutputs HTTP server (for example, an explicitly supported status or `tools/list` endpoint with verified keepalive behaviour), update this section with the concrete command and its observed effect. ### PR-creation windows -> **Authoritative override:** For PR timing and hard deadlines, this section supersedes any older guidance imported from `.github/prompts/00-base-contract.md` that suggests creating the PR at around **45 minutes**. The operative deadline for both runs is **30 minutes**, with Run 1 targeting **22–27 minutes** and Run 2 targeting **20–25 minutes**. - | Phase | Target PR window | Hard deadline | Floor for Pass 2 | |-------|------------------|---------------|------------------| | Analysis + aggregate + render | **22–27 min** after agent start | **30 min** | 5 min, skip beyond 25 min | -These windows are tighter than the historical 48-min figure because Timer B fires first on the 23-artifact pipeline. The 30-min hard deadline leaves ~5 minutes of margin for staging, `git commit`, and the safeoutputs round-trip before Timer B has been observed to fire, and ~25 minutes of margin before Timer A. +The 30-min hard deadline leaves ~5 minutes of margin for staging, `git commit`, and the safeoutputs round-trip before Timer C fires; ~30 minutes of margin before Timer B; and ~15 minutes of margin before Timer A. Do **not** schedule any analysis or article work after the PR call β€” the agent's only remaining job is to exit cleanly while the safe-outputs runner publishes the PR. ### If the run exceeds its hard deadline with no safe-output call yet diff --git a/.github/prompts/README.md b/.github/prompts/README.md index bdc36c45d1..dcd6fc717a 100644 --- a/.github/prompts/README.md +++ b/.github/prompts/README.md @@ -43,9 +43,10 @@ This directory is the **single source of truth** for how GitHub Agentic Workflow | [`02-mcp-access.md`](02-mcp-access.md) | MCP server inventory, tool naming, in-prompt health gate | All news workflows + translate | | [`03-data-download.md`](03-data-download.md) | Download pipeline, subfolder naming, lookback fallback, manifest | All content workflows | | [`04-analysis-pipeline.md`](04-analysis-pipeline.md) | Methodologies, templates, **23 required artifacts** (Families A+B+C+D), Pass 1 / Pass 2 | All content workflows | -| [`05-analysis-gate.md`](05-analysis-gate.md) | Single blocking gate before any article is touched (checks 1–8 across all 23 artifacts) | All content workflows | +| [`05-analysis-gate.md`](05-analysis-gate.md) | Single blocking gate before any article is touched (checks 1–9 across all 23 artifacts; supplementary check 9 is blocking for `comprehensive` / Tier-C / multi-run) | All content workflows | | [`06-article-generation.md`](06-article-generation.md) | Article sections, banned patterns, visualisation, translations | All content workflows | | [`07-commit-and-pr.md`](07-commit-and-pr.md) | Stage β†’ commit β†’ exactly one `create_pull_request` | All news workflows + translate | +| [`seo-metadata-contract.md`](seo-metadata-contract.md) | Reference contract for `` + `<meta description>` per language (used at render time, not imported) | Reference document β€” referenced by `06-article-generation.md` and the renderer | | [`ext/tier-c-aggregation.md`](ext/tier-c-aggregation.md) | Tier-C additive rules: period multipliers, cross-type sibling synthesis, prior-cycle PIR ingestion, article floor | Aggregation & reference-grade workflows | ## Dependency matrix @@ -124,7 +125,7 @@ The monolithic `.github/aw/SHARED_PROMPT_PATTERNS.md` was deleted when these mod - [`.github/agents/README.md`](../agents/README.md) β€” 24 agent files (14 persona + 9 workflow-specialist + 1 developer-instructions) - [`.github/skills/README.md`](../skills/README.md) β€” 91 skills by functional category -- [`.github/workflows/README.md`](../workflows/README.md) β€” 45 workflow files (21 `.yml` + 12 `.md` + 12 `.lock.yml`) +- [`.github/workflows/README.md`](../workflows/README.md) β€” 43 workflow files (21 `.yml` + 11 `.md` + 11 `.lock.yml`) - [`Article-Generation.md`](../../Article-Generation.md) β€” article-generation architecture, business value, UI/UX export, SEO, deployment and source index - [`analysis/README.md`](../../analysis/README.md) β€” on-disk artifact layout (`analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`) - [`analysis/methodologies/README.md`](../../analysis/methodologies/README.md) β€” 12 methodology modules (AI guide Β· 4 domain frameworks Β· 5 Family production methodologies Β· style guide Β· **OSINT / INTOP tradecraft standards** canon) diff --git a/.github/prompts/ext/tier-c-aggregation.md b/.github/prompts/ext/tier-c-aggregation.md index 1d3b0ade55..5f566b986b 100644 --- a/.github/prompts/ext/tier-c-aggregation.md +++ b/.github/prompts/ext/tier-c-aggregation.md @@ -8,7 +8,6 @@ Import this **in addition to** the 8 core modules for aggregation / reference-gr - `news-week-ahead` - `news-month-ahead` - `news-realtime-monitor` -- Any period-scoped Tier-C workflow: `news-evening-analysis`, `news-weekly-review`, `news-monthly-review`, `news-week-ahead`, `news-month-ahead`, `news-realtime-monitor` These are the flagship editorial surfaces of Riksdagsmonitor. Tier-C rules are **additive**, not replacements β€” all 23 Family A/B/C/D artifacts from `04-analysis-pipeline.md` are already mandatory for every workflow. Tier-C adds depth multipliers, cross-type synthesis, sibling-citation requirements and a higher article-output floor. diff --git a/.github/prompts/seo-metadata-contract.md b/.github/prompts/seo-metadata-contract.md index 6642cf74b2..8c4dd1655a 100644 --- a/.github/prompts/seo-metadata-contract.md +++ b/.github/prompts/seo-metadata-contract.md @@ -1,19 +1,21 @@ # πŸ”– SEO Metadata Contract β€” article `<title>` and `<meta description>` -> **Status:** Normative Β· **Owner:** Editorial Β· **Effective:** 2026-04-24 Β· -> **Consumed by:** `scripts/render-lib/aggregator.ts` Β· `scripts/render-lib/chrome.ts` Β· -> `scripts/generate-news-indexes/*` Β· `scripts/generate-sitemap-html.ts` Β· -> the `news-translate` agentic workflow Β· every human editor writing an -> `executive-brief.md`. -> **Enforced by:** `tests/render-lib.test.ts` (forward-fix) and (post-PR 5) -> `tests/seo-metadata.test.ts` as a CI-blocking gate. +> **Owner:** Editorial Β· **Consumed by:** `scripts/render-lib/aggregator.ts` Β· +> `scripts/render-lib/chrome.ts` Β· `scripts/generate-news-indexes/*` Β· +> `scripts/generate-sitemap-html.ts` Β· the `news-translate` agentic workflow Β· +> every human editor writing an `executive-brief.md`. +> **Enforced by:** `tests/render-lib.test.ts` and `tests/seo-metadata.test.ts` +> as a CI-blocking gate. This contract is the single source of truth for what the `<title>` and `<meta name="description">` of every published article must look like, -in every one of the 14 supported languages. It is the SEO-specific companion to [`Article-Generation.md`](../../Article-Generation.md), which describes the complete workflow β†’ analysis artifacts β†’ `article.md` β†’ HTML/UI export pipeline. Every article also propagates -these two strings into eight other SEO surfaces (`og:title`, -`og:description`, `twitter:title`, `twitter:description`, JSON-LD -`headline` / `alternativeHeadline` / `description`, and the human-readable +in every one of the 14 supported languages. It is the SEO-specific +companion to [`Article-Generation.md`](../../Article-Generation.md), which +describes the complete workflow β†’ analysis artifacts β†’ `article.md` β†’ +HTML/UI export pipeline. Every article also propagates these two strings +into eight other SEO surfaces (`og:title`, `og:description`, +`twitter:title`, `twitter:description`, JSON-LD `headline` / +`alternativeHeadline` / `description`, and the human-readable `sitemap*.html` / `news/index*.html` cards). Get the two sources right here and the other eight follow for free. @@ -21,17 +23,16 @@ here and the other eight follow for free. ## 1 Β· Why this exists -Scan of `news/*.html` on 2026-04-24 (2,736 articles across 14 languages) -surfaced six quality issues worth the price of a rewrite: +Six recurring quality issues in `news/*.html` motivate the rules below: -| Issue | Affected | Root cause | -| ------------------------------------------------------------------------ | -------: | ----------------------------------------------------------------------------------- | -| Description truncated mid-word (no sentence boundary) | 547 | `readFirstParagraph` used a blind `.slice(0, 300)`; legacy renderer used `.slice(0, 160)` | -| Admin metadata leaking into description (`Brief ID:`, `Classification:`) | 12 + 14-lang siblings | `ADMIN_FIELD_RE` only covered 12 field names; splitter missed `\|` | -| Boilerplate `Executive Brief β€” X YYYY-MM-DD` titles | 28 | `readFirstHeading()` picked the literal H1 of `executive-brief.md` | -| `YYYY-MM-DD` in `<title>` (SEO dilutive) | 83 | Same as above | -| Descriptions below Google's 70-char floor | dozens (mostly ja/zh/ar/he/ko committee-reports) | `news-translate` aggressively shortens; no lower-bound enforcement | -| Generic `"AI-generated political intelligence"` filler | 2 + 14-lang siblings | Executive-brief missing or had no prose paragraph β€” aggregator fell back to `prettifyFallbackTitle(subfolder)` | +| Issue | Root cause | +| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | +| Description truncated mid-word (no sentence boundary) | `readFirstParagraph` used a blind `.slice(0, 300)`; legacy renderer used `.slice(0, 160)` | +| Admin metadata leaking into description (`Brief ID:`, `Classification:`) | `ADMIN_FIELD_RE` only covered 12 field names; splitter missed `\|` | +| Boilerplate `Executive Brief β€” X YYYY-MM-DD` titles | `readFirstHeading()` picked the literal H1 of `executive-brief.md` | +| `YYYY-MM-DD` in `<title>` (SEO dilutive) | Same as above | +| Descriptions below Google's 70-char floor | `news-translate` aggressively shortens; no lower-bound enforcement | +| Generic `"AI-generated political intelligence"` filler | Executive-brief missing or had no prose paragraph β€” aggregator fell back to `prettifyFallbackTitle(subfolder)` | The contract below prevents all six from ever happening again. @@ -111,15 +112,15 @@ warn (not block) on it. ### 3.2 Good vs bad (real examples from `news/*.html`) -βœ… `Sweden's government tables 8 propositions covering electricity system overhaul, wind power revenue sharing, paid police education, digital fraud protection, and a new environmental permitting authority.` (198 chars, 8 concrete instruments, 2026-04-15) +βœ… `Sweden's government tables 8 propositions covering electricity system overhaul, wind power revenue sharing, paid police education, digital fraud protection, and a new environmental permitting authority.` (198 chars, 8 concrete instruments) -βœ… `With 2,308 rule violations flagged across 2,494 tracked politicians and 109,259 documents processed, the parliamentary session reveals a government struggling to translate coalition arithmetic into legislative momentum.` (200 chars, 3 numbers, named entity, 2026-02-13) +βœ… `With 2,308 rule violations flagged across 2,494 tracked politicians and 109,259 documents processed, the parliamentary session reveals a government struggling to translate coalition arithmetic into legislative momentum.` (200 chars, 3 numbers, named entity) -❌ `Brief ID: EB-2026-04-22-EVE001 Prepared by: James Pether SΓΆrling Prepared at: 2026-04-22 23:50 UTC Classification: Public β€” GDPR Art. 9(2)(e) Confidence: HIGH [A1] 60-second read: βœ…` (admin leak, 2026-04-22) +❌ `Brief ID: EB-2026-04-22-EVE001 Prepared by: James Pether SΓΆrling Prepared at: 2026-04-22 23:50 UTC Classification: Public β€” GDPR Art. 9(2)(e) Confidence: HIGH [A1] 60-second read: βœ…` (admin leak) -❌ `Riksdag Committee Reports β€” AI-generated political intelligence from Sweden's Riksdag` (generic filler, 2026-04-15) +❌ `Riksdag Committee Reports β€” AI-generated political intelligence from Sweden's Riksdag` (generic filler) -❌ `Analyse von 10 Ausschussberichten` (35 chars, below floor, no concrete content, 2026-02-14 DE) +❌ `Analyse von 10 Ausschussberichten` (35 chars, below floor, no concrete content) --- @@ -201,12 +202,4 @@ Before committing an `executive-brief.md` artifact: - [ ] Description contains at least one concrete number / instrument / named actor (Β§3.1). ---- - -## 7 Β· Change log - -| Date | Change | Author | -| ---------- | ----------------------------------------------------------- | -------- | -| 2026-04-24 | Initial contract (PR 1 of the 5-PR SEO rescue plan) | Copilot | - <!-- End of contract --> diff --git a/.github/skills/automated-content-generation/SKILL.md b/.github/skills/automated-content-generation/SKILL.md index 1c503f4542..467468b171 100644 --- a/.github/skills/automated-content-generation/SKILL.md +++ b/.github/skills/automated-content-generation/SKILL.md @@ -55,7 +55,7 @@ Expert knowledge in automated content generation using templates, focusing on in ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/behavioral-analysis/SKILL.md b/.github/skills/behavioral-analysis/SKILL.md index 267a863eff..5d0aa97993 100644 --- a/.github/skills/behavioral-analysis/SKILL.md +++ b/.github/skills/behavioral-analysis/SKILL.md @@ -896,7 +896,7 @@ This skill implements requirements from: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/cia-data-integration/SKILL.md b/.github/skills/cia-data-integration/SKILL.md index 11e9016799..431292a2a5 100644 --- a/.github/skills/cia-data-integration/SKILL.md +++ b/.github/skills/cia-data-integration/SKILL.md @@ -143,7 +143,7 @@ jobs: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/comparative-politics-reporting/SKILL.md b/.github/skills/comparative-politics-reporting/SKILL.md index 32f2f3888c..0a270303b7 100644 --- a/.github/skills/comparative-politics-reporting/SKILL.md +++ b/.github/skills/comparative-politics-reporting/SKILL.md @@ -378,7 +378,7 @@ indices (Freedom House, EIU)* ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/copilot-agent-patterns/SKILL.md b/.github/skills/copilot-agent-patterns/SKILL.md index bfc4764f02..a12140beba 100644 --- a/.github/skills/copilot-agent-patterns/SKILL.md +++ b/.github/skills/copilot-agent-patterns/SKILL.md @@ -66,7 +66,7 @@ tools: ["tool1", "tool2"] # Minimal set for non-meta agents ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/data-science-for-intelligence/SKILL.md b/.github/skills/data-science-for-intelligence/SKILL.md index 2f0f2a1eaf..12315c6261 100644 --- a/.github/skills/data-science-for-intelligence/SKILL.md +++ b/.github/skills/data-science-for-intelligence/SKILL.md @@ -869,7 +869,7 @@ class PoliticalNetworkAnalyzer: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/editorial-standards/SKILL.md b/.github/skills/editorial-standards/SKILL.md index 14cd1fe639..a36703a07f 100644 --- a/.github/skills/editorial-standards/SKILL.md +++ b/.github/skills/editorial-standards/SKILL.md @@ -234,7 +234,7 @@ Failure protocol: if any of 1–4 is not satisfied, the draft is returned to the ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/electoral-analysis/SKILL.md b/.github/skills/electoral-analysis/SKILL.md index 2c5712f5dd..c885af9ac9 100644 --- a/.github/skills/electoral-analysis/SKILL.md +++ b/.github/skills/electoral-analysis/SKILL.md @@ -741,7 +741,7 @@ ORDER BY avg_support ASC; ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/gh-aw-authentication-credentials/SKILL.md b/.github/skills/gh-aw-authentication-credentials/SKILL.md index 0910b150a3..8ab9b6a5ed 100644 --- a/.github/skills/gh-aw-authentication-credentials/SKILL.md +++ b/.github/skills/gh-aw-authentication-credentials/SKILL.md @@ -1475,7 +1475,7 @@ When managing authentication and credentials: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-containerization/SKILL.md b/.github/skills/gh-aw-containerization/SKILL.md index c55d70e919..2166d87ab2 100644 --- a/.github/skills/gh-aw-containerization/SKILL.md +++ b/.github/skills/gh-aw-containerization/SKILL.md @@ -1405,7 +1405,7 @@ When containerizing agentic workflows: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-continuous-ai-patterns/SKILL.md b/.github/skills/gh-aw-continuous-ai-patterns/SKILL.md index f78db870ef..37b4cf442f 100644 --- a/.github/skills/gh-aw-continuous-ai-patterns/SKILL.md +++ b/.github/skills/gh-aw-continuous-ai-patterns/SKILL.md @@ -1430,7 +1430,7 @@ The GitHub Next team operates 100+ agentic workflows. Key categories: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-firewall/SKILL.md b/.github/skills/gh-aw-firewall/SKILL.md index 1aebf2ae8b..7feb582e7b 100644 --- a/.github/skills/gh-aw-firewall/SKILL.md +++ b/.github/skills/gh-aw-firewall/SKILL.md @@ -878,7 +878,7 @@ network: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-github-actions-integration/SKILL.md b/.github/skills/gh-aw-github-actions-integration/SKILL.md index b647d578c7..069d256ac1 100644 --- a/.github/skills/gh-aw-github-actions-integration/SKILL.md +++ b/.github/skills/gh-aw-github-actions-integration/SKILL.md @@ -1534,7 +1534,7 @@ When integrating agentic workflows with GitHub Actions: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-logging-monitoring/SKILL.md b/.github/skills/gh-aw-logging-monitoring/SKILL.md index c3a237b979..742bab9c51 100644 --- a/.github/skills/gh-aw-logging-monitoring/SKILL.md +++ b/.github/skills/gh-aw-logging-monitoring/SKILL.md @@ -1479,7 +1479,7 @@ When implementing logging and monitoring for agentic workflows: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-mcp-configuration/SKILL.md b/.github/skills/gh-aw-mcp-configuration/SKILL.md index 64a820b1d1..ce39ba3776 100644 --- a/.github/skills/gh-aw-mcp-configuration/SKILL.md +++ b/.github/skills/gh-aw-mcp-configuration/SKILL.md @@ -1806,7 +1806,7 @@ For Copilot coding agent sessions (not agentic workflows), MCP servers are confi ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-mcp-gateway/SKILL.md b/.github/skills/gh-aw-mcp-gateway/SKILL.md index b935517c35..0e3016cb1c 100644 --- a/.github/skills/gh-aw-mcp-gateway/SKILL.md +++ b/.github/skills/gh-aw-mcp-gateway/SKILL.md @@ -2307,7 +2307,7 @@ curl -X POST http://localhost:8000/mcp/github \ ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-safe-outputs/SKILL.md b/.github/skills/gh-aw-safe-outputs/SKILL.md index 9b3e7986dd..4a05f5c0d8 100644 --- a/.github/skills/gh-aw-safe-outputs/SKILL.md +++ b/.github/skills/gh-aw-safe-outputs/SKILL.md @@ -704,7 +704,7 @@ safe-outputs: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-security-architecture/SKILL.md b/.github/skills/gh-aw-security-architecture/SKILL.md index 839a53f4b2..612694fd05 100644 --- a/.github/skills/gh-aw-security-architecture/SKILL.md +++ b/.github/skills/gh-aw-security-architecture/SKILL.md @@ -1795,7 +1795,7 @@ tools: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-tools-ecosystem/SKILL.md b/.github/skills/gh-aw-tools-ecosystem/SKILL.md index 04557c51b0..8635e722eb 100644 --- a/.github/skills/gh-aw-tools-ecosystem/SKILL.md +++ b/.github/skills/gh-aw-tools-ecosystem/SKILL.md @@ -811,7 +811,7 @@ tools: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/gh-aw-workflow-authoring/SKILL.md b/.github/skills/gh-aw-workflow-authoring/SKILL.md index f8776671fe..fcaf8c7972 100644 --- a/.github/skills/gh-aw-workflow-authoring/SKILL.md +++ b/.github/skills/gh-aw-workflow-authoring/SKILL.md @@ -1056,7 +1056,7 @@ tools: ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/github-agentic-workflows/SKILL.md b/.github/skills/github-agentic-workflows/SKILL.md index 0cf2c34cb7..2fc70e3e71 100644 --- a/.github/skills/github-agentic-workflows/SKILL.md +++ b/.github/skills/github-agentic-workflows/SKILL.md @@ -1827,7 +1827,7 @@ See [`Hack23/riksdagsmonitor`](https://github.com/Hack23/riksdagsmonitor): ## πŸ”— Integration with Riksdagsmonitor agentic workflows -This gh-aw skill is applied by the 12 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: +This gh-aw skill is applied by the 11 agentic news workflows in `.github/workflows/news-*.md`. Their domain contract (analysis-artifact product, gate, article contract) lives in: - [`.github/prompts/README.md`](../../prompts/README.md) β€” module catalogue, import rules, AI-FIRST 2-pass rule. - [`analysis/methodologies/ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + [`analysis/templates/`](../../../analysis/templates/) β€” 9 core / 14 Tier-C artifacts. diff --git a/.github/skills/intelligence-analysis-techniques/SKILL.md b/.github/skills/intelligence-analysis-techniques/SKILL.md index 2f79da6f69..5ae03126aa 100644 --- a/.github/skills/intelligence-analysis-techniques/SKILL.md +++ b/.github/skills/intelligence-analysis-techniques/SKILL.md @@ -804,7 +804,7 @@ ORDER BY vd.month DESC; ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/investigative-journalism/SKILL.md b/.github/skills/investigative-journalism/SKILL.md index 25078daca2..6edb73f1f0 100644 --- a/.github/skills/investigative-journalism/SKILL.md +++ b/.github/skills/investigative-journalism/SKILL.md @@ -250,7 +250,7 @@ Provides expertise in investigative journalism techniques for deep political acc ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/legislative-monitoring/SKILL.md b/.github/skills/legislative-monitoring/SKILL.md index 5be9c21bba..2c31fffeb9 100644 --- a/.github/skills/legislative-monitoring/SKILL.md +++ b/.github/skills/legislative-monitoring/SKILL.md @@ -1132,7 +1132,7 @@ This skill implements requirements from: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/osint-methodologies/SKILL.md b/.github/skills/osint-methodologies/SKILL.md index ac6abff039..bdc76796dd 100644 --- a/.github/skills/osint-methodologies/SKILL.md +++ b/.github/skills/osint-methodologies/SKILL.md @@ -691,7 +691,7 @@ LEFT JOIN ballot_data b ON v.ballot_id = b.ballot_id; ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/political-science-analysis/SKILL.md b/.github/skills/political-science-analysis/SKILL.md index 0aa9564257..6bb322d5fe 100644 --- a/.github/skills/political-science-analysis/SKILL.md +++ b/.github/skills/political-science-analysis/SKILL.md @@ -501,7 +501,7 @@ Track these KPIs to measure analytical quality: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/product-management-patterns/SKILL.md b/.github/skills/product-management-patterns/SKILL.md index 45f11d94bb..74b29819a5 100644 --- a/.github/skills/product-management-patterns/SKILL.md +++ b/.github/skills/product-management-patterns/SKILL.md @@ -58,7 +58,7 @@ Defines product management patterns for prioritizing features, planning roadmaps ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/prospective-news-coverage/SKILL.md b/.github/skills/prospective-news-coverage/SKILL.md index 089ea1aa8f..b38d419068 100644 --- a/.github/skills/prospective-news-coverage/SKILL.md +++ b/.github/skills/prospective-news-coverage/SKILL.md @@ -282,7 +282,7 @@ with committee members (3 MPs, anonymous)* ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/riksdag-regering-mcp/SKILL.md b/.github/skills/riksdag-regering-mcp/SKILL.md index 55b7768c1b..f9053e7197 100644 --- a/.github/skills/riksdag-regering-mcp/SKILL.md +++ b/.github/skills/riksdag-regering-mcp/SKILL.md @@ -567,7 +567,7 @@ riksdag-regering-mcp ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/risk-assessment-frameworks/SKILL.md b/.github/skills/risk-assessment-frameworks/SKILL.md index 56a45e040a..caa3d04f42 100644 --- a/.github/skills/risk-assessment-frameworks/SKILL.md +++ b/.github/skills/risk-assessment-frameworks/SKILL.md @@ -1212,7 +1212,7 @@ This skill implements requirements from: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/strategic-communication-analysis/SKILL.md b/.github/skills/strategic-communication-analysis/SKILL.md index 9f896d9594..f35a0fbe59 100644 --- a/.github/skills/strategic-communication-analysis/SKILL.md +++ b/.github/skills/strategic-communication-analysis/SKILL.md @@ -963,7 +963,7 @@ This skill implements requirements from: ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/skills/swedish-political-system/SKILL.md b/.github/skills/swedish-political-system/SKILL.md index 29d66980f4..d36b8f0771 100644 --- a/.github/skills/swedish-political-system/SKILL.md +++ b/.github/skills/swedish-political-system/SKILL.md @@ -669,7 +669,7 @@ graph LR ## πŸ”— Integration with agentic workflows & analysis artifacts -This skill is consumed by the 12 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. +This skill is consumed by the 11 agentic news workflows in `.github/workflows/news-*.md`. The authoritative contract lives in [`.github/prompts/README.md`](../../prompts/README.md); this skill supplies domain expertise on top of that contract. - **Analysis product** β†’ [`ai-driven-analysis-guide.md`](../../../analysis/methodologies/ai-driven-analysis-guide.md) + every template in [`analysis/templates/`](../../../analysis/templates/). - **Required before any article**: 9 core artifacts (14 for Tier-C) in `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`; [`05-analysis-gate.md`](../../prompts/05-analysis-gate.md) is the single blocking gate. diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 730b27b2e1..366c059268 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,6 +1,6 @@ # βš™οΈ `.github/workflows/` β€” GitHub Actions Catalog -This directory holds **45 workflow files** (21 standard `.yml` + 12 agentic Markdown sources + 12 compiled `.lock.yml` siblings) that power Riksdagsmonitor's CI/CD, security, data pipeline, agentic news generation, and monitoring. +This directory holds **43 workflow files** (21 standard `.yml` + 11 agentic Markdown sources + 11 compiled `.lock.yml` siblings) that power Riksdagsmonitor's CI/CD, security, data pipeline, agentic news generation, and monitoring. > **Canonical long-form workflow reference:** [`WORKFLOWS.md`](../../WORKFLOWS.md) at the repository root β€” version matrices, Mermaid pipeline diagrams, ISMS control mapping, troubleshooting, and KPIs. > **Agentic workflow contract (imports, analysis gate, 9/14 artifacts):** [`.github/prompts/README.md`](../prompts/README.md). diff --git a/.github/workflows/news-committee-reports.lock.yml b/.github/workflows/news-committee-reports.lock.yml index a19e227e98..28816aab11 100644 --- a/.github/workflows/news-committee-reports.lock.yml +++ b/.github/workflows/news-committee-reports.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"b5a0139e12bbdf1c1b04134087db2df86c42763210a9214305f05f6b839cf2d1","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"0304461c73f6e3442c2cfe49c654cd1b9cd4f6a3da6eb0ed4b91556c5a9ba252","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -46,7 +46,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -207,20 +207,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_215d350a2ac46473_EOF' + cat << 'GH_AW_PROMPT_fbb1b323cfc31268_EOF' <system> - GH_AW_PROMPT_215d350a2ac46473_EOF + GH_AW_PROMPT_fbb1b323cfc31268_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_215d350a2ac46473_EOF' + cat << 'GH_AW_PROMPT_fbb1b323cfc31268_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_215d350a2ac46473_EOF + GH_AW_PROMPT_fbb1b323cfc31268_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_215d350a2ac46473_EOF' + cat << 'GH_AW_PROMPT_fbb1b323cfc31268_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -250,9 +250,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_215d350a2ac46473_EOF + GH_AW_PROMPT_fbb1b323cfc31268_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_215d350a2ac46473_EOF' + cat << 'GH_AW_PROMPT_fbb1b323cfc31268_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -263,7 +263,7 @@ jobs: {{#runtime-import .github/prompts/06-article-generation.md}} {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/workflows/news-committee-reports.md}} - GH_AW_PROMPT_215d350a2ac46473_EOF + GH_AW_PROMPT_fbb1b323cfc31268_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -382,23 +382,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -474,9 +470,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_6bccd8238bc2f854_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_6bccd8238bc2f854_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_938fd3b3a28ac1d7_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_938fd3b3a28ac1d7_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -506,6 +502,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -742,7 +743,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_2920b547e588dece_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_50d5099f56b4ca72_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -859,7 +860,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_2920b547e588dece_EOF + GH_AW_MCP_CONFIG_50d5099f56b4ca72_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -877,7 +878,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1189,7 +1190,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1459,7 +1460,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-committee-reports.md b/.github/workflows/news-committee-reports.md index 343a500fb0..0f8f0312c6 100644 --- a/.github/workflows/news-committee-reports.md +++ b/.github/workflows/news-committee-reports.md @@ -40,7 +40,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-committee-reports-${{ inputs.article_date || 'today' }} @@ -51,7 +51,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -140,85 +140,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -238,7 +161,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-evening-analysis.lock.yml b/.github/workflows/news-evening-analysis.lock.yml index d4a857bf87..fcb7b5246b 100644 --- a/.github/workflows/news-evening-analysis.lock.yml +++ b/.github/workflows/news-evening-analysis.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"9eee18837bf1f82063f22bcdefc082ec7f7e80de3ae4a31fac43759510b19fcb","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"mcr.microsoft.com/playwright/mcp"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"4c629fb2bbf939636b60281c8331ed9d6ef3623c9a5cff2286634a12f1417fb9","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"mcr.microsoft.com/playwright/mcp"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -47,7 +47,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -212,21 +212,21 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF' + cat << 'GH_AW_PROMPT_39b247f23b589ad1_EOF' <system> - GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF + GH_AW_PROMPT_39b247f23b589ad1_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/playwright_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF' + cat << 'GH_AW_PROMPT_39b247f23b589ad1_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF + GH_AW_PROMPT_39b247f23b589ad1_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF' + cat << 'GH_AW_PROMPT_39b247f23b589ad1_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -256,9 +256,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF + GH_AW_PROMPT_39b247f23b589ad1_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF' + cat << 'GH_AW_PROMPT_39b247f23b589ad1_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -270,7 +270,7 @@ jobs: {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/prompts/ext/tier-c-aggregation.md}} {{#runtime-import .github/workflows/news-evening-analysis.md}} - GH_AW_PROMPT_4a5b8b8a3ddfd4ed_EOF + GH_AW_PROMPT_39b247f23b589ad1_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -389,23 +389,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -481,9 +477,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_7d28e0174bc63cf4_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_7d28e0174bc63cf4_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_c929838a43eb0ce8_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_c929838a43eb0ce8_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -513,6 +509,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -751,7 +752,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_2059aa8e26c53d64_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_26e9b44c805eddab_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -882,7 +883,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_2059aa8e26c53d64_EOF + GH_AW_MCP_CONFIG_26e9b44c805eddab_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -900,7 +901,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1212,7 +1213,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1482,7 +1483,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-evening-analysis.md b/.github/workflows/news-evening-analysis.md index 2a19837b5e..35d395a44a 100644 --- a/.github/workflows/news-evening-analysis.md +++ b/.github/workflows/news-evening-analysis.md @@ -48,7 +48,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-evening-analysis-${{ inputs.article_date || 'today' }} @@ -59,7 +59,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -149,85 +149,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -247,7 +170,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-interpellations.lock.yml b/.github/workflows/news-interpellations.lock.yml index ba66516967..b4d3690431 100644 --- a/.github/workflows/news-interpellations.lock.yml +++ b/.github/workflows/news-interpellations.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d102226e2c773a11183a7fcde977b092e5db1f413a57dc81fdc346a30a137176","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"c4b167cfc2574a356e0e496985740ba564b28d1686dc915b8fb18f1e0eb8e17c","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -46,7 +46,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -207,20 +207,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_6e50e8c24d9982ae_EOF' + cat << 'GH_AW_PROMPT_d77780dc3432c7e5_EOF' <system> - GH_AW_PROMPT_6e50e8c24d9982ae_EOF + GH_AW_PROMPT_d77780dc3432c7e5_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_6e50e8c24d9982ae_EOF' + cat << 'GH_AW_PROMPT_d77780dc3432c7e5_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_6e50e8c24d9982ae_EOF + GH_AW_PROMPT_d77780dc3432c7e5_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_6e50e8c24d9982ae_EOF' + cat << 'GH_AW_PROMPT_d77780dc3432c7e5_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -250,9 +250,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_6e50e8c24d9982ae_EOF + GH_AW_PROMPT_d77780dc3432c7e5_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_6e50e8c24d9982ae_EOF' + cat << 'GH_AW_PROMPT_d77780dc3432c7e5_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -263,7 +263,7 @@ jobs: {{#runtime-import .github/prompts/06-article-generation.md}} {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/workflows/news-interpellations.md}} - GH_AW_PROMPT_6e50e8c24d9982ae_EOF + GH_AW_PROMPT_d77780dc3432c7e5_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -382,23 +382,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -474,9 +470,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_ef7016dc270b506c_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_ef7016dc270b506c_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_10f384cded0a1973_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_10f384cded0a1973_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -506,6 +502,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -742,7 +743,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_a8d986b0c77ccec0_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_b50000fe8c0bccb8_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -859,7 +860,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_a8d986b0c77ccec0_EOF + GH_AW_MCP_CONFIG_b50000fe8c0bccb8_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -877,7 +878,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1189,7 +1190,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1459,7 +1460,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-interpellations.md b/.github/workflows/news-interpellations.md index a88cc3cebc..e7c7e25773 100644 --- a/.github/workflows/news-interpellations.md +++ b/.github/workflows/news-interpellations.md @@ -40,7 +40,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-interpellations-${{ inputs.article_date || 'today' }} @@ -51,7 +51,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -140,85 +140,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -238,7 +161,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-month-ahead.lock.yml b/.github/workflows/news-month-ahead.lock.yml index a307fcfaf4..db92239485 100644 --- a/.github/workflows/news-month-ahead.lock.yml +++ b/.github/workflows/news-month-ahead.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"077b625bc4bb72954dc70f131cc252c80a9b22f53a7011b54d383030f6dc261a","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"839dcde4771510582e7a808dc612cf9e9f2dba30a13b2df349edbeabcef902db","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -47,7 +47,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -207,20 +207,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_c271cc093de55284_EOF' + cat << 'GH_AW_PROMPT_fcd7876735186b88_EOF' <system> - GH_AW_PROMPT_c271cc093de55284_EOF + GH_AW_PROMPT_fcd7876735186b88_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_c271cc093de55284_EOF' + cat << 'GH_AW_PROMPT_fcd7876735186b88_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_c271cc093de55284_EOF + GH_AW_PROMPT_fcd7876735186b88_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_c271cc093de55284_EOF' + cat << 'GH_AW_PROMPT_fcd7876735186b88_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -250,9 +250,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_c271cc093de55284_EOF + GH_AW_PROMPT_fcd7876735186b88_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_c271cc093de55284_EOF' + cat << 'GH_AW_PROMPT_fcd7876735186b88_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -264,7 +264,7 @@ jobs: {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/prompts/ext/tier-c-aggregation.md}} {{#runtime-import .github/workflows/news-month-ahead.md}} - GH_AW_PROMPT_c271cc093de55284_EOF + GH_AW_PROMPT_fcd7876735186b88_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -383,23 +383,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -475,9 +471,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_71caf872d5701581_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_71caf872d5701581_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_2c8b05ddf1e85c81_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_2c8b05ddf1e85c81_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -507,6 +503,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -743,7 +744,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_d0127fbe18ef401d_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_055fa8d788cc6bcf_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -860,7 +861,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_d0127fbe18ef401d_EOF + GH_AW_MCP_CONFIG_055fa8d788cc6bcf_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -878,7 +879,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1190,7 +1191,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1460,7 +1461,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-month-ahead.md b/.github/workflows/news-month-ahead.md index 1a714db256..4a07c2f432 100644 --- a/.github/workflows/news-month-ahead.md +++ b/.github/workflows/news-month-ahead.md @@ -42,7 +42,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-month-ahead-${{ inputs.article_date || 'today' }} @@ -53,7 +53,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -142,85 +142,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -240,7 +163,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-monthly-review.lock.yml b/.github/workflows/news-monthly-review.lock.yml index f0405fc7f9..b707c253f9 100644 --- a/.github/workflows/news-monthly-review.lock.yml +++ b/.github/workflows/news-monthly-review.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"08b276b86653e88fa89232d9c81241006c6a159d63d749397d5d4f952263fd36","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"ba7ce1807e70d16d092bc5c814a152fe8aa5796c0d97bc1887a7d91ff5b6120e","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -47,7 +47,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -207,20 +207,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_f241598fc9858e63_EOF' + cat << 'GH_AW_PROMPT_97dbc35d1ec944ae_EOF' <system> - GH_AW_PROMPT_f241598fc9858e63_EOF + GH_AW_PROMPT_97dbc35d1ec944ae_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_f241598fc9858e63_EOF' + cat << 'GH_AW_PROMPT_97dbc35d1ec944ae_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_f241598fc9858e63_EOF + GH_AW_PROMPT_97dbc35d1ec944ae_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_f241598fc9858e63_EOF' + cat << 'GH_AW_PROMPT_97dbc35d1ec944ae_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -250,9 +250,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_f241598fc9858e63_EOF + GH_AW_PROMPT_97dbc35d1ec944ae_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_f241598fc9858e63_EOF' + cat << 'GH_AW_PROMPT_97dbc35d1ec944ae_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -264,7 +264,7 @@ jobs: {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/prompts/ext/tier-c-aggregation.md}} {{#runtime-import .github/workflows/news-monthly-review.md}} - GH_AW_PROMPT_f241598fc9858e63_EOF + GH_AW_PROMPT_97dbc35d1ec944ae_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -383,23 +383,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -475,9 +471,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_a057043f53e176ed_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_a057043f53e176ed_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_768706e48d74a1be_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_768706e48d74a1be_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -507,6 +503,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -743,7 +744,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_bca95fdf319e547a_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_7da86fcb4589e99e_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -860,7 +861,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_bca95fdf319e547a_EOF + GH_AW_MCP_CONFIG_7da86fcb4589e99e_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -878,7 +879,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1190,7 +1191,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1460,7 +1461,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-monthly-review.md b/.github/workflows/news-monthly-review.md index ee6783a6c8..9e17f173b3 100644 --- a/.github/workflows/news-monthly-review.md +++ b/.github/workflows/news-monthly-review.md @@ -42,7 +42,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-monthly-review-${{ inputs.article_date || 'today' }} @@ -53,7 +53,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -142,85 +142,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -240,7 +163,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-motions.lock.yml b/.github/workflows/news-motions.lock.yml index be6cf661f8..35c8ad46ba 100644 --- a/.github/workflows/news-motions.lock.yml +++ b/.github/workflows/news-motions.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"ee9b6515b08fe88d2b37b47008ec4d608f563f22321e39085546742af45b7269","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d28e82cb7467b8818385ad9710bd7823c7d8d4c2eef0b9b58e4e2a2d76e623bd","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -46,7 +46,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -207,20 +207,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_9774bd541387b389_EOF' + cat << 'GH_AW_PROMPT_3826f95af8b3878f_EOF' <system> - GH_AW_PROMPT_9774bd541387b389_EOF + GH_AW_PROMPT_3826f95af8b3878f_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_9774bd541387b389_EOF' + cat << 'GH_AW_PROMPT_3826f95af8b3878f_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_9774bd541387b389_EOF + GH_AW_PROMPT_3826f95af8b3878f_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_9774bd541387b389_EOF' + cat << 'GH_AW_PROMPT_3826f95af8b3878f_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -250,9 +250,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_9774bd541387b389_EOF + GH_AW_PROMPT_3826f95af8b3878f_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_9774bd541387b389_EOF' + cat << 'GH_AW_PROMPT_3826f95af8b3878f_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -263,7 +263,7 @@ jobs: {{#runtime-import .github/prompts/06-article-generation.md}} {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/workflows/news-motions.md}} - GH_AW_PROMPT_9774bd541387b389_EOF + GH_AW_PROMPT_3826f95af8b3878f_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -382,23 +382,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -474,9 +470,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_3bb8ee071da3af0f_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_3bb8ee071da3af0f_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_26f3cff672a3a5bd_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_26f3cff672a3a5bd_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -506,6 +502,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -742,7 +743,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_abdbd9021b5088b3_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_76990664e1112413_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -859,7 +860,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_abdbd9021b5088b3_EOF + GH_AW_MCP_CONFIG_76990664e1112413_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -877,7 +878,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1189,7 +1190,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1459,7 +1460,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-motions.md b/.github/workflows/news-motions.md index 3a0e314941..b1f901992f 100644 --- a/.github/workflows/news-motions.md +++ b/.github/workflows/news-motions.md @@ -40,7 +40,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-motions-${{ inputs.article_date || 'today' }} @@ -51,7 +51,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -140,85 +140,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -238,7 +161,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-propositions.lock.yml b/.github/workflows/news-propositions.lock.yml index 958a8c2797..88bc32440c 100644 --- a/.github/workflows/news-propositions.lock.yml +++ b/.github/workflows/news-propositions.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"cc35d7e5ce2c480df563da2691a2f72ace051650cb9a60f395c85eb0c4c632bf","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"e51535a017e251cb9ce1773b786fe5f0b611ae9ba236154a5adcc1d748723ca3","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -46,7 +46,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -207,20 +207,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_cd4d8170a394af56_EOF' + cat << 'GH_AW_PROMPT_bb74ae08846d887a_EOF' <system> - GH_AW_PROMPT_cd4d8170a394af56_EOF + GH_AW_PROMPT_bb74ae08846d887a_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_cd4d8170a394af56_EOF' + cat << 'GH_AW_PROMPT_bb74ae08846d887a_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_cd4d8170a394af56_EOF + GH_AW_PROMPT_bb74ae08846d887a_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_cd4d8170a394af56_EOF' + cat << 'GH_AW_PROMPT_bb74ae08846d887a_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -250,9 +250,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_cd4d8170a394af56_EOF + GH_AW_PROMPT_bb74ae08846d887a_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_cd4d8170a394af56_EOF' + cat << 'GH_AW_PROMPT_bb74ae08846d887a_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -263,7 +263,7 @@ jobs: {{#runtime-import .github/prompts/06-article-generation.md}} {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/workflows/news-propositions.md}} - GH_AW_PROMPT_cd4d8170a394af56_EOF + GH_AW_PROMPT_bb74ae08846d887a_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -382,23 +382,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -474,9 +470,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_44dc9e02f34452f0_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_44dc9e02f34452f0_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_f4e5392ffed57e81_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_f4e5392ffed57e81_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -506,6 +502,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -742,7 +743,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_5a8e0314d2c2a2b2_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_351f0b8fc5b1096f_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -859,7 +860,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_5a8e0314d2c2a2b2_EOF + GH_AW_MCP_CONFIG_351f0b8fc5b1096f_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -877,7 +878,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1189,7 +1190,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1459,7 +1460,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-propositions.md b/.github/workflows/news-propositions.md index f1efb4218d..2d13eded71 100644 --- a/.github/workflows/news-propositions.md +++ b/.github/workflows/news-propositions.md @@ -40,7 +40,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-propositions-${{ inputs.article_date || 'today' }} @@ -51,7 +51,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -140,85 +140,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -238,7 +161,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server runs a Streamable-HTTP session that expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the **download/manifest scope** if needed (for example, fewer `dok_id` entries in `data-download-manifest.md`), but maintain **1:1 per-document coverage** for every `dok_id` that remains in the manifest (required by `05-analysis-gate.md` check 2) and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice even if the input defaults to `deep`; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-realtime-monitor.lock.yml b/.github/workflows/news-realtime-monitor.lock.yml index c0deaeef80..1888d5a0d1 100644 --- a/.github/workflows/news-realtime-monitor.lock.yml +++ b/.github/workflows/news-realtime-monitor.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"381398028b3cfacabf954c04ab9fee1288426eb61815e7a99ba2a73a86fbd349","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"mcr.microsoft.com/playwright/mcp"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"e6e549a84b57cebddca187405a0f9dd6f71a1907f59d8e0278b6e952aa155be2","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"mcr.microsoft.com/playwright/mcp"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -47,7 +47,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -213,21 +213,21 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_1746c896c1b6aad2_EOF' + cat << 'GH_AW_PROMPT_f21e5ab83d01a33e_EOF' <system> - GH_AW_PROMPT_1746c896c1b6aad2_EOF + GH_AW_PROMPT_f21e5ab83d01a33e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/playwright_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_1746c896c1b6aad2_EOF' + cat << 'GH_AW_PROMPT_f21e5ab83d01a33e_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_1746c896c1b6aad2_EOF + GH_AW_PROMPT_f21e5ab83d01a33e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_1746c896c1b6aad2_EOF' + cat << 'GH_AW_PROMPT_f21e5ab83d01a33e_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -257,9 +257,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_1746c896c1b6aad2_EOF + GH_AW_PROMPT_f21e5ab83d01a33e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_1746c896c1b6aad2_EOF' + cat << 'GH_AW_PROMPT_f21e5ab83d01a33e_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -271,7 +271,7 @@ jobs: {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/prompts/ext/tier-c-aggregation.md}} {{#runtime-import .github/workflows/news-realtime-monitor.md}} - GH_AW_PROMPT_1746c896c1b6aad2_EOF + GH_AW_PROMPT_f21e5ab83d01a33e_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -390,23 +390,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -482,9 +478,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_8a022e0cd2f9d2cc_EOF' - {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_8a022e0cd2f9d2cc_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_287a4a3f0ff6a720_EOF' + {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_287a4a3f0ff6a720_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -514,6 +510,11 @@ jobs: "description": "Article type to translate (propositions, motions, committee-reports, week-ahead, month-ahead, weekly-review, monthly-review, breaking, evening-analysis, deep-inspection, interpellations). Leave empty to scan for all untranslated articles.", "type": "string" }, + "aw_context": { + "default": "", + "description": "Agent caller context (used internally by Agentic Workflows).", + "type": "string" + }, "languages": { "default": "all-extra", "description": "Target languages (da,no,fi,de,fr,es,nl,ar,he,ja,ko,zh | nordic-extra | eu-extra | cjk | rtl | all-extra). Default: all-extra (all except en,sv)", @@ -752,7 +753,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_ef96b4a1a35c15b6_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_30bcef9777c7cdda_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -883,7 +884,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_ef96b4a1a35c15b6_EOF + GH_AW_MCP_CONFIG_30bcef9777c7cdda_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -901,7 +902,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1213,7 +1214,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1483,7 +1484,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.imf.org,api.individual.githubcopilot.com,api.npms.io,api.scb.se,api.snapcraft.io,api.worldbank.org,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,data.imf.org,data.riksdagen.se,deb.nodesource.com,deno.land,docs.github.com,esm.sh,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,googleapis.deno.dev,googlechromelabs.github.io,hack23.com,hack23.github.io,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,localhost,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,regeringen.se,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,riksdag-regering-ai.onrender.com,riksdagen.se,riksdagsmonitor.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,statskontoret.se,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.hack23.com,www.imf.org,www.npmjs.com,www.npmjs.org,www.regeringen.se,www.riksdagen.se,www.riksdagsmonitor.com,www.scb.se,www.statskontoret.se,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"draft\":false,\"expires\":336,\"labels\":[\"agentic-news\",\"analysis-data\"],\"max\":1,\"max_patch_size\":4096,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"news-translate\"],\"max\":1,\"workflow_files\":{\"news-translate\":\".lock.yml\"},\"workflows\":[\"news-translate\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/news-realtime-monitor.md b/.github/workflows/news-realtime-monitor.md index 6f1b9379e6..0da3f9a7ed 100644 --- a/.github/workflows/news-realtime-monitor.md +++ b/.github/workflows/news-realtime-monitor.md @@ -51,7 +51,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-realtime-monitor-${{ inputs.article_date || 'today' }} @@ -62,7 +62,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -152,85 +152,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -250,7 +173,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-translate.lock.yml b/.github/workflows/news-translate.lock.yml index 3c6f468c45..ca6f500c60 100644 --- a/.github/workflows/news-translate.lock.yml +++ b/.github/workflows/news-translate.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"53633f2c07e738ee570972f46f04e2d57c50ffd72f321396403ef6d099d1c815","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"3d0a2cffa537de5cca84172fbb93bc22bdc75125c9ffb06be488a9b9aa031986","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -42,7 +42,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -206,20 +206,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_d11bf2d02b75c28e_EOF' + cat << 'GH_AW_PROMPT_e4505de006d21841_EOF' <system> - GH_AW_PROMPT_d11bf2d02b75c28e_EOF + GH_AW_PROMPT_e4505de006d21841_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_d11bf2d02b75c28e_EOF' + cat << 'GH_AW_PROMPT_e4505de006d21841_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, missing_tool, missing_data, noop - GH_AW_PROMPT_d11bf2d02b75c28e_EOF + GH_AW_PROMPT_e4505de006d21841_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_d11bf2d02b75c28e_EOF' + cat << 'GH_AW_PROMPT_e4505de006d21841_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -249,16 +249,16 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_d11bf2d02b75c28e_EOF + GH_AW_PROMPT_e4505de006d21841_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_d11bf2d02b75c28e_EOF' + cat << 'GH_AW_PROMPT_e4505de006d21841_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} {{#runtime-import .github/prompts/02-mcp-access.md}} {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/workflows/news-translate.md}} - GH_AW_PROMPT_d11bf2d02b75c28e_EOF + GH_AW_PROMPT_e4505de006d21841_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -377,23 +377,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - env: ARTICLE_DATE_INPUT: ${{ github.event.inputs.article_date }} GH_REPOSITORY: ${{ github.repository }} @@ -492,9 +488,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_8883b47b6da98292_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_eabe05fe5ef020d4_EOF' {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","translation"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_8883b47b6da98292_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_eabe05fe5ef020d4_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -725,7 +721,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_a50e333bf63ebd10_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_6e7b5854295b8ccb_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -842,7 +838,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_a50e333bf63ebd10_EOF + GH_AW_MCP_CONFIG_6e7b5854295b8ccb_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -860,7 +856,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1171,7 +1167,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "false" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/news-translate.md b/.github/workflows/news-translate.md index 88b7c2091a..b7b7bcaf3f 100644 --- a/.github/workflows/news-translate.md +++ b/.github/workflows/news-translate.md @@ -43,7 +43,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-translate-${{ inputs.article_type || 'batch' }}-${{ inputs.article_date || 'today' }} @@ -55,7 +55,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -142,85 +142,8 @@ safe-outputs: add-comment: {} steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Pre-flight content PR dependency check env: GH_TOKEN: ${{ github.token }} @@ -328,14 +251,20 @@ Translation is a pure-derivative workflow: - Keep the PR under the safe-outputs 100-file cap. If more translations are pending than fit in one PR, translate the highest-priority batch and leave the rest for the next scheduled run. - Skip any language whose translation already exists and is non-empty unless `force` is explicitly requested. -## Time budget (~40 min) +## Time budget + +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your single `safeoutputs___create_pull_request` call MUST happen by minute 28 at the latest** (hard deadline 30 min). The 45-min `timeout-minutes` job budget exists only as a safety margin; never plan a translate run beyond 28 min before the PR call. + +**Single run** (target ~26 min, hard deadline 28 min for the PR call): | Minutes | Phase | |---------|-------| | 0–2 | MCP pre-warm + date resolution | -| 2–6 | Scan untranslated articles; build work list | -| 6–36 | Translate + validate in priority order (highest-value types first) | -| 36–39 | Final validation, stage, commit | -| 39–41 | **One** `safeoutputs___create_pull_request` call | +| 2–4 | Scan untranslated articles; build prioritised work list, cap at safe-outputs 100-file budget | +| 4–22 | Translate + validate in priority order (highest-value types first); trim batch size before quality | +| 22–25 | Final validation with `scripts/validate-news-translations.ts`, stage scoped files, commit | +| 25–28 | **One** `safeoutputs___create_pull_request` call β€” **HARD DEADLINE minute 28** | + +If a batch cannot finish under this budget, commit the translations completed so far and call `safeoutputs___create_pull_request` with label `partial`; the next scheduled run picks up the remaining languages. A partial PR is always better than losing the whole batch to a `session not found` error. All non-workflow-specific rules are in the imported modules β€” do not restate them here. diff --git a/.github/workflows/news-week-ahead.lock.yml b/.github/workflows/news-week-ahead.lock.yml index a7e14a7bfd..03a7bdcac4 100644 --- a/.github/workflows/news-week-ahead.lock.yml +++ b/.github/workflows/news-week-ahead.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"833405fb3ad891a9e1d125d0bb161503e2a138f9b881d1ba0ba39309406ead3c","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"2da58cfb0edad659d00d4860e69d40781f872e660f6e9d60937a8283f657933f","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -47,7 +47,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -208,20 +208,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_81f8cd46afc24d28_EOF' + cat << 'GH_AW_PROMPT_24666bae305a5c36_EOF' <system> - GH_AW_PROMPT_81f8cd46afc24d28_EOF + GH_AW_PROMPT_24666bae305a5c36_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_81f8cd46afc24d28_EOF' + cat << 'GH_AW_PROMPT_24666bae305a5c36_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_81f8cd46afc24d28_EOF + GH_AW_PROMPT_24666bae305a5c36_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_81f8cd46afc24d28_EOF' + cat << 'GH_AW_PROMPT_24666bae305a5c36_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -251,9 +251,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_81f8cd46afc24d28_EOF + GH_AW_PROMPT_24666bae305a5c36_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_81f8cd46afc24d28_EOF' + cat << 'GH_AW_PROMPT_24666bae305a5c36_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -265,7 +265,7 @@ jobs: {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/prompts/ext/tier-c-aggregation.md}} {{#runtime-import .github/workflows/news-week-ahead.md}} - GH_AW_PROMPT_81f8cd46afc24d28_EOF + GH_AW_PROMPT_24666bae305a5c36_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -384,23 +384,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -476,9 +472,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_9f3b5f09815be1e7_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_a469586889a1688e_EOF' {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_9f3b5f09815be1e7_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_a469586889a1688e_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -749,7 +745,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_b93c8a24a42b71c9_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_5bbc9b99c08c83f7_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -866,7 +862,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_b93c8a24a42b71c9_EOF + GH_AW_MCP_CONFIG_5bbc9b99c08c83f7_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -884,7 +880,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1196,7 +1192,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/news-week-ahead.md b/.github/workflows/news-week-ahead.md index e22a37d14c..5585e1c6e2 100644 --- a/.github/workflows/news-week-ahead.md +++ b/.github/workflows/news-week-ahead.md @@ -41,7 +41,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-week-ahead-${{ inputs.article_date || 'today' }} @@ -52,7 +52,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -141,85 +141,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -239,7 +162,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/.github/workflows/news-weekly-review.lock.yml b/.github/workflows/news-weekly-review.lock.yml index da9f166c68..152ffc5772 100644 --- a/.github/workflows/news-weekly-review.lock.yml +++ b/.github/workflows/news-weekly-review.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a49a9b2e84d77d2065b045db81c9c0807c61f006423ba58ba5b02dc288ec3ada","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"6044e13b5dc448c55e2357c09f80417699197238","version":"6044e13b5dc448c55e2357c09f80417699197238"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8c1204f67bd455877ea10be0e2b74f109391ef7adf9a3950d94a9508198ec41c","compiler_version":"v0.69.3","agent_id":"copilot","agent_model":"claude-opus-4.7"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"006ffd856b868b71df342dbe0ba082a963249b31","version":"v0.69.3"}],"containers":[{"image":"alpine:latest"},{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:25-alpine"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -47,7 +47,7 @@ # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 -# - actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 +# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@006ffd856b868b71df342dbe0ba082a963249b31 # v0.69.3 # @@ -208,20 +208,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_83698bceae8303ea_EOF' + cat << 'GH_AW_PROMPT_11a094bddc1473e9_EOF' <system> - GH_AW_PROMPT_83698bceae8303ea_EOF + GH_AW_PROMPT_11a094bddc1473e9_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_83698bceae8303ea_EOF' + cat << 'GH_AW_PROMPT_11a094bddc1473e9_EOF' <safe-output-tools> Tools: add_comment, create_pull_request, dispatch_workflow, missing_tool, missing_data, noop - GH_AW_PROMPT_83698bceae8303ea_EOF + GH_AW_PROMPT_11a094bddc1473e9_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_83698bceae8303ea_EOF' + cat << 'GH_AW_PROMPT_11a094bddc1473e9_EOF' </safe-output-tools> <github-context> The following GitHub context information is available for this workflow: @@ -251,9 +251,9 @@ jobs: {{/if}} </github-context> - GH_AW_PROMPT_83698bceae8303ea_EOF + GH_AW_PROMPT_11a094bddc1473e9_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_83698bceae8303ea_EOF' + cat << 'GH_AW_PROMPT_11a094bddc1473e9_EOF' </system> {{#runtime-import .github/prompts/00-base-contract.md}} {{#runtime-import .github/prompts/01-bash-and-shell-safety.md}} @@ -265,7 +265,7 @@ jobs: {{#runtime-import .github/prompts/07-commit-and-pr.md}} {{#runtime-import .github/prompts/ext/tier-c-aggregation.md}} {{#runtime-import .github/workflows/news-weekly-review.md}} - GH_AW_PROMPT_83698bceae8303ea_EOF + GH_AW_PROMPT_11a094bddc1473e9_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -384,23 +384,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '25' + package-manager-cache: false - name: Create gh-aw temp directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" - name: Configure gh CLI for GitHub Enterprise run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # 6044e13b5dc448c55e2357c09f80417699197238 - with: - node-version: "25" - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: "echo \"πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol...\"\nMCP_URL=\"https://riksdag-regering-ai.onrender.com/mcp\"\nWARM=false\nfor i in 1 2 3 4 5 6; do\n RESP=$(curl -sf --max-time 30 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"$MCP_URL\" 2>/dev/null) || true\n if echo \"$RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$RESP\" | grep -o '\"name\"' | wc -l)\n echo \"βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered\"\n WARM=true\n break\n fi\n echo \"⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s...\"\n sleep 20\ndone\nif [ \"$WARM\" = \"false\" ]; then\n echo \"⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate\"\nfi\n" - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: "echo \"πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"\necho \"═══════════════════════════════════════════\"\necho \"\"\necho \"πŸ“‘ DNS Resolution Tests:\"\nfor domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do\n if nslookup \"$domain\" >/dev/null 2>&1; then\n IP=$(nslookup \"$domain\" 2>/dev/null | grep -A1 \"Name:\" | grep \"Address:\" | head -1 | awk '{print $2}')\n echo \" βœ… $domain β†’ $IP\"\n else\n echo \" ❌ $domain β€” DNS FAILED\"\n fi\ndone\necho \"\"\necho \"🌐 HTTPS Connectivity Tests:\"\nfor url in \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" \\\n \"https://api.scb.se/OV0104/v2beta\" \\\n \"https://api.worldbank.org/v2/country/SE?format=json\" \\\n \"https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1\" \\\n; do\n HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 \"$url\" 2>/dev/null || echo \"000\")\n DOMAIN=$(echo \"$url\" | sed 's|https://||' | cut -d/ -f1)\n if [ \"$HTTP_CODE\" -ge 200 ] && [ \"$HTTP_CODE\" -lt 400 ]; then\n echo \" βœ… $DOMAIN β†’ HTTP $HTTP_CODE\"\n elif [ \"$HTTP_CODE\" = \"000\" ]; then\n echo \" ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE\"\n else\n echo \" ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE\"\n fi\ndone\necho \"\"\necho \"πŸ”Œ MCP Server Tool Count:\"\nTOOL_RESP=$(curl -sf --max-time 15 -X POST \\\n -H \"Content-Type: application/json\" \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}' \\\n \"https://riksdag-regering-ai.onrender.com/mcp\" 2>/dev/null) || TOOL_RESP=\"\"\nif echo \"$TOOL_RESP\" | grep -q '\"tools\"'; then\n TOOL_COUNT=$(echo \"$TOOL_RESP\" | grep -o '\"name\"' | wc -l)\n echo \" βœ… riksdag-regering MCP: $TOOL_COUNT tools registered\"\nelse\n echo \" ❌ riksdag-regering MCP: No tools response (server may still be starting)\"\nfi\necho \"\"\necho \"═══════════════════════════════════════════\"\n" + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm - name: Configure Git credentials env: @@ -476,9 +472,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_ba6fc74861230a38_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_ba0101df3e0a8c8f_EOF' {"add_comment":{"max":1},"create_pull_request":{"draft":false,"expires":336,"labels":["agentic-news","analysis-data"],"max":1,"max_patch_size":4096,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["news-translate"],"max":1,"workflow_files":{"news-translate":".lock.yml"},"workflows":["news-translate"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_ba6fc74861230a38_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_ba0101df3e0a8c8f_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -749,7 +745,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_2bcefc0325123511_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_bf26249d3a634401_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -866,7 +862,7 @@ jobs: "keepaliveInterval": 300 } } - GH_AW_MCP_CONFIG_2bcefc0325123511_EOF + GH_AW_MCP_CONFIG_bf26249d3a634401_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -884,7 +880,7 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - timeout-minutes: 55 + timeout-minutes: 45 run: | set -o pipefail touch /tmp/gh-aw/agent-step-summary.md @@ -1196,7 +1192,7 @@ jobs: GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" - GH_AW_TIMEOUT_MINUTES: "55" + GH_AW_TIMEOUT_MINUTES: "45" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/news-weekly-review.md b/.github/workflows/news-weekly-review.md index aef4cdb8de..cbca519181 100644 --- a/.github/workflows/news-weekly-review.md +++ b/.github/workflows/news-weekly-review.md @@ -41,7 +41,7 @@ permissions: discussions: read security-events: read -timeout-minutes: 55 +timeout-minutes: 45 concurrency: group: gh-aw-news-weekly-review-${{ inputs.article_date || 'today' }} @@ -52,7 +52,7 @@ features: sandbox: mcp: - keepalive-interval: 300 # 5m ping to keep MCP connections alive; Copilot API token expires ~60min so PR must be created within 25min of agent start + keepalive-interval: 300 # 5m ping keeps upstream MCPs warm; safeoutputs HTTP idle session (~25-30 min) is the operative deadline β†’ safeoutputs___create_pull_request must be called by minute 28 (hard 30); see prompts/07-commit-and-pr.md Β§Deadline enforcement runtimes: node: @@ -141,85 +141,8 @@ safe-outputs: max: 1 steps: - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '25' - - - name: Install dependencies - run: | - npm ci --prefer-offline --no-audit - - - name: Pre-warm MCP server (Render.com cold start mitigation) - run: | - echo "πŸ”₯ Pre-warming riksdag-regering MCP server via MCP protocol..." - MCP_URL="https://riksdag-regering-ai.onrender.com/mcp" - WARM=false - for i in 1 2 3 4 5 6; do - RESP=$(curl -sf --max-time 30 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "$MCP_URL" 2>/dev/null) || true - if echo "$RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$RESP" | grep -o '"name"' | wc -l) - echo "βœ… MCP server responded on attempt $i with $TOOL_COUNT tools registered" - WARM=true - break - fi - echo "⏳ Attempt $i/6 β€” server may be cold-starting, waiting 20s..." - sleep 20 - done - if [ "$WARM" = "false" ]; then - echo "⚠️ MCP server did not respond after 6 attempts β€” agent will retry via in-prompt health gate" - fi - - - name: Pre-flight external endpoint reachability check (runs before MCP Gateway) - run: | - echo "πŸ” Network Diagnostics β€” $(date -u '+%Y-%m-%dT%H:%M:%SZ')" - echo "═══════════════════════════════════════════" - echo "" - echo "πŸ“‘ DNS Resolution Tests:" - for domain in riksdag-regering-ai.onrender.com api.scb.se api.worldbank.org data.riksdagen.se www.riksdagen.se www.regeringen.se www.statskontoret.se statskontoret.se; do - if nslookup "$domain" >/dev/null 2>&1; then - IP=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -1 | awk '{print $2}') - echo " βœ… $domain β†’ $IP" - else - echo " ❌ $domain β€” DNS FAILED" - fi - done - echo "" - echo "🌐 HTTPS Connectivity Tests:" - for url in \ - "https://riksdag-regering-ai.onrender.com/mcp" \ - "https://api.scb.se/OV0104/v2beta" \ - "https://api.worldbank.org/v2/country/SE?format=json" \ - "https://data.riksdagen.se/dokumentlista/?sok=test&doktyp=bet&utformat=json&a=1" \ - ; do - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000") - DOMAIN=$(echo "$url" | sed 's|https://||' | cut -d/ -f1) - if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then - echo " βœ… $DOMAIN β†’ HTTP $HTTP_CODE" - elif [ "$HTTP_CODE" = "000" ]; then - echo " ❌ $DOMAIN β†’ TIMEOUT/UNREACHABLE" - else - echo " ⚠️ $DOMAIN β†’ HTTP $HTTP_CODE" - fi - done - echo "" - echo "πŸ”Œ MCP Server Tool Count:" - TOOL_RESP=$(curl -sf --max-time 15 -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ - "https://riksdag-regering-ai.onrender.com/mcp" 2>/dev/null) || TOOL_RESP="" - if echo "$TOOL_RESP" | grep -q '"tools"'; then - TOOL_COUNT=$(echo "$TOOL_RESP" | grep -o '"name"' | wc -l) - echo " βœ… riksdag-regering MCP: $TOOL_COUNT tools registered" - else - echo " ❌ riksdag-regering MCP: No tools response (server may still be starting)" - fi - echo "" - echo "═══════════════════════════════════════════" - + - name: News pre-warm & pre-flight (composite) + uses: ./.github/actions/news-prewarm engine: id: copilot model: claude-opus-4.7 @@ -239,7 +162,7 @@ Generates deep political intelligence analysis **and** the rendered HTML article ## Time budget -> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30–35 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window described in `00-base-contract.md Β§Session keepalive requirement`. +> πŸ”΄ **CRITICAL β€” safeoutputs MCP idle timeout (~30 min)**: The `safeoutputs` MCP server's Streamable-HTTP session expires after **~30 minutes of idle time**. **Your first and only `safeoutputs___*` call MUST happen by minute 28 at the latest.** This is a harder deadline than the ~60-minute Copilot-API token window and the 45-minute job `timeout-minutes` budget described in `00-base-contract.md Β§Session keepalive requirement`. > > **AI-FIRST within the compressed budget**: Pass 2 is still mandatory. Under the tightened ~28-min budget, prefer **scope compression over iteration skipping** β€” reduce the download/manifest scope if needed, but maintain 1:1 per-document coverage and always perform a full read-back-and-improve Pass 2 on whatever artifacts exist. For scheduled runs treat `analysis_depth` as `standard` in practice; reserve `deep`/`comprehensive` for manual `workflow_dispatch` backfills. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0f26dbc924..eaeab051f2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -28,8 +28,8 @@ > - 🧠 Runtime baseline tightened to **Node.js β‰₯25**; toolchain bumped to TypeScript 6.0.3, Vite 8.0.9, Vitest 4.1.4, ESLint 10.2.1, Cypress 15.14.0 (optional), Playwright 1.59.1, typedoc 0.28.19, happy-dom 20.9.0, knip 6.5.0, ajv 8.18.0. > - πŸ—‚οΈ CIA data now spans **15 subsystems** under `cia-data/` (anomaly, coalition, committee, distribution, election, election-cycle, ministry, parties, party, percentile, politician, pre-election, risk, seasonal, voting). Prior "19 products" framing has been retired in favour of subsystem count. > - 🌍 Content footprint: **14 languages** (EN, SV, DA, NB (`_no`), DE, ES, FI, FR, HE RTL, AR RTL, JA, KO, NL, ZH) β€’ **2,669 files** under `news/`. -> - πŸ€– GitHub Actions surface: **45 files** total (21 standard `.yml`, 12 agentic `.md` sources, 12 compiled `.lock.yml` siblings). Twelve agentic news workflows orchestrated via the five-layer safe-output security model and egress firewall (Squid + iptables). -> - 🧩 Copilot ecosystem: **24 custom agents** under `.github/agents/`, **92 skills** under `.github/skills/`, **8 MCP servers** (`riksdag-regering`, `scb`, `world-bank`, `github` insiders, `filesystem`, `memory`, `sequential-thinking`, `playwright`) wired via `.github/copilot-mcp.json`. +> - πŸ€– GitHub Actions surface: **43 files** total (21 standard `.yml`, 11 agentic `.md` sources, 11 compiled `.lock.yml` siblings). Eleven agentic news workflows orchestrated via the five-layer safe-output security model and egress firewall (Squid + iptables). +> - 🧩 Copilot ecosystem: **24 custom agents** under `.github/agents/`, **91 skills** under `.github/skills/`, **8 MCP servers** (`riksdag-regering`, `scb`, `world-bank`, `github` insiders, `filesystem`, `memory`, `sequential-thinking`, `playwright`) wired via `.github/copilot-mcp.json`. > - ☁️ Production distribution: AWS CloudFront + S3 dual-region (us-east-1 primary, eu-west-1 replica) via OIDC-only deploy; GitHub Pages (`hack23.github.io`) as DR fallback. > - πŸ›‘οΈ Integrity: SRI enabled via `vite-plugin-sri-gen@1.3.2`; all Actions SHA-pinned; `step-security/harden-runner` across workflows; CodeQL, Dependabot, dependency-review, Scorecards, Secret Scanning, OpenSSF Best Practices #12069 active. > - 🏷️ Classification confirmed: **Public / Integrity High / Availability High**, RTO 1–4h, RPO 4–24h, Financial Impact Low (<$500/day). diff --git a/FUTURE_WORKFLOWS.md b/FUTURE_WORKFLOWS.md index cc28bf7e52..6ea3784199 100644 --- a/FUTURE_WORKFLOWS.md +++ b/FUTURE_WORKFLOWS.md @@ -188,12 +188,12 @@ flowchart TB | Metric | Value | | --- | --- | -| Total Workflow Files | 47 (23 YAML + 12 agentic `.md` + 12 `.lock.yml`) = **35 distinct workflows** | +| Total Workflow Files | 43 (21 YAML + 11 agentic `.md` + 11 `.lock.yml`) = **32 distinct workflows** | | TypeScript Modules | 31 (in `src/browser/`) | | Unit Tests | 2890 (Vitest) | | Language Support | 14 languages (incl. RTL) | | Deployment | Dual: AWS S3/CloudFront + GitHub Pages | -| AI Content | 12 agentic workflows (Claude Opus 4.7) | +| AI Content | 11 agentic workflows (Claude Opus 4.7) | | Security Compliance | ISO 27001, NIST CSF 2.0, CIS Controls v8.1 | --- @@ -682,12 +682,12 @@ gantt | Year | Projected Distinct Workflows | New Capabilities | | --- | --- | --- | -| 2026 Q1 | **35** (47 files) | TypeScript foundation, 12 agentic workflows, Node.js 25 βœ… | -| 2026 Q2 | **36** (48 files) | **Node.js 26 Current upgrade** (around Apr release; LTS later 2026) | -| 2026 Q4 | **42** (54 files) | CIA pipeline v2, preview deploys, visual regression | -| 2027 Q4 | **47** (59 files) | Node.js 27 LTS, OSINT pipeline, ML predictions, real-time streams | -| 2028 Q4 | **57** (69 files) | Node.js 28 LTS, self-healing, canary deploy, AI editorial board | -| 2029 Q4 | **67+** (79+ files) | Node.js 29 LTS, intelligence API, multi-parliament, federation | +| 2026 Q1 | **32** (43 files) | TypeScript foundation, 11 agentic workflows, Node.js 25 βœ… | +| 2026 Q2 | **33** (44 files) | **Node.js 26 Current upgrade** (around Apr release; LTS later 2026) | +| 2026 Q4 | **39** (50 files) | CIA pipeline v2, preview deploys, visual regression | +| 2027 Q4 | **44** (55 files) | Node.js 27 LTS, OSINT pipeline, ML predictions, real-time streams | +| 2028 Q4 | **54** (65 files) | Node.js 28 LTS, self-healing, canary deploy, AI editorial board | +| 2029 Q4 | **64+** (75+ files) | Node.js 29 LTS, intelligence API, multi-parliament, federation | --- diff --git a/MINDMAP.md b/MINDMAP.md index 78f73dae3a..24ead00eeb 100644 --- a/MINDMAP.md +++ b/MINDMAP.md @@ -24,7 +24,7 @@ > - πŸ“ˆ Added **🌐 IMF** branch under Data Integration alongside World Bank (WEO, Fiscal Monitor, IFS, SDMX 3.0, T+5 projections, pure-TypeScript client `scripts/imf-client.ts` β€” *not an MCP server*, per [ADR 0001](docs/adr/0001-adopt-imf-data-alongside-world-bank.md)). > > **πŸ†• What changed since last review (v1.1 β†’ v1.2, 2026-04-20):** -> - Mindmaps expanded to explicitly enumerate the **15 CIA data subsystems** (anomaly, coalition, committee, distribution, election, election-cycle, ministry, parties, party, percentile, politician, pre-election, risk, seasonal, voting), **12 agentic news workflows**, **24 Copilot agents**, **92 skills**, **8 MCP servers**, **14 languages**, and the **dual distribution model** (static site + `riksdagsmonitor` npm package with SLSA provenance). +> - Mindmaps expanded to explicitly enumerate the **15 CIA data subsystems** (anomaly, coalition, committee, distribution, election, election-cycle, ministry, parties, party, percentile, politician, pre-election, risk, seasonal, voting), **11 agentic news workflows**, **24 Copilot agents**, **91 skills**, **8 MCP servers**, **14 languages**, and the **dual distribution model** (static site + `riksdagsmonitor` npm package with SLSA provenance). > - Added mindmap branch for toolchain: Node.js β‰₯25, TypeScript 6.0.3, Vite 8.0.9, Vitest 4.1.4, ESLint 10.2.1, Cypress 15.14.0, Playwright 1.59.1, typedoc 0.28.19. > - Added mindmap branch for compliance frameworks anchored to ISMS-PUBLIC: ISO 27001:2022, NIST CSF 2.0, CIS Controls v8.1, GDPR, NIS2, EU CRA, OpenSSF Best Practices #12069, OpenSSF Scorecard. diff --git a/README.md b/README.md index 39c944d0b4..374afcdd63 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ Riksdagsmonitor is a comprehensive intelligence platform for monitoring politica </div> <div> <a href="https://riksdagsmonitor.com"><strong>🌐 Official Website</strong></a> β€’ + <a href="https://riksdagsmonitor.com/political-intelligence.html"><strong>πŸ•΅οΈ Political Intelligence</strong></a> β€’ + <a href="https://riksdagsmonitor.com/sitemap.html"><strong>πŸ—ΊοΈ Sitemap</strong></a> β€’ <a href="https://github.com/Hack23/riksdagsmonitor"><strong>πŸ“‚ Repository</strong></a> β€’ <a href="https://hack23.com/riksdagsmonitor-features.html"><strong>✨ Features</strong></a> β€’ <a href="https://hack23.com/riksdagsmonitor-docs.html"><strong>πŸ“š Documentation</strong></a> @@ -246,6 +248,17 @@ npm install chartjs-plugin-annotation # Optional β€” for chart annot **Website:** [riksdagsmonitor.com](https://riksdagsmonitor.com) +### πŸ—ΊοΈ Key Web Pages + +Two flagship pages are the entry points for analysts, journalists, search engines and citizens β€” both are auto-generated, multilingual (14 languages) and SEO-optimised with canonical URLs, Open Graph, Twitter Cards, JSON-LD `CollectionPage` schema and full `hreflang` alternates. + +| Icon | Page | URL | Description | +|------|------|-----|-------------| +| πŸ•΅οΈ | **Political Intelligence Index** | <https://riksdagsmonitor.com/political-intelligence.html> | Complete catalogue of Riksdagsmonitor's evidence-based intelligence work β€” every analysis methodology, template and **daily analysis artifact** (Family A baseline + Family B + Family C synthesis + Family D extension) covering the Swedish Riksdag and Regeringskansliet. The single best entry point for OSINT/INTOP researchers. | +| πŸ—ΊοΈ | **Sitemap (Human + Machine)** | <https://riksdagsmonitor.com/sitemap.html> | Human-readable navigation of every page on the platform β€” dashboards, news articles, methodologies, language variants β€” plus the machine-readable [`sitemap.xml`](https://riksdagsmonitor.com/sitemap.xml) and [`rss.xml`](https://riksdagsmonitor.com/rss.xml) feeds. Daily refreshed; honours `robots.txt` and search-engine indexing best practices. | + +Both pages are also localised β€” append `_<lang>` (e.g. `political-intelligence_sv.html`, `sitemap_de.html`) for any of the 14 supported languages. + **Available in 14 Languages:** - English, Swedish, Danish, Norwegian, Finnish - German, French, Spanish, Dutch @@ -650,7 +663,7 @@ Riksdagsmonitor uses **GitHub Copilot personas, skills, and agentic workflows** - [`.github/agents/README.md`](.github/agents/README.md) β€” **24 agent files** (14 persona agents + 9 workflow-specialist `.agent.md` + shared `developer.instructions.md`) - [`.github/skills/README.md`](.github/skills/README.md) β€” **91 skills** grouped by 12 functional categories - [`.github/prompts/README.md`](.github/prompts/README.md) β€” 8 bounded-context prompt modules + Tier-C extension, imported by every agentic news workflow -- [`.github/workflows/README.md`](.github/workflows/README.md) β€” 45 workflow files (standard + agentic) +- [`.github/workflows/README.md`](.github/workflows/README.md) β€” 43 workflow files (standard + agentic) - [AGENTS.md](AGENTS.md) β€” canonical persona catalog with skill-mapping tables and invocation examples - [SKILLS.md](SKILLS.md) β€” canonical skill catalog with agent-skill mappings @@ -761,7 +774,7 @@ Every published article is a deterministic projection of three input sources, in The aggregator concatenates the day's evidence in template order (with `intelligence-assessment.md` β€” the ICD-203 Key Judgments centrepiece β€” surfaced at position 3 immediately after the executive brief + synthesis), the renderer transforms the markdown into sanitised HTML, and the chrome layer wraps it with JSON-LD, a tagline-and-breadcrumb header, a 3-column footer (*Riksdagsmonitor* / *Resources* / *Trust & compliance*) and both a dropdown and an always-visible footer language switcher. The chrome's language switcher populates `hreflangAlternates` for **all 14 supported languages** at render time, so switching language from any article always lands on the sibling article (e.g. `news/2026-04-24-propositions-de.html`), never on the language homepage. Internally, `scripts/render-lib/` is split into six focused leaf modules β€” `aggregator.ts`, `markdown.ts`, `chrome.ts`, `article.ts`, `url-helpers.ts`, `constants.ts` β€” behind a thin barrel `index.ts`; see [`ARCHITECTURE.md`](ARCHITECTURE.md#pipeline-stages) for the full per-module contract. The `Sources of Method` block in every article footer links back to every methodology and template file actually used β€” provenance is preserved end-to-end. > πŸ“š **Directory-level catalogs** (single sources of truth): -> - [`.github/workflows/README.md`](.github/workflows/README.md) β€” 45 workflow files (21 standard `.yml` + 11 agentic `.md` sources + 11 compiled `.lock.yml`) +> - [`.github/workflows/README.md`](.github/workflows/README.md) β€” 43 workflow files (21 standard `.yml` + 11 agentic `.md` sources + 11 compiled `.lock.yml`) > - [`.github/prompts/README.md`](.github/prompts/README.md) β€” 8 bounded-context prompt modules + `ext/tier-c-aggregation.md`, imported by every news workflow > - [`.github/agents/README.md`](.github/agents/README.md) β€” 24 Copilot agent files (14 personas + 9 workflow-specialists + 1 shared developer-instructions) > - [`.github/skills/README.md`](.github/skills/README.md) β€” 91 skills grouped by 12 functional categories @@ -819,7 +832,7 @@ timeline title Riksdagsmonitor Evolution β€” 2026 to 2037 section Phase 3 β€” Foundation (2026) Q1-Q2 : TypeScript migration βœ… - : 12 agentic news workflows βœ… + : 11 agentic news workflows βœ… : 34 GitHub Actions workflows + 10 agent prompt files : Dual deployment (S3 + GitHub Pages) Q3-Q4 : CIA data pipeline integration diff --git a/SECURITY_ARCHITECTURE.md b/SECURITY_ARCHITECTURE.md index 59bd900b31..b5a979ad17 100644 --- a/SECURITY_ARCHITECTURE.md +++ b/SECURITY_ARCHITECTURE.md @@ -31,9 +31,9 @@ > - **Code:** CodeQL (javascript-typescript), ESLint 10.2.1, htmlhint 1.9.2, TypeScript 6.0.3 strict mode, secret scanning, knip 6.5.0 dead-code detection. > - **Supply chain:** Dependabot, `actions/dependency-review-action`, OpenSSF Scorecard, **npm publish with `--provenance` (SLSA attestations)**, SHA-pinning on every `uses:` reference. > - **Pipeline:** `step-security/harden-runner` with egress audit, AWS OIDC (no long-lived keys), least-privilege `permissions:` per workflow, SLSA Build L3 via GitHub-hosted runners. -> - **Agentic workloads (new category):** 12 agentic news workflows wrapped in the **five-layer safe-outputs** validator (sanitisation β†’ schema-validate β†’ policy-check β†’ human-review β†’ merge) behind a **Squid proxy + iptables egress firewall** (allow-list only to riksdagen.se, regeringen.se, scb.se, worldbank.org, **data.imf.org, api.imf.org, www.imf.org**, github.com, MCP endpoints). +> - **Agentic workloads (new category):** 11 agentic news workflows wrapped in the **five-layer safe-outputs** validator (sanitisation β†’ schema-validate β†’ policy-check β†’ human-review β†’ merge) behind a **Squid proxy + iptables egress firewall** (allow-list only to riksdagen.se, regeringen.se, scb.se, worldbank.org, **data.imf.org, api.imf.org, www.imf.org**, github.com, MCP endpoints). > - Added **MCP security posture**: 8 MCP servers defined in `.github/copilot-mcp.json` β€” `riksdag-regering` (HTTPS `riksdag-regering-ai.onrender.com/mcp`), `scb` (local `@jarib/pxweb-mcp@2.0.0` β†’ `api.scb.se/OV0104/v2beta`), `world-bank` (local `worldbank-mcp@1.0.1`), `github` (HTTPS `api.githubcopilot.com/mcp/insiders`), `filesystem`, `memory`, `sequential-thinking`, `playwright` (headless). -> - Added **24 Copilot agents** (`.github/agents/`) and **92 skills** (`.github/skills/`) under security review; each agent's tool allow-list is explicit and audited. +> - Added **24 Copilot agents** (`.github/agents/`) and **91 skills** (`.github/skills/`) under security review; each agent's tool allow-list is explicit and audited. > - OpenSSF Best Practices project #12069 confirmed active; Scorecard badge present. > - Compliance mapping reconfirmed: ISO 27001:2022 Annex A.5/A.8 (full), NIST CSF 2.0 GV/ID/PR/DE/RS/RC, CIS Controls v8.1 (#1–#18 applicable subset), GDPR Art. 32, NIS2 Art. 21, EU CRA Annex I. diff --git a/SWOT.md b/SWOT.md index 7b167c92c3..49794db195 100644 --- a/SWOT.md +++ b/SWOT.md @@ -27,7 +27,7 @@ > - πŸ“š Upstream data-source list updated to **(Riksdagen, Regeringen, SCB, World Bank, IMF)**. > > **πŸ†• What changed since last review (v1.0 β†’ v1.1, 2026-04-20):** -> - **Strengths (expanded):** `v0.8.48` shipped to npm with SLSA provenance; dual-distribution model (static site + public npm package); **2,669 files** across 14 languages including RTL (HE, AR); **15 CIA data subsystems**; **12 agentic news workflows** under five-layer safe-output control; OpenSSF Best Practices badge #12069; OpenSSF Scorecard transparency; AI FIRST quality process (minimum-2-iteration rule); full OIDC CI/CD with zero long-lived AWS credentials; 24 Copilot agents + 92 skills driving automation leverage. +> - **Strengths (expanded):** `v0.8.48` shipped to npm with SLSA provenance; dual-distribution model (static site + public npm package); **2,669 files** across 14 languages including RTL (HE, AR); **15 CIA data subsystems**; **11 agentic news workflows** under five-layer safe-output control; OpenSSF Best Practices badge #12069; OpenSSF Scorecard transparency; AI FIRST quality process (minimum-2-iteration rule); full OIDC CI/CD with zero long-lived AWS credentials; 24 Copilot agents + 91 skills driving automation leverage. > - **Weaknesses (expanded):** single-person company (CEO is sole owner of `Hack23/riksdagsmonitor` β€” key-person risk); dependency on a narrow set of upstream data sources (Riksdagen, Regeringen, SCB, World Bank, IMF); Swedish-first editorial posture requires translation quality gates for 13 non-Swedish locales; agentic news generation depends on LLM availability and prompt hygiene. > - **Opportunities (expanded):** positioning as the reference open-transparency platform for EU member-state parliaments (NIS2 tailwind); `riksdagsmonitor` npm package creates a developer-ecosystem moat for third-party dashboards and research; cross-referenced publication with Citizen Intelligence Agency (CIA) platform; multi-language reach into global journalist and research markets; EU CRA and AI Act compliance as competitive differentiation. > - **Threats (expanded):** disinformation / counter-narrative campaigns targeting article integrity; upstream data-source schema changes or de-platforming; Swedish legal landscape around political speech; supply-chain attacks on MCP servers or npm dependencies; prompt-injection attacks on agentic workflows (mitigated by the five-layer safe-outputs model and egress firewall); LLM provider outages or policy shifts affecting news generation cadence. diff --git a/analysis/methodologies/README.md b/analysis/methodologies/README.md index ec93104f88..4b6768cb61 100644 --- a/analysis/methodologies/README.md +++ b/analysis/methodologies/README.md @@ -113,7 +113,7 @@ ## πŸ€– How agentic workflows consume these methodologies -The 12 agentic news workflows in `.github/workflows/news-*.md` are the **primary consumer** of these methodologies. The authoritative workflow contract lives in [`.github/prompts/`](../../.github/prompts/) β€” see [`.github/prompts/README.md`](../../.github/prompts/README.md) for the full module catalogue. +The 11 agentic news workflows in `.github/workflows/news-*.md` are the **primary consumer** of these methodologies. The authoritative workflow contract lives in [`.github/prompts/`](../../.github/prompts/) β€” see [`.github/prompts/README.md`](../../.github/prompts/README.md) for the full module catalogue. | Methodology | Read in Pass 1 (mandatory) | Read in Pass 2 (improvement) | Enforced by | |-------------|---------------------------|------------------------------|-------------| diff --git a/analysis/templates/README.md b/analysis/templates/README.md index 62d7b7f74b..4e9652510f 100644 --- a/analysis/templates/README.md +++ b/analysis/templates/README.md @@ -221,7 +221,7 @@ The aggregator's structural projections (heading demotion, source-preamble strip ## πŸ€– Artifact β†’ workflow β†’ gate check mapping -The 12 agentic news workflows in `.github/workflows/news-*.md` render these templates into concrete artifacts under `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`. Authoring contract: [`.github/prompts/README.md`](../../.github/prompts/README.md). Tradecraft canon: [`../methodologies/osint-tradecraft-standards.md`](../methodologies/osint-tradecraft-standards.md). +The 11 agentic news workflows in `.github/workflows/news-*.md` render these templates into concrete artifacts under `analysis/daily/$ARTICLE_DATE/$SUBFOLDER/`. Authoring contract: [`.github/prompts/README.md`](../../.github/prompts/README.md). Tradecraft canon: [`../methodologies/osint-tradecraft-standards.md`](../methodologies/osint-tradecraft-standards.md). **23 always-produced artifacts per run** (every news workflow β€” single-type + Tier-C): diff --git a/docs/API_README.md b/docs/API_README.md index 69e6499332..462f8c2a88 100644 --- a/docs/API_README.md +++ b/docs/API_README.md @@ -1,15 +1,33 @@ # πŸ•΅οΈ Riksdagsmonitor Intelligence Platform β€” API Reference -> **Political Intelligence Analysis & OSINT Platform for Swedish Parliament Monitoring** +> **Political Intelligence Analysis & OSINT Platform for Swedish Parliament Monitoring** β€” TypeScript SDK, automated dashboards, election forecasting and 14-language news generation, published under Apache-2.0 with SLSA build provenance. [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/Hack23/riksdagsmonitor/blob/main/LICENSE) [![TypeDoc](https://img.shields.io/badge/docs-TypeDoc-blue.svg)](https://riksdagsmonitor.com/docs/api/) [![npm](https://img.shields.io/npm/v/riksdagsmonitor?logo=npm)](https://www.npmjs.com/package/riksdagsmonitor) [![Hack23 ISMS](https://img.shields.io/badge/Hack23-ISMS-blue?logo=shield)](https://github.com/Hack23/ISMS-PUBLIC) +[![ISO 27001](https://img.shields.io/badge/ISO-27001:2022-purple)](https://github.com/Hack23/ISMS-PUBLIC/blob/main/Information_Security_Policy.md) +[![NIST CSF](https://img.shields.io/badge/NIST-CSF_2.0-orange)](https://github.com/Hack23/ISMS-PUBLIC/blob/main/Information_Security_Policy.md) +[![CIS Controls](https://img.shields.io/badge/CIS-Controls_v8.1-red)](https://github.com/Hack23/ISMS-PUBLIC/blob/main/Information_Security_Policy.md) --- -## npm Package +## 🌐 Live Platform β€” Discover the Intelligence + +These two pages are the canonical entry points for OSINT analysts, journalists, researchers, search-engine crawlers and citizens. Both are auto-generated daily, fully localised across 14 languages, and ship with comprehensive SEO metadata (canonical URLs, Open Graph, Twitter Cards, JSON-LD `CollectionPage` schema, full `hreflang` alternates). + +| Icon | Page | URL | What you find | +|------|------|-----|---------------| +| πŸ•΅οΈ | **Political Intelligence Index** | <https://riksdagsmonitor.com/political-intelligence.html> | Complete catalogue of Riksdagsmonitor's evidence-based intelligence work β€” every analysis methodology, every analytical template, and every **daily analysis artifact** (Family A baseline + Family B + Family C synthesis + Family D extension) covering the Swedish Riksdag, Regeringskansliet and the surveillance authorities. The single best entry point for OSINT/INTOP researchers. | +| πŸ—ΊοΈ | **Sitemap (Human-readable)** | <https://riksdagsmonitor.com/sitemap.html> | Human navigation of every page on the platform β€” dashboards, news articles, methodologies, language variants, archives β€” paired with the machine-readable [`sitemap.xml`](https://riksdagsmonitor.com/sitemap.xml) and [`rss.xml`](https://riksdagsmonitor.com/rss.xml) feeds. | +| 🌐 | **Main Site** | <https://riksdagsmonitor.com> | Cyberpunk-themed landing page, dashboards (party performance, ministry power, coalition dynamics, anomaly detection, electoral cycle), news index. | +| πŸ“° | **News Index** | <https://riksdagsmonitor.com/news/> | Daily political-intelligence articles generated by the 11 agentic news workflows β€” propositions, motions, committee reports, interpellations, evening analysis, week-ahead, month-ahead, weekly review, monthly review, real-time monitor, plus 13-language translations. | + +> **Tip:** Every URL above also exists in 14 languages β€” append `_<lang>` (e.g. `political-intelligence_sv.html`, `sitemap_de.html`). `hreflang` alternates are emitted on every page so search engines surface the correct language variant per region. + +--- + +## πŸ“¦ npm Package Shared types, theme system, and dashboard utilities are published as an npm package with provenance: @@ -246,6 +264,10 @@ This platform aligns with **Hack23 AB ISMS** requirements per the [Secure Develo ## Links - **Live Platform**: [riksdagsmonitor.com](https://riksdagsmonitor.com) +- **πŸ•΅οΈ Political Intelligence Index**: [riksdagsmonitor.com/political-intelligence.html](https://riksdagsmonitor.com/political-intelligence.html) β€” every methodology, template and daily artifact +- **πŸ—ΊοΈ Human Sitemap**: [riksdagsmonitor.com/sitemap.html](https://riksdagsmonitor.com/sitemap.html) β€” full platform navigation in 14 languages +- **πŸ“° News Index**: [riksdagsmonitor.com/news/](https://riksdagsmonitor.com/news/) β€” daily AI-generated political-intelligence articles +- **πŸ“‘ RSS / XML feeds**: [`sitemap.xml`](https://riksdagsmonitor.com/sitemap.xml) Β· [`rss.xml`](https://riksdagsmonitor.com/rss.xml) - **Repository**: [github.com/Hack23/riksdagsmonitor](https://github.com/Hack23/riksdagsmonitor) - **npm Package**: [npmjs.com/package/riksdagsmonitor](https://www.npmjs.com/package/riksdagsmonitor) - **CIA Data Platform**: [github.com/Hack23/cia](https://github.com/Hack23/cia) diff --git a/typedoc.json b/typedoc.json index 53df67246a..b00db31815 100644 --- a/typedoc.json +++ b/typedoc.json @@ -121,12 +121,20 @@ "searchInDocuments": true, "navigationLinks": { "🏠 Home": "https://riksdagsmonitor.com", + "πŸ•΅οΈ Political Intelligence": "https://riksdagsmonitor.com/political-intelligence.html", + "πŸ—ΊοΈ Sitemap": "https://riksdagsmonitor.com/sitemap.html", "πŸ“¦ npm Package": "https://www.npmjs.com/package/riksdagsmonitor", "πŸ“¦ GitHub": "https://github.com/Hack23/riksdagsmonitor", "πŸ›‘οΈ ISMS": "https://github.com/Hack23/ISMS-PUBLIC", "πŸ›οΈ CIA Platform": "https://github.com/Hack23/cia" }, "sidebarLinks": { + "── Live Platform ──": "https://riksdagsmonitor.com", + "🌐 Riksdagsmonitor.com": "https://riksdagsmonitor.com", + "πŸ•΅οΈ Political Intelligence Index": "https://riksdagsmonitor.com/political-intelligence.html", + "πŸ—ΊοΈ Sitemap (Human + XML)": "https://riksdagsmonitor.com/sitemap.html", + "πŸ“° News & Articles": "https://riksdagsmonitor.com/news/", + "πŸ“¦ npm Package": "https://www.npmjs.com/package/riksdagsmonitor", "── Current Architecture ──": "https://github.com/Hack23/riksdagsmonitor/blob/main/ARCHITECTURE.md", "πŸ›οΈ Architecture": "https://github.com/Hack23/riksdagsmonitor/blob/main/ARCHITECTURE.md", "πŸ”’ Security Architecture": "https://github.com/Hack23/riksdagsmonitor/blob/main/SECURITY_ARCHITECTURE.md",