Summary: Fetch EP data first. Use feeds, fall back to direct endpoints. Download FULL document content, not metadata. Add IMF economic context (primary) + WB non-economic context (additive) for policy articles. Stay within the 10-minute budget.
[Stage A: Data Collection] → Stage B: Analysis → Stage C: Gate → Stage D: Article → PR
Time budget: ≤ 5 minutes of a 60-minute workflow (the Stage-A line in every workflow's parameter table; per-slug values authoritative in src/config/article-horizons.ts).
Every workflow downloads (tools and parameter corrections in
07-mcp-reference.md):
-
Feed endpoints with
timeframe: "today"→ fall back to"one-week"if empty/error/404/timeout. -
Direct lookups — always use these when a feed fails. They query the EP database directly and are usually more reliable than feeds.
-
Deep-fetch (best-effort under budget — prioritised, not exhaustive) — for adopted texts / procedures referenced. The deep-fetch set is best-effort under the budget caps below, not a per-item mandate. When the run references more items than the budget allows, apply the prioritisation policy in §3a to pick the top N items.
track_legislation({ procedureId })— status, timeline, committees. 404 fallback (identifier types differ):track_legislationtakes aprocedureId(e.g."2024/0001(COD)"), whileget_procedurestakes a different identifier —processId. Whentrack_legislationreturns 404 for a procedure ID extracted from an adopted text, read the same adopted-text payload item and extract itsprocessIdfield for the fallback direct lookup. Do not try to deriveprocessIdby transforming theprocedureIdstring — they are not equivalent. If the adopted-text item exposesprocessId, callget_procedures({ processId }). Iftrack_legislationreturns 404 and noprocessIdis present on that adopted-text item, log theprocedureIdundermanifest.dataVerification.unresolvedProcedureIds[]and proceed with adopted-text data only — do not abort the run.get_voting_records({ sessionId, limit: 50 })— actual vote countsget_latest_votes({ limit: 20 })— near-realtime DOCEO votes (v1.3.1+,dataFreshness: NEAR_REALTIME); use to identify recent group voting patterns whenget_voting_recordsreturns empty due to EP publication delayget_meeting_decisions({ sittingId })— adopted decisionsget_speeches({ dateFrom, dateTo, limit: 20 })— debate contributionsget_adopted_texts({ year, limit: 100 })— full text, not titles- Named-MEP cross-reference (best-effort, prioritised): for MEPs
named as immunity-waiver subjects, rapporteurs, shadow rapporteurs,
named defectors or named whips in any adopted text / procedure /
committee output, call
get_mep_details({ id: "MEP-NNNNNN" })once per named MEP. This gives biographical context (national party, committee assignments, prior votes) for stakeholder-map and actor-mapping artifacts. Prioritise immunity subjects first, then named rapporteurs / shadow rapporteurs, then named defectors. Cap at 10 MEP-detail calls per run; surplus MEPs go on a "deferred lookup" list inmanifest.dataVerification.deferredMepLookups[].
Budget caps: up to 10 deep-fetch calls + up to 10 MEP-detail calls. When the candidate set exceeds these caps, items not selected by §3a are not failures — they are deferred and logged under
manifest.dataVerification.deferredDeepFetches[].
When the candidate set exceeds the budget caps, score every candidate item (adopted text / procedure / named MEP) on this 0–10 salience rubric, then take the top N up to the budget cap:
| Signal | Weight | Score |
|---|---|---|
| Item appears in the lead / executive-brief candidate list | +4 | 0–4 |
| Item is referenced by ≥2 other already-collected artifacts | +2 | 0–2 |
| Item is a Rule 132 urgency motion or Rule 9 immunity waiver | +2 | 0–2 |
| Item is a binding act (REGULATION / DIRECTIVE / DECISION) vs. non-binding RESOLUTION | +1 | 0–1 |
| Item touches a Tier-1 economic indicator named in IMF minimums for this article type | +1 | 0–1 |
Rules:
- Always include every item referenced by the lead story / executive brief candidate, even if that consumes most of the budget.
- For named-MEP cross-reference, immunity-waiver subjects are a hard must-include (until the budget is exhausted) — they have political and legal salience that rapporteurs alone do not.
- Items not selected go to
deferredDeepFetches[]/deferredMepLookups[]with their salience score; a follow-up run on the same date+type can pick them up first via the prior-run-diff carry-forward path.
A run that respects the budget cap and logs deferred items is not
incomplete — it is correctly prioritised. Stage C does not penalise
deferred entries; it only penalises lead-story items missing from the
deep-fetch set.
4. Voting-data fallback (MANDATORY when get_voting_records returns empty)
EP roll-call data publishes with a 4–6 week delay (documented in
07-mcp-reference.md §11 item #6). When get_voting_records returns an empty
votes array, always activate the EP Open Data Portal fallback before writing
voting-patterns.md:
- In TypeScript: call
getVotingRecordsWithFallback(mcpResult, { dateFrom, dateTo })fromsrc/mcp/ep-open-data-client.ts. - This queries
https://data.europarl.europa.eu/api/v2/decisiondirectly. - Copy the returned
freshnessLabelintovoting-patterns.md§"Voting Data Freshness". If source is"unavailable", flag all coalition claims LOW and widen WEP bands +10 pp. See the full decision tree in07-mcp-reference.md §12. - Attribution: EP Open Data Portal data is CC BY 4.0. Include the
attribution string in §7 of every
voting-patterns.mdthat uses fallback data.
The canonical fallback map and parameter table live in
07-mcp-reference.md. In one sentence: if a feed
returns 404/timeout, try the corresponding direct endpoint before giving up.
Required for articles covering trade, employment, digital/tech, health, environment/energy, agriculture, housing, migration, defence.
IMF is the sole authoritative source for economic context. not secondary, not fallback):
- Economic / monetary / fiscal / trade / FDI / exchange-rate / banking
(GDP, inflation, unemployment, current account, debt, deficit, policy
rate, REER, FDI, bilateral trade) → IMF only. Use
imf-fetch-data— seeanalysis/imf/indicator-catalog.md,analysis/imf/database-directory.md,analysis/imf/release-calendar.md, andanalysis/methodologies/imf-indicator-mapping.md. AggregatesEU,EA,G7,G20are all valid. For Tier-1 articles citing high-sensitivity indicators (GDP growth, HICP, gov debt, ECB rate, current account), triangulate against ECB SDW / Eurostat / OECD peranalysis/imf/cross-source-triangulation.md. - Non-economic (health, education, social, environment,
demographics, defence, agriculture, innovation, governance) → World
Bank only. Use
get-social-data,get-health-data,get-education-data, or the raw-RESTsearch-indicatorspath — seeanalysis/worldbank/indicator-catalog.mdandanalysis/methodologies/worldbank-indicator-mapping.md. Do NOT pass aggregate codes (EUU,EMU,ECS,OED,WLD,NAC,EAS,SSF) to the WB MCP — the server rejects them withError: Country not found. Use individual member-state codes or cite IMFEU/EAfor any EU-level framing. Member-state proxy defaults (positive guidance): when an EU-level framing is desired but WB rejects the aggregate, default to the Big-Four (DE,FR,IT,ES) plus topic-specific affected states:- Migration / external border →
IT,ES,EL,PL,HU - Energy / Russia exposure / Eastern flank →
PL,RO,LT,LV,EE - Defence / NATO Eastern flank →
PL,RO,LT,LV,EE,FI,SE - Rule-of-law / immunity proceedings → use the named MEPs' national
member-state codes (e.g.
PLfor Polish-MEP immunity files) - Eurozone / banking →
DE,FR,IT,ES,NL,IE - Agriculture / CAP →
FR,PL,ES,RO,ITCite IMF aggregates (EU/EA) for the EU-level economic frame and the WB member-state proxy for the non-economic distributional detail. Never silently substitute one member state as a stand-in for the EU aggregate without naming it as a proxy in prose.
- Migration / external border →
- Per-article-type IMF minimums (editorial policy — enforced at
Stage-C completeness gate):
committee-reports/ECON ≥ 4 indicators, /BUDG ≥ 3, /INTA ≥ 3;
week-ahead / month-ahead / monthly-review ≥ 2;
breaking / weekly-review / motions / propositions ≥ 1. Full table in
analysis/methodologies/imf-indicator-mapping.md §8. - Connectivity probes:
source scripts/wb-mcp-probe.shandscripts/imf-mcp-probe.shafterscripts/mcp-setup.sh. The IMF probe uses the sharedfetch-proxyMCP gateway first (FETCH_MCP_GATEWAY_URL) and direct HTTPS only as a local/non-AWF fallback. The probe summary JSON includes a"gatewayStatus"field that distinguishes infrastructure failures (e.g."error:gateway-post-failed(exit=7)") from genuine IMF outages ("ok"with"available":false). IfgatewayStatusreports an error, fix the shared MCP component rather than treating IMF as unavailable. Forweek-in-review,month-in-review,week-ahead, andmonth-ahead, start the IMF probe in the background at the beginning of Stage A and cache its JSON under${ANALYSIS_DIR}/cache/imf/while EP MCP calls continue. The probe always exits 0;{"available": false}is a provenance signal, not a Stage-A abort condition. - Editorial rule: IMF is the sole authoritative source for
every economic / fiscal / monetary / trade / FDI / exchange-rate / banking-soundness
claim.
not secondary, not fallback). World Bank may be cited only as corroborating
evidence for non-economic indicators (health, education, social,
environment, demographics, defence, agriculture, innovation,
governance). WB
Country not foundresponses for EU-level aggregate codes are expected: switch to IMFEU/EAaggregates for economic framing and use WB for member-state non-economic data. Stage C fails anyeconomic-context.mdthat cites IMF figures from agent knowledge withoutcache/imf/*.json, and rejects any WB economic indicator code (NY.GDP.*,FP.CPI.*,SL.UEM.*,GC.DOD.*,NE.EXP.*,NE.TRD.*,BX.KLT.*, …) or "World Bank … GDP/inflation/…" prose claim insideintelligence/economic-context.md. - Forecast labelling: every IMF projection prose MUST include
"forecast"/"projection"/"projects"/"expects" within 30 words of the
number (regex-enforced), AND the section MUST carry
data-vintage="WEO-April-2026"on the<section class="economic-context">element. Seeanalysis/imf/forecast-accuracy-baseline.mdfor horizon-dependent optimism-bias caveats.
Integration requirements:
- Use the native IMF client virtual methods (
imf-search-databases,imf-fetch-data) throughsrc/mcp/imf-mcp-client.tsor the cached probe files; do not call a non-existent IMF MCP server. Callimf-search-databasesfirst to discover the best database (orsearch-indicatorsfor WB non-economic). - Fetch ≥ 2 EU countries (Big Four
DE/FR/IT/ESor affected member states) or use an IMF aggregate (EU/EA). - Surface data inside analytical prose (≥ 60 words).
- Include ≥ 1
<canvas data-chart-config="…">generated bybuildDashboardSection. - Every IMF citation carries the vintage string
(
IMF WEO April 2026,IMF Fiscal Monitor April 2026) in prose. - Bridge every economic indicator to a named EP file, committee, procedure, vote, or stakeholder pressure. A standalone macro paragraph with no EP political mechanism fails Stage C even when it cites IMF correctly.
- When IMF is unavailable, do not substitute World Bank GDP, inflation,
unemployment, fiscal, trade, FDI, exchange-rate, or banking indicators as
economic proxies. Mark the run IMF-degraded, cite the saved probe error,
and either proceed without quantitative economic claims (where allowed) or
stop with
ANALYSIS_ONLYfor ECON/BUDG/INTA scoped runs.
Every manifest.json records what was successfully downloaded:
{
"dataVerification": {
"adoptedTextsDownloaded": true,
"votingRecordsFetched": false,
"meetingDecisionsFetched": false,
"procedureDetailsTracked": ["2025/0261(COD)"],
"speechesFetched": false,
"committeeDocumentsFetched": false,
"reason": "Feeds returned 404; direct endpoints used as fallback"
}
}The manifest MUST include a top-level dataMode field declaring the
data-availability state of the run. This drives threshold adjustments in
Stage C — the validator reduces line floors for structurally constrained runs.
Stage A — data-availability-assessment first: Before writing any analysis artifact, produce data-availability-assessment.md in the run root. This artifact records the triage result for every data source (EP MCP endpoints, IMF SDMX, DOCEO XML, World Bank) and sets the manifest.dataMode field. Template: analysis/templates/data-availability-assessment.md. When dataMode = "degraded-voting", use analysis/templates/intelligence/voting-patterns.degraded.md instead of the standard voting-patterns.md. When dataMode = "degraded-imf", use analysis/templates/intelligence/economic-context.fallback.md instead of economic-context.md.
dataMode value |
When to set | Line-floor reduction |
|---|---|---|
"full" |
All primary sources (EP MCP, IMF, voting records) available | 0% (default) |
"title-only" |
Adopted texts available by title/reference only; full text not yet published (3–7 day EP delay) | 25% |
"degraded-imf" |
IMF SDMX unreachable; Eurostat used as triangulation fallback (WB remains non-economic only) | 15% |
"degraded-voting" |
Roll-call data unavailable (4–6 week EP publication lag); coalition analysis uses structural proxies only | 15% |
"minimal" |
Multiple data sources unavailable (combine title-only + degraded-imf + degraded-voting) | 35% |
Decision logic (Stage A exit checklist):
- If
cache/imf/imf-probe-summary.jsoncontains{"available": false}→ at minimum"degraded-imf" - If
getVotingRecordsWithFallbackreturnsunavailable→ at minimum"degraded-voting" - If adopted texts fetched but all full-text URLs return 404 → at minimum
"title-only" - If ≥2 of the above conditions apply →
"minimal" - Otherwise →
"full"
Set dataMode at the end of Stage A so Stage B and C can adapt.
Every artifact produced under a non-"full" dataMode MUST flag the
limitation in prose (confidence levels reduced, explicit caveat paragraph).
{
"articleType": "breaking",
"dataMode": "degraded-imf",
"dataVerification": { "..." }
}When IMF SDMX is unreachable (dataMode: "degraded-imf" or "minimal"),
attempt Eurostat as a secondary economic triangulation source. Do NOT fall
back to World Bank for economic data (Stage C rejects WB economic claims):
- Eurostat SDMX endpoint (via
web-fetchtool):https://ec.europa.eu/eurostat/api/dissemination/sdmx/2.1/data/{datasetCode}/{filter}?format=JSON- Key datasets:
namq_10_gdp(GDP),prc_hicp_manr(HICP),une_rt_m(unemployment),gov_10dd_edpt1(government debt) - Example:
https://ec.europa.eu/eurostat/api/dissemination/sdmx/2.1/data/namq_10_gdp/Q.SCA.CLV10_MEUR.B1GQ.EA20?format=JSON&startPeriod=2024-Q1(quarterly GDP, chain-linked volumes, Eurozone-20)
- Key datasets:
- Eurostat is NOT an IMF replacement — use only for EU-aggregate and member-state triangulation when IMF is down. Attribution: "Eurostat, [Dataset], accessed YYYY-MM-DD" in prose.
- Store fetched JSON under
${ANALYSIS_DIR}/cache/eurostat/with the dataset code as filename. - Record
"eurostatFetched": trueinmanifest.dataVerification. - Do NOT cite Eurostat as sole source for economic claims — it is a
triangulation signal. When both IMF and Eurostat are unavailable,
omit quantitative economic claims from
economic-context.mdentirely rather than using agent knowledge (which producesIMF Source: knowledge-onlyand fails Stage C). Instead, write a qualitative economic context section citing only structural EU fiscal rules, published Commission communications, and EP committee positions — never numeric GDP/inflation/fiscal figures without a live data source.
coalition_dynamics.cohesionwithsharedVotes === nullis a size-ratio artifact, not political alignment. Emit a data-quality warning.- Never trust
get_server_healthalone — cross-validate with ≥ 1 concrete feed (get_adopted_texts_feedis cheapest). - Empty-string document responses =
CONTENT_PENDING. Do not render blanks. - Sum group
memberCountbefore coalition math. Total < 600 (EP10 ≈ 720 seats) → cap probabilities at0.70 × raw. - When you observe new MCP defects, author
intelligence/mcp-reliability-audit.mdalongside the analysis. monitor_legislative_pipelinedate default (Defect #6 — v1.2.13): Always supplydateFrom: $LAST_MONTHanddateTo: $TODAYexplicitly. v1.2.13 defaults the reportedperiodto calendar 2024 when no dates are given, returning an empty pipeline for all current procedures. For forward-looking workflows (week-ahead,month-ahead) use the relevant future date span. As of v1.2.15 the server defaults to a rolling last-30-days window when no dates are supplied, but explicit dates remain the required calling pattern for reproducibility.- Chronic feed degradation — pivot fast, do not retry-loop. The
get_events_feedAPI errors andget_procedures_feedSTALE_TAILresponses are structural, not transient. After one failed call, immediately pivot to the documented compensating source — do not retry the same feed multiple times within Stage A. Compensating sources:get_events_feedfailure →get_adopted_texts_feed(today/one-week)get_meeting_decisions({ sittingId })for the in-window plenary sittings.
get_procedures_feedSTALE_TAIL→get_procedures({ processId })for procedure IDs harvested from adopted texts; for forward-looking workflows useget_meeting_foreseen_activities({ sittingId })fan-out (see01a-data-fanout.md§2).get_voting_recordsempty → EP Open Data Portal fallback (§2 item 4). Log the pivot decision inintelligence/mcp-reliability-audit.mdwith timestamp and the compensating source used.
- Roll-call follow-up forward statement (MANDATORY). EP publishes
roll-call records 4–6 weeks after the session date. When
getVotingRecordsWithFallbackreturnsunavailableoremptyfor the in-window plenary, append a forward statement to/tmp/new-forward-statements.json(per01a-data-fanout.md§1) of the form:This guarantees the proxy-only voting analysis is automatically superseded by confirmed roll-call data once it becomes available, and the next breaking / week-in-review run can validate the proxy coalitions estimated under the lag.{ "id": "FS-<YYYY>-vote-followup-<sessionDate>", "kind": "data-followup", "horizonStart": "<sessionDate + 35 days>", "horizonEnd": "<sessionDate + 50 days>", "trigger": "Roll-call records published for plenary <sessionDate>", "action": "Re-run voting-patterns.md analysis with confirmed roll-call data", "status": "open" }
Within a single run, take group seat counts from one source
(analyze_coalition_dynamics OR get_meps_feed). Record the source in the
manifest. Do not mix.
Canonical group-ID codes (consumer rule). When invoking
analyze_coalition_dynamics, compare_political_groups,
detect_voting_anomalies, or sentiment_tracker, always pass the
canonical English short codes
["EPP","S&D","Renew","Greens/EFA","ECR","PfE","Left","NI"].
Never pass the EP API native French/German variants
(PPE, Verts-ALE, legacy ID) or full group names
("Group of the European People's Party (Christian Democrats)") — on
gateways prior to v1.2.15 these mismatches produced memberCount: 0
and split groups; the upstream fix in
Hack23/European-Parliament-MCP-Server#405
(v1.2.15+) collapses native variants onto these canonical codes via
normalizePoliticalGroup. Triage table entry:
07-mcp-reference.md §11 row #2.
Before writing new analysis, mine forward-looking statements from:
- The most recent predecessor run of the same type
- The latest
breaking-run*with anintelligence/subdirectory - Adjacent-horizon runs (ahead ↔ in-review)
Read each run's intelligence/analysis-index.md,
intelligence/synthesis-summary.md, and intelligence/scenario-forecast.md.
Your new run MUST reference ≥ 3 prior-run forward-looking statements.
8a–8d · Fan-Out Helpers → see 01a-data-fanout.md
Forward-looking and long-horizon workflows (week-ahead, month-ahead,
quarter-ahead, year-ahead, term-outlook, election-cycle, and the
matching retrospective *-in-review horizons for §4 only) additionally
import 01a-data-fanout.md, which keeps Stage-A
fan-out helpers in a bounded sibling module:
| Helper | Module section |
|---|---|
| Forward-statements registry seed (replaces former §8a) | 01a-data-fanout.md §1 |
| Multi-day foreseen activities fan-out (replaces former §8b) | 01a-data-fanout.md §2 |
| Monday urgency motion sweep (replaces former §8c) | 01a-data-fanout.md §3 |
| Quarter+ horizon fan-out, ≥ 90 days (replaces former §8d) | 01a-data-fanout.md §4 |
Short-cycle (breaking, motions, propositions, committee-reports)
and retrospective (week-in-review, month-in-review) workflows do not
import that module — sections 1–8, 9 and 10 of this file are sufficient
for their Stage A.
- ❌ Do not skip data collection because feeds are 404 — try direct endpoints.
- ❌ Do not decide the article topic before Stage B is complete.
- ❌ Do not start new slow calls (30–120s feeds) after the late-workflow
deadline — see
06-pr-and-safe-outputs.md. - ✅ Log every tool failure; the noop diagnostic depends on it.
Before handing off to Stage B, verify all Stage A raw outputs are written under
${ANALYSIS_DIR} and referenced in manifest.json / data/artifact-index.json.
Do not run per-phase repo-memory checkpoint commands; continue directly to
02-analysis-protocol.md.