Repository navigation
Data pipeline: fetch, ingest, score and open one checked PR; stop the nowcast's silent no-op - #221
Draft
vahid-ahmadi wants to merge 6 commits into
Draft
vahid-ahmadi wants to merge 6 commits into
vahid-ahmadi wants to merge 6 commits into
Conversation
…at CI has already checked fetch-vintages.yml now runs data/refresh.py: carry -> fetch -> notes -> ingest -> score -> fans -> pages -> every PR-time gate -> append-only check, then pushes the bot branch and opens or updates one PR. Ingest and score never ran in this job before, so new outturns (GDP 2026Q2, CPI 2026Q3) could not reach the record and #195 could not merge without turning main red. - Carry vintages from the open refresh branch so daily snapshots stop being overwritten while the PR waits (27 Aug-4 Nov 2026 were lost this way). - Replace peter-evans/create-pull-request, which tries to create before it updates and has failed with 403 since 26 Oct, with a script that updates an existing PR first and refuses any branch outside data/* and forecasts/*. - nowcast.py --due exits 2 when every announced release is in the past; the nowcast job now fails on that instead of reporting a green no-op. - Optional DATA_PR_TOKEN secret so bot pushes trigger PR-time CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Nov 6, 2026
…sh time Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e is already archived nowcast.py --edge-gate reads BOE_REVISION from integration/modal_app.py, fetches boe-var-model's data/boe_var_data.csv at that commit from GitHub, and exits 1 when its last quarter is not after every archived boe-svar round's data edge. nowcast-round.yml runs it after --due and before the MCP install, so a due day with a stale hosted model logs a notice and stays green instead of a ~5.5-minute cold Modal solve that write_round would refuse as already archived (#224). An unreadable edge proceeds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 6, 2026
Contributor
Author
Merge order with the redesign stack (#200): simulated 6 NovRecommendation: if #200 can land by about 11 Nov, merge it first. Then this PR → token/setting (#223) → #228 recovery → dispatch fetch-vintages → close/reopen #195 for CI → merge #195 before 12 Nov. Otherwise keep the current order (this PR → dispatch → #195), and #200 takes the rebase steps in its comment. Findings (local scratch worktrees; nothing pushed or merged):
Side notes (nothing needed to merge):
No pre-emptive commits: all conflicts are generated output. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stacks Both stacks add entries; a shared heading with a separator line lets them merge in either order without a CHANGELOG.md conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vahid-ahmadi
added a commit
that referenced
this pull request
Nov 6, 2026
Merges the shared [Unreleased] anchor (84e9539) and lists every redesign-stack PR's bullets here, by PR number. The stacked PRs no longer edit CHANGELOG.md, so they stop conflicting with each other, and the pipeline stack (#221, #228) adds its entries below the separator line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vahid-ahmadi
added a commit
that referenced
this pull request
Nov 6, 2026
…ne group Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The forecast track record has not moved since 26 August, although UK GDP 2026Q2 and CPI 2026Q3 are both out. This PR fixes the pipeline so that a scheduled refresh goes fetch → ingest → score → one PR that has already passed every gate. It does not touch
data/vintages/,forecasts/rounds/,forecasts/outturns.jsonorforecasts/scorecard.json. Those files only change when the workflow itself runs.What was wrong (evidence)
GITHUB_TOKEN, and GitHub does not startpull_requestworkflows for those pushes. None of the append-only, provenance or archive gates has ever run on a bot refresh. Main has no protection or auto-merge, so the PR just sits there.forecasts/ingest_outturns.py --check:FAIL missing outturn cpi 2026Q3 (3.10, vintage 2026-11-05)andFAIL missing outturn gdp 2026Q2 (1.37, vintage 2026-11-05). forecast-archive runs that check on every push to main.fetch-vintages.ymlran fetch → notes → pages → PR. It never calledingest_outturns.pyorscore.py. Those scripts only appear as--checkgates in forecast-archive.yml, which (see 1) never runs on the bot PR.##[error]GitHub Actions is not permitted to create or approve pull requests.peter-evans/create-pull-requesttries to create the PR first and only updates on a 422 "already exists". Up to 23 Oct the log showsUpdated pull request #195. Now the create call returns 403 before the update is tried. The repo API showscan_approve_pull_request_reviews: false. The org policy is not readable with this token, so I can't see what changed on 24–25 Oct. The push happens before that step, so Refresh official data vintages #195's head still moved every day.nowcast.py --duereadsnext_releasefromdata/lateston main, which dates from 26 Aug: GDP "13 August 2026", unemployment "15 September", CPI "16 September". Run 41972099442 printsno scored series releases within 3 days of 2026-11-05and exits green.Outturns now published but not scored: GDP 2026Q2 y/y 1.37% (07-29 round median 1.135), CPI 2026Q3 3.1% (07-29 median 2.539), and unemployment 2026Q2 4.9% (satellite median 4.9714; this one is already on main but
MAPPINGhas no unemployment row, which #200 fixes). A dry run of ingest + score on a scratch copy of #195 took the record from 1 to 5 scored forecasts, with next period 2026Q3.The fix
data/refresh.py: one driver with a fixed order:carry → fetch → notes → ingest → score → fans → pages → gates → append-only.GATESlists every check from forecast-archive, site-provenance, data-immutability and site-tests. A test fails if one of those workflows gains a check thatGATESlacks, so the bot PR is green before anyone looks at it.data/vintages/files are carried. MANIFEST,latest/, notes, pages, outturns and the scorecard are rebuilt from them, so a stale branch never conflicts with main.notes/generate_release_notes.py --vintage <date>for each new vintage date, and the gate calls--check. Main's per-series generator and Redesign the static site: Autumn Budget look, one fact per home, readable layouts #200's per-date digest generator both accept these two flags, so this step works whichever is merged.generate_release_notes.pyitself is untouched..github/scripts/open-bot-pr.shreplacespeter-evans/create-pull-requestin both bot workflows. It looks for an open PR first and updates it over REST, so Refresh official data vintages #195 keeps updating even with the Actions PR setting off. Only a brand-new PR needs that permission, and if it is missing the job says what to change. The script refuses any branch outsidedata/*andforecasts/*, so it can never push to main. It pushes with force-with-lease against the tip it saw, and does nothing when nothing changed.fetch-vintages.yml: runs the driver, writes a PR body listing new vintages, outturns added and scorecard status, then calls the script. Newworkflow_dispatchinputsbranch,carry_fromandopen_prlet you test into a throwawaydata/...branch without touching Refresh official data vintages #195. An optionalDATA_PR_TOKENsecret is used for checkout and PR calls when set; with it, bot pushes also trigger PR-time CI.nowcast.py --duenow exits 2 when every announced release is in the past ("stale release calendar … merge the data vintage PR").nowcast-round.ymlfails on 2 instead of reporting a green no-op. It also uses the PR script.MAPPINGunemployment row. Redesign the static site: Autumn Budget look, one fact per home, readable layouts #200 already adds it along with the matchingoutturns.json/scorecard regeneration. Adding it here would force a scorecard regeneration that conflicts with Redesign the static site: Autumn Budget look, one fact per home, readable layouts #200's rewrittenscore.py.Tests
tests/test_refresh_pipeline.py(17): step order; ingest and score run in write mode;GATES⊇ every PR-workflow check; the notes step uses only flags both generators accept; the fetch workflow runs the driver before the PR step and no longer uses peter-evans; the nowcast stale branch exits 1; carry keeps newer snapshots and skips older ones or ones main already has; the PR script refusesmain,master,feature/xandvahid/...; the PR script looks up the existing PR before creating one.forecasts/tests/test_nowcast_due.py(6): all-past is stale, one future date is not, a release today is not, an empty calendar is stale,due()is unchanged, and the CLI exits 2.origin/mainwith onlydata/refresh.pycopied in. 7 of the 17 pipeline tests fail (both workflow tests, the four branch-refusal cases and the update-before-create test), and 5 of the 6 nowcast tests fail or error. All 23 pass on this branch. PR CI is green.workflow_dispatchon this branch withbranch=data/r5-pipeline-test,carry_from=data/vintage-refresh,open_pr=false. It carried Refresh official data vintages #195's 20 snapshots from 5 Nov and fetched 5 new ones for 6 Nov (Bank Rate, three gilts, US 10y). It wrote notes for both dates and added cpi 2026Q3 = 3.10 and gdp 2026Q2 = 1.37 (vintage 2026-11-05), taking the scorecard from 1 to 4 scored forecasts. Every gate passed, including the 1974 site tests,ingest --checkand the append-only check. It then pushed only the test branch: no M/D/R underdata/vintages/orforecasts/rounds/. I then tested the path step 3 below will take, after adding a fix that leases the push on the tip the job started from. Run 42148913882 recreated the test branch. Run 42149008458 carried from that same branch: 25 files carried (the 5 Nov and 6 Nov snapshots kept), nothing new written, and a force-with-lease updated27a861...89358de. Both green. The test branch is deleted. Nothing touched main or Refresh official data vintages #195. The REST update of an existing PR (PATCH /pulls/195) is the one step not exercised, because exercising it would edit Refresh official data vintages #195.What you need to do to get the record current
GDP 2026Q3 is published 12 Nov, unemployment 17 Nov and CPI 18 Nov. The archived rounds already forecast 2026Q3, so each release adds scored forecasts once the data is on main.
Allow the bot to open PRs (Bot PRs: GitHub Actions can no longer open PRs here (since 26 Oct), and bot pushes never trigger CI; choose a token or re-enable the setting #223). Either tick Settings → Actions → General → "Allow GitHub Actions to create and approve pull requests" (if it is greyed out, an org owner has to allow it), or add a
DATA_PR_TOKENsecret. The token is better, because it also makes CI run on bot PRs. Step 3 works without either, since Refresh official data vintages #195 already exists. Every later refresh needs one of them.Merge this PR.
Actions → Fetch data vintages → Run workflow on
mainwith the defaults. It can only pushdata/vintage-refresh. Refresh official data vintages #195 then gets the carried 5 Nov snapshots plus today's, the outturns, the scorecard and the pages, all checked inside the job. Read the "What this refresh contains" block in Refresh official data vintages #195's new body.Without a token, close and reopen Refresh official data vintages #195 so its PR checks run (a human
reopenedevent does start workflows). Then merge it, ideally before Thu 12 Nov.Then rebase Redesign the static site: Autumn Budget look, one fact per home, readable layouts #200 on main:
forecasts/outturns.jsonandscorecard.jsonhunks, then reruningest_outturns.pyandscore.py;notes/generate_release_notes.py --rebuildto fold the 5 Nov (and any later) per-series notes into digests;vercel.jsonlists 53 legacy notes one by one and has no pattern, so/notes/releases/2026-11-05-uk_gdp_cvmand the others would 404. A pattern rule such as/notes/releases/:date(\d{4}-\d{2}-\d{2})-:series→/notes/releases/:date#:serieswould cover future ones too.The reverse order (Redesign the static site: Autumn Budget look, one fact per home, readable layouts #200 first, then steps 2–4) also works, because the bot rebuilds from main. The record just stays stale until Redesign the static site: Autumn Budget look, one fact per home, readable layouts #200 lands.
New rounds before the 12 Nov release are not possible as deployed: the hosted
forecast_ukreads boe-var-model at the pinned 42cbcbb, whosedata/boe_var_data.csvends in 2026Q1. Refreshing the data store does not change that, sonowcast.pywill refuse with "data edge 2026Q1 is already archived" (as it did on 13 Aug and 19 Aug). See Nowcast can't archive a new round: the hosted forecast_uk is pinned to boe-var data ending 2026Q1 #224.Also noted (no issue opened)
score.pydecides whether a forecast predates its outturn by comparingarchived_utcwith the store vintage, not with the publisher's release date (release_updated). The one entry scored today, the 07-21 round's CPI 2026Q2, passes only because the archive date and the vintage are the same day (25 Jul), even though ONS released the figure on 22 Jul. The entry is still legitimate: the artifact it archives (sha256 991ba7f…) was committed to main in b66cadf at 14:54 on 21 Jul, before the release. The guard is loose, but no published score is wrong.Not done
data/vintages/, rounds, outturns and scorecard are unchanged.Nowcast edge gate (#224, commit d980660)
nowcast.py --edge-gatereads the hosted boe-var-model data edge from GitHub atBOE_REVISIONand skips the round, with no Modal call, when that edge is not after the newest archiveddata_edge. Today it skips (2026Q1 hosted, 2026Q2 required). This saves about $0.15 of Modal time per due day (~$1.30 in November). Tests:forecasts/tests/test_nowcast_edge_gate.py(9, all fail before). No published number changes.🤖 Generated with Claude Code