Repository navigation
Conversation
Max, 2026-10-21: "even if we've already published something, we should do a fresh comp review before big pushes like newsletters". Every policyengine.org analysis an edition dated on or after 2026-10-26 links must have a comparables search in PolicyEngine/policyengine-scorecard within its promotion window and no gap still pending. A new CI job and upload-newsletter both enforce it; /create-newsletter and /upload-draft say how to satisfy it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Links are recognised in every common form (no scheme, any case, escaped, blog/ and dated slugs, the site's redirects, the apps' own hosts), and tracking links and shorteners are refused. Posts are found by slug under any country. Every analysis is checked unless it may declare no estimate. The index's shape is validated, and fresh now requires the search to have compared the current results, tested against the scorecard's own cases. Uploads refuse undated files and judge on the later of the edition's date and today; CI checks only the editions a change adds or modifies. The draft update recipe goes through upload-newsletter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in CI Links are matched against policyengine-app-v2's analysisRoutes.json (every path, redirect and deployment host that leads to a research app) and the scorecard's records (each analysis's page and deployments), so tracker paths, country-wide zone routes, non-Vercel hosts, GitHub Pages projects and a delisted dashboard's own URL are all checked. URLs are normalised (dot segments, a trailing dot on the host). The index and route map are validated strictly, and every source is read at the commit its main branch points to. CI fails on an unreadable base, compares a new branch with the empty tree, and refuses social posts outside editions/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Max, 2026-10-21: "also like even if we've already published something, we should do a fresh comp review before big pushes like newsletters". This is the promotion-time half of the pre-publish comparables gate (PolicyEngine/policyengine-scorecard#208, PolicyEngine/policyengine-app-v2#1380).
The rule
Every policyengine.org analysis an edition links must have, in PolicyEngine/policyengine-scorecard:
promotion_window_daysbefore it (7 by default, counting both ends; the window is Max's call, queued);results_pinsequal the record'scurrent_pins);found_oncounts as found).An analysis here is an apps.json app listed with research or tagged
policy, or any post, under the rules the scorecard's index publishes (entry_rules). Only a post that is plainly not an analysis (taggedorg,event,givingand so on, and none of the analysis tags) may skip the check by declaringno_estimate;policywins over it, and an app never may. A page that has left the registry but still has a scorecard record is held to that record. The rule applies to pushes on or after 2026-10-26.Where links lead
Read from policyengine-app-v2's route map (
website/src/data/analysisRoutes.json, PolicyEngine/policyengine-app-v2#1380), built from the site's evaluated rewrites and redirects: every path, redirect (tracker, CliffWatch, OBBBA aliases, country-wide zone routes) and deployment host (Vercel, Modal, GitHub Pages narrowed by project path, a deployment shared by two countries narrowed by path) that leads to a research app. And from the scorecard's records: each analysis's page anddeployments, so a dashboard taken off the site, like the childcare one, is held to its record on every link, its own Vercel URL included. Links are normalised first: any scheme or none,www., case, ports, HTML entities and percent-encoding, dot segments, a trailing dot on the host, trailing punctuation; posts by slug under any country, through/research/,/blog/or a dated slug. Mailchimp tracking links and link shorteners are refused. Every source (registries, route map, index) is read at the commit its main branch points to, so a cached copy is never read.Where it is enforced
Fresh comparables for promoted analysesjob checks the editions a change adds or modifies undereditions/(on a push, the pushed range; a new branch against the empty tree), each on its own date, so an edition already sent is not re-judged against later data. A changed edition must be named for its date, a social post outsideeditions/fails, and a base commit the checkout cannot read fails rather than passing. It downloads its sources only when an edition is due; a failed download, or an index or route map of the wrong shape, fails the job.upload-newsletter, for new drafts and--campaign-idupdates: refuses an undated file, judges the edition on the later of its date and today, and refuses a stale one before calling Mailchimp./create-newsletter,/upload-draft, CLAUDE.md: the pre-send step, and CLAUDE.md's draft-update recipe now goes throughupload-newsletter --campaign-idrather than the content endpoint.The check confirms the search is fresh and every gap over the threshold has a written cause; it does not put the comparable in the edition.
The 20 October UK edition fails it, run with the cutover moved back, app-v2's current registries and scorecard#208's index:
The Scottish Budget social post (
2026-01-27-uk-scottish-budget-social.md), which links without a scheme, fails too: its dashboard has no record.Tests (
tests/test_comparables.py, 76; 106 in all)policyoverno_estimate, apps never exempt, untagged posts underus, posts under any country, the record a post's block names.freshon its 96 shared cases; an edition passes exactly when its analysis is fresh (Hypothesis); old results pins fail.found_on, non-string pins, missing page url).Order
This merges after scorecard#208, whose index carries the window, pins, entry rules and deployments, and after app-v2#1380, which publishes the route map.
🤖 Generated with Claude Code