Repository navigation
Conversation
A research entry dated on or after 2026-10-29 must name the record of its pre-publish comparables search in PolicyEngine/policyengine-scorecard. The Tests job checks each block's shape; the new Comparables gate workflow checks it resolves against the scorecard's published index on main, failing closed. The childcare dashboard carries the first (backfill) record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
# Conflicts: # app/src/data/apps/apps.json
An entry needs a comparables block unless it is on the list of entries live before the gate, whatever date it carries; an entry taken down leaves the list, and the list grows only before the cutover. no_estimate is for posts that are plainly not analyses. The gate job runs on every pull request, pins the index URL in the workflow, fails rather than skips without an index, checks the index's schema and entry rules, validates as well as resolves, and reports a failed weekly run. App routes and featured cards must name research entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dashboard proxied by a rewrite in next.config.ts, not appZoneRoutes.ts, must also be a research entry or on the grandfather list; the API and Python docs, and TAXSIM, are listed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A change that lists or re-lists an entry must cite a search no more than 30 days old that day, against the results the analysis reads now, with no gap pending; a card it adds to the featured banner needs a fresh search under the scorecard's promotion window. Proxied pages are read from the evaluated next.config rewrites, so a wildcard or single-quoted route is seen; pages that publish no analysis go on an infrastructure list. analysisRoutes.json maps every path and deployment host that leads to a research app, for the newsletters check. An unreadable base commit fails the gate. 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.
WIP: waits on PolicyEngine/policyengine-scorecard#208, whose index this gate reads.
The registry side of the pre-publish comparables gate Max asked for on 2026-10-21 ("how do we ensure we always do a full review of comparables to add to scorecard before publishing an analysis - pe-wide").
What it does
A research entry is an
apps.jsonapp withdisplayWithResearchor thepolicytag, or anyposts.jsonpost (a post with no country tag is filed underus, as the site does). Every research entry needs acomparablesblock naming the record of its comparables search in policyengine-scorecard, unless it is onwebsite/src/data/comparablesGrandfathered.json, the list of the 256 entries and 11 proxied pages live before the gate. The date an entry carries does not exempt it.The scorecard prints the block:
python -m scorecard_db.comparables record <source>.foundcounts the comparables staged as claims; the search log also lists any seen but not staged (a primary that cannot be read).prepublish, orreharvest/prepromotionfor an analysis republished after a revision).no_estimateis only for a post that is plainly not an analysis: taggedorg,event,giving,conferences,year-in-revieworapril-fools, and none of the analysis tags. An app never declares it.results_pinsequal the record'scurrent_pins); and that no gap it found is still pending. So a backdated draft, or a revised dashboard returning with a gap under investigation, is refused. Unchanged entries are not re-judged, so the archive does not expire.fresh, tested against its shared cases), grandfathered entries included.next.config.tsrewrites and redirects (website/src/data/analysisRoutes.ts), so a route in any syntax, wildcard or single-quoted, is seen. Every page proxied to another deployment is a research app's (or served from one's deployment), on the grandfather list'sroutes, or on its newinfrastructurelist of pages that publish no analysis (API and model docs, slides, the Belgium demo).website/src/data/analysisRoutes.jsonmaps every path, redirect and deployment host that leads to a research app, built byscripts/build-analysis-routes.ts; a test fails while it is stale. PolicyEngine/newsletters reads it.Comparables gateworkflow runs on every pull request (no path filter, so it can be a required check), on pushes to main, and weekly. It downloads the index from a URL pinned in the workflow itself (a test checkscomparables.tsagrees), fails rather than skips without an index (COMPARABLES_GATE=1), checks the index's schema and that its published entry rules equalcomparables.ts's, validates every entry and resolves every block (the record exists with the same kind, slug and country, and a search of that date and kind has the same producers and count), and checks the grandfather list has not grown after the cutover. A failed weekly run opens or updates an issue.docs/engineering/skills/repository-guidance.mdand the posts README state the rule.postSlugis now exported frompostTransformers.tsand shared.No entry carries a block yet. The first scorecard record is the £100,000 childcare dashboard (a backfill), which left
apps.jsonon 21 October (#1379); it needs a new search against its revised results to come back.Choices to check
MAX_SEARCH_AGE_DAYS, pinned at 30 or fewer).TestsandComparables gaterequired checks here, turning on code-owner review, and protecting the scorecard's main with a pull request and itspytest · ruff formatcheck. Required checks also close the[skip ci]hole.analysis-us-givecalc. Both predate the gate; a test refuses any such clash for an entry that needs a record.Proposed: "How we compare" on dashboards and posts (copy for Max)
Design only, nothing rendered yet. The scorecard index carries a
comparisonslist per analysis: each producer's figure as printed, with its period, our figure, the gap, the status and the cause.@policyengine/ui-kit(<HowWeCompare source="analysis-uk-…" />), reading the index at build time so the figures are pinned to a scorecard commit.Max decides the copy, and whether it ships at all, before anything renders.
Checks
bunx vitest run src/__tests__/content/: 41 passed; the live file (5 tests) passes withCOMPARABLES_GATE=1against the scorecard branch's index and main's registries as the base, and throws without an index path.tsc --noEmit, ESLint (--max-warnings 0) and Prettier: clean.Properties tested (fast-check):
researchEntriesover generated raw apps and posts (timestamped dates, underscores and capitals in file names, zero to several country tags, with and withoutpolicy).🤖 Generated with Claude Code