Commit graph

281 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
50554ff57e review: backfill writes an explicit Unknown band too (matches finaliser)
Aligns the historical backfill with the go-forward finaliser: it now writes a
boiler_efficiency_band row for EVERY main_heating_system row — the parseable band
(A-G) where present, else an explicit Unknown — so historical and go-forward data
match. Unknown is fine on non-boilers (inert to modelling). Confirmed with Khalim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 15:58:38 +00:00
Khalim Conn-Kowlessar
eb07b91614 review: guard-only band classifier, backfill count, docstring (PR #1713)
Addresses reviewer feedback:
- #3 (Khalim + kimjunte): the boiler_efficiency_band classifier column is now
  GUARD-ONLY — LLM fallback removed. The band format is deterministic, so an LLM
  guess could only fabricate a band the landlord never stated (moves SAP +
  eligibility). New LoggingUnknownColumnClassifier is the non-fabricating fallback:
  maps guard-misses to UNKNOWN (never stored) and logs them for review — kimjunte's
  'warn on None', placed in the classifier path not the shared guard (which sees
  legitimate None constantly on the modelling/backfill paths).
- #2 (Khalim): backfill --apply now reports rows ACTUALLY written (upsert
  rowcount), not the candidate count, so an idempotent re-run reports 0.
- #1 (Khalim): overlay module docstring scrubbed of stale 'slot/pending' wording
  to match the cert-native anchor mechanism.

kimjunte's finaliser optional-skip question (declared-vs-shared-column flow) left
for reviewer alignment, not changed. 529 tests green; pyright clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 14:57:11 +00:00
Khalim Conn-Kowlessar
c690cd3183 feat(backfill): boiler_efficiency_band rows from existing heating descriptions
Idempotent, dry-run-by-default script (mirrors reclassify_main_heating). Parses
the SEDBUK band off each main_heating_system row's original_spreadsheet_description
with the SAME guard as the live classifier (no drift), upserting a
boiler_efficiency_band row per boiler that carries one. Pure core band_backfill_rows
unit-tested. FE-enum-gated writes (Class-A/B deferred) (ADR-0068).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 16:34:53 +00:00
Jun-te Kim
9c3b901b8a Add Elmhurst accreditation evidence for the Apt 2 community cert 🟩
Reproducible RdSAP-10 build (build_100010472748.py) + downloaded Input Summary
and SAP Worksheets (accredited SAP 62 D) + the entry crib sheet, as the
ground-truth for the community-heating mapping fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 13:22:51 +00:00
Khalim Conn-Kowlessar
31be36cca5 Flag works bought for no real SAP gain 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 15:57:25 +00:00
Khalim Conn-Kowlessar
08d2b874d5 Flag works bought for no real SAP gain 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 15:53:59 +00:00
Khalim Conn-Kowlessar
68ffb0c47c Rank costed works on an already-compliant dwelling HIGH 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 10:12:58 +00:00
Khalim Conn-Kowlessar
27060f4d81 Band every continuous SAP score through the published-rating rule 🟪
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 10:11:06 +00:00
KhalimCK
08dc81332c
Merge pull request #1650 from Hestia-Homes/fix/pashub-sitenotes-boiler-thermostat-gable
PasHub Wythenshawe: fix 6 from_site_notes defects + re-pin harness to DB oracle (#1649)
2026-07-20 12:04:16 +01:00
Daniel Roth
dc96cf5aba
Merge pull request #1648 from Hestia-Homes/feature/abri-api-resource-field
Sync third_party_surveyor_identifier deal field from HubSpot
2026-07-20 11:02:11 +01:00
Khalim Conn-Kowlessar
1424e2110e Re-pin Wythenshawe accuracy harness to the DB oracle (#1649)
`test_pashub_sap_accuracy_wythenshawe` graded against the manifest `pre_sap`
(`hubspot_deal_data.pre_sap`) — surveyor hand-entered and frequently wrong,
which floated a misleading 79% / MAE 0.75. Grade instead against the DB
PasHub-assessment SAP (`epc_property_energy_performance.energy_rating_current`,
`ep.source='lodged'`), matched by UPRN or postcode+house-number.

`scripts/enrich_pashub_wythenshawe_oracle.py` resolves each fixture's oracle SAP
once (DB required, not run in CI) and bakes `oracle_sap` / `oracle_match` into
`manifest.json`, so the harness stays DB-free. 148/168 resolve (39 UPRN + 109
address); the 20 unmatched carry `oracle_sap` null and are excluded from the
aggregate until PasHub sources their SAP.

With the six from_site_notes fixes, the 148 matched score within-0.5 89.2%
(132/148), MAE 0.297 (was, vs pre_sap, 79.2% / 0.754). Ratchets re-baselined
0.75→0.88 floor, 0.85→0.31 ceiling. The residual tail is the integer-oracle
rounding floor (spec-correct dwellings) plus a couple of spec-literal gaps, not
engine defects.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 11:40:51 +00:00
Daniel Roth
edd4ec00de Make the OpenHousing resource mandatory, dropping the default fallback
The deal's third_party_surveyor_identifier is now required by the log
and amend flows: the trigger contract rejects messages without it
(blank treated as missing, since a blank resource makes OpenHousing
silently drop the appointment), and LogJobRequest/AmendJobRequest carry
it as a required field. The ABRI_RELAY_DEFAULT_RESOURCE fallback and
its config/terraform/workflow wiring are removed as dead code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 13:13:28 +00:00
Khalim Conn-Kowlessar
8fc8a90c8b Add WCHG Elmhurst summary ingest script (SharePoint -> S3 + epc_property)
One-time ingest of Wythenshawe Community Housing Group Elmhurst *Summary*
PDFs: resolve each property's SharePoint folder from the WCHG xlsx, download
the summary, run the existing extractor -> mapper -> SAP10 pipeline, and
(with --commit) push the PDF to S3, record an uploaded_files row, and save
the EpcPropertyData to epc_property keyed on the national UPRN (property_id
NULL, replace-by-(uprn,source)). Dry-run by default; also emits a SAP-accuracy
CSV vs Elmhurst's reported current SAP (% within 0.5 + MAE).

Adds DomnaSites.SOCIAL_HOUSING (SOCIAL_HOUSING_SHAREPOINT_ID) for the site.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 16:40:27 +00:00
Daniel Roth
d557e1b0b4 make pashub accuracy test more generic and add files for lincs rural 2026-07-16 11:22:39 +00:00
Daniel Roth
093e5ce041 Merge branch 'main' into fix/1589-refetch-epc-is-ignored 2026-07-15 09:45:20 +00:00
Daniel Roth
b02519320f update local trigger script 2026-07-15 09:42:24 +00:00
Khalim Conn-Kowlessar
178af2f044 Add local modelling runner + portfolio-838 problem-properties handover
scripts/run_pashub_modelling.py invokes the modelling_e2e handler in-process
over a portfolio using STORED EPCs (refetch_epc=False — the correct source for
PasHub cohorts, issue #1589), parametrised by env (portfolio/scenario/pids/
dry-run/batch). Handover documents the 3 re-extraction stragglers, the
rebaseliner pass-through gotcha (effective_sap_score IS the pashub rating for
unchanged lodged EPCs — never validate the calculator against it), and the 7
root-caused extractor bugs now tracked in #1590.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:24:37 +00:00
Daniel Roth
ff1302b514
Merge pull request #1545 from Hestia-Homes/backfill-epc-property-uprn
Script to backfill UPRN in epc_property for rows populated by sitenotes before the mapper included the UPRN
2026-07-14 17:02:55 +01:00
Khalim Conn-Kowlessar
e5fee3896a Add PAS Hub SAP-accuracy regression harness (Guinness 205 cohort)
Foundation for PRD #1555: runs each PAS Hub site-note PDF through the
extractor -> EpcPropertyData -> Sap10Calculator and gauges the computed
SAP against pashub's own SAP-10.2 `pre_sap` (from hubspot_deal_data).

- test_pashub_sap_accuracy.py: hybrid gate. Per-fixture "must compute"
  (xfail on the known in-progress mapper gaps MissingMainFuelType /
  UnmappedSapCode / UnmappedPasHubLabel) + aggregate within-0.5 ratchet
  floor, mirroring test_sap_accuracy_corpus.py.
- 205 image-stripped site-note PDFs + manifest.json. Images stripped so
  the repo footprint stays ~52MB while the text layer the extractor reads
  is byte-identical.
- build_pashub_accuracy_fixtures.py: provenance/rebuild from S3 +
  hubspot_deal_data.

All 206 currently xfail on the known heating-string mapper gaps; each fix
(#1556-1568) flips its fixtures to computing and ratchets the floor.

Refs #1555 #1568

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:32:18 +00:00
Daniel Roth
f5d2bdd651 update script 2026-07-14 09:40:38 +00:00
Daniel Roth
08e11538cd script 2026-07-14 09:13:12 +00:00
Jun-te Kim
44275aa6a1 Confirm multi-orientation window gap is not closeable for UPRN 100010086084
Re-attempted entering this SAP-15.0 cert's 4 real N/E/S/W windows (gov-API
sap_windows, 2.516 m^2 each) as separate Elmhurst Openings rows instead of
the accepted single combined South row, to test whether it closes the
residual ~2pt gap (engine 53 vs Elmhurst worksheet 51).

Reproduced live the documented elmhurst_lib.py window-grid limitation:
adding a 2nd row wipes the previously-added row's width/height to 0.00,
in both same-session and fresh-session-per-window attempts. Not fixable
via current Playwright automation. Restored the assessment to its original
single South 10.06 m^2 row (no PDFs re-downloaded, no worksheet change).

Separately confirmed our own engine already models this cert's windows
per-orientation correctly from gov-API sap_windows via
solar_gains.py's ORIENTATION_BY_SAP10_CODE cascade -- this is an Elmhurst
build-tooling ceiling, not an engine or mapper bug. sap_score=53 remains
unchanged; no calculator/mapper code was touched. Full accuracy suite
re-run clean (66 passed/67 skipped/1 xfailed + corpus test passed).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:38:10 +00:00
Jun-te Kim
e91e0fa33e Fix cylinder_size/boiler_flue_type input errors for UPRN 100010086084 (SAP-15.0)
Both flagged mismatches were Elmhurst input errors (same silent-stale-value
contamination class as the earlier chimneys/wall-thickness bugs), not
parser or calculator bugs:

- cylinder_size: build_100010086084.py's water_heating() selected
  DropDownListCylinderSize by raw value "2", but this DOM's option values
  ARE their visible litre-band text (no "2" among them) — Playwright
  silently no-ops on a non-matching value, leaving a prior cert's "Medium
  (131-170L)" selection in place. Fixed to match by text ("Normal"), and
  added the missing mapper dict entries (Normal/Large litre-suffixed
  labels) to _ELMHURST_CYLINDER_SIZE_LABEL_TO_SAP10 (a real mapper-coverage
  gap — the calculator raises UnmappedElmhurstLabel rather than silently
  mis-mapping).

- boiler_flue_type: the boiler-code search dialog's combined "Balanced/Open
  Flue" Table 4b category doesn't drive the separate, independently
  selectable RadioButtonListFlueType field, which was left at an inherited
  "Balanced" from a prior cert. Fixed space_heating() to explicitly select
  "Open" to match the lodged gov-API code. This field isn't consumed by
  Sap10Calculator (ML/generator-only), so it had zero effect on the SAP
  score.

Re-downloaded elmhurst_summary.pdf/elmhurst_worksheet.pdf after the fixes
(Recommendations page confirmed clean). Elmhurst-PDF-inputs path moved
46->47 SAP from the cylinder-volume correction; gov-API SAP (53) and
Elmhurst's own worksheet (51) are unchanged. Full accuracy suites re-run
clean (67 passed, 67 skipped, 1 xfailed, same as before).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:11:41 +00:00
Jun-te Kim
798d19d6ff Fix contaminated Elmhurst ground truth for UPRN 100010086084 (SAP-15.0)
The Elmhurst rebuild for this cert had two carryover bugs from the shared
Playwright session: TextBoxOpenChimneys silently inherited "2" from a prior
cert's build (this cert's register lodges open_fireplaces_count=0, which
the gov-API mapper already reads correctly), and wall thickness inherited
a stale 280mm. Also fixed a real bug in the space_heating() PCDB-ref-clearing
logic: input_value() returns the string "0" when already cleared, which is
truthy in Python, causing a spurious navigate-away that broke the next
E.goto() call.

Rebuilt cleanly (chimneys=0, wall thickness=220mm per RdSAP convention for
unrecorded solid-wall thickness, since CheckBoxWallThicknessUnknown does not
persist via Playwright in this tool version). Elmhurst's own worksheet score
moves from a contaminated 46/48 to 51, closing the gap against this engine's
53-on-gov-API-inputs from ~5-7pt to ~2pt. No mapper.py change was needed --
the gov-API mapper's open_chimneys_count=0 was correct all along.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 08:36:03 +00:00
Jun-te Kim
283b311fcd Real Elmhurst RdSAP10 ground truth for one SAP-Schema-15.0 cert
Built UPRN 100010086084 (the largest gov-API-vs-lodged outlier from the
20-cert batch) in Elmhurst's accredited RdSAP10 tool to get real ground
truth, per feedback that lodged rating isn't a valid comparison target.

Elmhurst worksheet: SAP 46-48 (orientation-dependent), vs this engine's
53 on gov-API inputs -- a real ~5-7pt residual gap. Ruled out with
direct empirical tests: total_floor_area, missing party_wall_length,
region/climate (SAP rating always uses UK-average weather per Appendix
U -- confirmed inert), boiler/secondary efficiency (exact match, 66%/
63% both sides). Confirmed real but NOT blind-fixed (need more than one
cert's evidence, and a wall-U-value patch tested the wrong direction in
isolation): a wall-thickness-unknown U-value fallback mismatch (this
engine 1.70, Elmhurst's own "unknown" resolution 1.40) and a window
U-value divergence (1.85 vs 2.52 W/m2K for the same nominal glazing
pick). Single-window orientation confirmed a ~2pt partial contributor.

Also fixes a small, separate, evidenced gap the build surfaced: the
Elmhurst summary parser didn't recognise the live tool's "Medium
(131-170L)" cylinder-size label (only the bare "Medium").

Full write-up is in the RealCertExpectation comment for this cert in
test_real_cert_sap_accuracy.py and the worklist. Residual gap is
intentionally left open for follow-up, not force-closed.
2026-07-09 22:31:01 +00:00
Jun-te Kim
f0bd5b9674
Merge pull request #1503 from Hestia-Homes/worktree-rdsap-glazing-bug
Derive multiple_glazed_proportion for 16.x certs with explicit glazing wording
2026-07-08 15:06:33 +01:00
Jun-te Kim
95322ac4ad Add Elmhurst build script + validated result for uprn 100021969385
Built the property-753950 cert (worklist P4, PR #1503) in the live RdSAP-10
Online tool via Playwright: SAP 44 (E), vs our engine's 42 and the lodged
2014 cert's 45 — a normal RdSAP-2012->SAP-10.2 recalculation spread, not a
defect surfaced by the multiple_glazed_proportion fix.

Also surfaced (and documented as a caveat, not fixed here) a pre-existing
SAP-16.2 gap: the cert lodges party_wall_length_m=0 on both floors despite
being semi-detached, which Elmhurst's validation rejects and this PR's
engine change doesn't touch.
2026-07-08 12:38:26 +00:00
Daniel Roth
8b7d32433e
Merge pull request #1492 from Hestia-Homes/feature/abri-api-integration
Abri API integration: abandon job
2026-07-08 10:53:21 +01:00
Jun-te Kim
dbcdf29bd9 refactor(address2uprn): name the match/decision return types; rename helper
Address PR review (dancafc):
- introduce UprnMatch NamedTuple (datatypes/address_match.py) for the
  (uprn, address, lexiscore, certificate_number) return, replacing the bare
  4-tuple in get_uprn_from_epc_df / get_uprn_from_historic_epc /
  HistoricEpcResolver.resolve_uprn. Tuple-compatible, so unpacking is unchanged.
- rename get_uprn_with_epc_df -> get_uprn_from_epc_df (+ callers).
- type resolve_group_ambiguity via a GroupDecision NamedTuple and trim its
  docstring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:00:00 +00:00
Daniel Roth
70fb6d5735 Repair the Abri trigger-builder import after its move into HubspotDealDiffer
The move in 3934e2d3 left the trigger-builder test and local smoke script
importing the deleted etl.hubspot.abri_flow_triggers module; point them at
HubspotDealDiffer.check_abri_triggers_and_construct_message so they collect
and run again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:52:55 +00:00
Daniel Roth
3934e2d359 move trigger check to HubspotDealDiffer 2026-07-07 13:15:40 +00:00
Daniel Roth
d9b441962f Name the Abri trigger builder for its None-or-message contract 🟪
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 13:02:25 +00:00
Daniel Roth
7ad0dc0595 Merge branch 'main' into feature/abri-api-integration 2026-07-07 12:46:17 +00:00
Daniel Roth
a3985389ab The deal row names the job number client_booking_reference, matching HubSpot and the schema 🟪
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 12:43:40 +00:00
Daniel Roth
55baddfd9e A local smoke drives HubSpot-to-write-back LogJob with only the Abri edge stubbed 🟩
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:47:03 +00:00
Daniel Roth
45bb3a7e61 A manual smoke script proves log then amend end-to-end against Abri UAT 🟩
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 10:30:08 +00:00
Daniel Roth
9bae8df6ea A changed booking amends the deal's OpenHousing appointment 🟩
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 10:01:01 +00:00
Jun-te Kim
bc1cca77db
Merge pull request #1356 from Hestia-Homes/feature/historic-epc-repository
Historic EPC repository: DDD port + resolver for address→UPRN
2026-07-07 10:56:33 +01:00
Daniel Roth
a5868cc2e0 One AbriOrchestrator runs every Abri flow for a deal 🟪
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:26:48 +00:00
Daniel Roth
6335796d6e
Merge pull request #1471 from Hestia-Homes/feature/abri-api-integration
Abri OpenHousing DomnaRelay — GetTenantData vertical (tenancy signatories to HubSpot)
2026-07-06 16:15:36 +01:00
Daniel Roth
859a7ec49a change fake contact details 2026-07-06 14:34:39 +00:00
Daniel Roth
de2a6d1d79 Add manual smoke script for the Abri tenant-contact HubSpot writes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 14:19:05 +00:00
Khalim Conn-Kowlessar
71bdd080c0 Expired-pairs integration gate: frozen single-file corpus + ratcheting floors 🟩
30 pairs (28 deterministically scoreable) from the 2,000-postcode sweep,
frozen as ONE anonymised raw-payload JSON (pairs + cohorts + actuals — a
thousand per-cert files would drown the PR diff). The gate replays the
whole conditioning path offline — mapper, conditioning, selection,
synthesis, comparison — in ~9s; floors are the measured values, tighten-
only. comparable_from_payload is extracted from the corpus loader so both
fixture formats share one payload->ComparableProperty path; the builder
(build_expired_pairs_corpus.py) refreezes from the raw-JSON disk cache.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 13:05:18 +00:00
Khalim Conn-Kowlessar
817c00720e The historic roof description conditions the cohort by form family 🟩
roof_construction codes group by FORM (empirical: 1=Flat 98%, 4/5/8=
Pitched 88-99%, 3=dwelling-above 100% over 7,974 certs; 7/9=premises-
above per #1452), so the filter matches families — an exact-code filter
would wrongly drop pitched neighbours lodged as 5/8. Historic prefixes
map to the same families; roof rooms and thatch stay unconditioned.
Harness ladder replay and telemetry mirror the new filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 12:05:56 +00:00
Khalim Conn-Kowlessar
13b75bcb0a Raw-JSON EPC disk cache + roof_construction co-occurrence sweep 🟩
JsonCachingEpcClient caches at the raw layer (cert payloads verbatim,
search rows as JSON) so warm re-runs replay through retry+mapper+parsing
in minutes AND the cache doubles as integration-test fixture material —
the ADR-0030 corpus pattern (anonymised raw JSON through the mapper),
which pickled domain objects could never be. Wired into the pairs
harness (--cache-dir). roof_construction_code_sweep pins the RdSAP roof
code table the basement-code-6 way: single-building-part certs only,
code x description-prefix purity table. Also fixes the tfa telemetry key
rename that left the agreement row empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:35:51 +00:00
Jun-te Kim
c238a0e6a0
Merge pull request #1449 from Hestia-Homes/feat/sap-corpus-campaign
fix(rdsap): RdSAP 10 Table 13 200/280mm solid-brick wall boundary
2026-07-06 12:25:17 +01:00
Khalim Conn-Kowlessar
38661c6bd7 Age band conditions within one band; the floor-area band widens to ±20% 🟩
Evidence (439-pair harness, PR #1466): historic-vs-new age band agrees
52% exactly but 90% within one band (assessors re-band, skewing newer);
TFA agrees 45% within ±5% but 82% within ±20%. Equality/±5% steered the
cohort toward stale values where they engaged and relaxed everywhere
else. Band definitions are public so the harness's ladder replay shares
one source of truth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:08:03 +00:00
Khalim Conn-Kowlessar
2903a069ea Pairs harness survives unmappable certs and appends telemetry incrementally 🟩
The 2000-postcode sweep died at ~884 on a strict-raising RdSAP-17.1 cert
(missing multiple_glazed_proportion) inside the pair-check, losing the
whole run's output. get_by_uprn and the cohort fetch now skip-and-log per
item; telemetry rows append as produced and carry raw values (age band,
TFA, fuel text) so band-width questions are answerable post hoc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:01:57 +00:00
Khalim Conn-Kowlessar
ee5bb6c4f2 Pairs harness telemetry: filter engagement + historic-vs-new agreement 🟩
Per pair, replay the age->fuel->TFA conditioning ladder over the plain
arm's cohort to record ENGAGED vs RELAXED per filter, and record whether
each historic stable attribute still agrees with the newly lodged cert
(the direct staleness measurement). Emitted as JSONL (--telemetry) and
aggregated into two diagnosis tables appended to the report.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 09:24:46 +00:00
Khalim Conn-Kowlessar
1d83637afa Pairs harness reports the full Component Accuracy suite per arm 🟩
Classification hit-rates for every compare_prediction component, all five
numeric residuals, and the secondary calculator-floored SAP residual
(calc(predicted) − lodged), plain vs conditioned side by side — the same
metric shape as the prediction-corpus gate (ADR-0030). Pair-check now
precedes the cohort fetch so a national postcode sweep only pays the
expensive search-by-postcode for shards that actually hold a pair.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 09:05:59 +00:00