Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
02af2d3
Vendor scorecard#183's base-side grid record and apply known gaps
MaxGhenis Oct 16, 2026
73820ab
Hold every received receipt and status to the vendored schema
MaxGhenis Oct 16, 2026
7a0ce5d
Merge remote-tracking branch 'origin/w4/d1344-automatic-promotion' in…
MaxGhenis Oct 16, 2026
21c0096
Rewrap the policy paragraph the merge joined
MaxGhenis Oct 16, 2026
53da3ae
Excuse only a known gap's inertness flag, and pin the rule's combinat…
MaxGhenis Oct 16, 2026
534ad0d
Merge remote-tracking branch 'origin/w4/d1344-automatic-promotion' in…
MaxGhenis Oct 16, 2026
4d30fcf
Replace the 1.58.0 metrics fixture with W3's suppressed 1.58.1 report
MaxGhenis Oct 16, 2026
1d17338
Merge w4/d1344-automatic-promotion: small-cell format and the 228a05a…
MaxGhenis Oct 16, 2026
86d2b4d
Merge w4/d1344-automatic-promotion: line up additive totals; supp-r1 …
MaxGhenis Oct 16, 2026
31d9b24
Let scorecard's record of a mixed known gap pass; counters must equal…
MaxGhenis Oct 16, 2026
3a072e0
Merge w4/d1344-automatic-promotion: suppress small counts in contract…
MaxGhenis Oct 16, 2026
73a0ea2
Merge w4/d1344-automatic-promotion: cancelled-run re-run, unsafe-repo…
MaxGhenis Oct 16, 2026
b9f5574
Fail any candidate value at a known gap; strip only valueless inertness
MaxGhenis Oct 16, 2026
5297320
Merge w4/d1344-automatic-promotion: withhold population totals over f…
MaxGhenis Oct 16, 2026
40a18a2
Excuse only a valueless inertness row; correct the lost-result sentence
MaxGhenis Oct 16, 2026
9f97fc2
Merge w4/d1344-automatic-promotion
MaxGhenis Oct 16, 2026
3decffb
Merge w4/d1344-automatic-promotion: population details
MaxGhenis Oct 16, 2026
656eede
Correct the replay gate's docstring; pin the gap record's level and s…
MaxGhenis Oct 16, 2026
50c09d8
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
2094ee5
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
34a249c
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
a7f7920
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
a814331
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
8ba4354
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
5edc7b3
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
5cd3c7c
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
f68f723
Merge w4/d1344-automatic-promotion: count only the candidate's own runs
MaxGhenis Oct 16, 2026
00627f3
Merge main (with #574, #632 and #635) into w4/replay-known-gaps
MaxGhenis Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/636.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Qualification reads policyengine-scorecard#183's receipts. The vendored replay receipt schema and its mirrors now carry the base's own grid record (`diff.base_events`) and the candidate's missing and unsupported measure-years. A gap counts as known only when the base's record lists the same measure-year as inert, or missing and supported.
64 changes: 48 additions & 16 deletions src/policyengine/data/qualification/replay_policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,69 @@

Decided under cos d1344 by workstream W4 on 15 October 2026, after two
independent reviews. The pull request that added this file records the
decision, the reviews and the alternatives considered.
decision, the reviews and the alternatives considered. Revised on 16
October 2026, before first use, after the third to fifth reviews of
policyengine.py#637: scorecard's own record of a mixed known gap no longer
blocks, flag counters must equal the flags the rows carry, and any
candidate value other than £0 at a known gap is a contradiction.
`evaluate_replay_receipt` in `policyengine.provenance.qualification`
applies this text. Each qualification receipt records the policy id and
this file's SHA-256 in its `replay` gate details.

The replay gate fails on the regressions a scorecard replay receipt
identifies. It calls a gap known only on positive evidence from the
comparison base. It sends every other flagged move to a named reviewer.
comparison base, and passes the rows that record a known gap. It sends
every other flagged move to a named reviewer.

## Fail

- A rejected request, `no_supported_years`, integrity `failed` (a crash or
missing outputs, persistent or not), or a receipt not bound to the
request.
- A mapping flag, whether a flagged row carries it or only the receipt's
counters state it.
- A lost result: a coverage row with a base value and no candidate value.
- A lost response, unless it is a known gap:
- a measure-year the candidate lists as inert;
- A mapping flag.
- A lost result: a coverage row with a base value and no candidate value,
unless it is the record of a known gap (below).
- A lost response:
- a measure-year the candidate lists as inert, unless it is a known gap;
- a measure-year total at exactly £0 where the base's absolute value is
at least the diff's bound, max(£1m, 1% of the base's absolute value),
whether the base was positive or negative.
whether the base was positive or negative. A known gap never excuses
this: a base whose record lists the measure-year as a gap cannot also
hold a material value for it.
- An event whose supported grid is incomplete, unless every inert or
missing measure-year in it is a known gap. A receipt whose integrity is
`incomplete` with no incomplete event also fails.
missing and supported measure-year in it is a known gap. An incomplete
event whose receipt does not list its missing measure-years fails, and so
does one with no inert and no missing and supported measure-year at all.
A receipt whose integrity is `incomplete` with no incomplete event also
fails.
- A receipt that contradicts itself, including a complete event that lists
an inert, or missing and supported, measure-year; flag counters that
differ, either way, from the flags its rows carry; and a candidate value
other than £0 for a measure-year that is a known gap.

## Known gaps

A measure-year is a known gap only when the receipt positively records it
as inert, or missing and supported, in the base, for the same event,
measure and year. Until the receipt carries that base-side record, there
are no known gaps.
A candidate measure-year that is inert, or missing and supported (in the
event's missing list and not its unsupported list), is a known gap only
when the receipt's base-side record for the same event (`diff.base_events`,
taken from the base's verified staging and run manifests) lists the same
measure and year as inert, or as missing and supported, in the base. The
gate records each known gap with the base's staging manifest SHA-256. A
legacy-layout base, or an event the base did not replay, has no record, so
none of its gaps are known.

A known gap does not block. Where one side is inert and the other missing,
scorecard records the gap as a coverage row with exactly £0 on the inert
side and no value on the other, and an inertness flag on the inert side
only, on a row with no values. Those flags are the gap itself and neither
fail nor send the row to review. (Where the candidate is the inert side, its
inert list already decides that flag.) The gate records every row a known
gap accounts for, in whole or in part, beside the known gaps; the rest of a
partly excused row's flags are judged as usual. Any other row at a known gap
is judged as usual: a coverage row with a base value and no candidate value,
even £0, is still a lost result, and any candidate value other than £0 at a
known gap contradicts the candidate's own record, which lists the
measure-year as inert (exactly £0) or missing (no value).

## Review

Expand All @@ -48,8 +79,9 @@ review:
- support flags (the separate `supported_years` gate fails a candidate that
loses a year the previous certificate supported);
- coverage gains, coverage rows with no value on either side, and any other
coverage row that is not a lost result;
- inertness flags on a measure-year the candidate does not list as inert;
coverage row that is not a lost result or the record of a known gap;
- inertness flags on a measure-year the candidate does not list as inert,
other than the record of a known gap;
- a receipt with no diff against a certified variant.

Unsupported years alone never fail. A move below the diff's bound raises
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Vendored policyengine-scorecard schemas

Copied unchanged from PolicyEngine/policyengine-scorecard, branch
`w6/replay-variants`, commit `dc040de` (`docs/uk_replay/schemas/`): the v1
Copied unchanged from PolicyEngine/policyengine-scorecard, `main` at commit
`71cad306f37f7f9bfb4b58497ff9ddd78b396e00` (the merge of scorecard#183, which
added `diff.base_events` and the corpus grid lists;
`docs/uk_replay/schemas/`): the v1
pre-promotion replay interface between policyengine.py qualification (W4)
and the replay corpus (W6). `policyengine.provenance.qualification` mirrors
them, and `tests/test_qualification_contracts.py` checks the mirrors and the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,12 @@
}
}
}
},
"base_events": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/base_event"
}
}
}
}
Expand Down Expand Up @@ -614,23 +620,74 @@
"type": "boolean"
},
"inert_measure_years": {
"$ref": "#/$defs/measure_years"
},
"missing_measure_years": {
"$ref": "#/$defs/measure_years"
},
"unsupported_measure_years": {
"$ref": "#/$defs/measure_years"
}
}
},
"measure_years": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"measure_key",
"year"
],
"properties": {
"measure_key": {
"type": "string",
"minLength": 1
},
"year": {
"type": "integer"
}
}
},
"uniqueItems": true
},
"base_event": {
"type": "object",
"additionalProperties": false,
"required": [
"staging_manifest_sha256",
"run_manifest_sha256",
"supported_years",
"full_supported_grid_complete",
"inert_measure_years",
"missing_measure_years",
"unsupported_measure_years"
],
"properties": {
"staging_manifest_sha256": {
"$ref": "#/$defs/sha256"
},
"run_manifest_sha256": {
"$ref": "#/$defs/sha256"
},
"supported_years": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"measure_key",
"year"
],
"properties": {
"measure_key": {
"type": "string"
},
"year": {
"type": "integer"
}
}
}
"type": "integer"
},
"uniqueItems": true
},
"full_supported_grid_complete": {
"type": "boolean"
},
"inert_measure_years": {
"$ref": "#/$defs/measure_years"
},
"missing_measure_years": {
"$ref": "#/$defs/measure_years"
},
"unsupported_measure_years": {
"$ref": "#/$defs/measure_years"
}
}
}
Expand Down
Loading
Loading