Skip to content

Dashboard: state what the headline assumes (#9 A1-A3) - #12

Merged
vahid-ahmadi merged 6 commits into
mainfrom
issue-9-headline-conditions
Oct 1, 2026
Merged

vahid-ahmadi merged 6 commits into
mainfrom
issue-9-headline-conditions

Conversation

@vahid-ahmadi

@vahid-ahmadi vahid-ahmadi commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Answers the presentation side of María's review in #9. The review's point is that the headline figures are conditional, so the dashboard now says on what, next to the headline and with the numbers.

What changes

Under the four Budget impact cards, a "What these figures assume" strip gives three conditions. Every number comes from results.json.

Finding Condition shown
A3 Today's pensioners, held fixed: survey ages and State Pension types are fixed to 2039-40, and pensioner numbers change only through survey weights and the State Pension age. DWP's costing projects the population.
A2 One model of prices and earnings: reweighting the same full runs (gap variance, lead switching, and in some versions the floor share) gives separate point estimates. The lowest is £6.6bn gross (SE £1.0bn); the highest is £10.7bn, on about 44 effective runs (SE £5.2bn). No other model of prices and earnings is tested.
A1 Survey benefit baselines above DWP's: in 2026-27, 1.82m Pension Credit claims against 1.31m and £13.4bn pension-age Housing Benefit against £7.3bn (UK model vs DWP's GB). On the same 40 paired paths, Microcosm's net saving is £0.6bn higher (SE £0.1bn).

A2's point about the path-sampling standard error was already covered by #11. The chart's explanation says the average line's ±£0.1bn is "how precisely the full runs pin down the average, not how much the saving could vary", and the headline shows the spread across paths.

A new test checks each number in the strip against the file.

Also, from María's Slack notes:

  • the Household impact tab is renamed Distributional impact;
  • the Method tab is renamed Methodology;
  • the households card now says 20% is the expected share, and that it lies between 20% and 21% on 80% of paths;
  • the middle and 90th-percentile paths come with a plain explanation of how they are picked, from the file's selection fields;
  • the income breakdown is by decile only;
  • the backtest no longer mentions "an earlier version of this page".

getCoverageRow now checks the rows are a list and needs only dwp and primary (review S1).

Still open in #9 (need model work, not in this PR)

Refs #9.

Checks

  • bunx vitest run: 63 passed.
  • bun run build: succeeds.
  • Checked in Safari.

🤖 Generated with Claude Code

…A1-A3)

Under the Budget impact cards, three conditions the figures rest on, each read
from results.json: the pensioner population and pension types held fixed to
2039-40 (A3); one model of prices and earnings, with the gross range across
every reweighting of the same runs (A2); and survey Pension Credit and
pension-age Housing Benefit baselines above DWP's, with the net saving on the
Microcosm dataset (A1). A test checks each number against the file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
uk-triple-lock Ready Ready Preview Sep 30, 2026 4:19pm UTC

Request Review

@juaristi22

Copy link
Copy Markdown

Program review

Base repository: PolicyEngine/uk-triple-lock
PR number: 12
Reviewed head SHA: 76885b7
Merge base SHA: f6f5505
Mode: full
Scope: PR #12's three dashboard presentation/helper/test changes and affected headline-result semantics, against current main f6f5505
Source manifest: retained with the local review artifacts
Review status: PARTIAL

Source documents

The DWP State Pension uprating analysis was checked live for GB coverage and its dynamic population projection. Two OBR workbooks were verified against publisher bytes. The OBR long-term and DWP benchmark workbooks were inspected as committed copies without publisher-byte authentication.

Critical

None.

Should Address

A1 — SHOULD ADDRESS — Do not present uncertain reweightings as a precise gross range (OPEN)

Location: dashboard/src/components/LandingTab.jsx:103-107; dashboard/src/lib/dataHelpers.js:369-377. Trigger: A reader interprets “Weighting the same runs to match past volatility instead gives £6.6bn to £10.7bn gross” as a reliable model sensitivity interval. Expected: The strip should identify what the reweightings target and their large simulation uncertainty, especially since it sits immediately below the headline. Observed: The numeric endpoints match committed data/results.json: minimum £6.611bn (shift_dynamics.2001_2025.suspended) and maximum £10.659bn (shift_dynamics_floor.2001_2025.covid_excluded). But the high endpoint also targets the historical share of years below the 2.5% floor, beyond gap variance and lead changes (src/triple_lock/expected_value.py:93-96,224-231); the floor's frequency directly affects this reform. That endpoint rests on 43.8 effective full runs and has a £5.184bn gross sampling SE. The low endpoint's SE is £0.999bn. Main already warns that reweighted intervals are approximate and can be too narrow (docs/METHOD.md:76-81, dashboard/src/components/SummaryTab.jsx:200-211). Impact: The prominent £6.6–£10.7 strip wrongly attributes the full span to “past volatility” and suggests more precision than the endpoint estimates support. Name gap variance, lead switching and floor frequency, call these point estimates from reweightings of one macro model, and put the high endpoint's weak effective-run support beside the numbers or avoid making it a bounded range. This is issue #9 A2 only partly addressed; it does not test another macro model or mean path. Evidence: Committed expected_value.sensitivities means/SE/effective_runs; method implementation and existing method disclosure. No new source is needed for this numeric finding.

Coordinator assessment: Independent code tracing confirms the helper correctly computes extrema over all 12 rows; the problem is the explanation of those rows and omission of the high endpoint's £5.184bn sampling SE. The new UI test checks the numeric extrema but not their interpretation.

A2 — SHOULD ADDRESS — Date, geography and paired sample qualify the benefit comparison (OPEN)

Location: dashboard/src/components/LandingTab.jsx:108-111. Trigger: A reader compares the new benefit-baseline numbers or the £5.9bn Microcosm net figure directly with the adjacent 2039–40 £5.4bn primary headline. Expected: The strip should state the periods and populations, then show the matched-path dataset comparison if that is its point. Observed: The Pension Credit 1.82m versus 1.31m and pension-age Housing Benefit £13.4bn versus £7.3bn numbers exactly match data/results.json coverage.rows, but they are 2026–27 values (src/triple_lock/dwp.py:20,64-89), with a UK model against DWP's Great Britain benchmark; neither qualification appears in this new headline copy. The £5.9bn Microcosm net estimate is also correct, but comes from a 40-path paired subsample (src/triple_lock/expected_value.py:102-104,540-575). On the same 40 paths Enhanced FRS is £5.251bn, and the computed paired Microcosm minus Enhanced FRS effect is +£0.613bn (SE £0.089bn). The nearby £5.392bn primary headline uses 200 sampled paths, so subtracting the displayed £5.9bn and £5.4bn does not recover the paired dataset effect. Main's detailed SummaryTab.jsx:155-166,183-195 has these caveats, but the new top-level strip does not. Impact: The omitted scopes can make a baseline diagnostic appear contemporaneous with the 2039 outcome and make the Microcosm number look like a directly comparable full-sample estimate. Add “2026–27; UK model versus DWP Great Britain” and “40 paired paths”; if showing the dataset difference, use the stored paired result. This is issue #9 A1 only partly addressed. Evidence: Committed coverage.year, coverage.rows, expected_value.estimates and paired_difference; DWP's State Pension uprating analysis confirms Great Britain and a dynamically projected population. The DWP Spring Forecast workbook is a committed copy whose publisher bytes remain unauthenticated, but the new UI numbers do match that copy and results.json.

Coordinator assessment: Code review confirmed the displayed coverage values are the 2026–27 primary Enhanced FRS rows; Microcosm baseline rows sit below the cited DWP benchmarks. The new test does not assert the period, geography or paired-path context.

Suggestions

S1 — Coverage row validation couples the visible primary comparison to an unused field (MINOR) (OPEN)

Location: dashboard/src/lib/dataHelpers.js:380-384; gating in dashboard/src/components/LandingTab.jsx:108.

Trigger and observed output: getCoverageRow returns null if row.sensitivity is absent or nonnumeric, even though the visible claims and Housing Benefit comparisons use only row.primary and row.dwp. A valid primary/DWP comparison therefore disappears if an optional sensitivity value is unavailable. For non-array coverage.rows, .find throws and the landing component cannot render. Current committed results have all three finite values and an array, so neither branch occurs on this head.

Expected / impact: Validate fields needed by the consumer and guard the row container with Array.isArray if partially populated or malformed data are accepted by the dashboard data contract. This is a robustness suggestion rather than a demonstrated defect in current output.

Reproduction: Bounded Node helper invocation in pr-12-review-20260930-review-node.log and pr-12-review-20260930-review-edge.log: absent sensitivity returns null; object rows raises TypeError.

Evidence Gaps

  • Private Enhanced FRS/Microcosm data and the pinned PolicyEngine bundle were unavailable, so the 200 primary and 40 Microcosm population runs and benefit baselines could not be independently regenerated. The PR changes no model/output data.
  • The OBR long-term and DWP benchmark workbooks were inspected as committed copies; publisher-byte equivalence could not be independently authenticated in this environment.
  • Local React tests/build could not start without dashboard node_modules/vitest; GitHub CI success at the captured head is recorded separately. Browser rendering and accessibility were not executed.

Notes

  • The displayed £6.611bn–£10.659bn, £5.864bn Microcosm net, and benefit-baseline values match committed results.json. PR Dashboard: state what the headline assumes (#9 A1-A3) #12 changes no model code or result numbers.
  • The survey's ages and pension types are fixed, while weights and State Pension age can still change; the strip's population shorthand could state that nuance more precisely.
  • The earlier issue Full review of triple lock modeling, dashboard, and PR #8 paper #9 modeling work remains open: this PR improves presentation but does not calibrate benefits, test another macro model/mean path, or age the pensioner cohort.

Validation Summary

At head 76885b7, GitHub Dashboard, Pipeline and Vercel checks: SUCCESS. Read-only Node helper diagnostics reproduced the displayed values and current-data rendering; no model or results JSON changed. Bounded local React test attempt failed before collection with vitest: command not found because node_modules are absent; no local build or browser check. Five cached/committed source files passed SHA-256 integrity; two OBR workbook bytes were publisher-authenticated, while the long-term OBR and DWP benchmark copies were not. Official DWP publication was checked live for GB/dynamic-population context.

Timing

setup seconds: 183.00s; scope seconds: 19.00s; parallel review seconds: 546.00s; policy role seconds: 426.00s; code role seconds: 524.00s; adjudication seconds: 0.00s; consolidation cleanup seconds: 210.00s; elapsed seconds: 917.00s

Review Severity

COMMENT. Open findings: 0 critical, 2 should address, 1 suggestions.

The tab holds the population and distributional results as well as the
example pensioners (María, Slack).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vahid-ahmadi and others added 2 commits September 30, 2026 15:00
- Budget impact: the households-losing card says plainly what its numbers
  are (expected share in 2039-40; the 10th-90th percentile span across paths).
- Forecast paths: the drawn paths' first line now explains, from the file's
  selection fields, how each was picked. 50,000 simulated paths; the middle
  and 90th-percentile views show one real path, chosen among the draws whose
  2039-40 gap lies within 2.5 points of that percentile as the one whose
  statutory CPI and earnings are closest to those draws' average
  (trajectories.py select_draws); the expected saving rests on the full runs
  sampled across all paths. Falls back to the file's sentence if fields are
  missing.
- Distributional impact: income breakdown by decile only (default), label
  "Income decile"; quintile option removed.
- Assumptions strip: the reweighting item says these are point estimates of
  reweighting the same full runs (gap variance, lead switching, in some
  versions the floor share) and gives the highest one's effective runs and
  standard error; the benefits item names the coverage year and UK vs GB,
  and gives the paired Microcosm minus Enhanced FRS net difference; the
  population item says headcount moves only through weights and SPA.
- getCoverageRow guards the rows array and needs only dwp and primary;
  getSensitivityRange returns the highest row's effective runs and SE.
- Tab "Method" renamed "Methodology" (id unchanged), with references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lier page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22

Copy link
Copy Markdown

Incremental re-review at 14790cb

I compared this head with the previously reviewed 76885b7. The only new diff is Dashboard.jsx:22: “Household impact” becomes “Distributional impact.” The tab contains population incidence, poverty and example pensioners, so the new label fits. Its households ID, URL and legacy aliases are unchanged; I found no stale old-label reference or new actionable defect.

The previous review's A1 and A2 remain open. The landing strip still calls the £6.6bn–£10.7bn endpoints a past-volatility reweighting, although the upper endpoint also targets floor frequency and has a £5.184bn sampling SE. It also still omits the 2026–27 UK-model/DWP-GB scope of the benefit baselines and the 40-path paired basis for Microcosm. The minor S1 helper-validation suggestion is unchanged.

At 14790cb, Dashboard, Pipeline and Vercel CI checks passed. The scoped code/source review is complete; the overall review remains partial for the earlier evidence limits, and I could not run local React tests without the dashboard dependencies. No source files were changed during this review.

… other model is tested

Answers María's A1 in full: the strip no longer reads as a bounded range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vahid-ahmadi

Copy link
Copy Markdown
Contributor Author

Thanks! All addressed in f65e57f, 1883242 and 10e25c2:

  • A1: the strip now names what the reweightings match (gap variance, lead switching, and in some versions the floor share). It gives separate point estimates, each with its own uncertainty: the lowest £6.6bn gross (SE £1.0bn), the highest £10.7bn on about 44 effective runs (SE £5.2bn). It also says no other model of prices and earnings is tested.
  • A2: the benefit baselines are labelled 2026-27, UK model vs DWP's GB. The Microcosm line now uses the stored paired result: on the same 40 paths, net saving £0.6bn higher (SE £0.1bn).
  • S1: getCoverageRow checks the rows are a list and needs only dwp and primary.
  • Note: the population line now says pensioner numbers change only through survey weights and the State Pension age.

Also from your Slack notes:

  • the households card wording;
  • a plain explanation of how the middle and 90th-percentile paths are picked;
  • deciles only;
  • the Methodology tab name;
  • no mention of an "earlier version" in the backtest.

The modelling parts of #9 (benefit calibration, another macro model or mean path, ageing) are still open.

@juaristi22

Copy link
Copy Markdown

Re-review at 10e25c2

This head addresses the findings in my earlier PR #12 review:

  • A1 resolved: the strip now identifies gap variance, lead switches and floor-frequency variants, gives the endpoint standard errors, and flags that the £10.7bn endpoint rests on about 44 effective full runs.
  • A2 resolved: it identifies the 2026–27 UK-model/DWP-GB comparison and gives the paired Microcosm net difference (£0.613bn, SE £0.089bn) on the same 40 paths.
  • S1 resolved: the coverage helper no longer requires an unused sensitivity field and guards malformed row containers.

I found one new issue to address. LandingTab.jsx:115 says “No other model of prices and earnings is tested.” The repository does test and summarize bootstrap, Student-t copula and Gaussian CPI/earnings models (trajectories.forward_specs), but only the bootstrap model is carried through the full fiscal runs. The accurate claim is that this fiscal sensitivity range does not include another CPI/earnings model. The current sentence could wrongly tell readers no alternative joint model was tested at all.

One minor path-description point: the new percentile-path text says it picks the closest of the 2,500 candidate paths, while select_draws first limits eligibility to candidates at or above the median weight. “Among the more heavily weighted candidates” would reflect the actual selection rule. The reported path and result numbers are unchanged.

The additional tab labels, decile breakdown and tests show no other material issue in this scoped review. Dashboard, Pipeline and Vercel CI are green at 10e25c2; local React tests remained unavailable without dashboard/node_modules. The underlying model/data concerns in issue #9 remain separate from these copy fixes. The overall independent review remains partial for the previously stated private-data/source limits.

… fiscal range; the path pick's weight filter

From María's re-review of PR #12: the range excludes other CPI/earnings
models rather than none being tested, and the percentile path is picked
among candidates with at least their median weight (all of them, as every
path has the same weight).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vahid-ahmadi

Copy link
Copy Markdown
Contributor Author

Thanks, both fixed in the latest commit:

  • Other models: the strip now says "This range does not include another model of prices and earnings: Student-t and Gaussian versions are tested against past forecasts (Methodology tab) but not run through the full fiscal model." A test pins the wording.
  • Path pick: the text now includes the weight filter: among the candidates "with at least their median weight (all of them here, as every path has the same weight)". I used that wording rather than "the more heavily weighted candidates" because the draws are equally weighted, so the filter doesn't exclude any path here.

@vahid-ahmadi
vahid-ahmadi merged commit 43e5102 into main Oct 1, 2026
4 checks passed
@juaristi22

Copy link
Copy Markdown

Program review

Base repository: PolicyEngine/uk-triple-lock
PR number: 12
Reviewed head SHA: 963cc60
Merge base SHA: f6f5505
Mode: incremental from 10e25c2
Scope: three-file dashboard wording/test delta; prior open A3 and S2 plus affected macro-model and path-selection dependencies; A1/A2/S1 carried forward
Source manifest: /private/tmp/policyengine-command-runs/23429b7be472/pr-12-rereview-20261001-review-sources.json
Review status: PARTIAL

Source Documents

Critical

None.

Should Address

A1 — SHOULD ADDRESS — Do not present uncertain reweightings as a precise gross range (RESOLVED)

Location: dashboard/src/components/LandingTab.jsx:103-107; dashboard/src/lib/dataHelpers.js:369-377. Trigger: A reader interprets “Weighting the same runs to match past volatility instead gives £6.6bn to £10.7bn gross” as a reliable model sensitivity interval. Expected: The strip should identify what the reweightings target and their large simulation uncertainty, especially since it sits immediately below the headline. Observed: The numeric endpoints match committed data/results.json: minimum £6.611bn (shift_dynamics.2001_2025.suspended) and maximum £10.659bn (shift_dynamics_floor.2001_2025.covid_excluded). But the high endpoint also targets the historical share of years below the 2.5% floor, beyond gap variance and lead changes (src/triple_lock/expected_value.py:93-96,224-231); the floor's frequency directly affects this reform. That endpoint rests on 43.8 effective full runs and has a £5.184bn gross sampling SE. The low endpoint's SE is £0.999bn. Main already warns that reweighted intervals are approximate and can be too narrow (docs/METHOD.md:76-81, dashboard/src/components/SummaryTab.jsx:200-211). Impact: The prominent £6.6–£10.7 strip wrongly attributes the full span to “past volatility” and suggests more precision than the endpoint estimates support. Name gap variance, lead switching and floor frequency, call these point estimates from reweightings of one macro model, and put the high endpoint's weak effective-run support beside the numbers or avoid making it a bounded range. This is issue #9 A2 only partly addressed; it does not test another macro model or mean path. Evidence: Committed expected_value.sensitivities means/SE/effective_runs; method implementation and existing method disclosure. No new source is needed for this numeric finding.

Coordinator assessment: Independent code tracing confirms the helper correctly computes extrema over all 12 rows; the problem is the explanation of those rows and omission of the high endpoint's £5.184bn sampling SE. The new UI test checks the numeric extrema but not their interpretation.

Coordinator assessment: At 10e25c2, the strip identifies gap variance, lead switches and floor-frequency variants; reports separately estimated endpoints with each SE; and states the upper endpoint rests on about 44 effective full runs. The original missing-target/precision problem is resolved. A distinct new false statement about other models is recorded below.

A2 — SHOULD ADDRESS — Date, geography and paired sample qualify the benefit comparison (RESOLVED)

Location: dashboard/src/components/LandingTab.jsx:108-111. Trigger: A reader compares the new benefit-baseline numbers or the £5.9bn Microcosm net figure directly with the adjacent 2039–40 £5.4bn primary headline. Expected: The strip should state the periods and populations, then show the matched-path dataset comparison if that is its point. Observed: The Pension Credit 1.82m versus 1.31m and pension-age Housing Benefit £13.4bn versus £7.3bn numbers exactly match data/results.json coverage.rows, but they are 2026–27 values (src/triple_lock/dwp.py:20,64-89), with a UK model against DWP's Great Britain benchmark; neither qualification appears in this new headline copy. The £5.9bn Microcosm net estimate is also correct, but comes from a 40-path paired subsample (src/triple_lock/expected_value.py:102-104,540-575). On the same 40 paths Enhanced FRS is £5.251bn, and the computed paired Microcosm minus Enhanced FRS effect is +£0.613bn (SE £0.089bn). The nearby £5.392bn primary headline uses 200 sampled paths, so subtracting the displayed £5.9bn and £5.4bn does not recover the paired dataset effect. Main's detailed SummaryTab.jsx:155-166,183-195 has these caveats, but the new top-level strip does not. Impact: The omitted scopes can make a baseline diagnostic appear contemporaneous with the 2039 outcome and make the Microcosm number look like a directly comparable full-sample estimate. Add “2026–27; UK model versus DWP Great Britain” and “40 paired paths”; if showing the dataset difference, use the stored paired result. This is issue #9 A1 only partly addressed. Evidence: Committed coverage.year, coverage.rows, expected_value.estimates and paired_difference; DWP's State Pension uprating analysis confirms Great Britain and a dynamically projected population. The DWP Spring Forecast workbook is a committed copy whose publisher bytes remain unauthenticated, but the new UI numbers do match that copy and results.json.

Coordinator assessment: Code review confirmed the displayed coverage values are the 2026–27 primary Enhanced FRS rows; Microcosm baseline rows sit below the cited DWP benchmarks. The new test does not assert the period, geography or paired-path context.

Coordinator assessment: At 10e25c2, the strip labels the 2026–27 UK-model versus DWP-GB baseline and reports the £0.613bn paired Microcosm net difference (SE £0.089bn) across the same 40 paths, rather than presenting an unmatched total.

A3 — Limit the “no other model” claim to the sensitivity range (RESOLVED)

P2; PR12 head 10e25c2, dashboard/src/components/LandingTab.jsx:115. The sentence “No other model of prices and earnings is tested” appears in the at-a-glance assumptions beside the £6.6bn–£10.7bn range. But src/triple_lock/trajectories.py:22-28 summarizes Student-t copula and Gaussian shock variants, and src/triple_lock/ts_backtest.py tests alternative monthly models. Those variants do not have full fiscal runs, so the range does rely on one model; the unqualified sentence could make readers think alternative joint CPI/earnings models were never examined. Change it to “This range does not include a different model of prices and earnings.”

Coordinator assessment: Code adjudication confirmed that trajectories.forward_specs tests boot, Student-t copula and Gaussian price/earnings models, but only boot receives full PolicyEngine fiscal runs. The sentence should distinguish the macro comparison from this fiscal sensitivity range.

Coordinator assessment: At 963cc60, LandingTab confines the statement to the fiscal sensitivity range and explicitly describes the Student-t and Gaussian backtests. Statutory backtest code and committed results include both variants; only the boot variant receives full fiscal runs.

Suggestions

S1 — Coverage row validation couples the visible primary comparison to an unused field (MINOR) (RESOLVED)

Location: dashboard/src/lib/dataHelpers.js:380-384; gating in dashboard/src/components/LandingTab.jsx:108.

Trigger and observed output: getCoverageRow returns null if row.sensitivity is absent or nonnumeric, even though the visible claims and Housing Benefit comparisons use only row.primary and row.dwp. A valid primary/DWP comparison therefore disappears if an optional sensitivity value is unavailable. For non-array coverage.rows, .find throws and the landing component cannot render. Current committed results have all three finite values and an array, so neither branch occurs on this head.

Expected / impact: Validate fields needed by the consumer and guard the row container with Array.isArray if partially populated or malformed data are accepted by the dashboard data contract. This is a robustness suggestion rather than a demonstrated defect in current output.

Reproduction: Bounded Node helper invocation in pr-12-review-20260930-review-node.log and pr-12-review-20260930-review-edge.log: absent sensitivity returns null; object rows raises TypeError.

Coordinator assessment: At 10e25c2, getCoverageRow validates the array and the DWP/primary fields actually used, without requiring an optional sensitivity value. Bounded Node checks passed.

S2 — Path-selection explanation omits its weight eligibility filter (MINOR) (RESOLVED)

Location: dashboard/src/lib/trajectoryHelpers.js:134-140, surfaced in dashboard/src/components/StepPath.jsx:148-169. Trigger/observed: The new percentile-path text says the view takes all 2,500 paths in the gap band and “picks the one whose CPI and earnings … are closest to those paths' average.” The actual selector first restricts those candidates to paths with weight at least the candidate median weight, then minimizes the standardized distance to the weighted candidate mean (src/triple_lock/trajectories.py:102-130). Impact: The explanation gives the wrong selection rule in a dashboard intended to explain representative joint CPI/earnings paths. It can imply a rare, low-weight path is eligible to be chosen solely for closeness. Add a short qualifier such as “among the more heavily weighted candidates” and, if precision is desired, mention standardization across years and series. The reported path ids, bands, and counts agree with committed selection metadata; no observed numerical result changes.

Coordinator assessment: At 963cc60, trajectoryHelpers explains the median candidate-weight threshold. The selector implements it, and the published primary paths have equal weights, so all 2,500 band candidates remain eligible.

S3 — Update the PR description's superseded model claim (OPEN)

P3 documentation suggestion, PR body A2 table. The coordinator's live gh pr view 12 --json body read still found “No other model of prices and earnings is tested” in the PR description, while LandingTab.jsx:115 and the actual backtest now correctly distinguish alternate CPI/earnings models from full fiscal runs. A reader relying on the PR description could retain the mistaken conclusion that alternative joint models were never examined. Align that PR-body row with the corrected dashboard wording. This does not block the dashboard code or reopen A3; the PR body is review context rather than an application artifact. My own gh API attempt returned a connection error, so the current-body observation is attributed to the coordinator's live read, not independently refreshed here.

Evidence Gaps

  • Inherited from full review: private Enhanced FRS/Microcosm inputs and pinned PolicyEngine bundle unavailable to independently regenerate the 200/40 population runs; this PR does not change model/results data.
  • Inherited from full review: OBR long-term and DWP benchmark workbooks were checked as committed copies without publisher-byte authentication.

Notes

Validation Summary

At head 963cc60, GitHub Dashboard lint/test/build, Pipeline tests/committed-output checks, and Vercel succeeded. Scoped read-only review traced the three-file delta through statutory backtests, fiscal-path gate and committed results. Five cached source items passed SHA-256 integrity. Local React tests/build and browser rendering were NOT RUN in the isolated snapshot (node_modules/Vitest unavailable); prior full review validation and its gaps are inherited. No model/results data changed.

Timing

setup seconds: 98.00s; scope seconds: 16.00s; parallel review seconds: 137.00s; policy role seconds: 121.00s; code role seconds: 60.00s; adjudication seconds: 8.00s; consolidation cleanup seconds: 13.00s; elapsed seconds: 245.00s

Review Severity

COMMENT. Open findings: 0 critical, 0 should address, 1 suggestions.

This branch was successfully deployed

1 active deployment
Preview — 963cc60e Deployed Sep 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants